diff options
885 files changed, 28141 insertions, 18248 deletions
diff --git a/.github/actions/godot-build/action.yml b/.github/actions/godot-build/action.yml index 377480b123..0a0899db78 100644 --- a/.github/actions/godot-build/action.yml +++ b/.github/actions/godot-build/action.yml @@ -31,6 +31,18 @@ runs: SCONS_CACHE_LIMIT: ${{ inputs.scons-cache-limit }} run: | echo "Building with flags:" platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }} - if [ "${{ inputs.target }}" != "editor" ]; then rm -rf editor; fi # Ensure we don't include editor code. + + if [ "${{ inputs.target }}" != "editor" ]; then + # Ensure we don't include editor code in export template builds. + rm -rf editor + fi + + if [ "${{ github.event.number }}" != "" ]; then + # Set build identifier with pull request number if available. This is displayed throughout the editor. + export BUILD_NAME="gh-${{ github.event.number }}" + else + export BUILD_NAME="gh" + fi + scons platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }} ls -l bin/ diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index 4b8a246df0..c549761beb 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -483,7 +483,7 @@ License: Expat Files: ./thirdparty/thorvg/ Comment: ThorVG -Copyright: 2020-2023, The ThorVG Project +Copyright: 2020-2024, The ThorVG Project License: Expat Files: ./thirdparty/tinyexr/ diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 56e041be1b..90e2e27320 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1393,8 +1393,8 @@ ProjectSettings::ProjectSettings() { // - Have a 16:9 aspect ratio, // - Have both dimensions divisible by 8 to better play along with video recording, // - Be displayable correctly in windowed mode on a 1366×768 display (tested on Windows 10 with default settings). - GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/viewport_width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 1152); // 8K resolution - GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 648); // 8K resolution + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/viewport_width", PROPERTY_HINT_RANGE, "1,7680,1,or_greater"), 1152); // 8K resolution + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "1,4320,1,or_greater"), 648); // 8K resolution GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen"), 0); @@ -1410,8 +1410,8 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("display/window/size/extend_to_title", false); GLOBAL_DEF("display/window/size/no_focus", false); - GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 0); // 8K resolution - GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution + GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "1,7680,1,or_greater"), 0); // 8K resolution + GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "1,4320,1,or_greater"), 0); // 8K resolution GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true); GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor", false); @@ -1462,7 +1462,6 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("debug/settings/crash_handler/message.editor", String("Please include this when reporting the bug on: https://github.com/godotengine/godot/issues")); GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/occlusion_culling/bvh_build_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), 2); - GLOBAL_DEF(PropertyInfo(Variant::INT, "memory/limits/multithreaded_server/rid_pool_prealloc", PROPERTY_HINT_RANGE, "0,500,1"), 60); // No negative and limit to 500 due to crashes. GLOBAL_DEF_RST("internationalization/rendering/force_right_to_left_layout_direction", false); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "internationalization/rendering/root_node_layout_direction", PROPERTY_HINT_ENUM, "Based on Application Locale,Left-to-Right,Right-to-Left,Based on System Locale"), 0); @@ -1471,11 +1470,11 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_BASIC("gui/common/snap_controls_to_pixels", true); GLOBAL_DEF_BASIC("gui/fonts/dynamic_fonts/use_oversampling", true); - 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/pipeline_cache/save_chunk_size_mb", 3.0); - GLOBAL_DEF("rendering/rendering_device/vulkan/max_descriptors_per_pool", 64); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/block_size_kb", PROPERTY_HINT_RANGE, "4,2048,1,or_greater"), 256); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/max_size_mb", PROPERTY_HINT_RANGE, "1,1024,1,or_greater"), 128); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/texture_upload_region_size_px", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64); + GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/rendering_device/pipeline_cache/save_chunk_size_mb", PROPERTY_HINT_RANGE, "0.000001,64.0,0.001,or_greater"), 3.0); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/vulkan/max_descriptors_per_pool", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64); GLOBAL_DEF_RST("rendering/rendering_device/d3d12/max_resource_descriptors_per_frame", 16384); custom_prop_info["rendering/rendering_device/d3d12/max_resource_descriptors_per_frame"] = PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/max_resource_descriptors_per_frame", PROPERTY_HINT_RANGE, "512,262144"); @@ -1484,6 +1483,8 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_RST("rendering/rendering_device/d3d12/max_misc_descriptors_per_frame", 512); custom_prop_info["rendering/rendering_device/d3d12/max_misc_descriptors_per_frame"] = PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/max_misc_descriptors_per_frame", PROPERTY_HINT_RANGE, "32,4096"); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/agility_sdk_version"), 610); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), 1); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM, "Disable,Enable,Mirror"), 0); diff --git a/core/core_bind.cpp b/core/core_bind.cpp index d91c659d1e..e5363f9acc 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -1040,6 +1040,10 @@ Vector<Vector3> Geometry3D::clip_polygon(const Vector<Vector3> &p_points, const return ::Geometry3D::clip_polygon(p_points, p_plane); } +Vector<int32_t> Geometry3D::tetrahedralize_delaunay(const Vector<Vector3> &p_points) { + return ::Geometry3D::tetrahedralize_delaunay(p_points); +} + void Geometry3D::_bind_methods() { ClassDB::bind_method(D_METHOD("compute_convex_mesh_points", "planes"), &Geometry3D::compute_convex_mesh_points); ClassDB::bind_method(D_METHOD("build_box_planes", "extents"), &Geometry3D::build_box_planes); @@ -1061,6 +1065,7 @@ void Geometry3D::_bind_methods() { ClassDB::bind_method(D_METHOD("segment_intersects_convex", "from", "to", "planes"), &Geometry3D::segment_intersects_convex); ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &Geometry3D::clip_polygon); + ClassDB::bind_method(D_METHOD("tetrahedralize_delaunay", "points"), &Geometry3D::tetrahedralize_delaunay); } ////// Marshalls ////// @@ -1370,11 +1375,11 @@ Variant ClassDB::instantiate(const StringName &p_class) const { } } -bool ClassDB::class_has_signal(StringName p_class, StringName p_signal) const { +bool ClassDB::class_has_signal(const StringName &p_class, const StringName &p_signal) const { return ::ClassDB::has_signal(p_class, p_signal); } -Dictionary ClassDB::class_get_signal(StringName p_class, StringName p_signal) const { +Dictionary ClassDB::class_get_signal(const StringName &p_class, const StringName &p_signal) const { MethodInfo signal; if (::ClassDB::get_signal(p_class, p_signal, &signal)) { return signal.operator Dictionary(); @@ -1383,7 +1388,7 @@ Dictionary ClassDB::class_get_signal(StringName p_class, StringName p_signal) co } } -TypedArray<Dictionary> ClassDB::class_get_signal_list(StringName p_class, bool p_no_inheritance) const { +TypedArray<Dictionary> ClassDB::class_get_signal_list(const StringName &p_class, bool p_no_inheritance) const { List<MethodInfo> signals; ::ClassDB::get_signal_list(p_class, &signals, p_no_inheritance); TypedArray<Dictionary> ret; @@ -1395,7 +1400,7 @@ TypedArray<Dictionary> ClassDB::class_get_signal_list(StringName p_class, bool p return ret; } -TypedArray<Dictionary> ClassDB::class_get_property_list(StringName p_class, bool p_no_inheritance) const { +TypedArray<Dictionary> ClassDB::class_get_property_list(const StringName &p_class, bool p_no_inheritance) const { List<PropertyInfo> plist; ::ClassDB::get_property_list(p_class, &plist, p_no_inheritance); TypedArray<Dictionary> ret; @@ -1423,11 +1428,11 @@ Error ClassDB::class_set_property(Object *p_object, const StringName &p_property return OK; } -bool ClassDB::class_has_method(StringName p_class, StringName p_method, bool p_no_inheritance) const { +bool ClassDB::class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance) const { return ::ClassDB::has_method(p_class, p_method, p_no_inheritance); } -TypedArray<Dictionary> ClassDB::class_get_method_list(StringName p_class, bool p_no_inheritance) const { +TypedArray<Dictionary> ClassDB::class_get_method_list(const StringName &p_class, bool p_no_inheritance) const { List<MethodInfo> methods; ::ClassDB::get_method_list(p_class, &methods, p_no_inheritance); TypedArray<Dictionary> ret; @@ -1508,7 +1513,7 @@ StringName ClassDB::class_get_integer_constant_enum(const StringName &p_class, c return ::ClassDB::get_integer_constant_enum(p_class, p_name, p_no_inheritance); } -bool ClassDB::is_class_enabled(StringName p_class) const { +bool ClassDB::is_class_enabled(const StringName &p_class) const { return ::ClassDB::is_class_enabled(p_class); } @@ -1718,6 +1723,16 @@ bool Engine::is_printing_error_messages() const { return ::Engine::get_singleton()->is_printing_error_messages(); } +void Engine::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { + String pf = p_function; + if (p_idx == 0 && (pf == "has_singleton" || pf == "get_singleton" || pf == "unregister_singleton")) { + for (const String &E : get_singleton_list()) { + r_options->push_back(E.quote()); + } + } + Object::get_argument_options(p_function, p_idx, r_options); +} + void Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("set_physics_ticks_per_second", "physics_ticks_per_second"), &Engine::set_physics_ticks_per_second); ClassDB::bind_method(D_METHOD("get_physics_ticks_per_second"), &Engine::get_physics_ticks_per_second); diff --git a/core/core_bind.h b/core/core_bind.h index 715e26cf23..94d95f2ce9 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -337,6 +337,7 @@ public: Vector<Vector3> segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const TypedArray<Plane> &p_planes); Vector<Vector3> clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane); + Vector<int32_t> tetrahedralize_delaunay(const Vector<Vector3> &p_points); Geometry3D() { singleton = this; } }; @@ -434,17 +435,17 @@ public: bool can_instantiate(const StringName &p_class) const; Variant instantiate(const StringName &p_class) const; - bool class_has_signal(StringName p_class, StringName p_signal) const; - Dictionary class_get_signal(StringName p_class, StringName p_signal) const; - TypedArray<Dictionary> class_get_signal_list(StringName p_class, bool p_no_inheritance = false) const; + bool class_has_signal(const StringName &p_class, const StringName &p_signal) const; + Dictionary class_get_signal(const StringName &p_class, const StringName &p_signal) const; + TypedArray<Dictionary> class_get_signal_list(const StringName &p_class, bool p_no_inheritance = false) const; - TypedArray<Dictionary> class_get_property_list(StringName p_class, bool p_no_inheritance = false) const; + TypedArray<Dictionary> class_get_property_list(const StringName &p_class, bool p_no_inheritance = false) const; Variant class_get_property(Object *p_object, const StringName &p_property) const; Error class_set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const; - bool class_has_method(StringName p_class, StringName p_method, bool p_no_inheritance = false) const; + bool class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const; - TypedArray<Dictionary> class_get_method_list(StringName p_class, bool p_no_inheritance = false) const; + TypedArray<Dictionary> class_get_method_list(const StringName &p_class, bool p_no_inheritance = false) const; PackedStringArray class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const; bool class_has_integer_constant(const StringName &p_class, const StringName &p_name) const; @@ -455,7 +456,7 @@ public: PackedStringArray class_get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const; StringName class_get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const; - bool is_class_enabled(StringName p_class) const; + bool is_class_enabled(const StringName &p_class) const; ClassDB() {} ~ClassDB() {} @@ -527,6 +528,8 @@ public: void set_print_error_messages(bool p_enabled); bool is_printing_error_messages() const; + virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; + Engine() { singleton = this; } }; diff --git a/core/core_constants.cpp b/core/core_constants.cpp index 2f70fdf219..3b96fc20c6 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -845,7 +845,7 @@ bool CoreConstants::is_global_enum(const StringName &p_enum) { return _global_enums.has(p_enum); } -void CoreConstants::get_enum_values(StringName p_enum, HashMap<StringName, int64_t> *p_values) { +void CoreConstants::get_enum_values(const StringName &p_enum, HashMap<StringName, int64_t> *p_values) { ERR_FAIL_NULL_MSG(p_values, "Trying to get enum values with null map."); ERR_FAIL_COND_MSG(!_global_enums.has(p_enum), "Trying to get values of non-existing enum."); for (const _CoreConstant &constant : _global_enums[p_enum]) { diff --git a/core/core_constants.h b/core/core_constants.h index 51842490c8..82d626c749 100644 --- a/core/core_constants.h +++ b/core/core_constants.h @@ -45,7 +45,7 @@ public: static bool is_global_constant(const StringName &p_name); static int get_global_constant_index(const StringName &p_name); static bool is_global_enum(const StringName &p_enum); - static void get_enum_values(StringName p_enum, HashMap<StringName, int64_t> *p_values); + static void get_enum_values(const StringName &p_enum, HashMap<StringName, int64_t> *p_values); }; #endif // CORE_CONSTANTS_H diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp index 32dc060aa2..0cce44d02f 100644 --- a/core/debugger/engine_debugger.cpp +++ b/core/debugger/engine_debugger.cpp @@ -162,7 +162,7 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, Ve singleton_script_debugger->set_skip_breakpoints(p_skip_breakpoints); for (int i = 0; i < p_breakpoints.size(); i++) { - String bp = p_breakpoints[i]; + const String &bp = p_breakpoints[i]; int sp = bp.rfind(":"); ERR_CONTINUE_MSG(sp == -1, "Invalid breakpoint: '" + bp + "', expected file:line format."); diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index 2bac1f6592..ce01531b5c 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -666,12 +666,12 @@ void GDExtension::_get_library_path(GDExtensionClassLibraryPtr p_library, GDExte HashMap<StringName, GDExtensionInterfaceFunctionPtr> GDExtension::gdextension_interface_functions; -void GDExtension::register_interface_function(StringName p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) { +void GDExtension::register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) { ERR_FAIL_COND_MSG(gdextension_interface_functions.has(p_function_name), "Attempt to register interface function '" + p_function_name + "', which appears to be already registered."); gdextension_interface_functions.insert(p_function_name, p_function_pointer); } -GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(StringName p_function_name) { +GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(const StringName &p_function_name) { GDExtensionInterfaceFunctionPtr *function = gdextension_interface_functions.getptr(p_function_name); ERR_FAIL_NULL_V_MSG(function, nullptr, "Attempt to get non-existent interface function: " + String(p_function_name) + "."); return *function; @@ -715,10 +715,8 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb #endif Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, true, &library_path); - if (err != OK) { - ERR_PRINT("GDExtension dynamic library not found: " + abs_path); - return err; - } + ERR_FAIL_COND_V_MSG(err == ERR_FILE_NOT_FOUND, err, "GDExtension dynamic library not found: " + abs_path); + ERR_FAIL_COND_V_MSG(err != OK, err, "Can't open GDExtension dynamic library: " + abs_path); #if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) // If we copied the file, let's change the library path to point at the original, diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index 0d20b8e50c..0b39581751 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -154,8 +154,8 @@ public: void initialize_library(InitializationLevel p_level); void deinitialize_library(InitializationLevel p_level); - static void register_interface_function(StringName p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer); - static GDExtensionInterfaceFunctionPtr get_interface_function(StringName p_function_name); + static void register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer); + static GDExtensionInterfaceFunctionPtr get_interface_function(const StringName &p_function_name); static void initialize_gdextensions(); static void finalize_gdextensions(); diff --git a/core/input/input.cpp b/core/input/input.cpp index 8f976cbaa3..2ba4b1d1e8 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -198,6 +198,7 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S r_options->push_back(name.quote()); } } + Object::get_argument_options(p_function, p_idx, r_options); } void Input::VelocityTrack::update(const Vector2 &p_delta_p) { @@ -1518,7 +1519,7 @@ void Input::add_joy_mapping(String p_mapping, bool p_update_existing) { parse_mapping(p_mapping); if (p_update_existing) { Vector<String> entry = p_mapping.split(","); - String uid = entry[0]; + const String &uid = entry[0]; for (KeyValue<int, Joypad> &E : joy_names) { Joypad &joy = E.value; if (joy.uid == uid) { diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 78b9ada884..70041ecfd6 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -754,7 +754,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins_with_featur String fullname = E.key; Vector<String> split = fullname.split("."); - String name = split[0]; + const String &name = split[0]; String override_for = split.size() > 1 ? split[1] : String(); if (!override_for.is_empty() && OS::get_singleton()->has_feature(override_for)) { @@ -766,7 +766,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins_with_featur String fullname = E.key; Vector<String> split = fullname.split("."); - String name = split[0]; + const String &name = split[0]; String override_for = split.size() > 1 ? split[1] : String(); if (builtins_with_overrides.has(name) && override_for.is_empty()) { diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 265d9ef56c..5a4d6dd099 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -491,7 +491,7 @@ PackedData::PackedDir *DirAccessPack::_find_dir(String p_dir) { } for (int i = 0; i < paths.size(); i++) { - String p = paths[i]; + const String &p = paths[i]; if (p == ".") { continue; } else if (p == "..") { diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 09505ea05d..833fd1adc3 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -73,7 +73,7 @@ String HTTPClient::query_string_from_dict(const Dictionary &p_dict) { Array keys = p_dict.keys(); for (int i = 0; i < keys.size(); ++i) { String encoded_key = String(keys[i]).uri_encode(); - Variant value = p_dict[keys[i]]; + const Variant &value = p_dict[keys[i]]; switch (value.get_type()) { case Variant::ARRAY: { // Repeat the key with every values diff --git a/core/io/image.cpp b/core/io/image.cpp index c72064e4f7..9aa7c9794a 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -3013,6 +3013,7 @@ void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) { } ImageMemLoadFunc Image::_png_mem_loader_func = nullptr; +ImageMemLoadFunc Image::_png_mem_unpacker_func = nullptr; ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr; ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr; ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr; diff --git a/core/io/image.h b/core/io/image.h index a21d05187b..be308b0ac1 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -145,6 +145,7 @@ public: }; static ImageMemLoadFunc _png_mem_loader_func; + static ImageMemLoadFunc _png_mem_unpacker_func; static ImageMemLoadFunc _jpg_mem_loader_func; static ImageMemLoadFunc _webp_mem_loader_func; static ImageMemLoadFunc _tga_mem_loader_func; @@ -312,8 +313,8 @@ public: Error save_jpg(const String &p_path, float p_quality = 0.75) const; Vector<uint8_t> save_png_to_buffer() const; Vector<uint8_t> save_jpg_to_buffer(float p_quality = 0.75) const; - Vector<uint8_t> save_exr_to_buffer(bool p_grayscale) const; - Error save_exr(const String &p_path, bool p_grayscale) const; + Vector<uint8_t> save_exr_to_buffer(bool p_grayscale = false) const; + Error save_exr(const String &p_path, bool p_grayscale = false) const; Error save_webp(const String &p_path, const bool p_lossy = false, const float p_quality = 0.75f) const; Vector<uint8_t> save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) const; diff --git a/platform/macos/export/plist.cpp b/core/io/plist.cpp index f494c58fc9..86737609bf 100644 --- a/platform/macos/export/plist.cpp +++ b/core/io/plist.cpp @@ -448,7 +448,9 @@ PList::PList() { } PList::PList(const String &p_string) { - load_string(p_string); + String err_str; + bool ok = load_string(p_string, err_str); + ERR_FAIL_COND_MSG(!ok, "PList: " + err_str); } uint64_t PList::read_bplist_var_size_int(Ref<FileAccess> p_file, uint8_t p_size) { @@ -642,11 +644,15 @@ bool PList::load_file(const String &p_filename) { String ret; ret.parse_utf8((const char *)array.ptr(), array.size()); - return load_string(ret); + String err_str; + bool ok = load_string(ret, err_str); + ERR_FAIL_COND_V_MSG(!ok, false, "PList: " + err_str); + + return true; } } -bool PList::load_string(const String &p_string) { +bool PList::load_string(const String &p_string, String &r_err_out) { root = Ref<PListNode>(); int pos = 0; @@ -657,14 +663,16 @@ bool PList::load_string(const String &p_string) { while (pos >= 0) { int open_token_s = p_string.find("<", pos); if (open_token_s == -1) { - ERR_FAIL_V_MSG(false, "PList: Unexpected end of data. No tags found."); + r_err_out = "Unexpected end of data. No tags found."; + return false; } int open_token_e = p_string.find(">", open_token_s); pos = open_token_e; String token = p_string.substr(open_token_s + 1, open_token_e - open_token_s - 1); if (token.is_empty()) { - ERR_FAIL_V_MSG(false, "PList: Invalid token name."); + r_err_out = "Invalid token name."; + return false; } String value; if (token[0] == '?' || token[0] == '!') { // Skip <?xml ... ?> and <!DOCTYPE ... > @@ -684,7 +692,8 @@ bool PList::load_string(const String &p_string) { } if (!in_plist) { - ERR_FAIL_V_MSG(false, "PList: Node outside of <plist> tag."); + r_err_out = "Node outside of <plist> tag."; + return false; } if (token == "dict") { @@ -693,13 +702,15 @@ bool PList::load_string(const String &p_string) { Ref<PListNode> dict = PListNode::new_dict(); dict->data_type = PList::PLNodeType::PL_NODE_TYPE_DICT; if (!stack.back()->get()->push_subnode(dict, key)) { - ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type."); + r_err_out = "Can't push subnode, invalid parent type."; + return false; } stack.push_back(dict); } else { // Add root node. if (!root.is_null()) { - ERR_FAIL_V_MSG(false, "PList: Root node already set."); + r_err_out = "Root node already set."; + return false; } Ref<PListNode> dict = PListNode::new_dict(); stack.push_back(dict); @@ -711,7 +722,8 @@ bool PList::load_string(const String &p_string) { if (token == "/dict") { // Exit current dict. if (stack.is_empty() || stack.back()->get()->data_type != PList::PLNodeType::PL_NODE_TYPE_DICT) { - ERR_FAIL_V_MSG(false, "PList: Mismatched </dict> tag."); + r_err_out = "Mismatched </dict> tag."; + return false; } stack.pop_back(); continue; @@ -722,13 +734,15 @@ bool PList::load_string(const String &p_string) { // Add subnode end enter it. Ref<PListNode> arr = PListNode::new_array(); if (!stack.back()->get()->push_subnode(arr, key)) { - ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type."); + r_err_out = "Can't push subnode, invalid parent type."; + return false; } stack.push_back(arr); } else { // Add root node. if (!root.is_null()) { - ERR_FAIL_V_MSG(false, "PList: Root node already set."); + r_err_out = "Root node already set."; + return false; } Ref<PListNode> arr = PListNode::new_array(); stack.push_back(arr); @@ -740,7 +754,8 @@ bool PList::load_string(const String &p_string) { if (token == "/array") { // Exit current array. if (stack.is_empty() || stack.back()->get()->data_type != PList::PLNodeType::PL_NODE_TYPE_ARRAY) { - ERR_FAIL_V_MSG(false, "PList: Mismatched </array> tag."); + r_err_out = "Mismatched </array> tag."; + return false; } stack.pop_back(); continue; @@ -751,13 +766,15 @@ bool PList::load_string(const String &p_string) { } else { int end_token_s = p_string.find("</", pos); if (end_token_s == -1) { - ERR_FAIL_V_MSG(false, vformat("PList: Mismatched <%s> tag.", token)); + r_err_out = vformat("Mismatched <%s> tag.", token); + return false; } int end_token_e = p_string.find(">", end_token_s); pos = end_token_e; String end_token = p_string.substr(end_token_s + 2, end_token_e - end_token_s - 2); if (end_token != token) { - ERR_FAIL_V_MSG(false, vformat("PList: Mismatched <%s> and <%s> token pair.", token, end_token)); + r_err_out = vformat("Mismatched <%s> and <%s> token pair.", token, end_token); + return false; } value = p_string.substr(open_token_e + 1, end_token_s - open_token_e - 1); } @@ -780,15 +797,18 @@ bool PList::load_string(const String &p_string) { } else if (token == "date") { var = PListNode::new_date(value); } else { - ERR_FAIL_V_MSG(false, "PList: Invalid value type."); + r_err_out = vformat("Invalid value type: %s.", token); + return false; } if (stack.is_empty() || !stack.back()->get()->push_subnode(var, key)) { - ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type."); + r_err_out = "Can't push subnode, invalid parent type."; + return false; } } } if (!stack.is_empty() || !done_plist) { - ERR_FAIL_V_MSG(false, "PList: Unexpected end of data. Root node is not closed."); + r_err_out = "Unexpected end of data. Root node is not closed."; + return false; } return true; } diff --git a/platform/macos/export/plist.h b/core/io/plist.h index 28b02e4eb7..7d8b8ef0b4 100644 --- a/platform/macos/export/plist.h +++ b/core/io/plist.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef MACOS_PLIST_H -#define MACOS_PLIST_H +#ifndef PLIST_H +#define PLIST_H // Property list file format (application/x-plist) parser, property list ASN-1 serialization. @@ -75,7 +75,7 @@ public: PList(const String &p_string); bool load_file(const String &p_filename); - bool load_string(const String &p_string); + bool load_string(const String &p_string, String &r_err_out); PackedByteArray save_asn1() const; String save_text() const; @@ -125,4 +125,4 @@ public: ~PListNode() {} }; -#endif // MACOS_PLIST_H +#endif // PLIST_H diff --git a/core/io/resource.cpp b/core/io/resource.cpp index 04ecabaf27..daa57be76f 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -204,7 +204,58 @@ void Resource::reload_from_file() { copy_from(s); } -Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &remap_cache) { +void Resource::_dupe_sub_resources(Variant &r_variant, Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_remap_cache) { + switch (r_variant.get_type()) { + case Variant::ARRAY: { + Array a = r_variant; + for (int i = 0; i < a.size(); i++) { + _dupe_sub_resources(a[i], p_for_scene, p_remap_cache); + } + } break; + case Variant::DICTIONARY: { + Dictionary d = r_variant; + List<Variant> keys; + d.get_key_list(&keys); + for (Variant &k : keys) { + if (k.get_type() == Variant::OBJECT) { + // Replace in dictionary key. + Ref<Resource> sr = k; + if (sr.is_valid() && sr->is_local_to_scene()) { + if (p_remap_cache.has(sr)) { + d[p_remap_cache[sr]] = d[k]; + d.erase(k); + } else { + Ref<Resource> dupe = sr->duplicate_for_local_scene(p_for_scene, p_remap_cache); + d[dupe] = d[k]; + d.erase(k); + p_remap_cache[sr] = dupe; + } + } + } else { + _dupe_sub_resources(k, p_for_scene, p_remap_cache); + } + + _dupe_sub_resources(d[k], p_for_scene, p_remap_cache); + } + } break; + case Variant::OBJECT: { + Ref<Resource> sr = r_variant; + if (sr.is_valid() && sr->is_local_to_scene()) { + if (p_remap_cache.has(sr)) { + r_variant = p_remap_cache[sr]; + } else { + Ref<Resource> dupe = sr->duplicate_for_local_scene(p_for_scene, p_remap_cache); + r_variant = dupe; + p_remap_cache[sr] = dupe; + } + } + } break; + default: { + } + } +} + +Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_remap_cache) { List<PropertyInfo> plist; get_property_list(&plist); @@ -217,21 +268,9 @@ Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, HashMap<Ref if (!(E.usage & PROPERTY_USAGE_STORAGE)) { continue; } - Variant p = get(E.name); - if (p.get_type() == Variant::OBJECT) { - Ref<Resource> sr = p; - if (sr.is_valid()) { - if (sr->is_local_to_scene()) { - if (remap_cache.has(sr)) { - p = remap_cache[sr]; - } else { - Ref<Resource> dupe = sr->duplicate_for_local_scene(p_for_scene, remap_cache); - p = dupe; - remap_cache[sr] = dupe; - } - } - } - } + Variant p = get(E.name).duplicate(true); + + _dupe_sub_resources(p, p_for_scene, p_remap_cache); r->set(E.name, p); } @@ -239,7 +278,35 @@ Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, HashMap<Ref return r; } -void Resource::configure_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &remap_cache) { +void Resource::_find_sub_resources(const Variant &p_variant, HashSet<Ref<Resource>> &p_resources_found) { + switch (p_variant.get_type()) { + case Variant::ARRAY: { + Array a = p_variant; + for (int i = 0; i < a.size(); i++) { + _find_sub_resources(a[i], p_resources_found); + } + } break; + case Variant::DICTIONARY: { + Dictionary d = p_variant; + List<Variant> keys; + d.get_key_list(&keys); + for (const Variant &k : keys) { + _find_sub_resources(k, p_resources_found); + _find_sub_resources(d[k], p_resources_found); + } + } break; + case Variant::OBJECT: { + Ref<Resource> r = p_variant; + if (r.is_valid()) { + p_resources_found.insert(r); + } + } break; + default: { + } + } +} + +void Resource::configure_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_remap_cache) { List<PropertyInfo> plist; get_property_list(&plist); @@ -251,14 +318,15 @@ void Resource::configure_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource continue; } Variant p = get(E.name); - if (p.get_type() == Variant::OBJECT) { - Ref<Resource> sr = p; - if (sr.is_valid()) { - if (sr->is_local_to_scene()) { - if (!remap_cache.has(sr)) { - sr->configure_for_local_scene(p_for_scene, remap_cache); - remap_cache[sr] = sr; - } + + HashSet<Ref<Resource>> sub_resources; + _find_sub_resources(p, sub_resources); + + for (Ref<Resource> sr : sub_resources) { + if (sr->is_local_to_scene()) { + if (!p_remap_cache.has(sr)) { + sr->configure_for_local_scene(p_for_scene, p_remap_cache); + p_remap_cache[sr] = sr; } } } diff --git a/core/io/resource.h b/core/io/resource.h index 610c2150db..b885b773ac 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -74,6 +74,9 @@ private: SelfList<Resource> remapped_list; + void _dupe_sub_resources(Variant &r_variant, Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_remap_cache); + void _find_sub_resources(const Variant &p_variant, HashSet<Ref<Resource>> &p_resources_found); + protected: virtual void _resource_path_changed(); static void _bind_methods(); @@ -111,8 +114,8 @@ public: String get_scene_unique_id() const; virtual Ref<Resource> duplicate(bool p_subresources = false) const; - Ref<Resource> duplicate_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &remap_cache); - void configure_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &remap_cache); + Ref<Resource> duplicate_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_remap_cache); + void configure_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_remap_cache); void set_local_to_scene(bool p_enable); bool is_local_to_scene() const; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 0c7764392a..ba11d84bce 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -340,7 +340,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) { if (load_task.resource.is_valid()) { if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { - load_task.resource->set_path(load_task.local_path, load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); + load_task.resource->set_path(load_task.local_path); } else if (!load_task.local_path.is_resource_file()) { load_task.resource->set_path_cache(load_task.local_path); } @@ -361,17 +361,6 @@ void ResourceLoader::_thread_load_function(void *p_userdata) { if (_loaded_callback) { _loaded_callback(load_task.resource, load_task.local_path); } - } else if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { - Ref<Resource> existing = ResourceCache::get_ref(load_task.local_path); - if (existing.is_valid()) { - load_task.resource = existing; - load_task.status = THREAD_LOAD_LOADED; - load_task.progress = 1.0; - - if (_loaded_callback) { - _loaded_callback(load_task.resource, load_task.local_path); - } - } } thread_load_mutex.unlock(); @@ -474,7 +463,7 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path, load_task.type_hint = p_type_hint; load_task.cache_mode = p_cache_mode; load_task.use_sub_threads = p_thread_mode == LOAD_THREAD_DISTRIBUTE; - if (p_cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE) { + if (p_cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { Ref<Resource> existing = ResourceCache::get_ref(local_path); if (existing.is_valid()) { //referencing is fine @@ -641,15 +630,16 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro if (load_task.task_id != 0) { // Loading thread is in the worker pool. - load_task.awaited = true; thread_load_mutex.unlock(); Error err = WorkerThreadPool::get_singleton()->wait_for_task_completion(load_task.task_id); if (err == ERR_BUSY) { - // The WorkerThreadPool has scheduled tasks in a way that the current load depends on - // another one in a lower stack frame. Restart such load here. When the stack is eventually - // unrolled, the original load will have been notified to go on. + // The WorkerThreadPool has reported that the current task wants to await on an older one. + // That't not allowed for safety, to avoid deadlocks. Fortunately, though, in the context of + // resource loading that means that the task to wait for can be restarted here to break the + // cycle, with as much recursion into this process as needed. + // When the stack is eventually unrolled, the original load will have been notified to go on. #ifdef DEV_ENABLED - print_verbose("ResourceLoader: Load task happened to wait on another one deep in the call stack. Attempting to avoid deadlock by re-issuing the load now."); + print_verbose("ResourceLoader: Potential for deadlock detected in task dependency. Attempting to avoid it by re-issuing the load now."); #endif // CACHE_MODE_IGNORE is needed because, otherwise, the new request would just see there's // an ongoing load for that resource and wait for it again. This value forces a new load. @@ -663,6 +653,7 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro } else { DEV_ASSERT(err == OK); thread_load_mutex.lock(); + load_task.awaited = true; } } else { // Loading thread is main or user thread. diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 1c6c18b015..51ebea7f2c 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -120,9 +120,8 @@ Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, String local_path = ProjectSettings::get_singleton()->localize_path(path); - Ref<Resource> rwcopy = p_resource; if (p_flags & FLAG_CHANGE_PATH) { - rwcopy->set_path(local_path); + p_resource->set_path(local_path); } err = saver[i]->save(p_resource, path, p_flags); @@ -139,7 +138,7 @@ Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, #endif if (p_flags & FLAG_CHANGE_PATH) { - rwcopy->set_path(old_path); + p_resource->set_path(old_path); } if (save_callback && path.begins_with("res://")) { diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index f0f160940d..fb54058bd9 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -69,7 +69,7 @@ void AStar3D::add_point(int64_t p_id, const Vector3 &p_pos, real_t p_weight_scal } Vector3 AStar3D::get_point_position(int64_t p_id) const { - Point *p; + Point *p = nullptr; bool p_exists = points.lookup(p_id, p); ERR_FAIL_COND_V_MSG(!p_exists, Vector3(), vformat("Can't get point's position. Point with id: %d doesn't exist.", p_id)); @@ -77,7 +77,7 @@ Vector3 AStar3D::get_point_position(int64_t p_id) const { } void AStar3D::set_point_position(int64_t p_id, const Vector3 &p_pos) { - Point *p; + Point *p = nullptr; bool p_exists = points.lookup(p_id, p); ERR_FAIL_COND_MSG(!p_exists, vformat("Can't set point's position. Point with id: %d doesn't exist.", p_id)); @@ -85,7 +85,7 @@ void AStar3D::set_point_position(int64_t p_id, const Vector3 &p_pos) { } real_t AStar3D::get_point_weight_scale(int64_t p_id) const { - Point *p; + Point *p = nullptr; bool p_exists = points.lookup(p_id, p); ERR_FAIL_COND_V_MSG(!p_exists, 0, vformat("Can't get point's weight scale. Point with id: %d doesn't exist.", p_id)); @@ -93,7 +93,7 @@ real_t AStar3D::get_point_weight_scale(int64_t p_id) const { } void AStar3D::set_point_weight_scale(int64_t p_id, real_t p_weight_scale) { - Point *p; + Point *p = nullptr; bool p_exists = points.lookup(p_id, p); ERR_FAIL_COND_MSG(!p_exists, vformat("Can't set point's weight scale. Point with id: %d doesn't exist.", p_id)); ERR_FAIL_COND_MSG(p_weight_scale < 0.0, vformat("Can't set point's weight scale less than 0.0: %f.", p_weight_scale)); @@ -102,7 +102,7 @@ void AStar3D::set_point_weight_scale(int64_t p_id, real_t p_weight_scale) { } void AStar3D::remove_point(int64_t p_id) { - Point *p; + Point *p = nullptr; bool p_exists = points.lookup(p_id, p); ERR_FAIL_COND_MSG(!p_exists, vformat("Can't remove point. Point with id: %d doesn't exist.", p_id)); @@ -130,11 +130,11 @@ void AStar3D::remove_point(int64_t p_id) { void AStar3D::connect_points(int64_t p_id, int64_t p_with_id, bool bidirectional) { ERR_FAIL_COND_MSG(p_id == p_with_id, vformat("Can't connect point with id: %d to itself.", p_id)); - Point *a; + Point *a = nullptr; bool from_exists = points.lookup(p_id, a); ERR_FAIL_COND_MSG(!from_exists, vformat("Can't connect points. Point with id: %d doesn't exist.", p_id)); - Point *b; + Point *b = nullptr; bool to_exists = points.lookup(p_with_id, b); ERR_FAIL_COND_MSG(!to_exists, vformat("Can't connect points. Point with id: %d doesn't exist.", p_with_id)); @@ -166,11 +166,11 @@ void AStar3D::connect_points(int64_t p_id, int64_t p_with_id, bool bidirectional } void AStar3D::disconnect_points(int64_t p_id, int64_t p_with_id, bool bidirectional) { - Point *a; + Point *a = nullptr; bool a_exists = points.lookup(p_id, a); ERR_FAIL_COND_MSG(!a_exists, vformat("Can't disconnect points. Point with id: %d doesn't exist.", p_id)); - Point *b; + Point *b = nullptr; bool b_exists = points.lookup(p_with_id, b); ERR_FAIL_COND_MSG(!b_exists, vformat("Can't disconnect points. Point with id: %d doesn't exist.", p_with_id)); @@ -220,7 +220,7 @@ PackedInt64Array AStar3D::get_point_ids() { } Vector<int64_t> AStar3D::get_point_connections(int64_t p_id) { - Point *p; + Point *p = nullptr; bool p_exists = points.lookup(p_id, p); ERR_FAIL_COND_V_MSG(!p_exists, Vector<int64_t>(), vformat("Can't get point's connections. Point with id: %d doesn't exist.", p_id)); @@ -386,11 +386,11 @@ real_t AStar3D::_estimate_cost(int64_t p_from_id, int64_t p_to_id) { return scost; } - Point *from_point; + Point *from_point = nullptr; bool from_exists = points.lookup(p_from_id, from_point); ERR_FAIL_COND_V_MSG(!from_exists, 0, vformat("Can't estimate cost. Point with id: %d doesn't exist.", p_from_id)); - Point *to_point; + Point *to_point = nullptr; bool to_exists = points.lookup(p_to_id, to_point); ERR_FAIL_COND_V_MSG(!to_exists, 0, vformat("Can't estimate cost. Point with id: %d doesn't exist.", p_to_id)); @@ -403,11 +403,11 @@ real_t AStar3D::_compute_cost(int64_t p_from_id, int64_t p_to_id) { return scost; } - Point *from_point; + Point *from_point = nullptr; bool from_exists = points.lookup(p_from_id, from_point); ERR_FAIL_COND_V_MSG(!from_exists, 0, vformat("Can't compute cost. Point with id: %d doesn't exist.", p_from_id)); - Point *to_point; + Point *to_point = nullptr; bool to_exists = points.lookup(p_to_id, to_point); ERR_FAIL_COND_V_MSG(!to_exists, 0, vformat("Can't compute cost. Point with id: %d doesn't exist.", p_to_id)); @@ -415,11 +415,11 @@ real_t AStar3D::_compute_cost(int64_t p_from_id, int64_t p_to_id) { } Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id) { - Point *a; + Point *a = nullptr; bool from_exists = points.lookup(p_from_id, a); ERR_FAIL_COND_V_MSG(!from_exists, Vector<Vector3>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_from_id)); - Point *b; + Point *b = nullptr; bool to_exists = points.lookup(p_to_id, b); ERR_FAIL_COND_V_MSG(!to_exists, Vector<Vector3>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_to_id)); @@ -464,11 +464,11 @@ Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id) { } Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id) { - Point *a; + Point *a = nullptr; bool from_exists = points.lookup(p_from_id, a); ERR_FAIL_COND_V_MSG(!from_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id)); - Point *b; + Point *b = nullptr; bool to_exists = points.lookup(p_to_id, b); ERR_FAIL_COND_V_MSG(!to_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_to_id)); @@ -513,7 +513,7 @@ Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id) { } void AStar3D::set_point_disabled(int64_t p_id, bool p_disabled) { - Point *p; + Point *p = nullptr; bool p_exists = points.lookup(p_id, p); ERR_FAIL_COND_MSG(!p_exists, vformat("Can't set if point is disabled. Point with id: %d doesn't exist.", p_id)); @@ -521,7 +521,7 @@ void AStar3D::set_point_disabled(int64_t p_id, bool p_disabled) { } bool AStar3D::is_point_disabled(int64_t p_id) const { - Point *p; + Point *p = nullptr; bool p_exists = points.lookup(p_id, p); ERR_FAIL_COND_V_MSG(!p_exists, false, vformat("Can't get if point is disabled. Point with id: %d doesn't exist.", p_id)); @@ -660,11 +660,11 @@ real_t AStar2D::_estimate_cost(int64_t p_from_id, int64_t p_to_id) { return scost; } - AStar3D::Point *from_point; + AStar3D::Point *from_point = nullptr; bool from_exists = astar.points.lookup(p_from_id, from_point); ERR_FAIL_COND_V_MSG(!from_exists, 0, vformat("Can't estimate cost. Point with id: %d doesn't exist.", p_from_id)); - AStar3D::Point *to_point; + AStar3D::Point *to_point = nullptr; bool to_exists = astar.points.lookup(p_to_id, to_point); ERR_FAIL_COND_V_MSG(!to_exists, 0, vformat("Can't estimate cost. Point with id: %d doesn't exist.", p_to_id)); @@ -677,11 +677,11 @@ real_t AStar2D::_compute_cost(int64_t p_from_id, int64_t p_to_id) { return scost; } - AStar3D::Point *from_point; + AStar3D::Point *from_point = nullptr; bool from_exists = astar.points.lookup(p_from_id, from_point); ERR_FAIL_COND_V_MSG(!from_exists, 0, vformat("Can't compute cost. Point with id: %d doesn't exist.", p_from_id)); - AStar3D::Point *to_point; + AStar3D::Point *to_point = nullptr; bool to_exists = astar.points.lookup(p_to_id, to_point); ERR_FAIL_COND_V_MSG(!to_exists, 0, vformat("Can't compute cost. Point with id: %d doesn't exist.", p_to_id)); @@ -689,11 +689,11 @@ real_t AStar2D::_compute_cost(int64_t p_from_id, int64_t p_to_id) { } Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) { - AStar3D::Point *a; + AStar3D::Point *a = nullptr; bool from_exists = astar.points.lookup(p_from_id, a); ERR_FAIL_COND_V_MSG(!from_exists, Vector<Vector2>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_from_id)); - AStar3D::Point *b; + AStar3D::Point *b = nullptr; bool to_exists = astar.points.lookup(p_to_id, b); ERR_FAIL_COND_V_MSG(!to_exists, Vector<Vector2>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_to_id)); @@ -737,11 +737,11 @@ Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) { } Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id) { - AStar3D::Point *a; + AStar3D::Point *a = nullptr; bool from_exists = astar.points.lookup(p_from_id, a); ERR_FAIL_COND_V_MSG(!from_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id)); - AStar3D::Point *b; + AStar3D::Point *b = nullptr; bool to_exists = astar.points.lookup(p_to_id, b); ERR_FAIL_COND_V_MSG(!to_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_to_id)); diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp index 379d34aa2a..d17f465ab8 100644 --- a/core/math/a_star_grid_2d.cpp +++ b/core/math/a_star_grid_2d.cpp @@ -106,16 +106,45 @@ Size2 AStarGrid2D::get_cell_size() const { return cell_size; } +void AStarGrid2D::set_cell_shape(CellShape p_cell_shape) { + if (cell_shape == p_cell_shape) { + return; + } + + ERR_FAIL_INDEX(p_cell_shape, CellShape::CELL_SHAPE_MAX); + cell_shape = p_cell_shape; + dirty = true; +} + +AStarGrid2D::CellShape AStarGrid2D::get_cell_shape() const { + return cell_shape; +} + void AStarGrid2D::update() { points.clear(); const int32_t end_x = region.get_end().x; const int32_t end_y = region.get_end().y; + const Vector2 half_cell_size = cell_size / 2; for (int32_t y = region.position.y; y < end_y; y++) { LocalVector<Point> line; for (int32_t x = region.position.x; x < end_x; x++) { - line.push_back(Point(Vector2i(x, y), offset + Vector2(x, y) * cell_size)); + Vector2 v = offset; + switch (cell_shape) { + case CELL_SHAPE_ISOMETRIC_RIGHT: + v += half_cell_size + Vector2(x + y, y - x) * half_cell_size; + break; + case CELL_SHAPE_ISOMETRIC_DOWN: + v += half_cell_size + Vector2(x - y, x + y) * half_cell_size; + break; + case CELL_SHAPE_SQUARE: + v += Vector2(x, y) * cell_size; + break; + default: + break; + } + line.push_back(Point(Vector2i(x, y), v)); } points.push_back(line); } @@ -620,6 +649,8 @@ void AStarGrid2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_offset"), &AStarGrid2D::get_offset); ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &AStarGrid2D::set_cell_size); ClassDB::bind_method(D_METHOD("get_cell_size"), &AStarGrid2D::get_cell_size); + ClassDB::bind_method(D_METHOD("set_cell_shape", "cell_shape"), &AStarGrid2D::set_cell_shape); + ClassDB::bind_method(D_METHOD("get_cell_shape"), &AStarGrid2D::get_cell_shape); ClassDB::bind_method(D_METHOD("is_in_bounds", "x", "y"), &AStarGrid2D::is_in_bounds); ClassDB::bind_method(D_METHOD("is_in_boundsv", "id"), &AStarGrid2D::is_in_boundsv); ClassDB::bind_method(D_METHOD("is_dirty"), &AStarGrid2D::is_dirty); @@ -651,6 +682,7 @@ void AStarGrid2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cell_size"), "set_cell_size", "get_cell_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_shape", PROPERTY_HINT_ENUM, "Square,IsometricRight,IsometricDown"), "set_cell_shape", "get_cell_shape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "jumping_enabled"), "set_jumping_enabled", "is_jumping_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "default_compute_heuristic", PROPERTY_HINT_ENUM, "Euclidean,Manhattan,Octile,Chebyshev"), "set_default_compute_heuristic", "get_default_compute_heuristic"); @@ -668,4 +700,9 @@ void AStarGrid2D::_bind_methods() { BIND_ENUM_CONSTANT(DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE); BIND_ENUM_CONSTANT(DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES); BIND_ENUM_CONSTANT(DIAGONAL_MODE_MAX); + + BIND_ENUM_CONSTANT(CELL_SHAPE_SQUARE); + BIND_ENUM_CONSTANT(CELL_SHAPE_ISOMETRIC_RIGHT); + BIND_ENUM_CONSTANT(CELL_SHAPE_ISOMETRIC_DOWN); + BIND_ENUM_CONSTANT(CELL_SHAPE_MAX); } diff --git a/core/math/a_star_grid_2d.h b/core/math/a_star_grid_2d.h index 619551b754..69cb77dd3e 100644 --- a/core/math/a_star_grid_2d.h +++ b/core/math/a_star_grid_2d.h @@ -56,11 +56,19 @@ public: HEURISTIC_MAX, }; + enum CellShape { + CELL_SHAPE_SQUARE, + CELL_SHAPE_ISOMETRIC_RIGHT, + CELL_SHAPE_ISOMETRIC_DOWN, + CELL_SHAPE_MAX, + }; + private: Rect2i region; Vector2 offset; Size2 cell_size = Size2(1, 1); bool dirty = false; + CellShape cell_shape = CELL_SHAPE_SQUARE; bool jumping_enabled = false; DiagonalMode diagonal_mode = DIAGONAL_MODE_ALWAYS; @@ -157,6 +165,9 @@ public: void set_cell_size(const Size2 &p_cell_size); Size2 get_cell_size() const; + void set_cell_shape(CellShape p_cell_shape); + CellShape get_cell_shape() const; + void update(); bool is_in_bounds(int32_t p_x, int32_t p_y) const; @@ -193,5 +204,6 @@ public: VARIANT_ENUM_CAST(AStarGrid2D::DiagonalMode); VARIANT_ENUM_CAST(AStarGrid2D::Heuristic); +VARIANT_ENUM_CAST(AStarGrid2D::CellShape) #endif // A_STAR_GRID_2D_H diff --git a/core/math/basis.h b/core/math/basis.h index b4d971464e..e3094114e8 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -136,6 +136,8 @@ struct _NO_DISCARD_ Basis { _FORCE_INLINE_ Basis operator-(const Basis &p_matrix) const; _FORCE_INLINE_ void operator*=(const real_t p_val); _FORCE_INLINE_ Basis operator*(const real_t p_val) const; + _FORCE_INLINE_ void operator/=(const real_t p_val); + _FORCE_INLINE_ Basis operator/(const real_t p_val) const; bool is_orthogonal() const; bool is_orthonormal() const; @@ -289,6 +291,18 @@ _FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const { return ret; } +_FORCE_INLINE_ void Basis::operator/=(const real_t p_val) { + rows[0] /= p_val; + rows[1] /= p_val; + rows[2] /= p_val; +} + +_FORCE_INLINE_ Basis Basis::operator/(const real_t p_val) const { + Basis ret(*this); + ret /= p_val; + return ret; +} + Vector3 Basis::xform(const Vector3 &p_vector) const { return Vector3( rows[0].dot(p_vector), diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h index 99c554fe05..305a64e39c 100644 --- a/core/math/geometry_3d.h +++ b/core/math/geometry_3d.h @@ -31,6 +31,7 @@ #ifndef GEOMETRY_3D_H #define GEOMETRY_3D_H +#include "core/math/delaunay_3d.h" #include "core/math/face3.h" #include "core/object/object.h" #include "core/templates/local_vector.h" @@ -532,6 +533,21 @@ public: return clipped; } + static Vector<int32_t> tetrahedralize_delaunay(const Vector<Vector3> &p_points) { + Vector<Delaunay3D::OutputSimplex> tetr = Delaunay3D::tetrahedralize(p_points); + Vector<int32_t> tetrahedrons; + + tetrahedrons.resize(4 * tetr.size()); + int32_t *ptr = tetrahedrons.ptrw(); + for (int i = 0; i < tetr.size(); i++) { + *ptr++ = tetr[i].points[0]; + *ptr++ = tetr[i].points[1]; + *ptr++ = tetr[i].points[2]; + *ptr++ = tetr[i].points[3]; + } + return tetrahedrons; + } + // Create a "wrap" that encloses the given geometry. static Vector<Face3> wrap_geometry(Vector<Face3> p_array, real_t *p_error = nullptr); diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 366ccca4cb..3060f31970 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -198,6 +198,22 @@ public: #endif } + // These methods assume (p_num + p_den) doesn't overflow. + static _ALWAYS_INLINE_ int32_t division_round_up(int32_t p_num, int32_t p_den) { + int32_t offset = (p_num < 0 && p_den < 0) ? 1 : -1; + return (p_num + p_den + offset) / p_den; + } + static _ALWAYS_INLINE_ uint32_t division_round_up(uint32_t p_num, uint32_t p_den) { + return (p_num + p_den - 1) / p_den; + } + static _ALWAYS_INLINE_ int64_t division_round_up(int64_t p_num, int64_t p_den) { + int32_t offset = (p_num < 0 && p_den < 0) ? 1 : -1; + return (p_num + p_den + offset) / p_den; + } + static _ALWAYS_INLINE_ uint64_t division_round_up(uint64_t p_num, uint64_t p_den) { + return (p_num + p_den - 1) / p_den; + } + static _ALWAYS_INLINE_ bool is_finite(double p_val) { return isfinite(p_val); } static _ALWAYS_INLINE_ bool is_finite(float p_val) { return isfinite(p_val); } diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index bc4682fd90..a22d075b64 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -295,6 +295,18 @@ Transform2D Transform2D::operator*(const real_t p_val) const { return ret; } +void Transform2D::operator/=(const real_t p_val) { + columns[0] /= p_val; + columns[1] /= p_val; + columns[2] /= p_val; +} + +Transform2D Transform2D::operator/(const real_t p_val) const { + Transform2D ret(*this); + ret /= p_val; + return ret; +} + Transform2D::operator String() const { return "[X: " + columns[0].operator String() + ", Y: " + columns[1].operator String() + diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index dd1a33c5d5..9ff925f66f 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -109,6 +109,8 @@ struct _NO_DISCARD_ Transform2D { Transform2D operator*(const Transform2D &p_transform) const; void operator*=(const real_t p_val); Transform2D operator*(const real_t p_val) const; + void operator/=(const real_t p_val); + Transform2D operator/(const real_t p_val) const; Transform2D interpolate_with(const Transform2D &p_transform, const real_t p_c) const; diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp index cdc94676c9..20713349d7 100644 --- a/core/math/transform_3d.cpp +++ b/core/math/transform_3d.cpp @@ -208,6 +208,17 @@ Transform3D Transform3D::operator*(const real_t p_val) const { return ret; } +void Transform3D::operator/=(const real_t p_val) { + basis /= p_val; + origin /= p_val; +} + +Transform3D Transform3D::operator/(const real_t p_val) const { + Transform3D ret(*this); + ret /= p_val; + return ret; +} + Transform3D::operator String() const { return "[X: " + basis.get_column(0).operator String() + ", Y: " + basis.get_column(1).operator String() + diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h index 70141a3dbe..d1ec34d53f 100644 --- a/core/math/transform_3d.h +++ b/core/math/transform_3d.h @@ -104,6 +104,8 @@ struct _NO_DISCARD_ Transform3D { Transform3D operator*(const Transform3D &p_transform) const; void operator*=(const real_t p_val); Transform3D operator*(const real_t p_val) const; + void operator/=(const real_t p_val); + Transform3D operator/(const real_t p_val) const; Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const; diff --git a/core/math/vector2i.h b/core/math/vector2i.h index e6850347c3..b2c75beb4d 100644 --- a/core/math/vector2i.h +++ b/core/math/vector2i.h @@ -85,6 +85,14 @@ struct _NO_DISCARD_ Vector2i { return Vector2i(MAX(x, p_vector2i.x), MAX(y, p_vector2i.y)); } + double distance_to(const Vector2i &p_to) const { + return (p_to - *this).length(); + } + + int64_t distance_squared_to(const Vector2i &p_to) const { + return (p_to - *this).length_squared(); + } + Vector2i operator+(const Vector2i &p_v) const; void operator+=(const Vector2i &p_v); Vector2i operator-(const Vector2i &p_v) const; diff --git a/core/math/vector3i.h b/core/math/vector3i.h index 53d3829a99..5a5e9deda8 100644 --- a/core/math/vector3i.h +++ b/core/math/vector3i.h @@ -87,6 +87,9 @@ struct _NO_DISCARD_ Vector3i { Vector3i clamp(const Vector3i &p_min, const Vector3i &p_max) const; Vector3i snapped(const Vector3i &p_step) const; + _FORCE_INLINE_ double distance_to(const Vector3i &p_to) const; + _FORCE_INLINE_ int64_t distance_squared_to(const Vector3i &p_to) const; + /* Operators */ _FORCE_INLINE_ Vector3i &operator+=(const Vector3i &p_v); @@ -143,6 +146,14 @@ Vector3i Vector3i::sign() const { return Vector3i(SIGN(x), SIGN(y), SIGN(z)); } +double Vector3i::distance_to(const Vector3i &p_to) const { + return (p_to - *this).length(); +} + +int64_t Vector3i::distance_squared_to(const Vector3i &p_to) const { + return (p_to - *this).length_squared(); +} + /* Operators */ Vector3i &Vector3i::operator+=(const Vector3i &p_v) { diff --git a/core/math/vector4i.h b/core/math/vector4i.h index b815aa8e76..7d85d473d9 100644 --- a/core/math/vector4i.h +++ b/core/math/vector4i.h @@ -84,6 +84,9 @@ struct _NO_DISCARD_ Vector4i { _FORCE_INLINE_ void zero(); + _FORCE_INLINE_ double distance_to(const Vector4i &p_to) const; + _FORCE_INLINE_ int64_t distance_squared_to(const Vector4i &p_to) const; + _FORCE_INLINE_ Vector4i abs() const; _FORCE_INLINE_ Vector4i sign() const; Vector4i clamp(const Vector4i &p_min, const Vector4i &p_max) const; @@ -139,6 +142,14 @@ double Vector4i::length() const { return Math::sqrt((double)length_squared()); } +double Vector4i::distance_to(const Vector4i &p_to) const { + return (p_to - *this).length(); +} + +int64_t Vector4i::distance_squared_to(const Vector4i &p_to) const { + return (p_to - *this).length_squared(); +} + Vector4i Vector4i::abs() const { return Vector4i(Math::abs(x), Math::abs(y), Math::abs(z), Math::abs(w)); } diff --git a/core/object/object.h b/core/object/object.h index fdd1c0b267..d697f14b7e 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -235,7 +235,7 @@ struct MethodInfo { return arguments_metadata.size() > p_arg ? arguments_metadata[p_arg] : 0; } - inline bool operator==(const MethodInfo &p_method) const { return id == p_method.id; } + inline bool operator==(const MethodInfo &p_method) const { return id == p_method.id && name == p_method.name; } inline bool operator<(const MethodInfo &p_method) const { return id == p_method.id ? (name < p_method.name) : (id < p_method.id); } operator Dictionary() const; diff --git a/core/object/script_language.h b/core/object/script_language.h index 69da50f074..66106bf139 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -243,7 +243,7 @@ public: virtual void get_doc_comment_delimiters(List<String> *p_delimiters) const = 0; virtual void get_string_delimiters(List<String> *p_delimiters) const = 0; virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const { return Ref<Script>(); } - virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) { return Vector<ScriptTemplate>(); } + virtual Vector<ScriptTemplate> get_built_in_templates(const StringName &p_object) { return Vector<ScriptTemplate>(); } virtual bool is_using_templates() { return false; } virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptError> *r_errors = nullptr, List<Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const = 0; virtual String validate_path(const String &p_path) const { return ""; } diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp index 79f39cb626..be62cabe25 100644 --- a/core/object/script_language_extension.cpp +++ b/core/object/script_language_extension.cpp @@ -107,7 +107,7 @@ void ScriptLanguageExtension::_bind_methods() { GDVIRTUAL_BIND(_supports_builtin_mode); GDVIRTUAL_BIND(_supports_documentation); GDVIRTUAL_BIND(_can_inherit_from_file); - GDVIRTUAL_BIND(_find_function, "class_name", "function_name"); + GDVIRTUAL_BIND(_find_function, "function", "code"); GDVIRTUAL_BIND(_make_function, "class_name", "function_name", "function_args"); GDVIRTUAL_BIND(_open_in_external_editor, "script", "line", "column"); GDVIRTUAL_BIND(_overrides_external_editor); diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h index 852b2aebd8..8b01667519 100644 --- a/core/object/script_language_extension.h +++ b/core/object/script_language_extension.h @@ -265,7 +265,7 @@ public: GDVIRTUAL1RC(TypedArray<Dictionary>, _get_built_in_templates, StringName) - virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override { + virtual Vector<ScriptTemplate> get_built_in_templates(const StringName &p_object) override { TypedArray<Dictionary> ret; GDVIRTUAL_REQUIRED_CALL(_get_built_in_templates, p_object, ret); Vector<ScriptTemplate> stret; diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp index 631767219f..8e8a2ef06b 100644 --- a/core/object/worker_thread_pool.cpp +++ b/core/object/worker_thread_pool.cpp @@ -33,6 +33,7 @@ #include "core/object/script_language.h" #include "core/os/os.h" #include "core/os/thread_safe.h" +#include "core/templates/command_queue_mt.h" void WorkerThreadPool::Task::free_template_userdata() { ERR_FAIL_NULL(template_userdata); @@ -43,24 +44,17 @@ void WorkerThreadPool::Task::free_template_userdata() { WorkerThreadPool *WorkerThreadPool::singleton = nullptr; -void WorkerThreadPool::_process_task_queue() { - task_mutex.lock(); - Task *task = task_queue.first()->self(); - task_queue.remove(task_queue.first()); - task_mutex.unlock(); - _process_task(task); -} +thread_local CommandQueueMT *WorkerThreadPool::flushing_cmd_queue = nullptr; void WorkerThreadPool::_process_task(Task *p_task) { - bool low_priority = p_task->low_priority; - int pool_thread_index = -1; - Task *prev_low_prio_task = nullptr; // In case this is recursively called. + int pool_thread_index = thread_ids[Thread::get_caller_id()]; + ThreadData &curr_thread = threads[pool_thread_index]; + Task *prev_task = nullptr; // In case this is recursively called. + bool safe_for_nodes_backup = is_current_thread_safe_for_nodes(); - if (!use_native_low_priority_threads) { + { // Tasks must start with this unset. They are free to set-and-forget otherwise. set_current_thread_safe_for_nodes(false); - pool_thread_index = thread_ids[Thread::get_caller_id()]; - ThreadData &curr_thread = threads[pool_thread_index]; // Since the WorkerThreadPool is started before the script server, // its pre-created threads can't have ScriptServer::thread_enter() called on them early. // Therefore, we do it late at the first opportunity, so in case the task @@ -71,13 +65,8 @@ void WorkerThreadPool::_process_task(Task *p_task) { } task_mutex.lock(); p_task->pool_thread_index = pool_thread_index; - if (low_priority) { - low_priority_tasks_running++; - prev_low_prio_task = curr_thread.current_low_prio_task; - curr_thread.current_low_prio_task = p_task; - } else { - curr_thread.current_low_prio_task = nullptr; - } + prev_task = curr_thread.current_task; + curr_thread.current_task = p_task; task_mutex.unlock(); } @@ -111,33 +100,24 @@ void WorkerThreadPool::_process_task(Task *p_task) { memdelete(p_task->template_userdata); // This is no longer needed at this point, so get rid of it. } - if (low_priority && use_native_low_priority_threads) { - p_task->completed = true; - p_task->done_semaphore.post(); - if (do_post) { - p_task->group->completed.set_to(true); - } - } else { - if (do_post) { - p_task->group->done_semaphore.post(); - p_task->group->completed.set_to(true); - } - uint32_t max_users = p_task->group->tasks_used + 1; // Add 1 because the thread waiting for it is also user. Read before to avoid another thread freeing task after increment. - uint32_t finished_users = p_task->group->finished.increment(); - - if (finished_users == max_users) { - // Get rid of the group, because nobody else is using it. - task_mutex.lock(); - group_allocator.free(p_task->group); - task_mutex.unlock(); - } - - // For groups, tasks get rid of themselves. + if (do_post) { + p_task->group->done_semaphore.post(); + p_task->group->completed.set_to(true); + } + uint32_t max_users = p_task->group->tasks_used + 1; // Add 1 because the thread waiting for it is also user. Read before to avoid another thread freeing task after increment. + uint32_t finished_users = p_task->group->finished.increment(); + if (finished_users == max_users) { + // Get rid of the group, because nobody else is using it. task_mutex.lock(); - task_allocator.free(p_task); + group_allocator.free(p_task->group); task_mutex.unlock(); } + + // For groups, tasks get rid of themselves. + + task_mutex.lock(); + task_allocator.free(p_task); } else { if (p_task->native_func) { p_task->native_func(p_task->native_func_userdata); @@ -150,88 +130,162 @@ void WorkerThreadPool::_process_task(Task *p_task) { task_mutex.lock(); p_task->completed = true; - for (uint8_t i = 0; i < p_task->waiting; i++) { - p_task->done_semaphore.post(); + p_task->pool_thread_index = -1; + if (p_task->waiting_user) { + p_task->done_semaphore.post(p_task->waiting_user); } - if (!use_native_low_priority_threads) { - p_task->pool_thread_index = -1; + // Let awaiters know. + for (uint32_t i = 0; i < threads.size(); i++) { + if (threads[i].awaited_task == p_task) { + threads[i].cond_var.notify_one(); + threads[i].signaled = true; + } } - task_mutex.unlock(); // Keep mutex down to here since on unlock the task may be freed. } - // Task may have been freed by now (all callers notified). - p_task = nullptr; - - if (!use_native_low_priority_threads) { - bool post = false; - task_mutex.lock(); - ThreadData &curr_thread = threads[pool_thread_index]; - curr_thread.current_low_prio_task = prev_low_prio_task; - if (low_priority) { + { + curr_thread.current_task = prev_task; + if (p_task->low_priority) { low_priority_threads_used--; - low_priority_tasks_running--; - // A low prioriry task was freed, so see if we can move a pending one to the high priority queue. - if (_try_promote_low_priority_task()) { - post = true; - } - if (low_priority_tasks_awaiting_others == low_priority_tasks_running) { - _prevent_low_prio_saturation_deadlock(); + if (_try_promote_low_priority_task()) { + if (prev_task) { // Otherwise, this thread will catch it. + _notify_threads(&curr_thread, 1, 0); + } } } + task_mutex.unlock(); - if (post) { - task_available_semaphore.post(); - } } + + set_current_thread_safe_for_nodes(safe_for_nodes_backup); } void WorkerThreadPool::_thread_function(void *p_user) { + ThreadData *thread_data = (ThreadData *)p_user; while (true) { - singleton->task_available_semaphore.wait(); - if (singleton->exit_threads) { - break; + Task *task_to_process = nullptr; + { + MutexLock lock(singleton->task_mutex); + if (singleton->exit_threads) { + return; + } + thread_data->signaled = false; + + if (singleton->task_queue.first()) { + task_to_process = singleton->task_queue.first()->self(); + singleton->task_queue.remove(singleton->task_queue.first()); + } else { + thread_data->cond_var.wait(lock); + DEV_ASSERT(singleton->exit_threads || thread_data->signaled); + } } - singleton->_process_task_queue(); - } -} -void WorkerThreadPool::_native_low_priority_thread_function(void *p_user) { - Task *task = (Task *)p_user; - singleton->_process_task(task); + if (task_to_process) { + singleton->_process_task(task_to_process); + } + } } -void WorkerThreadPool::_post_task(Task *p_task, bool p_high_priority) { +void WorkerThreadPool::_post_tasks_and_unlock(Task **p_tasks, uint32_t p_count, bool p_high_priority) { // Fall back to processing on the calling thread if there are no worker threads. // Separated into its own variable to make it easier to extend this logic // in custom builds. bool process_on_calling_thread = threads.size() == 0; if (process_on_calling_thread) { - _process_task(p_task); + task_mutex.unlock(); + for (uint32_t i = 0; i < p_count; i++) { + _process_task(p_tasks[i]); + } return; } - task_mutex.lock(); - p_task->low_priority = !p_high_priority; - if (!p_high_priority && use_native_low_priority_threads) { - p_task->low_priority_thread = native_thread_allocator.alloc(); - task_mutex.unlock(); + uint32_t to_process = 0; + uint32_t to_promote = 0; - if (p_task->group) { - p_task->group->low_priority_native_tasks.push_back(p_task); + ThreadData *caller_pool_thread = thread_ids.has(Thread::get_caller_id()) ? &threads[thread_ids[Thread::get_caller_id()]] : nullptr; + + for (uint32_t i = 0; i < p_count; i++) { + p_tasks[i]->low_priority = !p_high_priority; + if (p_high_priority || low_priority_threads_used < max_low_priority_threads) { + task_queue.add_last(&p_tasks[i]->task_elem); + if (!p_high_priority) { + low_priority_threads_used++; + } + to_process++; + } else { + // Too many threads using low priority, must go to queue. + low_priority_task_queue.add_last(&p_tasks[i]->task_elem); + to_promote++; } - p_task->low_priority_thread->start(_native_low_priority_thread_function, p_task); // Pask task directly to thread. - } else if (p_high_priority || low_priority_threads_used < max_low_priority_threads) { - task_queue.add_last(&p_task->task_elem); - if (!p_high_priority) { - low_priority_threads_used++; + } + + _notify_threads(caller_pool_thread, to_process, to_promote); + + task_mutex.unlock(); +} + +void WorkerThreadPool::_notify_threads(const ThreadData *p_current_thread_data, uint32_t p_process_count, uint32_t p_promote_count) { + uint32_t to_process = p_process_count; + uint32_t to_promote = p_promote_count; + + // This is where which threads are awaken is decided according to the workload. + // Threads that will anyway have a chance to check the situation and process/promote tasks + // are excluded from being notified. Others will be tried anyway to try to distribute load. + // The current thread, if is a pool thread, is also excluded depending on the promoting/processing + // needs because it will anyway loop again. However, it will contribute to decreasing the count, + // which helps reducing sync traffic. + + uint32_t thread_count = threads.size(); + + // First round: + // 1. For processing: notify threads that are not running tasks, to keep the stacks as shallow as possible. + // 2. For promoting: since it's exclusive with processing, we fin threads able to promote low-prio tasks now. + for (uint32_t i = 0; + i < thread_count && (to_process || to_promote); + i++, notify_index = (notify_index + 1) % thread_count) { + ThreadData &th = threads[notify_index]; + + if (th.signaled) { + continue; + } + if (th.current_task) { + // Good thread for promoting low-prio? + if (to_promote && th.awaited_task && th.current_task->low_priority) { + if (likely(&th != p_current_thread_data)) { + th.cond_var.notify_one(); + } + th.signaled = true; + to_promote--; + } + } else { + if (to_process) { + if (likely(&th != p_current_thread_data)) { + th.cond_var.notify_one(); + } + th.signaled = true; + to_process--; + } + } + } + + // Second round: + // For processing: if the first round wasn't enough, let's try now with threads processing tasks but currently awaiting. + for (uint32_t i = 0; + i < thread_count && to_process; + i++, notify_index = (notify_index + 1) % thread_count) { + ThreadData &th = threads[notify_index]; + + if (th.signaled) { + continue; + } + if (th.awaited_task) { + if (likely(&th != p_current_thread_data)) { + th.cond_var.notify_one(); + } + th.signaled = true; + to_process--; } - task_mutex.unlock(); - task_available_semaphore.post(); - } else { - // Too many threads using low priority, must go to queue. - low_priority_task_queue.add_last(&p_task->task_elem); - task_mutex.unlock(); } } @@ -247,23 +301,6 @@ bool WorkerThreadPool::_try_promote_low_priority_task() { } } -void WorkerThreadPool::_prevent_low_prio_saturation_deadlock() { - if (low_priority_tasks_awaiting_others == low_priority_tasks_running) { -#ifdef DEV_ENABLED - print_verbose("WorkerThreadPool: Low-prio slots saturated with tasks all waiting for other low-prio tasks. Attempting to avoid deadlock by scheduling one extra task."); -#endif - // In order not to create dependency cycles, we can only schedule the next one. - // We'll keep doing the same until the deadlock is broken, - SelfList<Task> *to_promote = low_priority_task_queue.first(); - if (to_promote) { - low_priority_task_queue.remove(to_promote); - task_queue.add_last(to_promote); - low_priority_threads_used++; - task_available_semaphore.post(); - } - } -} - WorkerThreadPool::TaskID WorkerThreadPool::add_native_task(void (*p_func)(void *), void *p_userdata, bool p_high_priority, const String &p_description) { return _add_task(Callable(), p_func, p_userdata, nullptr, p_high_priority, p_description); } @@ -273,15 +310,15 @@ WorkerThreadPool::TaskID WorkerThreadPool::_add_task(const Callable &p_callable, // Get a free task Task *task = task_allocator.alloc(); TaskID id = last_task++; + task->self = id; task->callable = p_callable; task->native_func = p_func; task->native_func_userdata = p_userdata; task->description = p_description; task->template_userdata = p_template_userdata; tasks.insert(id, task); - task_mutex.unlock(); - _post_task(task, p_high_priority); + _post_tasks_and_unlock(&task, 1, p_high_priority); return id; } @@ -313,105 +350,117 @@ Error WorkerThreadPool::wait_for_task_completion(TaskID p_task_id) { } Task *task = *taskp; - if (!task->completed) { - if (!use_native_low_priority_threads && task->pool_thread_index != -1) { // Otherwise, it's not running yet. - int caller_pool_th_index = thread_ids.has(Thread::get_caller_id()) ? thread_ids[Thread::get_caller_id()] : -1; - if (caller_pool_th_index == task->pool_thread_index) { - // Deadlock prevention. - // Waiting for a task run on this same thread? That means the task to be awaited started waiting as well - // and another task was run to make use of the thread in the meantime, with enough bad luck as to - // the need to wait for the original task arose in turn. - // In other words, the task we want to wait for is buried in the stack. - // Let's report the caller about the issue to it handles as it sees fit. - task_mutex.unlock(); - return ERR_BUSY; - } + if (task->completed) { + if (task->waiting_pool == 0 && task->waiting_user == 0) { + tasks.erase(p_task_id); + task_allocator.free(task); } + task_mutex.unlock(); + return OK; + } + + ThreadData *caller_pool_thread = thread_ids.has(Thread::get_caller_id()) ? &threads[thread_ids[Thread::get_caller_id()]] : nullptr; + if (caller_pool_thread && p_task_id <= caller_pool_thread->current_task->self) { + // Deadlock prevention: + // When a pool thread wants to wait for an older task, the following situations can happen: + // 1. Awaited task is deep in the stack of the awaiter. + // 2. A group of awaiter threads end up depending on some tasks buried in the stack + // of their worker threads in such a way that progress can't be made. + // Both would entail a deadlock. Some may be handled here in the WorkerThreadPool + // with some extra logic and bookkeeping. However, there would still be unavoidable + // cases of deadlock because of the way waiting threads process outstanding tasks. + // Taking into account there's no feasible solution for every possible case + // with the current design, we just simply reject attempts to await on older tasks, + // with a specific error code that signals the situation so the caller can handle it. + task_mutex.unlock(); + return ERR_BUSY; + } - task->waiting++; - - bool is_low_prio_waiting_for_another = false; - if (!use_native_low_priority_threads) { - // Deadlock prevention: - // If all low-prio tasks are waiting for other low-prio tasks and there are no more free low-prio slots, - // we have a no progressable situation. We can apply a workaround, consisting in promoting an awaited queued - // low-prio task to the schedule queue so it can run and break the "impasse". - // NOTE: A similar reasoning could be made about high priority tasks, but there are usually much more - // than low-prio. Therefore, a deadlock there would only happen when dealing with a very complex task graph - // or when there are too few worker threads (limited platforms or exotic settings). If that turns out to be - // an issue in the real world, a further fix can be applied against that. - if (task->low_priority) { - bool awaiter_is_a_low_prio_task = thread_ids.has(Thread::get_caller_id()) && threads[thread_ids[Thread::get_caller_id()]].current_low_prio_task; - if (awaiter_is_a_low_prio_task) { - is_low_prio_waiting_for_another = true; - low_priority_tasks_awaiting_others++; - if (low_priority_tasks_awaiting_others == low_priority_tasks_running) { - _prevent_low_prio_saturation_deadlock(); + if (caller_pool_thread) { + task->waiting_pool++; + } else { + task->waiting_user++; + } + + task_mutex.unlock(); + + if (caller_pool_thread) { + while (true) { + Task *task_to_process = nullptr; + { + MutexLock lock(task_mutex); + bool was_signaled = caller_pool_thread->signaled; + caller_pool_thread->signaled = false; + + if (task->completed) { + // This thread was awaken also for some reason, but it's about to exit. + // Let's find out what may be pending and forward the requests. + if (!exit_threads && was_signaled) { + uint32_t to_process = task_queue.first() ? 1 : 0; + uint32_t to_promote = caller_pool_thread->current_task->low_priority && low_priority_task_queue.first() ? 1 : 0; + if (to_process || to_promote) { + // This thread must be left alone since it won't loop again. + caller_pool_thread->signaled = true; + _notify_threads(caller_pool_thread, to_process, to_promote); + } + } + + task->waiting_pool--; + if (task->waiting_pool == 0 && task->waiting_user == 0) { + tasks.erase(p_task_id); + task_allocator.free(task); } + + break; } - } - } - task_mutex.unlock(); + if (!exit_threads) { + // This is a thread from the pool. It shouldn't just idle. + // Let's try to process other tasks while we wait. - if (use_native_low_priority_threads && task->low_priority) { - task->done_semaphore.wait(); - } else { - bool current_is_pool_thread = thread_ids.has(Thread::get_caller_id()); - if (current_is_pool_thread) { - // We are an actual process thread, we must not be blocked so continue processing stuff if available. - bool must_exit = false; - while (true) { - if (task->done_semaphore.try_wait()) { - // If done, exit - break; + if (caller_pool_thread->current_task->low_priority && low_priority_task_queue.first()) { + if (_try_promote_low_priority_task()) { + _notify_threads(caller_pool_thread, 1, 0); + } + } + + if (singleton->task_queue.first()) { + task_to_process = task_queue.first()->self(); + task_queue.remove(task_queue.first()); } - if (!must_exit) { - if (task_available_semaphore.try_wait()) { - if (exit_threads) { - must_exit = true; - } else { - // Solve tasks while they are around. - bool safe_for_nodes_backup = is_current_thread_safe_for_nodes(); - _process_task_queue(); - set_current_thread_safe_for_nodes(safe_for_nodes_backup); - continue; - } - } else if (!use_native_low_priority_threads && task->low_priority) { - // A low prioriry task started waiting, so see if we can move a pending one to the high priority queue. - task_mutex.lock(); - bool post = _try_promote_low_priority_task(); - task_mutex.unlock(); - if (post) { - task_available_semaphore.post(); - } + + if (!task_to_process) { + caller_pool_thread->awaited_task = task; + + if (flushing_cmd_queue) { + flushing_cmd_queue->unlock(); } + caller_pool_thread->cond_var.wait(lock); + if (flushing_cmd_queue) { + flushing_cmd_queue->lock(); + } + + DEV_ASSERT(exit_threads || caller_pool_thread->signaled || task->completed); + caller_pool_thread->awaited_task = nullptr; } - OS::get_singleton()->delay_usec(1); // Microsleep, this could be converted to waiting for multiple objects in supported platforms for a bit more performance. } - } else { - task->done_semaphore.wait(); } - } - task_mutex.lock(); - if (is_low_prio_waiting_for_another) { - low_priority_tasks_awaiting_others--; + if (task_to_process) { + _process_task(task_to_process); + } } - - task->waiting--; - } - - if (task->waiting == 0) { - if (use_native_low_priority_threads && task->low_priority) { - task->low_priority_thread->wait_to_finish(); - native_thread_allocator.free(task->low_priority_thread); + } else { + task->done_semaphore.wait(); + task_mutex.lock(); + task->waiting_user--; + if (task->waiting_pool == 0 && task->waiting_user == 0) { + tasks.erase(p_task_id); + task_allocator.free(task); } - tasks.erase(p_task_id); - task_allocator.free(task); + task_mutex.unlock(); } - task_mutex.unlock(); return OK; } @@ -455,11 +504,8 @@ WorkerThreadPool::GroupID WorkerThreadPool::_add_group_task(const Callable &p_ca } groups[id] = group; - task_mutex.unlock(); - for (int i = 0; i < p_tasks; i++) { - _post_task(tasks_posted[i], p_high_priority); - } + _post_tasks_and_unlock(tasks_posted, p_tasks, p_high_priority); return id; } @@ -502,22 +548,17 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) { if (!groupp) { ERR_FAIL_MSG("Invalid Group ID"); } - Group *group = *groupp; - if (group->low_priority_native_tasks.size() > 0) { - for (Task *task : group->low_priority_native_tasks) { - task->low_priority_thread->wait_to_finish(); - task_mutex.lock(); - native_thread_allocator.free(task->low_priority_thread); - task_allocator.free(task); - task_mutex.unlock(); - } + { + Group *group = *groupp; - task_mutex.lock(); - group_allocator.free(group); - task_mutex.unlock(); - } else { + if (flushing_cmd_queue) { + flushing_cmd_queue->unlock(); + } group->done_semaphore.wait(); + if (flushing_cmd_queue) { + flushing_cmd_queue->lock(); + } uint32_t max_users = group->tasks_used + 1; // Add 1 because the thread waiting for it is also user. Read before to avoid another thread freeing task after increment. uint32_t finished_users = group->finished.increment(); // fetch happens before inc, so increment later. @@ -540,19 +581,23 @@ int WorkerThreadPool::get_thread_index() { return singleton->thread_ids.has(tid) ? singleton->thread_ids[tid] : -1; } -void WorkerThreadPool::init(int p_thread_count, bool p_use_native_threads_low_priority, float p_low_priority_task_ratio) { +void WorkerThreadPool::thread_enter_command_queue_mt_flush(CommandQueueMT *p_queue) { + ERR_FAIL_COND(flushing_cmd_queue != nullptr); + flushing_cmd_queue = p_queue; +} + +void WorkerThreadPool::thread_exit_command_queue_mt_flush() { + ERR_FAIL_NULL(flushing_cmd_queue); + flushing_cmd_queue = nullptr; +} + +void WorkerThreadPool::init(int p_thread_count, float p_low_priority_task_ratio) { ERR_FAIL_COND(threads.size() > 0); if (p_thread_count < 0) { p_thread_count = OS::get_singleton()->get_default_thread_pool_size(); } - if (p_use_native_threads_low_priority) { - max_low_priority_threads = 0; - } else { - max_low_priority_threads = CLAMP(p_thread_count * p_low_priority_task_ratio, 1, p_thread_count - 1); - } - - use_native_low_priority_threads = p_use_native_threads_low_priority; + max_low_priority_threads = CLAMP(p_thread_count * p_low_priority_task_ratio, 1, p_thread_count - 1); threads.resize(p_thread_count); @@ -568,24 +613,33 @@ void WorkerThreadPool::finish() { return; } - task_mutex.lock(); - SelfList<Task> *E = low_priority_task_queue.first(); - while (E) { - print_error("Task waiting was never re-claimed: " + E->self()->description); - E = E->next(); + { + MutexLock lock(task_mutex); + SelfList<Task> *E = low_priority_task_queue.first(); + while (E) { + print_error("Task waiting was never re-claimed: " + E->self()->description); + E = E->next(); + } } - task_mutex.unlock(); - exit_threads = true; - - for (uint32_t i = 0; i < threads.size(); i++) { - task_available_semaphore.post(); + { + MutexLock lock(task_mutex); + exit_threads = true; + } + for (ThreadData &data : threads) { + data.cond_var.notify_one(); } - for (ThreadData &data : threads) { data.thread.wait_to_finish(); } + { + MutexLock lock(task_mutex); + for (KeyValue<TaskID, Task *> &E : tasks) { + task_allocator.free(E.value); + } + } + threads.clear(); } diff --git a/core/object/worker_thread_pool.h b/core/object/worker_thread_pool.h index dd56f95cae..c9921c808d 100644 --- a/core/object/worker_thread_pool.h +++ b/core/object/worker_thread_pool.h @@ -31,6 +31,7 @@ #ifndef WORKER_THREAD_POOL_H #define WORKER_THREAD_POOL_H +#include "core/os/condition_variable.h" #include "core/os/memory.h" #include "core/os/os.h" #include "core/os/semaphore.h" @@ -40,6 +41,8 @@ #include "core/templates/rid.h" #include "core/templates/safe_refcount.h" +class CommandQueueMT; + class WorkerThreadPool : public Object { GDCLASS(WorkerThreadPool, Object) public: @@ -60,7 +63,7 @@ private: }; struct Group { - GroupID self; + GroupID self = -1; SafeNumeric<uint32_t> index; SafeNumeric<uint32_t> completed_index; uint32_t max = 0; @@ -68,23 +71,23 @@ private: SafeFlag completed; SafeNumeric<uint32_t> finished; uint32_t tasks_used = 0; - TightLocalVector<Task *> low_priority_native_tasks; }; struct Task { + TaskID self = -1; Callable callable; void (*native_func)(void *) = nullptr; void (*native_group_func)(void *, uint32_t) = nullptr; void *native_func_userdata = nullptr; String description; - Semaphore done_semaphore; + Semaphore done_semaphore; // For user threads awaiting. bool completed = false; Group *group = nullptr; SelfList<Task> task_elem; - uint32_t waiting = 0; + uint32_t waiting_pool = 0; + uint32_t waiting_user = 0; bool low_priority = false; BaseTemplateUserdata *template_userdata = nullptr; - Thread *low_priority_thread = nullptr; int pool_thread_index = -1; void free_template_userdata(); @@ -92,51 +95,65 @@ private: task_elem(this) {} }; - PagedAllocator<Task> task_allocator; - PagedAllocator<Group> group_allocator; - PagedAllocator<Thread> native_thread_allocator; + static const uint32_t TASKS_PAGE_SIZE = 1024; + static const uint32_t GROUPS_PAGE_SIZE = 256; + + PagedAllocator<Task, false, TASKS_PAGE_SIZE> task_allocator; + PagedAllocator<Group, false, GROUPS_PAGE_SIZE> group_allocator; SelfList<Task>::List low_priority_task_queue; SelfList<Task>::List task_queue; - Mutex task_mutex; - Semaphore task_available_semaphore; + BinaryMutex task_mutex; struct ThreadData { - uint32_t index; + uint32_t index = 0; Thread thread; - Task *current_low_prio_task = nullptr; bool ready_for_scripting = false; + bool signaled = false; + Task *current_task = nullptr; + Task *awaited_task = nullptr; // Null if not awaiting the condition variable. Special value for idle-waiting. + ConditionVariable cond_var; }; TightLocalVector<ThreadData> threads; bool exit_threads = false; HashMap<Thread::ID, int> thread_ids; - HashMap<TaskID, Task *> tasks; - HashMap<GroupID, Group *> groups; + HashMap< + TaskID, + Task *, + HashMapHasherDefault, + HashMapComparatorDefault<TaskID>, + PagedAllocator<HashMapElement<TaskID, Task *>, false, TASKS_PAGE_SIZE>> + tasks; + HashMap< + GroupID, + Group *, + HashMapHasherDefault, + HashMapComparatorDefault<GroupID>, + PagedAllocator<HashMapElement<GroupID, Group *>, false, GROUPS_PAGE_SIZE>> + groups; - bool use_native_low_priority_threads = false; uint32_t max_low_priority_threads = 0; uint32_t low_priority_threads_used = 0; - uint32_t low_priority_tasks_running = 0; - uint32_t low_priority_tasks_awaiting_others = 0; + uint32_t notify_index = 0; // For rotating across threads, no help distributing load. uint64_t last_task = 1; static void _thread_function(void *p_user); - static void _native_low_priority_thread_function(void *p_user); - void _process_task_queue(); void _process_task(Task *task); - void _post_task(Task *p_task, bool p_high_priority); + void _post_tasks_and_unlock(Task **p_tasks, uint32_t p_count, bool p_high_priority); + void _notify_threads(const ThreadData *p_current_thread_data, uint32_t p_process_count, uint32_t p_promote_count); bool _try_promote_low_priority_task(); - void _prevent_low_prio_saturation_deadlock(); static WorkerThreadPool *singleton; + static thread_local CommandQueueMT *flushing_cmd_queue; + TaskID _add_task(const Callable &p_callable, void (*p_func)(void *), void *p_userdata, BaseTemplateUserdata *p_template_userdata, bool p_high_priority, const String &p_description); GroupID _add_group_task(const Callable &p_callable, void (*p_func)(void *, uint32_t), void *p_userdata, BaseTemplateUserdata *p_template_userdata, int p_elements, int p_tasks, bool p_high_priority, const String &p_description); @@ -199,7 +216,10 @@ public: static WorkerThreadPool *get_singleton() { return singleton; } static int get_thread_index(); - void init(int p_thread_count = -1, bool p_use_native_threads_low_priority = true, float p_low_priority_task_ratio = 0.3); + static void thread_enter_command_queue_mt_flush(CommandQueueMT *p_queue); + static void thread_exit_command_queue_mt_flush(); + + void init(int p_thread_count = -1, float p_low_priority_task_ratio = 0.3); void finish(); WorkerThreadPool(); ~WorkerThreadPool(); diff --git a/core/os/condition_variable.h b/core/os/condition_variable.h index 6a6996019d..6a49ced31b 100644 --- a/core/os/condition_variable.h +++ b/core/os/condition_variable.h @@ -31,6 +31,8 @@ #ifndef CONDITION_VARIABLE_H #define CONDITION_VARIABLE_H +#include "core/os/mutex.h" + #ifdef MINGW_ENABLED #define MINGW_STDTHREAD_REDUNDANCY_WARNING #include "thirdparty/mingw-std-threads/mingw.condition_variable.h" diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp index 6078882839..973c216d15 100644 --- a/core/os/keyboard.cpp +++ b/core/os/keyboard.cpp @@ -410,7 +410,7 @@ Key find_keycode(const String &p_codestr) { return keycode; } - String last_part = code_parts[code_parts.size() - 1]; + const String &last_part = code_parts[code_parts.size() - 1]; const _KeyCodeText *kct = &_keycodes[0]; while (kct->text) { @@ -422,7 +422,7 @@ Key find_keycode(const String &p_codestr) { } for (int part = 0; part < code_parts.size() - 1; part++) { - String code_part = code_parts[part]; + const String &code_part = code_parts[part]; if (code_part.nocasecmp_to(find_keycode_name(Key::SHIFT)) == 0) { keycode |= KeyModifierMask::SHIFT; } else if (code_part.nocasecmp_to(find_keycode_name(Key::CTRL)) == 0) { diff --git a/core/os/semaphore.h b/core/os/semaphore.h index 8bb1529bbd..b8ae35b86b 100644 --- a/core/os/semaphore.h +++ b/core/os/semaphore.h @@ -58,10 +58,12 @@ private: #endif public: - _ALWAYS_INLINE_ void post() const { + _ALWAYS_INLINE_ void post(uint32_t p_count = 1) const { std::lock_guard lock(mutex); - count++; - condition.notify_one(); + count += p_count; + for (uint32_t i = 0; i < p_count; ++i) { + condition.notify_one(); + } } _ALWAYS_INLINE_ void wait() const { diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 2785d1daa5..82b3d27942 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -307,7 +307,6 @@ void register_core_settings() { GLOBAL_DEF(PropertyInfo(Variant::STRING, "network/tls/certificate_bundle_override", PROPERTY_HINT_FILE, "*.crt"), ""); GLOBAL_DEF("threading/worker_pool/max_threads", -1); - GLOBAL_DEF("threading/worker_pool/use_system_threads_for_low_priority_tasks", true); GLOBAL_DEF("threading/worker_pool/low_priority_thread_ratio", 0.3); } diff --git a/core/string/translation.cpp b/core/string/translation.cpp index 8fcf2b24b5..829c9bf777 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -881,7 +881,7 @@ StringName TranslationServer::tool_pseudolocalize(const StringName &p_message) c String TranslationServer::get_override_string(String &p_message) const { String res; - for (int i = 0; i < p_message.size(); i++) { + for (int i = 0; i < p_message.length(); i++) { if (pseudolocalization_skip_placeholders_enabled && is_placeholder(p_message, i)) { res += p_message[i]; res += p_message[i + 1]; @@ -895,7 +895,7 @@ String TranslationServer::get_override_string(String &p_message) const { String TranslationServer::double_vowels(String &p_message) const { String res; - for (int i = 0; i < p_message.size(); i++) { + for (int i = 0; i < p_message.length(); i++) { if (pseudolocalization_skip_placeholders_enabled && is_placeholder(p_message, i)) { res += p_message[i]; res += p_message[i + 1]; @@ -913,7 +913,7 @@ String TranslationServer::double_vowels(String &p_message) const { String TranslationServer::replace_with_accented_string(String &p_message) const { String res; - for (int i = 0; i < p_message.size(); i++) { + for (int i = 0; i < p_message.length(); i++) { if (pseudolocalization_skip_placeholders_enabled && is_placeholder(p_message, i)) { res += p_message[i]; res += p_message[i + 1]; @@ -936,7 +936,7 @@ String TranslationServer::wrap_with_fakebidi_characters(String &p_message) const char32_t fakebidisuffix = U'\u202c'; res += fakebidiprefix; // The fake bidi unicode gets popped at every newline so pushing it back at every newline. - for (int i = 0; i < p_message.size(); i++) { + for (int i = 0; i < p_message.length(); i++) { if (p_message[i] == '\n') { res += fakebidisuffix; res += p_message[i]; @@ -978,7 +978,7 @@ const char32_t *TranslationServer::get_accented_version(char32_t p_character) co } bool TranslationServer::is_placeholder(String &p_message, int p_index) const { - return p_index < p_message.size() - 1 && p_message[p_index] == '%' && + return p_index < p_message.length() - 1 && p_message[p_index] == '%' && (p_message[p_index + 1] == 's' || p_message[p_index + 1] == 'c' || p_message[p_index + 1] == 'd' || p_message[p_index + 1] == 'o' || p_message[p_index + 1] == 'x' || p_message[p_index + 1] == 'X' || p_message[p_index + 1] == 'f'); } diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index a24cff4f11..6afe28a6a7 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -1117,7 +1117,7 @@ String String::get_with_code_lines() const { return ret; } -int String::get_slice_count(String p_splitter) const { +int String::get_slice_count(const String &p_splitter) const { if (is_empty()) { return 0; } @@ -1136,7 +1136,7 @@ int String::get_slice_count(String p_splitter) const { return slices; } -String String::get_slice(String p_splitter, int p_slice) const { +String String::get_slice(const String &p_splitter, int p_slice) const { if (is_empty() || p_splitter.is_empty()) { return ""; } @@ -3515,7 +3515,7 @@ bool String::matchn(const String &p_wildcard) const { return _wildcard_match(p_wildcard.get_data(), get_data(), false); } -String String::format(const Variant &values, String placeholder) const { +String String::format(const Variant &values, const String &placeholder) const { String new_string = String(this->ptr()); if (values.get_type() == Variant::ARRAY) { @@ -3961,27 +3961,42 @@ static int _humanize_digits(int p_num) { } String String::humanize_size(uint64_t p_size) { + int magnitude = 0; uint64_t _div = 1; - Vector<String> prefixes; - prefixes.push_back(RTR("B")); - prefixes.push_back(RTR("KiB")); - prefixes.push_back(RTR("MiB")); - prefixes.push_back(RTR("GiB")); - prefixes.push_back(RTR("TiB")); - prefixes.push_back(RTR("PiB")); - prefixes.push_back(RTR("EiB")); - - int prefix_idx = 0; - - while (prefix_idx < prefixes.size() - 1 && p_size > (_div * 1024)) { + while (p_size > _div * 1024 && magnitude < 6) { _div *= 1024; - prefix_idx++; + magnitude++; } - const int digits = prefix_idx > 0 ? _humanize_digits(p_size / _div) : 0; - const double divisor = prefix_idx > 0 ? _div : 1; + if (magnitude == 0) { + return String::num(p_size) + " " + RTR("B"); + } else { + String suffix; + switch (magnitude) { + case 1: + suffix = RTR("KiB"); + break; + case 2: + suffix = RTR("MiB"); + break; + case 3: + suffix = RTR("GiB"); + break; + case 4: + suffix = RTR("TiB"); + break; + case 5: + suffix = RTR("PiB"); + break; + case 6: + suffix = RTR("EiB"); + break; + } - return String::num(p_size / divisor).pad_decimals(digits) + " " + prefixes[prefix_idx]; + const double divisor = _div; + const int digits = _humanize_digits(p_size / _div); + return String::num(p_size / divisor).pad_decimals(digits) + " " + suffix; + } } bool String::is_absolute_path() const { @@ -4569,7 +4584,7 @@ bool String::is_valid_ip_address() const { if (find(":") >= 0) { Vector<String> ip = split(":"); for (int i = 0; i < ip.size(); i++) { - String n = ip[i]; + const String &n = ip[i]; if (n.is_empty()) { continue; } @@ -4591,7 +4606,7 @@ bool String::is_valid_ip_address() const { return false; } for (int i = 0; i < ip.size(); i++) { - String n = ip[i]; + const String &n = ip[i]; if (!n.is_valid_int()) { return false; } @@ -5208,7 +5223,7 @@ String String::sprintf(const Array &values, bool *error) const { return formatted; } -String String::quote(String quotechar) const { +String String::quote(const String "echar) const { return quotechar + *this + quotechar; } diff --git a/core/string/ustring.h b/core/string/ustring.h index 897b06fc6d..5ed20396d6 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -299,7 +299,7 @@ public: bool is_quoted() const; Vector<String> bigrams() const; float similarity(const String &p_string) const; - String format(const Variant &values, String placeholder = "{_}") const; + String format(const Variant &values, const String &placeholder = "{_}") const; String replace_first(const String &p_key, const String &p_with) const; String replace(const String &p_key, const String &p_with) const; String replace(const char *p_key, const char *p_with) const; @@ -315,7 +315,7 @@ public: String lpad(int min_length, const String &character = " ") const; String rpad(int min_length, const String &character = " ") const; String sprintf(const Array &values, bool *error) const; - String quote(String quotechar = "\"") const; + String quote(const String "echar = "\"") const; String unquote() const; static String num(double p_num, int p_decimals = -1); static String num_scientific(double p_num); @@ -349,8 +349,8 @@ public: String to_snake_case() const; String get_with_code_lines() const; - int get_slice_count(String p_splitter) const; - String get_slice(String p_splitter, int p_slice) const; + int get_slice_count(const String &p_splitter) const; + String get_slice(const String &p_splitter, int p_slice) const; String get_slicec(char32_t p_splitter, int p_slice) const; Vector<String> split(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const; diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h index 7e480653ac..b1010f7f43 100644 --- a/core/templates/command_queue_mt.h +++ b/core/templates/command_queue_mt.h @@ -31,6 +31,7 @@ #ifndef COMMAND_QUEUE_MT_H #define COMMAND_QUEUE_MT_H +#include "core/object/worker_thread_pool.h" #include "core/os/memory.h" #include "core/os/mutex.h" #include "core/os/semaphore.h" @@ -306,15 +307,15 @@ class CommandQueueMT { struct CommandBase { virtual void call() = 0; - virtual void post() {} - virtual ~CommandBase() {} + virtual SyncSemaphore *get_sync_semaphore() { return nullptr; } + virtual ~CommandBase() = default; // Won't be called. }; struct SyncCommand : public CommandBase { SyncSemaphore *sync_sem = nullptr; - virtual void post() override { - sync_sem->sem.post(); + virtual SyncSemaphore *get_sync_semaphore() override { + return sync_sem; } }; @@ -340,6 +341,7 @@ class CommandQueueMT { SyncSemaphore sync_sems[SYNC_SEMAPHORES]; Mutex mutex; Semaphore *sync = nullptr; + uint64_t flush_read_ptr = 0; template <class T> T *allocate() { @@ -362,31 +364,41 @@ class CommandQueueMT { void _flush() { lock(); - uint64_t read_ptr = 0; - uint64_t limit = command_mem.size(); - - while (read_ptr < limit) { - uint64_t size = *(uint64_t *)&command_mem[read_ptr]; - read_ptr += 8; - CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[read_ptr]); - - cmd->call(); //execute the function - cmd->post(); //release in case it needs sync/ret - cmd->~CommandBase(); //should be done, so erase the command - - read_ptr += size; + WorkerThreadPool::thread_enter_command_queue_mt_flush(this); + while (flush_read_ptr < command_mem.size()) { + uint64_t size = *(uint64_t *)&command_mem[flush_read_ptr]; + flush_read_ptr += 8; + CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[flush_read_ptr]); + + SyncSemaphore *sync_sem = cmd->get_sync_semaphore(); + cmd->call(); + if (sync_sem) { + sync_sem->sem.post(); // Release in case it needs sync/ret. + } + + if (unlikely(flush_read_ptr == 0)) { + // A reentrant call flushed. + DEV_ASSERT(command_mem.is_empty()); + unlock(); + return; + } + + flush_read_ptr += size; } + WorkerThreadPool::thread_exit_command_queue_mt_flush(); command_mem.clear(); + flush_read_ptr = 0; unlock(); } - void lock(); - void unlock(); void wait_for_flush(); SyncSemaphore *_alloc_sync_sem(); public: + void lock(); + void unlock(); + /* NORMAL PUSH COMMANDS */ DECL_PUSH(0) SPACE_SEP_LIST(DECL_PUSH, 15) diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h index 6f3f78d4d2..d880eae0c3 100644 --- a/core/templates/paged_allocator.h +++ b/core/templates/paged_allocator.h @@ -40,7 +40,7 @@ #include <type_traits> #include <typeinfo> -template <class T, bool thread_safe = false> +template <class T, bool thread_safe = false, uint32_t DEFAULT_PAGE_SIZE = 4096> class PagedAllocator { T **page_pool = nullptr; T ***available_pool = nullptr; @@ -53,10 +53,6 @@ class PagedAllocator { SpinLock spin_lock; public: - enum { - DEFAULT_PAGE_SIZE = 4096 - }; - template <class... Args> T *alloc(Args &&...p_args) { if (thread_safe) { diff --git a/core/templates/paged_array.h b/core/templates/paged_array.h index 863e3eef11..69a792958a 100644 --- a/core/templates/paged_array.h +++ b/core/templates/paged_array.h @@ -53,7 +53,12 @@ class PagedArrayPool { SpinLock spin_lock; public: - uint32_t alloc_page() { + struct PageInfo { + T *page = nullptr; + uint32_t page_id = 0; + }; + + PageInfo alloc_page() { spin_lock.lock(); if (unlikely(pages_available == 0)) { uint32_t pages_used = pages_allocated; @@ -69,13 +74,11 @@ public: } pages_available--; - uint32_t page = available_page_pool[pages_available]; + uint32_t page_id = available_page_pool[pages_available]; + T *page = page_pool[page_id]; spin_lock.unlock(); - return page; - } - T *get_page(uint32_t p_page_id) { - return page_pool[p_page_id]; + return PageInfo{ page, page_id }; } void free_page(uint32_t p_page_id) { @@ -190,9 +193,9 @@ public: _grow_page_array(); //keep out of inline } - uint32_t page_id = page_pool->alloc_page(); - page_data[page_count] = page_pool->get_page(page_id); - page_ids[page_count] = page_id; + typename PagedArrayPool<T>::PageInfo page_info = page_pool->alloc_page(); + page_data[page_count] = page_info.page; + page_ids[page_count] = page_info.page_id; } // place the new value diff --git a/core/templates/self_list.h b/core/templates/self_list.h index fdf91beacc..afa0501c75 100644 --- a/core/templates/self_list.h +++ b/core/templates/self_list.h @@ -159,6 +159,9 @@ public: _FORCE_INLINE_ SelfList<T> *first() { return _first; } _FORCE_INLINE_ const SelfList<T> *first() const { return _first; } + // Forbid copying, which has broken behavior. + void operator=(const List &) = delete; + _FORCE_INLINE_ List() {} _FORCE_INLINE_ ~List() { // A self list must be empty on destruction. @@ -185,6 +188,9 @@ public: _FORCE_INLINE_ const SelfList<T> *prev() const { return _prev; } _FORCE_INLINE_ T *self() const { return _self; } + // Forbid copying, which has broken behavior. + void operator=(const SelfList<T> &) = delete; + _FORCE_INLINE_ SelfList(T *p_self) { _self = p_self; } diff --git a/core/typedefs.h b/core/typedefs.h index 803b2e5ae0..8b04960b9a 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -233,6 +233,10 @@ constexpr T get_num_bits(T x) { #define BSWAP16(x) __builtin_bswap16(x) #define BSWAP32(x) __builtin_bswap32(x) #define BSWAP64(x) __builtin_bswap64(x) +#elif defined(_MSC_VER) +#define BSWAP16(x) _byteswap_ushort(x) +#define BSWAP32(x) _byteswap_ulong(x) +#define BSWAP64(x) _byteswap_uint64(x) #else static inline uint16_t BSWAP16(uint16_t x) { return (x >> 8) | (x << 8); diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp index 0b1174c873..55f687bdf9 100644 --- a/core/variant/callable.cpp +++ b/core/variant/callable.cpp @@ -31,13 +31,12 @@ #include "callable.h" #include "callable_bind.h" -#include "core/object/message_queue.h" #include "core/object/object.h" #include "core/object/ref_counted.h" #include "core/object/script_language.h" void Callable::call_deferredp(const Variant **p_arguments, int p_argcount) const { - MessageQueue::get_singleton()->push_callablep(*this, p_arguments, p_argcount); + MessageQueue::get_singleton()->push_callablep(*this, p_arguments, p_argcount, true); } void Callable::callp(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const { diff --git a/core/variant/variant.h b/core/variant/variant.h index 480f21df98..602d287f22 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -572,6 +572,7 @@ public: static ValidatedBuiltInMethod get_validated_builtin_method(Variant::Type p_type, const StringName &p_method); static PTRBuiltInMethod get_ptr_builtin_method(Variant::Type p_type, const StringName &p_method); + static MethodInfo get_builtin_method_info(Variant::Type p_type, const StringName &p_method); static int get_builtin_method_argument_count(Variant::Type p_type, const StringName &p_method); static Variant::Type get_builtin_method_argument_type(Variant::Type p_type, const StringName &p_method, int p_argument); static String get_builtin_method_argument_name(Variant::Type p_type, const StringName &p_method, int p_argument); @@ -707,9 +708,20 @@ public: bool has_key(const Variant &p_key, bool &r_valid) const; /* Generic */ - - void set(const Variant &p_index, const Variant &p_value, bool *r_valid = nullptr); - Variant get(const Variant &p_index, bool *r_valid = nullptr) const; + enum VariantSetError { + SET_OK, + SET_KEYED_ERR, + SET_NAMED_ERR, + SET_INDEXED_ERR + }; + enum VariantGetError { + GET_OK, + GET_KEYED_ERR, + GET_NAMED_ERR, + GET_INDEXED_ERR + }; + void set(const Variant &p_index, const Variant &p_value, bool *r_valid = nullptr, VariantSetError *err_code = nullptr); + Variant get(const Variant &p_index, bool *r_valid = nullptr, VariantGetError *err_code = nullptr) const; bool in(const Variant &p_index, bool *r_valid = nullptr) const; bool iter_init(Variant &r_iter, bool &r_valid) const; @@ -769,8 +781,8 @@ public: static Variant get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = nullptr); static void get_enums_for_type(Variant::Type p_type, List<StringName> *p_enums); - static void get_enumerations_for_enum(Variant::Type p_type, StringName p_enum_name, List<StringName> *p_enumerations); - static int get_enum_value(Variant::Type p_type, StringName p_enum_name, StringName p_enumeration, bool *r_valid = nullptr); + static void get_enumerations_for_enum(Variant::Type p_type, const StringName &p_enum_name, List<StringName> *p_enumerations); + static int get_enum_value(Variant::Type p_type, const StringName &p_enum_name, const StringName &p_enumeration, bool *r_valid = nullptr); typedef String (*ObjectDeConstruct)(const Variant &p_object, void *ud); typedef void (*ObjectConstruct)(const String &p_text, void *ud, Variant &r_value); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 7121b4da96..03836985f3 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1071,14 +1071,14 @@ struct _VariantCall { static ConstantData *constant_data; - static void add_constant(int p_type, StringName p_constant_name, int64_t p_constant_value) { + static void add_constant(int p_type, const StringName &p_constant_name, int64_t p_constant_value) { constant_data[p_type].value[p_constant_name] = p_constant_value; #ifdef DEBUG_ENABLED constant_data[p_type].value_ordered.push_back(p_constant_name); #endif } - static void add_variant_constant(int p_type, StringName p_constant_name, const Variant &p_constant_value) { + static void add_variant_constant(int p_type, const StringName &p_constant_name, const Variant &p_constant_value) { constant_data[p_type].variant_value[p_constant_name] = p_constant_value; #ifdef DEBUG_ENABLED constant_data[p_type].variant_value_ordered.push_back(p_constant_name); @@ -1091,7 +1091,7 @@ struct _VariantCall { static EnumData *enum_data; - static void add_enum_constant(int p_type, StringName p_enum_type_name, StringName p_enumeration_name, int p_enum_value) { + static void add_enum_constant(int p_type, const StringName &p_enum_type_name, const StringName &p_enumeration_name, int p_enum_value) { enum_data[p_type].value[p_enum_type_name][p_enumeration_name] = p_enum_value; } }; @@ -1114,6 +1114,46 @@ struct VariantBuiltInMethodInfo { Variant::Type return_type; int argument_count = 0; Variant::Type (*get_argument_type)(int p_arg) = nullptr; + + MethodInfo get_method_info(const StringName &p_name) const { + MethodInfo mi; + mi.name = p_name; + + if (has_return_type) { + mi.return_val.type = return_type; + if (mi.return_val.type == Variant::NIL) { + mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + } + } + + if (is_const) { + mi.flags |= METHOD_FLAG_CONST; + } + if (is_vararg) { + mi.flags |= METHOD_FLAG_VARARG; + } + if (is_static) { + mi.flags |= METHOD_FLAG_STATIC; + } + + for (int i = 0; i < argument_count; i++) { + PropertyInfo pi; +#ifdef DEBUG_METHODS_ENABLED + pi.name = argument_names[i]; +#else + pi.name = "arg" + itos(i + 1); +#endif + pi.type = (*get_argument_type)(i); + if (pi.type == Variant::NIL) { + pi.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + } + mi.arguments.push_back(pi); + } + + mi.default_arguments = default_arguments; + + return mi; + } }; typedef OAHashMap<StringName, VariantBuiltInMethodInfo> BuiltinMethodMap; @@ -1268,6 +1308,13 @@ Variant::PTRBuiltInMethod Variant::get_ptr_builtin_method(Variant::Type p_type, return method->ptrcall; } +MethodInfo Variant::get_builtin_method_info(Variant::Type p_type, const StringName &p_method) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, MethodInfo()); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_NULL_V(method, MethodInfo()); + return method->get_method_info(p_method); +} + int Variant::get_builtin_method_argument_count(Variant::Type p_type, const StringName &p_method) { ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0); const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); @@ -1378,43 +1425,7 @@ void Variant::get_method_list(List<MethodInfo> *p_list) const { for (const StringName &E : builtin_method_names[type]) { const VariantBuiltInMethodInfo *method = builtin_method_info[type].lookup_ptr(E); ERR_CONTINUE(!method); - - MethodInfo mi; - mi.name = E; - - //return type - if (method->has_return_type) { - mi.return_val.type = method->return_type; - if (mi.return_val.type == Variant::NIL) { - mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; - } - } - - if (method->is_const) { - mi.flags |= METHOD_FLAG_CONST; - } - if (method->is_vararg) { - mi.flags |= METHOD_FLAG_VARARG; - } - if (method->is_static) { - mi.flags |= METHOD_FLAG_STATIC; - } - for (int i = 0; i < method->argument_count; i++) { - PropertyInfo pi; -#ifdef DEBUG_METHODS_ENABLED - pi.name = method->argument_names[i]; -#else - pi.name = "arg" + itos(i + 1); -#endif - pi.type = method->get_argument_type(i); - if (pi.type == Variant::NIL) { - pi.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; - } - mi.arguments.push_back(pi); - } - - mi.default_arguments = method->default_arguments; - p_list->push_back(mi); + p_list->push_back(method->get_method_info(E)); } } } @@ -1493,7 +1504,7 @@ void Variant::get_enums_for_type(Variant::Type p_type, List<StringName> *p_enums } } -void Variant::get_enumerations_for_enum(Variant::Type p_type, StringName p_enum_name, List<StringName> *p_enumerations) { +void Variant::get_enumerations_for_enum(Variant::Type p_type, const StringName &p_enum_name, List<StringName> *p_enumerations) { ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX); _VariantCall::EnumData &enum_data = _VariantCall::enum_data[p_type]; @@ -1505,7 +1516,7 @@ void Variant::get_enumerations_for_enum(Variant::Type p_type, StringName p_enum_ } } -int Variant::get_enum_value(Variant::Type p_type, StringName p_enum_name, StringName p_enumeration, bool *r_valid) { +int Variant::get_enum_value(Variant::Type p_type, const StringName &p_enum_name, const StringName &p_enumeration, bool *r_valid) { if (r_valid) { *r_valid = false; } @@ -1796,6 +1807,8 @@ static void _register_variant_builtin_methods() { bind_method(Vector2i, aspect, sarray(), varray()); bind_method(Vector2i, max_axis_index, sarray(), varray()); bind_method(Vector2i, min_axis_index, sarray(), varray()); + bind_method(Vector2i, distance_to, sarray("to"), varray()); + bind_method(Vector2i, distance_squared_to, sarray("to"), varray()); bind_method(Vector2i, length, sarray(), varray()); bind_method(Vector2i, length_squared, sarray(), varray()); bind_method(Vector2i, sign, sarray(), varray()); @@ -1886,6 +1899,8 @@ static void _register_variant_builtin_methods() { bind_method(Vector3i, min_axis_index, sarray(), varray()); bind_method(Vector3i, max_axis_index, sarray(), varray()); + bind_method(Vector3i, distance_to, sarray("to"), varray()); + bind_method(Vector3i, distance_squared_to, sarray("to"), varray()); bind_method(Vector3i, length, sarray(), varray()); bind_method(Vector3i, length_squared, sarray(), varray()); bind_method(Vector3i, sign, sarray(), varray()); @@ -1932,6 +1947,8 @@ static void _register_variant_builtin_methods() { bind_method(Vector4i, abs, sarray(), varray()); bind_method(Vector4i, clamp, sarray("min", "max"), varray()); bind_method(Vector4i, snapped, sarray("step"), varray()); + bind_method(Vector4i, distance_to, sarray("to"), varray()); + bind_method(Vector4i, distance_squared_to, sarray("to"), varray()); /* Plane */ diff --git a/core/variant/variant_callable.cpp b/core/variant/variant_callable.cpp new file mode 100644 index 0000000000..dc31b6d1ac --- /dev/null +++ b/core/variant/variant_callable.cpp @@ -0,0 +1,81 @@ +/**************************************************************************/ +/* variant_callable.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "variant_callable.h" + +#include "core/templates/hashfuncs.h" + +bool VariantCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) { + return p_a->hash() == p_b->hash(); +} + +bool VariantCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) { + return p_a->hash() < p_b->hash(); +} + +uint32_t VariantCallable::hash() const { + return h; +} + +String VariantCallable::get_as_text() const { + return vformat("%s::%s (Callable)", Variant::get_type_name(variant.get_type()), method); +} + +CallableCustom::CompareEqualFunc VariantCallable::get_compare_equal_func() const { + return compare_equal; +} + +CallableCustom::CompareLessFunc VariantCallable::get_compare_less_func() const { + return compare_less; +} + +bool VariantCallable::is_valid() const { + return Variant::has_builtin_method(variant.get_type(), method); +} + +StringName VariantCallable::get_method() const { + return method; +} + +ObjectID VariantCallable::get_object() const { + return ObjectID(); +} + +void VariantCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { + Variant v = variant; + v.callp(method, p_arguments, p_argcount, r_return_value, r_call_error); +} + +VariantCallable::VariantCallable(const Variant &p_variant, const StringName &p_method) { + variant = p_variant; + method = p_method; + h = variant.hash(); + h = hash_murmur3_one_64(Variant::get_builtin_method_hash(variant.get_type(), method), h); +} diff --git a/core/variant/variant_callable.h b/core/variant/variant_callable.h new file mode 100644 index 0000000000..3f2b058aaf --- /dev/null +++ b/core/variant/variant_callable.h @@ -0,0 +1,58 @@ +/**************************************************************************/ +/* variant_callable.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef VARIANT_CALLABLE_H +#define VARIANT_CALLABLE_H + +#include "core/variant/callable.h" +#include "core/variant/variant.h" + +class VariantCallable : public CallableCustom { + Variant variant; + StringName method; + uint32_t h = 0; + + static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b); + static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b); + +public: + uint32_t hash() const override; + String get_as_text() const override; + CompareEqualFunc get_compare_equal_func() const override; + CompareLessFunc get_compare_less_func() const override; + bool is_valid() const override; + StringName get_method() const override; + ObjectID get_object() const override; + void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override; + + VariantCallable(const Variant &p_variant, const StringName &p_method); +}; + +#endif // VARIANT_CALLABLE_H diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp index aed83ac010..4f9c38dc4c 100644 --- a/core/variant/variant_op.cpp +++ b/core/variant/variant_op.cpp @@ -412,6 +412,15 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorDivNZ<Vector4, Vector4i, double>>(Variant::OP_DIVIDE, Variant::VECTOR4I, Variant::FLOAT); register_op<OperatorEvaluatorDivNZ<Vector4i, Vector4i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR4I, Variant::INT); + register_op<OperatorEvaluatorDiv<Transform2D, Transform2D, int64_t>>(Variant::OP_DIVIDE, Variant::TRANSFORM2D, Variant::INT); + register_op<OperatorEvaluatorDiv<Transform2D, Transform2D, double>>(Variant::OP_DIVIDE, Variant::TRANSFORM2D, Variant::FLOAT); + + register_op<OperatorEvaluatorDiv<Transform3D, Transform3D, int64_t>>(Variant::OP_DIVIDE, Variant::TRANSFORM3D, Variant::INT); + register_op<OperatorEvaluatorDiv<Transform3D, Transform3D, double>>(Variant::OP_DIVIDE, Variant::TRANSFORM3D, Variant::FLOAT); + + register_op<OperatorEvaluatorDiv<Basis, Basis, int64_t>>(Variant::OP_DIVIDE, Variant::BASIS, Variant::INT); + register_op<OperatorEvaluatorDiv<Basis, Basis, double>>(Variant::OP_DIVIDE, Variant::BASIS, Variant::FLOAT); + register_op<OperatorEvaluatorDiv<Quaternion, Quaternion, double>>(Variant::OP_DIVIDE, Variant::QUATERNION, Variant::FLOAT); register_op<OperatorEvaluatorDiv<Quaternion, Quaternion, int64_t>>(Variant::OP_DIVIDE, Variant::QUATERNION, Variant::INT); diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index 05f7abf32c..50c9c10987 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -30,6 +30,8 @@ #include "variant_setget.h" +#include "variant_callable.h" + struct VariantSetterGetterInfo { void (*setter)(Variant *base, const Variant *value, bool &valid); void (*getter)(const Variant *base, Variant *value); @@ -264,42 +266,45 @@ void Variant::set_named(const StringName &p_member, const Variant &p_value, bool } Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { - Variant ret; uint32_t s = variant_setters_getters[type].size(); if (s) { for (uint32_t i = 0; i < s; i++) { if (variant_setters_getters_names[type][i] == p_member) { + Variant ret; variant_setters_getters[type][i].getter(this, &ret); r_valid = true; return ret; } } + } - r_valid = false; - - } else if (type == Variant::OBJECT) { - Object *obj = get_validated_object(); - if (!obj) { - r_valid = false; - return "Instance base is null."; - } else { - return obj->get(p_member, &r_valid); - } - } else if (type == Variant::DICTIONARY) { - const Variant *v = VariantGetInternalPtr<Dictionary>::get_ptr(this)->getptr(p_member); - if (v) { - r_valid = true; - - return *v; - } else { - r_valid = false; - } - - } else { - r_valid = false; + switch (type) { + case Variant::OBJECT: { + Object *obj = get_validated_object(); + if (!obj) { + r_valid = false; + return "Instance base is null."; + } else { + return obj->get(p_member, &r_valid); + } + } break; + case Variant::DICTIONARY: { + const Variant *v = VariantGetInternalPtr<Dictionary>::get_ptr(this)->getptr(p_member); + if (v) { + r_valid = true; + return *v; + } + } break; + default: { + if (Variant::has_builtin_method(type, p_member)) { + r_valid = true; + return Callable(memnew(VariantCallable(*this, p_member))); + } + } break; } - return ret; + r_valid = false; + return Variant(); } /**** INDEXED SETTERS AND GETTERS ****/ @@ -1166,30 +1171,48 @@ bool Variant::has_key(const Variant &p_key, bool &r_valid) const { } } -void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) { +void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid, VariantSetError *err_code) { + if (err_code) { + *err_code = VariantSetError::SET_OK; + } if (type == DICTIONARY || type == OBJECT) { bool valid; set_keyed(p_index, p_value, valid); if (r_valid) { *r_valid = valid; + if (!valid && err_code) { + *err_code = VariantSetError::SET_KEYED_ERR; + } } } else { bool valid = false; if (p_index.get_type() == STRING_NAME) { set_named(*VariantGetInternalPtr<StringName>::get_ptr(&p_index), p_value, valid); + if (!valid && err_code) { + *err_code = VariantSetError::SET_NAMED_ERR; + } } else if (p_index.get_type() == INT) { bool obb; set_indexed(*VariantGetInternalPtr<int64_t>::get_ptr(&p_index), p_value, valid, obb); if (obb) { valid = false; + if (err_code) { + *err_code = VariantSetError::SET_INDEXED_ERR; + } } } else if (p_index.get_type() == STRING) { // less efficient version of named set_named(*VariantGetInternalPtr<String>::get_ptr(&p_index), p_value, valid); + if (!valid && err_code) { + *err_code = VariantSetError::SET_NAMED_ERR; + } } else if (p_index.get_type() == FLOAT) { // less efficient version of indexed bool obb; set_indexed(*VariantGetInternalPtr<double>::get_ptr(&p_index), p_value, valid, obb); if (obb) { valid = false; + if (err_code) { + *err_code = VariantSetError::SET_INDEXED_ERR; + } } } if (r_valid) { @@ -1198,31 +1221,49 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) } } -Variant Variant::get(const Variant &p_index, bool *r_valid) const { +Variant Variant::get(const Variant &p_index, bool *r_valid, VariantGetError *err_code) const { + if (err_code) { + *err_code = VariantGetError::GET_OK; + } Variant ret; if (type == DICTIONARY || type == OBJECT) { bool valid; ret = get_keyed(p_index, valid); if (r_valid) { *r_valid = valid; + if (!valid && err_code) { + *err_code = VariantGetError::GET_KEYED_ERR; + } } } else { bool valid = false; if (p_index.get_type() == STRING_NAME) { ret = get_named(*VariantGetInternalPtr<StringName>::get_ptr(&p_index), valid); + if (!valid && err_code) { + *err_code = VariantGetError::GET_NAMED_ERR; + } } else if (p_index.get_type() == INT) { bool obb; ret = get_indexed(*VariantGetInternalPtr<int64_t>::get_ptr(&p_index), valid, obb); if (obb) { valid = false; + if (err_code) { + *err_code = VariantGetError::GET_INDEXED_ERR; + } } } else if (p_index.get_type() == STRING) { // less efficient version of named ret = get_named(*VariantGetInternalPtr<String>::get_ptr(&p_index), valid); + if (!valid && err_code) { + *err_code = VariantGetError::GET_NAMED_ERR; + } } else if (p_index.get_type() == FLOAT) { // less efficient version of indexed bool obb; ret = get_indexed(*VariantGetInternalPtr<double>::get_ptr(&p_index), valid, obb); if (obb) { valid = false; + if (err_code) { + *err_code = VariantGetError::GET_INDEXED_ERR; + } } } if (r_valid) { diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 77c5a168f3..8fa15a2736 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -234,20 +234,9 @@ var b = clamp(8.1, 0.9, 5.5) # b is 5.5 - - var c = clamp(Vector2(-3.5, -4), Vector2(-3.2, -2), Vector2(2, 6.5)) - # c is (-3.2, -2) - - var d = clamp(Vector2i(7, 8), Vector2i(-3, -2), Vector2i(2, 6)) - # d is (2, 6) - - var e = clamp(Vector3(-7, 8.5, -3.8), Vector3(-3, -2, 5.4), Vector3(-2, 6, -4.1)) - # e is (-3, -2, 5.4) - - var f = clamp(Vector3i(-7, -8, -9), Vector3i(-1, 2, 3), Vector3i(-4, -5, -6)) - # f is (-4, -5, -6) [/codeblock] - [b]Note:[/b] For better type safety, use [method clampf], [method clampi], [method Vector2.clamp], [method Vector2i.clamp], [method Vector3.clamp], [method Vector3i.clamp], [method Vector4.clamp], [method Vector4i.clamp], or [method Color.clamp]. + [b]Note:[/b] For better type safety, use [method clampf], [method clampi], [method Vector2.clamp], [method Vector2i.clamp], [method Vector3.clamp], [method Vector3i.clamp], [method Vector4.clamp], [method Vector4i.clamp], or [method Color.clamp] (not currently supported by this method). + [b]Note:[/b] When using this on vectors it will [i]not[/i] perform component-wise clamping, and will pick [param min] if [code]value < min[/code] or [param max] if [code]value > max[/code]. To perform component-wise clamping use the methods listed above. </description> </method> <method name="clampf"> diff --git a/doc/classes/AStarGrid2D.xml b/doc/classes/AStarGrid2D.xml index 277630588a..7764233116 100644 --- a/doc/classes/AStarGrid2D.xml +++ b/doc/classes/AStarGrid2D.xml @@ -157,6 +157,9 @@ </method> </methods> <members> + <member name="cell_shape" type="int" setter="set_cell_shape" getter="get_cell_shape" enum="AStarGrid2D.CellShape" default="0"> + The cell shape. Affects how the positions are placed in the grid. If changed, [method update] needs to be called before finding the next path. + </member> <member name="cell_size" type="Vector2" setter="set_cell_size" getter="get_cell_size" default="Vector2(1, 1)"> The size of the point cell which will be applied to calculate the resulting point position returned by [method get_point_path]. If changed, [method update] needs to be called before finding the next path. </member> @@ -238,5 +241,17 @@ <constant name="DIAGONAL_MODE_MAX" value="4" enum="DiagonalMode"> Represents the size of the [enum DiagonalMode] enum. </constant> + <constant name="CELL_SHAPE_SQUARE" value="0" enum="CellShape"> + Rectangular cell shape. + </constant> + <constant name="CELL_SHAPE_ISOMETRIC_RIGHT" value="1" enum="CellShape"> + Diamond cell shape (for isometric look). Cell coordinates layout where the horizontal axis goes up-right, and the vertical one goes down-right. + </constant> + <constant name="CELL_SHAPE_ISOMETRIC_DOWN" value="2" enum="CellShape"> + Diamond cell shape (for isometric look). Cell coordinates layout where the horizontal axis goes down-right, and the vertical one goes down-left. + </constant> + <constant name="CELL_SHAPE_MAX" value="3" enum="CellShape"> + Represents the size of the [enum CellShape] enum. + </constant> </constants> </class> diff --git a/doc/classes/AnimationMixer.xml b/doc/classes/AnimationMixer.xml index 4a489a3ef2..31308c4e20 100644 --- a/doc/classes/AnimationMixer.xml +++ b/doc/classes/AnimationMixer.xml @@ -15,10 +15,10 @@ <param index="0" name="animation" type="Animation" /> <param index="1" name="track" type="int" /> <param index="2" name="value" type="Variant" /> - <param index="3" name="object" type="Object" /> - <param index="4" name="object_idx" type="int" /> + <param index="3" name="object_id" type="int" /> + <param index="4" name="object_sub_idx" type="int" /> <description> - A virtual function for processing after key getting during playback. + A virtual function for processing after getting a key during playback. </description> </method> <method name="add_animation_library"> diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index fccf16fcaa..3252cbf840 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -544,6 +544,7 @@ <param index="0" name="size" type="int" /> <description> Resizes the array to contain a different number of elements. If the array size is smaller, elements are cleared, if bigger, new elements are [code]null[/code]. Returns [constant OK] on success, or one of the other [enum Error] values if the operation failed. + Calling [method resize] once and assigning the new values is faster than adding new elements one by one. [b]Note:[/b] This method acts in-place and doesn't return a modified array. </description> </method> diff --git a/doc/classes/AudioEffectCapture.xml b/doc/classes/AudioEffectCapture.xml index 275e5ab0b6..e17c510907 100644 --- a/doc/classes/AudioEffectCapture.xml +++ b/doc/classes/AudioEffectCapture.xml @@ -6,11 +6,10 @@ <description> AudioEffectCapture is an AudioEffect which copies all audio frames from the attached audio effect bus into its internal ring buffer. Application code should consume these audio frames from this ring buffer using [method get_buffer] and process it as needed, for example to capture data from an [AudioStreamMicrophone], implement application-defined effects, or to transmit audio over the network. When capturing audio data from a microphone, the format of the samples will be stereo 32-bit floating point PCM. - [b]Note:[/b] [member ProjectSettings.audio/driver/enable_input] must be [code]true[/code] for audio input to work. See also that setting's description for caveats related to permissions and operating system privacy settings. + Unlike [AudioEffectRecord], this effect only returns the raw audio samples instead of encoding them into an [AudioStream]. </description> <tutorials> <link title="Audio buses">$DOCS_URL/tutorials/audio/audio_buses.html</link> - <link title="Audio Mic Record Demo">https://github.com/godotengine/godot-demo-projects/tree/master/audio/mic_record</link> </tutorials> <methods> <method name="can_get_buffer" qualifiers="const"> diff --git a/doc/classes/AudioEffectRecord.xml b/doc/classes/AudioEffectRecord.xml index e07d66fa7b..5b43c5ebaa 100644 --- a/doc/classes/AudioEffectRecord.xml +++ b/doc/classes/AudioEffectRecord.xml @@ -4,9 +4,10 @@ Audio effect used for recording the sound from an audio bus. </brief_description> <description> - Allows the user to record the sound from an audio bus. This can include all audio output by Godot when used on the "Master" audio bus. + Allows the user to record the sound from an audio bus into an [AudioStreamWAV]. When used on the "Master" audio bus, this includes all audio output by Godot. + Unlike [AudioEffectCapture], this effect encodes the recording with the given format (8-bit, 16-bit, or compressed) instead of giving access to the raw audio samples. Can be used (with an [AudioStreamMicrophone]) to record from a microphone. - It sets and gets the format in which the audio file will be recorded (8-bit, 16-bit, or compressed). It checks whether or not the recording is active, and if it is, records the sound. It then returns the recorded sample. + [b]Note:[/b] [member ProjectSettings.audio/driver/enable_input] must be [code]true[/code] for audio input to work. See also that setting's description for caveats related to permissions and operating system privacy settings. </description> <tutorials> <link title="Recording with microphone">$DOCS_URL/tutorials/audio/recording_with_microphone.html</link> diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index 653397ebc3..e3a7eda563 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -383,7 +383,7 @@ If [code]true[/code], enables subsurface scattering transmittance. Only effective if [member subsurf_scatter_enabled] is [code]true[/code]. See also [member backlight_enabled]. </member> <member name="subsurf_scatter_transmittance_texture" type="Texture2D" setter="set_texture" getter="get_texture"> - The texture to use for multiplying the intensity of the subsurface scattering transmitteance intensity. See also [member subsurf_scatter_texture]. Ignored if [member subsurf_scatter_skin_mode] is [code]true[/code]. + The texture to use for multiplying the intensity of the subsurface scattering transmittance intensity. See also [member subsurf_scatter_texture]. Ignored if [member subsurf_scatter_skin_mode] is [code]true[/code]. </member> <member name="texture_filter" type="int" setter="set_texture_filter" getter="get_texture_filter" enum="BaseMaterial3D.TextureFilter" default="3"> Filter flags for the texture. See [enum TextureFilter] for options. diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml index f98c207a6e..c271e23f2e 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -7,7 +7,7 @@ A 3×3 matrix used for representing 3D rotation and scale. Usually used as an orthogonal basis for a [Transform3D]. Contains 3 vector fields X, Y and Z as its columns, which are typically interpreted as the local basis vectors of a transformation. For such use, it is composed of a scaling and a rotation matrix, in that order (M = R.S). Basis can also be accessed as an array of 3D vectors. These vectors are usually orthogonal to each other, but are not necessarily normalized (due to scaling). - For more information, read the "Matrices and transforms" documentation article. + For a general introduction, see the [url=$DOCS_URL/tutorials/math/matrices_and_transforms.html]Matrices and transforms[/url] tutorial. </description> <tutorials> <link title="Math documentation index">$DOCS_URL/tutorials/math/index.html</link> @@ -71,6 +71,20 @@ <param index="1" name="order" type="int" default="2" /> <description> Constructs a pure rotation Basis matrix from Euler angles in the specified Euler rotation order. By default, use YXZ order (most common). See the [enum EulerOrder] enum for possible values. + [codeblocks] + [gdscript] + # Creates a Basis whose z axis points down. + var my_basis = Basis.from_euler(Vector3(TAU / 4, 0, 0)) + + print(my_basis.z) # Prints (0, -1, 0). + [/gdscript] + [csharp] + // Creates a Basis whose z axis points down. + var myBasis = Basis.FromEuler(new Vector3(Mathf.Tau / 4.0f, 0.0f, 0.0f)); + + GD.Print(myBasis.Z); // Prints (0, -1, 0). + [/csharp] + [/codeblocks] </description> </method> <method name="from_scale" qualifiers="static"> @@ -78,6 +92,22 @@ <param index="0" name="scale" type="Vector3" /> <description> Constructs a pure scale basis matrix with no rotation or shearing. The scale values are set as the diagonal of the matrix, and the other parts of the matrix are zero. + [codeblocks] + [gdscript] + var my_basis = Basis.from_scale(Vector3(2, 4, 8)) + + print(my_basis.x) # Prints (2, 0, 0). + print(my_basis.y) # Prints (0, 4, 0). + print(my_basis.z) # Prints (0, 0, 8). + [/gdscript] + [csharp] + var myBasis = Basis.FromScale(new Vector3(2.0f, 4.0f, 8.0f)); + + GD.Print(myBasis.X); // Prints (2, 0, 0). + GD.Print(myBasis.Y); // Prints (0, 4, 0). + GD.Print(myBasis.Z); // Prints (0, 0, 8). + [/csharp] + [/codeblocks] </description> </method> <method name="get_euler" qualifiers="const"> @@ -98,6 +128,32 @@ <return type="Vector3" /> <description> Assuming that the matrix is the combination of a rotation and scaling, return the absolute value of scaling factors along each axis. + [codeblocks] + [gdscript] + var my_basis = Basis( + Vector3(2, 0, 0), + Vector3(0, 4, 0), + Vector3(0, 0, 8) + ) + # Rotating the Basis in any way preserves its scale. + my_basis = my_basis.rotated(Vector3.UP, TAU / 2) + my_basis = my_basis.rotated(Vector3.RIGHT, TAU / 4) + + print(my_basis.get_scale()) # Prints (2, 4, 8). + [/gdscript] + [csharp] + var myBasis = new Basis( + Vector3(2.0f, 0.0f, 0.0f), + Vector3(0.0f, 4.0f, 0.0f), + Vector3(0.0f, 0.0f, 8.0f) + ); + // Rotating the Basis in any way preserves its scale. + myBasis = myBasis.Rotated(Vector3.Up, Mathf.Tau / 2.0f); + myBasis = myBasis.Rotated(Vector3.Right, Mathf.Tau / 4.0f); + + GD.Print(myBasis.Scale); // Prints (2, 4, 8). + [/csharp] + [/codeblocks] </description> </method> <method name="inverse" qualifiers="const"> @@ -140,6 +196,25 @@ <return type="Basis" /> <description> Returns the orthonormalized version of the matrix (useful to call from time to time to avoid rounding error for orthogonal matrices). This performs a Gram-Schmidt orthonormalization on the basis of the matrix. + [codeblocks] + [gdscript] + # Rotate this Node3D every frame. + func _process(delta): + basis = basis.rotated(Vector3.UP, TAU * delta) + basis = basis.rotated(Vector3.RIGHT, TAU * delta) + + basis = basis.orthonormalized() + [/gdscript] + [csharp] + // Rotate this Node3D every frame. + public override void _Process(double delta) + { + Basis = Basis.Rotated(Vector3.Up, Mathf.Tau * (float)delta) + .Rotated(Vector3.Right, Mathf.Tau * (float)delta) + .Orthonormalized(); + } + [/csharp] + [/codeblocks] </description> </method> <method name="rotated" qualifiers="const"> @@ -148,6 +223,24 @@ <param index="1" name="angle" type="float" /> <description> Introduce an additional rotation around the given axis by [param angle] (in radians). The axis must be a normalized vector. + [codeblocks] + [gdscript] + var my_basis = Basis.IDENTITY + var angle = TAU / 2 + + my_basis = my_basis.rotated(Vector3.UP, angle) # Rotate around the up axis (yaw). + my_basis = my_basis.rotated(Vector3.RIGHT, angle) # Rotate around the right axis (pitch). + my_basis = my_basis.rotated(Vector3.BACK, angle) # Rotate around the back axis (roll). + [/gdscript] + [csharp] + var myBasis = Basis.Identity; + var angle = Mathf.Tau / 2.0f; + + myBasis = myBasis.Rotated(Vector3.Up, angle); // Rotate around the up axis (yaw). + myBasis = myBasis.Rotated(Vector3.Right, angle); // Rotate around the right axis (pitch). + myBasis = myBasis.Rotated(Vector3.Back, angle); // Rotate around the back axis (roll). + [/csharp] + [/codeblocks] </description> </method> <method name="scaled" qualifiers="const"> @@ -155,6 +248,32 @@ <param index="0" name="scale" type="Vector3" /> <description> Introduce an additional scaling specified by the given 3D scaling factor. + [codeblocks] + [gdscript] + var my_basis = Basis( + Vector3(1, 1, 1), + Vector3(2, 2, 2), + Vector3(3, 3, 3) + ) + my_basis = my_basis.scaled(Vector3(0, 2, -2)) + + print(my_basis.x) # Prints (0, 2, -2). + print(my_basis.y) # Prints (0, 4, -4). + print(my_basis.z) # Prints (0, 6, -6). + [/gdscript] + [csharp] + var myBasis = new Basis( + new Vector3(1.0f, 1.0f, 1.0f), + new Vector3(2.0f, 2.0f, 2.0f), + new Vector3(3.0f, 3.0f, 3.0f) + ); + myBasis = myBasis.Scaled(new Vector3(0.0f, 2.0f, -2.0f)); + + GD.Print(myBasis.X); // Prints (0, 2, -2). + GD.Print(myBasis.Y); // Prints (0, 4, -4). + GD.Print(myBasis.Z); // Prints (0, 6, -6). + [/csharp] + [/codeblocks] </description> </method> <method name="slerp" qualifiers="const"> @@ -190,6 +309,32 @@ <return type="Basis" /> <description> Returns the transposed version of the matrix. + [codeblocks] + [gdscript] + var my_basis = Basis( + Vector3(1, 2, 3), + Vector3(4, 5, 6), + Vector3(7, 8, 9) + ) + my_basis = my_basis.transposed() + + print(my_basis.x) # Prints (1, 4, 7). + print(my_basis.y) # Prints (2, 5, 8). + print(my_basis.z) # Prints (3, 6, 9). + [/gdscript] + [csharp] + var myBasis = new Basis( + new Vector3(1.0f, 2.0f, 3.0f), + new Vector3(4.0f, 5.0f, 6.0f), + new Vector3(7.0f, 8.0f, 9.0f) + ); + myBasis = myBasis.Transposed(); + + GD.Print(myBasis.X); // Prints (1, 4, 7). + GD.Print(myBasis.Y); // Prints (2, 5, 8). + GD.Print(myBasis.Z); // Prints (3, 6, 9). + [/csharp] + [/codeblocks] </description> </method> </methods> @@ -256,6 +401,20 @@ This operator multiplies all components of the [Basis], which scales it uniformly. </description> </operator> + <operator name="operator /"> + <return type="Basis" /> + <param index="0" name="right" type="float" /> + <description> + This operator divides all components of the [Basis], which inversely scales it uniformly. + </description> + </operator> + <operator name="operator /"> + <return type="Basis" /> + <param index="0" name="right" type="int" /> + <description> + This operator divides all components of the [Basis], which inversely scales it uniformly. + </description> + </operator> <operator name="operator =="> <return type="bool" /> <param index="0" name="right" type="Basis" /> diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml index b903e98319..3550a6b7bd 100644 --- a/doc/classes/Callable.xml +++ b/doc/classes/Callable.xml @@ -46,17 +46,6 @@ # Prints "Attack!", when the button_pressed signal is emitted. button_pressed.connect(func(): print("Attack!")) [/codeblock] - [b]Note:[/b] Methods of native types such as [Signal], [Array], or [Dictionary] are not of type [Callable] in order to avoid unnecessary overhead. If you need to pass those methods as [Callable], use a lambda function as a wrapper. - [codeblock] - func _init(): - var my_dictionary = { "hello": "world" } - - # This will not work, `clear` is not a callable. - create_tween().tween_callback(my_dictionary.clear) - - # This will work, as lambdas are custom callables. - create_tween().tween_callback(func(): my_dictionary.clear()) - [/codeblock] </description> <tutorials> </tutorials> diff --git a/doc/classes/CameraAttributesPractical.xml b/doc/classes/CameraAttributesPractical.xml index 8a5956cc87..893bc27f91 100644 --- a/doc/classes/CameraAttributesPractical.xml +++ b/doc/classes/CameraAttributesPractical.xml @@ -17,7 +17,7 @@ The minimum sensitivity (in ISO) used when calculating auto exposure. When calculating scene average luminance, color values will be clamped to at least this value. This limits the auto-exposure from exposing above a certain brightness, resulting in a cut off point where the scene will remain dark. </member> <member name="dof_blur_amount" type="float" setter="set_dof_blur_amount" getter="get_dof_blur_amount" default="0.1"> - Sets the maximum amount of blur. When using physically-based blur amounts, will instead act as a multiplier. High values lead to an increased amount of bluriness, but can be much more expensive to calculate. It is best to keep this as low as possible for a given art style. + Sets the maximum amount of blur. When using physically-based blur amounts, will instead act as a multiplier. High values lead to an increased amount of blurriness, but can be much more expensive to calculate. It is best to keep this as low as possible for a given art style. </member> <member name="dof_blur_far_distance" type="float" setter="set_dof_blur_far_distance" getter="get_dof_blur_far_distance" default="10.0"> Objects further from the [Camera3D] by this amount will be blurred by the depth of field effect. Measured in meters. diff --git a/doc/classes/CanvasTexture.xml b/doc/classes/CanvasTexture.xml index 1b22adb723..a14f71cc46 100644 --- a/doc/classes/CanvasTexture.xml +++ b/doc/classes/CanvasTexture.xml @@ -5,7 +5,7 @@ </brief_description> <description> [CanvasTexture] is an alternative to [ImageTexture] for 2D rendering. It allows using normal maps and specular maps in any node that inherits from [CanvasItem]. [CanvasTexture] also allows overriding the texture's filter and repeat mode independently of the node's properties (or the project settings). - [b]Note:[/b] [CanvasTexture] cannot be used in 3D rendering. For physically-based materials in 3D, use [BaseMaterial3D] instead. + [b]Note:[/b] [CanvasTexture] cannot be used in 3D. It will not display correctly when applied to any [VisualInstance3D], such as [Sprite3D] or [Decal]. For physically-based materials in 3D, use [BaseMaterial3D] instead. </description> <tutorials> <link title="2D Lights and Shadows">$DOCS_URL/tutorials/2d/2d_lights_and_shadows.html</link> diff --git a/doc/classes/CollisionPolygon2D.xml b/doc/classes/CollisionPolygon2D.xml index d6f3b7cb5d..acb3f66c17 100644 --- a/doc/classes/CollisionPolygon2D.xml +++ b/doc/classes/CollisionPolygon2D.xml @@ -25,6 +25,7 @@ </member> <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array()"> The polygon's list of vertices. Each point will be connected to the next, and the final point will be connected to the first. + [b]Note:[/b] The returned vertices are in the local coordinate space of the given [CollisionPolygon2D]. [b]Warning:[/b] The returned value is a clone of the [PackedVector2Array], not a reference. </member> </members> diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index dfa8d7d840..ce450f6786 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -186,6 +186,9 @@ <theme_item name="sample_bg" data_type="icon" type="Texture2D"> Background panel for the color preview box (visible when the color is translucent). </theme_item> + <theme_item name="sample_revert" data_type="icon" type="Texture2D"> + The icon for the revert button (visible on the middle of the "old" color when it differs from the currently selected color). This icon is modulated with a dark color if the "old" color is bright enough, so the icon should be bright to ensure visibility in both scenarios. + </theme_item> <theme_item name="screen_picker" data_type="icon" type="Texture2D"> The icon for the screen color picker button. </theme_item> diff --git a/doc/classes/CompressedCubemap.xml b/doc/classes/CompressedCubemap.xml index 6ab0cc5d88..406ab4909a 100644 --- a/doc/classes/CompressedCubemap.xml +++ b/doc/classes/CompressedCubemap.xml @@ -4,7 +4,7 @@ An optionally compressed [Cubemap]. </brief_description> <description> - A cubemap that is loaded from a [code].ccube[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedCubemap] can use one of 4 compresson methods: + A cubemap that is loaded from a [code].ccube[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedCubemap] can use one of 4 compression methods: - Lossless (WebP or PNG, uncompressed on the GPU) - Lossy (WebP, uncompressed on the GPU) - VRAM Compressed (compressed on the GPU) diff --git a/doc/classes/CompressedCubemapArray.xml b/doc/classes/CompressedCubemapArray.xml index 32687229ed..195449ee99 100644 --- a/doc/classes/CompressedCubemapArray.xml +++ b/doc/classes/CompressedCubemapArray.xml @@ -4,7 +4,7 @@ An optionally compressed [CubemapArray]. </brief_description> <description> - A cubemap array that is loaded from a [code].ccubearray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedCubemapArray] can use one of 4 compresson methods: + A cubemap array that is loaded from a [code].ccubearray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedCubemapArray] can use one of 4 compression methods: - Lossless (WebP or PNG, uncompressed on the GPU) - Lossy (WebP, uncompressed on the GPU) - VRAM Compressed (compressed on the GPU) diff --git a/doc/classes/CompressedTexture2DArray.xml b/doc/classes/CompressedTexture2DArray.xml index ab0684fa06..6570e8f931 100644 --- a/doc/classes/CompressedTexture2DArray.xml +++ b/doc/classes/CompressedTexture2DArray.xml @@ -4,7 +4,7 @@ Array of 2-dimensional textures, optionally compressed. </brief_description> <description> - A texture array that is loaded from a [code].ctexarray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedTexture2DArray] can use one of 4 compresson methods: + A texture array that is loaded from a [code].ctexarray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedTexture2DArray] can use one of 4 compression methods: - Lossless (WebP or PNG, uncompressed on the GPU) - Lossy (WebP, uncompressed on the GPU) - VRAM Compressed (compressed on the GPU) diff --git a/doc/classes/Curve2D.xml b/doc/classes/Curve2D.xml index 197d03f0d8..0e75c65f50 100644 --- a/doc/classes/Curve2D.xml +++ b/doc/classes/Curve2D.xml @@ -107,16 +107,14 @@ <param index="0" name="offset" type="float" default="0.0" /> <param index="1" name="cubic" type="bool" default="false" /> <description> - Similar to [method sample_baked], but returns [Transform2D] that includes a rotation along the curve, with [member Transform2D.origin] as the point position, [member Transform2D.x] as the sideways vector, and [member Transform2D.y] as the forward vector. Returns an empty transform if the length of the curve is [code]0[/code]. + Similar to [method sample_baked], but returns [Transform2D] that includes a rotation along the curve, with [member Transform2D.origin] as the point position and the [member Transform2D.x] vector pointing in the direction of the path at that point. Returns an empty transform if the length of the curve is [code]0[/code]. [codeblock] var baked = curve.sample_baked_with_rotation(offset) - # This will rotate and position the node with the up direction pointing along the curve. + # The returned Transform2D can be set directly. + transform = baked + # You can also read the origin and rotation separately from the returned Transform2D. position = baked.get_origin() rotation = baked.get_rotation() - # Alternatively, not preserving scale. - transform = baked * Transform2D.FLIP_Y - # To match the rotation of PathFollow2D, not preserving scale. - transform = Transform2D(baked.y, baked.x, baked.origin) [/codeblock] </description> </method> diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml index 82ba956151..88a6eeec26 100644 --- a/doc/classes/EditorImportPlugin.xml +++ b/doc/classes/EditorImportPlugin.xml @@ -120,6 +120,13 @@ <link title="Import plugins">$DOCS_URL/tutorials/plugins/editor/import_plugins.html</link> </tutorials> <methods> + <method name="_can_import_threaded" qualifiers="virtual const"> + <return type="bool" /> + <description> + Tells whether this importer can be run in parallel on threads, or, on the contrary, it's only safe for the editor to call it from the main thread, for one file at a time. + If this method is not overridden, it will return [code]true[/code] by default (i.e., safe for parallel importing). + </description> + </method> <method name="_get_import_options" qualifiers="virtual const"> <return type="Dictionary[]" /> <param index="0" name="path" type="String" /> diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml index cfdc172fd1..6b25be490e 100644 --- a/doc/classes/EditorInspector.xml +++ b/doc/classes/EditorInspector.xml @@ -28,6 +28,7 @@ </method> </methods> <members> + <member name="follow_focus" type="bool" setter="set_follow_focus" getter="is_following_focus" overrides="ScrollContainer" default="true" /> <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> <signals> diff --git a/doc/classes/EditorNode3DGizmo.xml b/doc/classes/EditorNode3DGizmo.xml index 1680400384..7597489601 100644 --- a/doc/classes/EditorNode3DGizmo.xml +++ b/doc/classes/EditorNode3DGizmo.xml @@ -9,6 +9,13 @@ <tutorials> </tutorials> <methods> + <method name="_begin_handle_action" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="id" type="int" /> + <param index="1" name="secondary" type="bool" /> + <description> + </description> + </method> <method name="_commit_handle" qualifiers="virtual"> <return type="void" /> <param index="0" name="id" type="int" /> diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml index da7ee17335..8fd7c167d9 100644 --- a/doc/classes/EditorNode3DGizmoPlugin.xml +++ b/doc/classes/EditorNode3DGizmoPlugin.xml @@ -11,6 +11,14 @@ <link title="Node3D gizmo plugins">$DOCS_URL/tutorials/plugins/editor/3d_gizmos.html</link> </tutorials> <methods> + <method name="_begin_handle_action" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="gizmo" type="EditorNode3DGizmo" /> + <param index="1" name="handle_id" type="int" /> + <param index="2" name="secondary" type="bool" /> + <description> + </description> + </method> <method name="_can_be_hidden" qualifiers="virtual const"> <return type="bool" /> <description> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 50709f9ef5..148a6541a2 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -327,7 +327,7 @@ <param index="0" name="object" type="Object" /> <description> Implement this function if your plugin edits a specific type of object (Resource or Node). If you return [code]true[/code], then you will get the functions [method _edit] and [method _make_visible] called when the editor requests them. If you have declared the methods [method _forward_canvas_gui_input] and [method _forward_3d_gui_input] these will be called too. - [b]Note:[/b] Each plugin should handle only one type of objects at a time. If a plugin handes more types of objects and they are edited at the same time, it will result in errors. + [b]Note:[/b] Each plugin should handle only one type of objects at a time. If a plugin handles more types of objects and they are edited at the same time, it will result in errors. </description> </method> <method name="_has_main_screen" qualifiers="virtual const"> diff --git a/doc/classes/GDExtension.xml b/doc/classes/GDExtension.xml index ee55c89131..533b32218f 100644 --- a/doc/classes/GDExtension.xml +++ b/doc/classes/GDExtension.xml @@ -1,31 +1,42 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="GDExtension" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> + A native library for GDExtension. </brief_description> <description> + The [GDExtension] resource type represents a [url=https://en.wikipedia.org/wiki/Shared_library]shared library[/url] which can expand the functionality of the engine. The [GDExtensionManager] singleton is responsible for loading, reloading, and unloading [GDExtension] resources. + [b]Note:[/b] GDExtension itself is not a scripting language and has no relation to [GDScript] resources. </description> <tutorials> + <link title="GDExtension overview">$DOCS_URL/tutorials/scripting/gdextension/what_is_gdextension.html</link> + <link title="GDExtension example in C++">$DOCS_URL/tutorials/scripting/gdextension/gdextension_cpp_example.html</link> </tutorials> <methods> <method name="close_library"> <return type="void" /> <description> + Closes the current library. + [b]Note:[/b] You normally should not call this method directly. This is handled automatically by [method GDExtensionManager.unload_extension]. </description> </method> <method name="get_minimum_library_initialization_level" qualifiers="const"> <return type="int" enum="GDExtension.InitializationLevel" /> <description> + Returns the lowest level required for this extension to be properly initialized (see the [enum InitializationLevel] enum). </description> </method> <method name="initialize_library"> <return type="void" /> <param index="0" name="level" type="int" enum="GDExtension.InitializationLevel" /> <description> + Initializes the library bound to this GDextension at the given initialization [param level]. + [b]Note:[/b] You normally should not call this method directly. This is handled automatically by [method GDExtensionManager.load_extension]. </description> </method> <method name="is_library_open" qualifiers="const"> <return type="bool" /> <description> + Returns [code]true[/code] if this extension's library has been opened. </description> </method> <method name="open_library"> @@ -33,17 +44,23 @@ <param index="0" name="path" type="String" /> <param index="1" name="entry_symbol" type="String" /> <description> + Opens the library at the specified [param path]. + [b]Note:[/b] You normally should not call this method directly. This is handled automatically by [method GDExtensionManager.load_extension]. </description> </method> </methods> <constants> <constant name="INITIALIZATION_LEVEL_CORE" value="0" enum="InitializationLevel"> + The library is initialized at the same time as the core features of the engine. </constant> <constant name="INITIALIZATION_LEVEL_SERVERS" value="1" enum="InitializationLevel"> + The library is initialized at the same time as the engine's servers (such as [RenderingServer] or [PhysicsServer3D]). </constant> <constant name="INITIALIZATION_LEVEL_SCENE" value="2" enum="InitializationLevel"> + The library is initialized at the same time as the engine's scene-related classes. </constant> <constant name="INITIALIZATION_LEVEL_EDITOR" value="3" enum="InitializationLevel"> + The library is initialized at the same time as the engine's editor classes. Only happens when loading the GDExtension in the editor. </constant> </constants> </class> diff --git a/doc/classes/GDExtensionManager.xml b/doc/classes/GDExtensionManager.xml index 8d2515dc28..1ecb23a03b 100644 --- a/doc/classes/GDExtensionManager.xml +++ b/doc/classes/GDExtensionManager.xml @@ -1,65 +1,82 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="GDExtensionManager" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> + Provides access to GDExtension functionality. </brief_description> <description> + The GDExtensionManager loads, initializes, and keeps track of all available [GDExtension] libraries in the project. + [b]Note:[/b] Do not worry about GDExtension unless you know what you are doing. </description> <tutorials> + <link title="GDExtension overview">$DOCS_URL/tutorials/scripting/gdextension/what_is_gdextension.html</link> + <link title="GDExtension example in C++">$DOCS_URL/tutorials/scripting/gdextension/gdextension_cpp_example.html</link> </tutorials> <methods> <method name="get_extension"> <return type="GDExtension" /> <param index="0" name="path" type="String" /> <description> + Returns the [GDExtension] at the given file [param path], or [code]null[/code] if it has not been loaded or does not exist. </description> </method> <method name="get_loaded_extensions" qualifiers="const"> <return type="PackedStringArray" /> <description> + Returns the file paths of all currently loaded extensions. </description> </method> <method name="is_extension_loaded" qualifiers="const"> <return type="bool" /> <param index="0" name="path" type="String" /> <description> + Returns [code]true[/code] if the extension at the given file [param path] has already been loaded successfully. See also [method get_loaded_extensions]. </description> </method> <method name="load_extension"> <return type="int" enum="GDExtensionManager.LoadStatus" /> <param index="0" name="path" type="String" /> <description> + Loads an extension by absolute file path. The [param path] needs to point to a valid [GDExtension]. Returns [constant LOAD_STATUS_OK] if successful. </description> </method> <method name="reload_extension"> <return type="int" enum="GDExtensionManager.LoadStatus" /> <param index="0" name="path" type="String" /> <description> + Reloads the extension at the given file path. The [param path] needs to point to a valid [GDExtension], otherwise this method may return either [constant LOAD_STATUS_NOT_LOADED] or [constant LOAD_STATUS_FAILED]. + [b]Note:[/b] You can only reload extensions in the editor. In release builds, this method always fails and returns [constant LOAD_STATUS_FAILED]. </description> </method> <method name="unload_extension"> <return type="int" enum="GDExtensionManager.LoadStatus" /> <param index="0" name="path" type="String" /> <description> + Unloads an extension by file path. The [param path] needs to point to an already loaded [GDExtension], otherwise this method returns [constant LOAD_STATUS_NOT_LOADED]. </description> </method> </methods> <signals> <signal name="extensions_reloaded"> <description> - Emitted after the editor has automatically reloaded any extensions. + Emitted after the editor has finished reloading one or more extensions. </description> </signal> </signals> <constants> <constant name="LOAD_STATUS_OK" value="0" enum="LoadStatus"> + The extension has loaded successfully. </constant> <constant name="LOAD_STATUS_FAILED" value="1" enum="LoadStatus"> + The extension has failed to load, possibly because it does not exist or has missing dependencies. </constant> <constant name="LOAD_STATUS_ALREADY_LOADED" value="2" enum="LoadStatus"> + The extension has already been loaded. </constant> <constant name="LOAD_STATUS_NOT_LOADED" value="3" enum="LoadStatus"> + The extension has not been loaded. </constant> <constant name="LOAD_STATUS_NEEDS_RESTART" value="4" enum="LoadStatus"> + The extension requires the application to restart to fully load. </constant> </constants> </class> diff --git a/doc/classes/Geometry3D.xml b/doc/classes/Geometry3D.xml index a85d17d925..9f87682983 100644 --- a/doc/classes/Geometry3D.xml +++ b/doc/classes/Geometry3D.xml @@ -142,5 +142,12 @@ Tests if the segment ([param from], [param to]) intersects the triangle [param a], [param b], [param c]. If yes, returns the point of intersection as [Vector3]. If no intersection takes place, returns [code]null[/code]. </description> </method> + <method name="tetrahedralize_delaunay"> + <return type="PackedInt32Array" /> + <param index="0" name="points" type="PackedVector3Array" /> + <description> + Tetrahedralizes the volume specified by a discrete set of [param points] in 3D space, ensuring that no point lies within the circumsphere of any resulting tetrahedron. The method returns a [PackedInt32Array] where each tetrahedron consists of four consecutive point indices into the [param points] array (resulting in an array with [code]n * 4[/code] elements, where [code]n[/code] is the number of tetrahedra found). If the tetrahedralization is unsuccessful, an empty [PackedInt32Array] is returned. + </description> + </method> </methods> </class> diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml index 9e1392567a..5bb3a25158 100644 --- a/doc/classes/GraphNode.xml +++ b/doc/classes/GraphNode.xml @@ -116,6 +116,20 @@ Returns the right (output) [Color] of the slot with the given [param slot_index]. </description> </method> + <method name="get_slot_custom_icon_left" qualifiers="const"> + <return type="Texture2D" /> + <param index="0" name="slot_index" type="int" /> + <description> + Returns the left (input) custom [Texture2D] of the slot with the given [param slot_index]. + </description> + </method> + <method name="get_slot_custom_icon_right" qualifiers="const"> + <return type="Texture2D" /> + <param index="0" name="slot_index" type="int" /> + <description> + Returns the right (output) custom [Texture2D] of the slot with the given [param slot_index]. + </description> + </method> <method name="get_slot_type_left" qualifiers="const"> <return type="int" /> <param index="0" name="slot_index" type="int" /> @@ -195,6 +209,22 @@ Sets the [Color] of the right (output) side of the slot with the given [param slot_index] to [param color]. </description> </method> + <method name="set_slot_custom_icon_left"> + <return type="void" /> + <param index="0" name="slot_index" type="int" /> + <param index="1" name="custom_icon" type="Texture2D" /> + <description> + Sets the custom [Texture2D] of the left (input) side of the slot with the given [param slot_index] to [param custom_icon]. + </description> + </method> + <method name="set_slot_custom_icon_right"> + <return type="void" /> + <param index="0" name="slot_index" type="int" /> + <param index="1" name="custom_icon" type="Texture2D" /> + <description> + Sets the custom [Texture2D] of the right (output) side of the slot with the given [param slot_index] to [param custom_icon]. + </description> + </method> <method name="set_slot_draw_stylebox"> <return type="void" /> <param index="0" name="slot_index" type="int" /> diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 5677999d5d..6c1ecb3aea 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -19,6 +19,7 @@ <param index="1" name="contrast" type="float" /> <param index="2" name="saturation" type="float" /> <description> + Adjusts this image's [param brightness], [param contrast], and [param saturation] by the given values. Does not work if the image is compressed (see [method is_compressed]). </description> </method> <method name="blend_rect"> @@ -163,6 +164,7 @@ <return type="int" enum="Image.UsedChannels" /> <param index="0" name="source" type="int" enum="Image.CompressSource" default="0" /> <description> + Returns the color channels used by this image, as one of the [enum UsedChannels] constants. If the image is compressed, the original [param source] must be specified. </description> </method> <method name="fill"> @@ -612,6 +614,7 @@ OpenGL texture format [code]RGBA[/code] with four components, each with a bitdepth of 4. </constant> <constant name="FORMAT_RGB565" value="7" enum="Format"> + OpenGL texture format [code]RGB[/code] with three components. Red and blue have a bitdepth of 5, and green has a bitdepth of 6. </constant> <constant name="FORMAT_RF" value="8" enum="Format"> OpenGL texture format [code]GL_R32F[/code] where there's one component, a 32-bit floating-point value. @@ -696,8 +699,10 @@ [b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space conversion is performed. </constant> <constant name="FORMAT_ETC2_RA_AS_RG" value="33" enum="Format"> + [url=https://en.wikipedia.org/wiki/Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression format 2[/url] ([code]RGBA8[/code] variant), which compresses RA data and interprets it as two channels (red and green). See also [constant FORMAT_ETC2_RGBA8]. </constant> <constant name="FORMAT_DXT5_RA_AS_RG" value="34" enum="Format"> + The [url=https://en.wikipedia.org/wiki/S3_Texture_Compression]S3TC[/url] texture format also known as Block Compression 3 or BC3, which compresses RA data and interprets it as two channels (red and green). See also [constant FORMAT_DXT5]. </constant> <constant name="FORMAT_ASTC_4x4" value="35" enum="Format"> [url=https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression]Adaptive Scalable Texture Compression[/url]. This implements the 4x4 (high quality) mode. @@ -731,7 +736,7 @@ On the other hand, if the image already has mipmaps, they will be used, and a new set will be generated for the resulting image. </constant> <constant name="INTERPOLATE_LANCZOS" value="4" enum="Interpolation"> - Performs Lanczos interpolation. This is the slowest image resizing mode, but it typically gives the best results, especially when downscalng images. + Performs Lanczos interpolation. This is the slowest image resizing mode, but it typically gives the best results, especially when downscaling images. </constant> <constant name="ALPHA_NONE" value="0" enum="AlphaMode"> Image does not have alpha. @@ -761,16 +766,22 @@ Represents the size of the [enum CompressMode] enum. </constant> <constant name="USED_CHANNELS_L" value="0" enum="UsedChannels"> + The image only uses one channel for luminance (grayscale). </constant> <constant name="USED_CHANNELS_LA" value="1" enum="UsedChannels"> + The image uses two channels for luminance and alpha, respectively. </constant> <constant name="USED_CHANNELS_R" value="2" enum="UsedChannels"> + The image only uses the red channel. </constant> <constant name="USED_CHANNELS_RG" value="3" enum="UsedChannels"> + The image uses two channels for red and green. </constant> <constant name="USED_CHANNELS_RGB" value="4" enum="UsedChannels"> + The image uses three channels for red, green, and blue. </constant> <constant name="USED_CHANNELS_RGBA" value="5" enum="UsedChannels"> + The image uses four channels for red, green, blue, and alpha. </constant> <constant name="COMPRESS_SOURCE_GENERIC" value="0" enum="CompressSource"> Source texture (before compression) is a regular texture. Default for all textures. diff --git a/doc/classes/InputEventMIDI.xml b/doc/classes/InputEventMIDI.xml index d685fdfa41..8e2ad52801 100644 --- a/doc/classes/InputEventMIDI.xml +++ b/doc/classes/InputEventMIDI.xml @@ -75,7 +75,7 @@ If the message is [constant MIDI_MESSAGE_CONTROL_CHANGE], this indicates the controller value, otherwise this is zero. Controllers include devices such as pedals and levers. </member> <member name="instrument" type="int" setter="set_instrument" getter="get_instrument" default="0"> - The instrument of this input event. This value ranges from 0 to 127. Refer to the instrument list on the General MIDI wikipedia article to see a list of instruments, except that this value is 0-index, so subtract one from every number on that chart. A standard piano will have an instrument number of 0. + The instrument of this input event. This value ranges from 0 to 127. Refer to the instrument list for [url=https://en.wikipedia.org/wiki/General_MIDI#Program_change_events]General MIDI[/url] to see a list of instruments, except that this value is 0-index, so subtract one from every number on that chart. A standard piano will have an instrument number of 0. </member> <member name="message" type="int" setter="set_message" getter="get_message" enum="MIDIMessage" default="0"> Returns a value indicating the type of message for this MIDI signal. This is a member of the [enum MIDIMessage] enum. diff --git a/doc/classes/LightmapGI.xml b/doc/classes/LightmapGI.xml index ec75d85898..fa3bfe513f 100644 --- a/doc/classes/LightmapGI.xml +++ b/doc/classes/LightmapGI.xml @@ -65,6 +65,9 @@ The quality preset to use when baking lightmaps. This affects bake times, but output file sizes remain mostly identical across quality levels. To further speed up bake times, decrease [member bounces], disable [member use_denoiser] and increase the lightmap texel size on 3D scenes in the Import doc. </member> + <member name="texel_scale" type="float" setter="set_texel_scale" getter="get_texel_scale" default="1.0"> + Scales the lightmap texel density of all meshes for the current bake. This is a multiplier that builds upon the existing lightmap texel size defined in each imported 3D scene, along with the per-mesh density multiplier (which is designed to be used when the same mesh is used at different scales). Lower values will result in faster bake times. + </member> <member name="use_denoiser" type="bool" setter="set_use_denoiser" getter="is_using_denoiser" default="true"> If [code]true[/code], uses a GPU-based denoising algorithm on the generated lightmap. This eliminates most noise within the generated lightmap at the cost of longer bake times. File sizes are generally not impacted significantly by the use of a denoiser, although lossless compression may do a better job at compressing a denoised image. </member> diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index 20af517397..c04017651c 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -278,7 +278,7 @@ <param index="1" name="enabled" type="bool" /> <description> Sets if the agent uses the 2D avoidance or the 3D avoidance while avoidance is enabled. - If [code]true[/code] the agent calculates avoidance velocities in 3D for the xyz-axis, e.g. for games that take place in air, unterwater or space. The 3D using agent only avoids other 3D avoidance using agent's. The 3D using agent only reacts to radius based avoidance obstacles. The 3D using agent ignores any vertices based obstacles. The 3D using agent only avoids other 3D using agent's. + If [code]true[/code] the agent calculates avoidance velocities in 3D for the xyz-axis, e.g. for games that take place in air, underwater or space. The 3D using agent only avoids other 3D avoidance using agent's. The 3D using agent only reacts to radius based avoidance obstacles. The 3D using agent ignores any vertices based obstacles. The 3D using agent only avoids other 3D using agent's. If [code]false[/code] the agent calculates avoidance velocities in 2D along the xz-axis ignoring the y-axis. The 2D using agent only avoids other 2D avoidance using agent's. The 2D using agent reacts to radius avoidance obstacles. The 2D using agent reacts to vertices based avoidance obstacles. The 2D using agent only avoids other 2D using agent's. 2D using agents will ignore other 2D using agents or obstacles that are below their current position or above their current position including the agents height in 2D avoidance. </description> </method> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 0ace4357fa..5dd3d22062 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -11,11 +11,11 @@ This means that when adding a node to the scene tree, the following order will be used for the callbacks: [method _enter_tree] of the parent, [method _enter_tree] of the children, [method _ready] of the children and finally [method _ready] of the parent (recursively for the entire scene tree). [b]Processing:[/b] Nodes can override the "process" state, so that they receive a callback on each frame requesting them to process (do something). Normal processing (callback [method _process], toggled with [method set_process]) happens as fast as possible and is dependent on the frame rate, so the processing time [i]delta[/i] (in seconds) is passed as an argument. Physics processing (callback [method _physics_process], toggled with [method set_physics_process]) happens a fixed number of times per second (60 by default) and is useful for code related to the physics engine. Nodes can also process input events. When present, the [method _input] function will be called for each input that the program receives. In many cases, this can be overkill (unless used for simple projects), and the [method _unhandled_input] function might be preferred; it is called when the input event was not handled by anyone else (typically, GUI [Control] nodes), ensuring that the node only receives the events that were meant for it. - To keep track of the scene hierarchy (especially when instancing scenes into other scenes), an "owner" can be set for the node with the [member owner] property. This keeps track of who instantiated what. This is mostly useful when writing editors and tools, though. + To keep track of the scene hierarchy (especially when instantiating scenes into other scenes), an "owner" can be set for the node with the [member owner] property. This keeps track of who instantiated what. This is mostly useful when writing editors and tools, though. Finally, when a node is freed with [method Object.free] or [method queue_free], it will also free all its children. [b]Groups:[/b] Nodes can be added to as many groups as you want to be easy to manage, you could create groups like "enemies" or "collectables" for example, depending on your game. See [method add_to_group], [method is_in_group] and [method remove_from_group]. You can then retrieve all nodes in these groups, iterate them and even call methods on groups via the methods on [SceneTree]. [b]Networking with nodes:[/b] After connecting to a server (or making one, see [ENetMultiplayerPeer]), it is possible to use the built-in RPC (remote procedure call) system to communicate over the network. By calling [method rpc] with a method name, it will be called locally and in all connected peers (peers = clients and the server that accepts connections). To identify which node receives the RPC call, Godot will use its [NodePath] (make sure node names are the same on all peers). Also, take a look at the high-level networking tutorial and corresponding demos. - [b]Note:[/b] The [code]script[/code] property is part of the [Object] class, not [Node]. It isn't exposed like most properties but does have a setter and getter ([code]set_script()[/code] and [code]get_script()[/code]). + [b]Note:[/b] The [code]script[/code] property is part of the [Object] class, not [Node]. It isn't exposed like most properties but does have a setter and getter (see [method Object.set_script] and [method Object.get_script]). </description> <tutorials> <link title="Nodes and scenes">$DOCS_URL/getting_started/step_by_step/nodes_and_scenes.html</link> @@ -25,7 +25,7 @@ <method name="_enter_tree" qualifiers="virtual"> <return type="void" /> <description> - Called when the node enters the [SceneTree] (e.g. upon instancing, scene changing, or after calling [method add_child] in a script). If the node has children, its [method _enter_tree] callback will be called first, and then that of the children. + Called when the node enters the [SceneTree] (e.g. upon instantiating, scene changing, or after calling [method add_child] in a script). If the node has children, its [method _enter_tree] callback will be called first, and then that of the children. Corresponds to the [constant NOTIFICATION_ENTER_TREE] notification in [method Object._notification]. </description> </method> @@ -93,7 +93,7 @@ Called when the node is "ready", i.e. when both the node and its children have entered the scene tree. If the node has children, their [method _ready] callbacks get triggered first, and the parent node will receive the ready notification afterwards. Corresponds to the [constant NOTIFICATION_READY] notification in [method Object._notification]. See also the [code]@onready[/code] annotation for variables. Usually used for initialization. For even earlier initialization, [method Object._init] may be used. See also [method _enter_tree]. - [b]Note:[/b] [method _ready] may be called only once for each node. After removing a node from the scene tree and adding it again, [method _ready] will not be called a second time. This can be bypassed by requesting another call with [method request_ready], which may be called anywhere before adding the node again. + [b]Note:[/b] This method may be called only once for each node. After removing a node from the scene tree and adding it again, [method _ready] will [b]not[/b] be called a second time. This can be bypassed by requesting another call with [method request_ready], which may be called anywhere before adding the node again. </description> </method> <method name="_shortcut_input" qualifiers="virtual"> @@ -138,8 +138,8 @@ <description> Adds a child [param node]. Nodes can have any number of children, but every child must have a unique name. Child nodes are automatically deleted when the parent node is deleted, so an entire scene can be removed by deleting its topmost node. If [param force_readable_name] is [code]true[/code], improves the readability of the added [param node]. If not named, the [param node] is renamed to its type, and if it shares [member name] with a sibling, a number is suffixed more appropriately. This operation is very slow. As such, it is recommended leaving this to [code]false[/code], which assigns a dummy name featuring [code]@[/code] in both situations. - If [param internal] is different than [constant INTERNAL_MODE_DISABLED], the child will be added as internal node. Such nodes are ignored by methods like [method get_children], unless their parameter [code]include_internal[/code] is [code]true[/code]. The intended usage is to hide the internal nodes from the user, so the user won't accidentally delete or modify them. Used by some GUI nodes, e.g. [ColorPicker]. See [enum InternalMode] for available modes. - [b]Note:[/b] If the child node already has a parent, the function will fail. Use [method remove_child] first to remove the node from its current parent. For example: + If [param internal] is different than [constant INTERNAL_MODE_DISABLED], the child will be added as internal node. These nodes are ignored by methods like [method get_children], unless their parameter [code]include_internal[/code] is [code]true[/code]. The intended usage is to hide the internal nodes from the user, so the user won't accidentally delete or modify them. Used by some GUI nodes, e.g. [ColorPicker]. See [enum InternalMode] for available modes. + [b]Note:[/b] If [param node] already has a parent, this method will fail. Use [method remove_child] first to remove [param node] from its current parent. For example: [codeblocks] [gdscript] var child_node = get_child(0) @@ -165,10 +165,10 @@ <param index="0" name="sibling" type="Node" /> <param index="1" name="force_readable_name" type="bool" default="false" /> <description> - Adds a [param sibling] node to current's node parent, at the same level as that node, right below it. + Adds a [param sibling] node to this node's parent, and moves the added sibling right below this node. If [param force_readable_name] is [code]true[/code], improves the readability of the added [param sibling]. If not named, the [param sibling] is renamed to its type, and if it shares [member name] with a sibling, a number is suffixed more appropriately. This operation is very slow. As such, it is recommended leaving this to [code]false[/code], which assigns a dummy name featuring [code]@[/code] in both situations. Use [method add_child] instead of this method if you don't need the child node to be added below a specific node in the list of children. - [b]Note:[/b] If this node is internal, the new sibling will be internal too (see [code]internal[/code] parameter in [method add_child]). + [b]Note:[/b] If this node is internal, the added sibling will be internal too (see [method add_child]'s [code]internal[/code] parameter). </description> </method> <method name="add_to_group"> @@ -176,9 +176,10 @@ <param index="0" name="group" type="StringName" /> <param index="1" name="persistent" type="bool" default="false" /> <description> - Adds the node to a group. Groups are helpers to name and organize a subset of nodes, for example "enemies" or "collectables". A node can be in any number of groups. Nodes can be assigned a group at any time, but will not be added until they are inside the scene tree (see [method is_inside_tree]). See notes in the description, and the group methods in [SceneTree]. - The [param persistent] option is used when packing node to [PackedScene] and saving to file. Non-persistent groups aren't stored. - [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. + Adds the node to the [param group]. Groups can be helpful to organize a subset of nodes, for example [code]"enemies"[/code] or [code]"collectables"[/code]. See notes in the description, and the group methods in [SceneTree]. + If [param persistent] is [code]true[/code], the group will be stored when saved inside a [PackedScene]. All groups created and displayed in the Node dock are persistent. + [b]Note:[/b] To improve performance, the order of group names is [i]not[/i] guaranteed and may vary between project runs. Therefore, do not rely on the group order. + [b]Note:[/b] [SceneTree]'s group methods will [i]not[/i] work on this node if not inside the tree (see [method is_inside_tree]). </description> </method> <method name="call_deferred_thread_group" qualifiers="vararg"> @@ -198,13 +199,14 @@ <method name="can_process" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if the node can process while the scene tree is paused (see [member process_mode]). Always returns [code]true[/code] if the scene tree is not paused, and [code]false[/code] if the node is not in the tree. + Returns [code]true[/code] if the node can receive processing notifications and input callbacks ([constant NOTIFICATION_PROCESS], [method _input], etc) from the [SceneTree] and [Viewport]. The value depends on both the current [member process_mode] and [member SceneTree.paused]. Returns [code]false[/code] if the node is not inside the tree. </description> </method> <method name="create_tween"> <return type="Tween" /> <description> - Creates a new [Tween] and binds it to this node. This is equivalent of doing: + Creates a new [Tween] and binds it to this node. Fails if the node is not inside the tree. + This is the equivalent of doing: [codeblocks] [gdscript] get_tree().create_tween().bind_node(self) @@ -220,9 +222,8 @@ <return type="Node" /> <param index="0" name="flags" type="int" default="15" /> <description> - Duplicates the node, returning a new node. - You can fine-tune the behavior using the [param flags] (see [enum DuplicateFlags]). - [b]Note:[/b] It will not work properly if the node contains a script with constructor arguments (i.e. needs to supply arguments to [method Object._init] method). In that case, the node will be duplicated without a script. + Duplicates the node, returning a new node with all of its properties, signals and groups copied from the original. The behavior can be tweaked through the [param flags] (see [enum DuplicateFlags]). + [b]Note:[/b] For nodes with a [Script] attached, if [method Object._init] has been defined with required parameters, the duplicated node will not have a [Script]. </description> </method> <method name="find_child" qualifiers="const"> @@ -231,12 +232,10 @@ <param index="1" name="recursive" type="bool" default="true" /> <param index="2" name="owned" type="bool" default="true" /> <description> - Finds the first descendant of this node whose name matches [param pattern] as in [method String.match]. Internal children are also searched over (see [code]internal[/code] parameter in [method add_child]). - [param pattern] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]). - If [param recursive] is [code]true[/code], all child nodes are included, even if deeply nested. Nodes are checked in tree order, so this node's first direct child is checked first, then its own direct children, etc., before moving to the second direct child, and so on. If [param recursive] is [code]false[/code], only this node's direct children are matched. - If [param owned] is [code]true[/code], this method only finds nodes who have an assigned [member Node.owner]. This is especially important for scenes instantiated through a script, because those scenes don't have an owner. - Returns [code]null[/code] if no matching [Node] is found. - [b]Note:[/b] As this method walks through all the descendants of the node, it is the slowest way to get a reference to another node. Whenever possible, consider using [method get_node] with unique names instead (see [member unique_name_in_owner]), or caching the node references into variable. + Finds the first descendant of this node whose [member name] matches [param pattern], returning [code]null[/code] if no match is found. The matching is done against node names, [i]not[/i] their paths, through [method String.match]. As such, it is case-sensitive, [code]"*"[/code] matches zero or more characters, and [code]"?"[/code] matches any single character. + If [param recursive] is [code]false[/code], only this node's direct children are checked. Nodes are checked in tree order, so this node's first direct child is checked first, then its own direct children, etc., before moving to the second direct child, and so on. Internal children are also included in the search (see [code]internal[/code] parameter in [method add_child]). + If [param owned] is [code]true[/code], only descendants with a valid [member owner] node are checked. + [b]Note:[/b] This method can be very slow. Consider storing a reference to the found node in a variable. Alternatively, use [method get_node] with unique names (see [member unique_name_in_owner]). [b]Note:[/b] To find all descendant nodes matching a pattern or a class type, see [method find_children]. </description> </method> @@ -247,23 +246,20 @@ <param index="2" name="recursive" type="bool" default="true" /> <param index="3" name="owned" type="bool" default="true" /> <description> - Finds descendants of this node whose name matches [param pattern] as in [method String.match], and/or type matches [param type] as in [method Object.is_class]. Internal children are also searched over (see [code]internal[/code] parameter in [method add_child]). - [param pattern] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]). - [param type] will check equality or inheritance, and is case-sensitive. [code]"Object"[/code] will match a node whose type is [code]"Node"[/code] but not the other way around. - If [param recursive] is [code]true[/code], all child nodes are included, even if deeply nested. Nodes are checked in tree order, so this node's first direct child is checked first, then its own direct children, etc., before moving to the second direct child, and so on. If [param recursive] is [code]false[/code], only this node's direct children are matched. - If [param owned] is [code]true[/code], this method only finds nodes who have an assigned [member Node.owner]. This is especially important for scenes instantiated through a script, because those scenes don't have an owner. - Returns an empty array if no matching nodes are found. - [b]Note:[/b] As this method walks through all the descendants of the node, it is the slowest way to get references to other nodes. Whenever possible, consider caching the node references into variables. - [b]Note:[/b] If you only want to find the first descendant node that matches a pattern, see [method find_child]. + Finds all descendants of this node whose names match [param pattern], returning an empty [Array] if no match is found. The matching is done against node names, [i]not[/i] their paths, through [method String.match]. As such, it is case-sensitive, [code]"*"[/code] matches zero or more characters, and [code]"?"[/code] matches any single character. + If [param type] is not empty, only ancestors inheriting from [param type] are included (see [method Object.is_class]). + If [param recursive] is [code]false[/code], only this node's direct children are checked. Nodes are checked in tree order, so this node's first direct child is checked first, then its own direct children, etc., before moving to the second direct child, and so on. Internal children are also included in the search (see [code]internal[/code] parameter in [method add_child]). + If [param owned] is [code]true[/code], only descendants with a valid [member owner] node are checked. + [b]Note:[/b] This method can be very slow. Consider storing references to the found nodes in a variable. + [b]Note:[/b] To find a single descendant node matching a pattern, see [method find_child]. </description> </method> <method name="find_parent" qualifiers="const"> <return type="Node" /> <param index="0" name="pattern" type="String" /> <description> - Finds the first parent of the current node whose name matches [param pattern] as in [method String.match]. - [param pattern] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]). - [b]Note:[/b] As this method walks upwards in the scene tree, it can be slow in large, deeply nested scene trees. Whenever possible, consider using [method get_node] with unique names instead (see [member unique_name_in_owner]), or caching the node references into variable. + Finds the first ancestor of this node whose [member name] matches [param pattern], returning [code]null[/code] if no match is found. The matching is done through [method String.match]. As such, it is case-sensitive, [code]"*"[/code] matches zero or more characters, and [code]"?"[/code] matches any single character. See also [method find_child] and [method find_children]. + [b]Note:[/b] As this method walks upwards in the scene tree, it can be slow in large, deeply nested nodes. Consider storing a reference to the found node in a variable. Alternatively, use [method get_node] with unique names (see [member unique_name_in_owner]). </description> </method> <method name="get_child" qualifiers="const"> @@ -271,44 +267,52 @@ <param index="0" name="idx" type="int" /> <param index="1" name="include_internal" type="bool" default="false" /> <description> - Returns a child node by its index (see [method get_child_count]). This method is often used for iterating all children of a node. - Negative indices access the children from the last one. - If [param include_internal] is [code]false[/code], internal children are skipped (see [code]internal[/code] parameter in [method add_child]). - To access a child node via its name, use [method get_node]. + Fetches a child node by its index. Each child node has an index relative its siblings (see [method get_index]). The first child is at index 0. Negative values can also be used to start from the end of the list. This method can be used in combination with [method get_child_count] to iterate over this node's children. If no child exists at the given index, this method returns [code]null[/code] and an error is generated. + If [param include_internal] is [code]false[/code], internal children are ignored (see [method add_child]'s [code]internal[/code] parameter). + [codeblock] + # Assuming the following are children of this node, in order: + # First, Middle, Last. + + var a = get_child(0).name # a is "First" + var b = get_child(1).name # b is "Middle" + var b = get_child(2).name # b is "Last" + var c = get_child(-1).name # c is "Last" + [/codeblock] + [b]Note:[/b] To fetch a node by [NodePath], use [method get_node]. </description> </method> <method name="get_child_count" qualifiers="const"> <return type="int" /> <param index="0" name="include_internal" type="bool" default="false" /> <description> - Returns the number of child nodes. - If [param include_internal] is [code]false[/code], internal children aren't counted (see [code]internal[/code] parameter in [method add_child]). + Returns the number of children of this node. + If [param include_internal] is [code]false[/code], internal children are not counted (see [method add_child]'s [code]internal[/code] parameter). </description> </method> <method name="get_children" qualifiers="const"> <return type="Node[]" /> <param index="0" name="include_internal" type="bool" default="false" /> <description> - Returns an array of references to node's children. - If [param include_internal] is [code]false[/code], the returned array won't include internal children (see [code]internal[/code] parameter in [method add_child]). + Returns all children of this node inside an [Array]. + If [param include_internal] is [code]false[/code], excludes internal children from the returned array (see [method add_child]'s [code]internal[/code] parameter). </description> </method> <method name="get_groups" qualifiers="const"> <return type="StringName[]" /> <description> - 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: + Returns an [Array] of group names that the node has been added to. + [b]Note:[/b] To improve performance, the order of group names is [i]not[/i] guaranteed and may vary between project runs. Therefore, do not rely on the group order. + [b]Note:[/b] This method may also return some group names starting with an underscore ([code]_[/code]). These are internally used by the engine. To avoid conflicts, do not use custom groups starting with underscores. To exclude internal groups, see the following code snippet: [codeblocks] [gdscript] - # Stores the node's non-internal groups only (as an array of Strings). + # Stores the node's non-internal groups only (as an array of StringNames). var non_internal_groups = [] for group in get_groups(): - if not group.begins_with("_"): + if not str(group).begins_with("_"): non_internal_groups.push_back(group) [/gdscript] [csharp] - // Stores the node's non-internal groups only (as a List of strings). + // Stores the node's non-internal groups only (as a List of StringNames). List<string> nonInternalGroups = new List<string>(); foreach (string group in GetGroups()) { @@ -323,8 +327,8 @@ <return type="int" /> <param index="0" name="include_internal" type="bool" default="false" /> <description> - Returns the node's order in the scene tree branch. For example, if called on the first child node the position is [code]0[/code]. - If [param include_internal] is [code]false[/code], the index won't take internal children into account, i.e. first non-internal child will have index of 0 (see [code]internal[/code] parameter in [method add_child]). + Returns this node's order among its siblings. The first node's index is [code]0[/code]. See also [method get_child]. + If [param include_internal] is [code]false[/code], returns the index ignoring internal children. The first, non-internal child will have an index of [code]0[/code] (see [method add_child]'s [code]internal[/code] parameter). </description> </method> <method name="get_last_exclusive_window" qualifiers="const"> @@ -343,20 +347,22 @@ <return type="Node" /> <param index="0" name="path" type="NodePath" /> <description> - Fetches a node. The [NodePath] can be either a relative path (from the current node) or an absolute path (in the scene tree) to a node. If the path does not exist, [code]null[/code] is returned and an error is logged. Attempts to access methods on the return value will result in an "Attempt to call <method> on a null instance." error. - [b]Note:[/b] Fetching absolute paths only works when the node is inside the scene tree (see [method is_inside_tree]). - [b]Example:[/b] Assume your current node is Character and the following tree: + Fetches a node. The [NodePath] can either be a relative path (from this node), or an absolute path (from the [member SceneTree.root]) to a node. If [param path] does not point to a valid node, generates an error and returns [code]null[/code]. Attempts to access methods on the return value will result in an [i]"Attempt to call <method> on a null instance."[/i] error. + [b]Note:[/b] Fetching by absolute path only works when the node is inside the scene tree (see [method is_inside_tree]). + [b]Example:[/b] Assume this method is called from the Character node, inside the following tree: [codeblock] - /root - /root/Character - /root/Character/Sword - /root/Character/Backpack/Dagger - /root/MyGame - /root/Swamp/Alligator - /root/Swamp/Mosquito - /root/Swamp/Goblin + ┖╴root + ┠╴Character (you are here!) + ┃ ┠╴Sword + ┃ ┖╴Backpack + ┃ ┖╴Dagger + ┠╴MyGame + ┖╴Swamp + ┠╴Alligator + ┠╴Mosquito + ┖╴Goblin [/codeblock] - Possible paths are: + The following calls will return a valid node: [codeblocks] [gdscript] get_node("Sword") @@ -377,19 +383,43 @@ <return type="Array" /> <param index="0" name="path" type="NodePath" /> <description> - Fetches a node and one of its resources as specified by the [NodePath]'s subname (e.g. [code]Area2D/CollisionShape2D:shape[/code]). If several nested resources are specified in the [NodePath], the last one will be fetched. - The return value is an array of size 3: the first index points to the [Node] (or [code]null[/code] if not found), the second index points to the [Resource] (or [code]null[/code] if not found), and the third index is the remaining [NodePath], if any. - For example, assuming that [code]Area2D/CollisionShape2D[/code] is a valid node and that its [code]shape[/code] property has been assigned a [RectangleShape2D] resource, one could have this kind of output: + Fetches a node and its most nested resource as specified by the [NodePath]'s subname. Returns an [Array] of size [code]3[/code] where: + - Element [code]0[/code] is the [Node], or [code]null[/code] if not found; + - Element [code]1[/code] is the subname's last nested [Resource], or [code]null[/code] if not found; + - Element [code]2[/code] is the remaining [NodePath], referring to an existing, non-[Resource] property (see [method Object.get_indexed]). + [b]Example:[/b] Assume that the child's [member Sprite2D.texture] has been assigned a [AtlasTexture]: [codeblocks] [gdscript] - print(get_node_and_resource("Area2D/CollisionShape2D")) # [[CollisionShape2D:1161], Null, ] - print(get_node_and_resource("Area2D/CollisionShape2D:shape")) # [[CollisionShape2D:1161], [RectangleShape2D:1156], ] - print(get_node_and_resource("Area2D/CollisionShape2D:shape:extents")) # [[CollisionShape2D:1161], [RectangleShape2D:1156], :extents] + var a = get_node_and_resource("Area2D/Sprite2D") + print(a[0].name) # Prints Sprite2D + print(a[1]) # Prints <null> + print(a[2]) # Prints ^"" + + var b = get_node_and_resource("Area2D/Sprite2D:texture:atlas") + print(b[0].name) # Prints Sprite2D + print(b[1].get_class()) # Prints AtlasTexture + print(b[2]) # Prints ^"" + + var c = get_node_and_resource("Area2D/Sprite2D:texture:atlas:region") + print(c[0].name) # Prints Sprite2D + print(c[1].get_class()) # Prints AtlasTexture + print(c[2]) # Prints ^":region" [/gdscript] [csharp] - GD.Print(GetNodeAndResource("Area2D/CollisionShape2D")); // [[CollisionShape2D:1161], Null, ] - GD.Print(GetNodeAndResource("Area2D/CollisionShape2D:shape")); // [[CollisionShape2D:1161], [RectangleShape2D:1156], ] - GD.Print(GetNodeAndResource("Area2D/CollisionShape2D:shape:extents")); // [[CollisionShape2D:1161], [RectangleShape2D:1156], :extents] + var a = GetNodeAndResource(NodePath("Area2D/Sprite2D")); + GD.Print(a[0].Name); // Prints Sprite2D + GD.Print(a[1]); // Prints <null> + GD.Print(a[2]); // Prints ^" + + var b = GetNodeAndResource(NodePath("Area2D/Sprite2D:texture:atlas")); + GD.Print(b[0].name); // Prints Sprite2D + GD.Print(b[1].get_class()); // Prints AtlasTexture + GD.Print(b[2]); // Prints ^"" + + var c = GetNodeAndResource(NodePath("Area2D/Sprite2D:texture:atlas:region")); + GD.Print(c[0].name); // Prints Sprite2D + GD.Print(c[1].get_class()); // Prints AtlasTexture + GD.Print(c[2]); // Prints ^":region" [/csharp] [/codeblocks] </description> @@ -398,19 +428,19 @@ <return type="Node" /> <param index="0" name="path" type="NodePath" /> <description> - Similar to [method get_node], but does not log an error if [param path] does not point to a valid [Node]. + Fetches a node by [NodePath]. Similar to [method get_node], but does not generate an error if [param path] does not point to a valid node. </description> </method> <method name="get_parent" qualifiers="const"> <return type="Node" /> <description> - Returns the parent node of the current node, or [code]null[/code] if the node lacks a parent. + Returns this node's parent node, or [code]null[/code] if the node doesn't have a parent. </description> </method> <method name="get_path" qualifiers="const"> <return type="NodePath" /> <description> - Returns the absolute path of the current node. This only works if the current node is inside the scene tree (see [method is_inside_tree]). + Returns the node's absolute path, relative to the [member SceneTree.root]. If the node is not inside the scene tree, this method fails and returns an empty [NodePath]. </description> </method> <method name="get_path_to" qualifiers="const"> @@ -418,33 +448,33 @@ <param index="0" name="node" type="Node" /> <param index="1" name="use_unique_path" type="bool" default="false" /> <description> - Returns the relative [NodePath] from this node to the specified [param node]. Both nodes must be in the same scene or the function will fail. - If [param use_unique_path] is [code]true[/code], returns the shortest path considering unique node. - [b]Note:[/b] If you get a relative path which starts from a unique node, the path may be longer than a normal relative path due to the addition of the unique node's name. + Returns the relative [NodePath] from this node to the specified [param node]. Both nodes must be in the same [SceneTree], otherwise this method fails and returns an empty [NodePath]. + If [param use_unique_path] is [code]true[/code], returns the shortest path accounting for this node's unique name (see [member unique_name_in_owner]). + [b]Note:[/b] If you get a relative path which starts from a unique node, the path may be longer than a normal relative path, due to the addition of the unique node's name. </description> </method> <method name="get_physics_process_delta_time" qualifiers="const"> <return type="float" /> <description> - Returns the time elapsed (in seconds) since the last physics-bound frame (see [method _physics_process]). This is always a constant value in physics processing unless the frames per second is changed via [member Engine.physics_ticks_per_second]. + Returns the time elapsed (in seconds) since the last physics callback. This value is identical to [method _physics_process]'s [code]delta[/code] parameter, and is often consistent at run-time, unless [member Engine.physics_ticks_per_second] is changed. See also [constant NOTIFICATION_PHYSICS_PROCESS]. </description> </method> <method name="get_process_delta_time" qualifiers="const"> <return type="float" /> <description> - Returns the time elapsed (in seconds) since the last process callback. This value may vary from frame to frame. + Returns the time elapsed (in seconds) since the last process callback. This value is identical to [method _process]'s [code]delta[/code] parameter, and may vary from frame to frame. See also [constant NOTIFICATION_PROCESS]. </description> </method> <method name="get_scene_instance_load_placeholder" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if this is an instance load placeholder. See [InstancePlaceholder]. + Returns [code]true[/code] if this node is an instance load placeholder. See [InstancePlaceholder] and [method set_scene_instance_load_placeholder]. </description> </method> <method name="get_tree" qualifiers="const"> <return type="SceneTree" /> <description> - Returns the [SceneTree] that contains this node. Returns [code]null[/code] and prints an error if this node is not inside the scene tree. See also [method is_inside_tree]. + Returns the [SceneTree] that contains this node. If this node is not inside the tree, generates an error and returns [code]null[/code]. See also [method is_inside_tree]. </description> </method> <method name="get_tree_string"> @@ -480,7 +510,7 @@ <method name="get_viewport" qualifiers="const"> <return type="Viewport" /> <description> - Returns the node's [Viewport]. + Returns the node's closest [Viewport] ancestor, if the node is inside the tree. Otherwise, returns [code]null[/code]. </description> </method> <method name="get_window" qualifiers="const"> @@ -493,54 +523,54 @@ <return type="bool" /> <param index="0" name="path" type="NodePath" /> <description> - Returns [code]true[/code] if the node that the [NodePath] points to exists. + Returns [code]true[/code] if the [param path] points to a valid node. See also [method get_node]. </description> </method> <method name="has_node_and_resource" qualifiers="const"> <return type="bool" /> <param index="0" name="path" type="NodePath" /> <description> - Returns [code]true[/code] if the [NodePath] points to a valid node and its subname points to a valid resource, e.g. [code]Area2D/CollisionShape2D:shape[/code]. Properties with a non-[Resource] type (e.g. nodes or primitive math types) are not considered resources. + Returns [code]true[/code] if [param path] points to a valid node and its subnames point to a valid [Resource], e.g. [code]Area2D/CollisionShape2D:shape[/code]. Properties that are not [Resource] types (such as nodes or other [Variant] types) are not considered. See also [method get_node_and_resource]. </description> </method> <method name="is_ancestor_of" qualifiers="const"> <return type="bool" /> <param index="0" name="node" type="Node" /> <description> - Returns [code]true[/code] if the given node is a direct or indirect child of the current node. + Returns [code]true[/code] if the given [param node] is a direct or indirect child of this node. </description> </method> <method name="is_displayed_folded" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if the node is folded (collapsed) in the Scene dock. This method is only intended for use with editor tooling. + Returns [code]true[/code] if the node is folded (collapsed) in the Scene dock. This method is intended to be used in editor plugins and tools. See also [method set_display_folded]. </description> </method> <method name="is_editable_instance" qualifiers="const"> <return type="bool" /> <param index="0" name="node" type="Node" /> <description> - Returns [code]true[/code] if [param node] has editable children enabled relative to this node. This method is only intended for use with editor tooling. + Returns [code]true[/code] if [param node] has editable children enabled relative to this node. This method is intended to be used in editor plugins and tools. See also [method set_editable_instance]. </description> </method> <method name="is_greater_than" qualifiers="const"> <return type="bool" /> <param index="0" name="node" type="Node" /> <description> - Returns [code]true[/code] if the given node occurs later in the scene hierarchy than the current node. + Returns [code]true[/code] if the given [param node] occurs later in the scene hierarchy than this node. A node occurring later is usually processed last. </description> </method> <method name="is_in_group" qualifiers="const"> <return type="bool" /> <param index="0" name="group" type="StringName" /> <description> - Returns [code]true[/code] if this node is in the specified group. See notes in the description, and the group methods in [SceneTree]. + Returns [code]true[/code] if this node has been added to the given [param group]. See [method add_to_group] and [method remove_from_group]. See also notes in the description, and the [SceneTree]'s group methods. </description> </method> <method name="is_inside_tree" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if this node is currently inside a [SceneTree]. + Returns [code]true[/code] if this node is currently inside a [SceneTree]. See also [method get_tree]. </description> </method> <method name="is_multiplayer_authority" qualifiers="const"> @@ -609,8 +639,8 @@ <param index="0" name="child_node" type="Node" /> <param index="1" name="to_index" type="int" /> <description> - Moves a child node to a different index (order) among the other children. Since calls, signals, etc. are performed by tree order, changing the order of children nodes may be useful. If [param to_index] is negative, the index will be counted from the end. - [b]Note:[/b] Internal children can only be moved within their expected "internal range" (see [code]internal[/code] parameter in [method add_child]). + Moves [param child_node] to the given index. A node's index is the order among its siblings. If [param to_index] is negative, the index is counted from the end of the list. See also [method get_child] and [method get_index]. + [b]Note:[/b] The processing order of several engine callbacks ([method _ready], [method _process], etc.) and notifications sent through [method propagate_notification] is affected by tree order. [CanvasItem] nodes are also rendered in tree order. See also [member process_priority]. </description> </method> <method name="notify_deferred_thread_group"> @@ -630,29 +660,29 @@ <method name="print_orphan_nodes" qualifiers="static"> <return type="void" /> <description> - Prints all orphan nodes (nodes outside the [SceneTree]). Used for debugging. - [b]Note:[/b] [method print_orphan_nodes] only works in debug builds. When called in a project exported in release mode, [method print_orphan_nodes] will not print anything. + Prints all orphan nodes (nodes outside the [SceneTree]). Useful for debugging. + [b]Note:[/b] This method only works in debug builds. Does nothing in a project exported in release mode. </description> </method> <method name="print_tree"> <return type="void" /> <description> - Prints the tree to stdout. Used mainly for debugging purposes. This version displays the path relative to the current node, and is good for copy/pasting into the [method get_node] function. + Prints the node and its children to the console, recursively. The node does not have to be inside the tree. This method outputs [NodePath]s relative to this node, and is good for copy/pasting into [method get_node]. See also [method print_tree_pretty]. [b]Example output:[/b] [codeblock] - TheGame - TheGame/Menu - TheGame/Menu/Label - TheGame/Menu/Camera2D - TheGame/SplashScreen - TheGame/SplashScreen/Camera2D + . + Menu + Menu/Label + Menu/Camera2D + SplashScreen + SplashScreen/Camera2D [/codeblock] </description> </method> <method name="print_tree_pretty"> <return type="void" /> <description> - Similar to [method print_tree], this prints the tree to stdout. This version displays a more graphical representation similar to what is displayed in the Scene Dock. It is useful for inspecting larger trees. + Prints the node and its children to the console, recursively. The node does not have to be inside the tree. Similar to [method print_tree], but the graphical representation looks like what is displayed in the editor's Scene dock. It is useful for inspecting larger trees. [b]Example output:[/b] [codeblock] ┖╴TheGame @@ -670,37 +700,38 @@ <param index="1" name="args" type="Array" default="[]" /> <param index="2" name="parent_first" type="bool" default="false" /> <description> - Calls the given method (if present) with the arguments given in [param args] on this node and recursively on all its children. If the [param parent_first] argument is [code]true[/code], the method will be called on the current node first, then on all its children. If [param parent_first] is [code]false[/code], the children will be called first. + Calls the given [param method] name, passing [param args] as arguments, on this node and all of its children, recursively. + If [param parent_first] is [code]true[/code], the method is called on this node first, then on all of its children. If [code]false[/code], the children's methods are called first. </description> </method> <method name="propagate_notification"> <return type="void" /> <param index="0" name="what" type="int" /> <description> - Notifies the current node and all its children recursively by calling [method Object.notification] on all of them. + Calls [method Object.notification] with [param what] on this node and all of its children, recursively. </description> </method> <method name="queue_free"> <return type="void" /> <description> - Queues a node for deletion at the end of the current frame. When deleted, all of its child nodes will be deleted as well, and all references to the node and its children will become invalid, see [method Object.free]. - It is safe to call [method queue_free] multiple times per frame on a node, and to [method Object.free] a node that is currently queued for deletion. Use [method Object.is_queued_for_deletion] to check whether a node will be deleted at the end of the frame. - The node will only be freed after all other deferred calls are finished, so using [method queue_free] is not always the same as calling [method Object.free] through [method Object.call_deferred]. + Queues this node to be deleted at the end of the current frame. When deleted, all of its children are deleted as well, and all references to the node and its children become invalid. + Unlike with [method Object.free], the node is not deleted instantly, and it can still be accessed before deletion. It is also safe to call [method queue_free] multiple times. Use [method Object.is_queued_for_deletion] to check if the node will be deleted at the end of the frame. + [b]Note:[/b] The node will only be freed after all other deferred calls are finished. Using this method is not always the same as calling [method Object.free] through [method Object.call_deferred]. </description> </method> <method name="remove_child"> <return type="void" /> <param index="0" name="node" type="Node" /> <description> - Removes a child node. The node is NOT deleted and must be deleted manually. - [b]Note:[/b] This function may set the [member owner] of the removed Node (or its descendants) to be [code]null[/code], if that [member owner] is no longer a parent or ancestor. + Removes a child [param node]. The [param node], along with its children, are [b]not[/b] deleted. To delete a node, see [method queue_free]. + [b]Note:[/b] When this node is inside the tree, this method sets the [member owner] of the removed [param node] (or its descendants) to [code]null[/code], if their [member owner] is no longer an ancestor (see [method is_ancestor_of]). </description> </method> <method name="remove_from_group"> <return type="void" /> <param index="0" name="group" type="StringName" /> <description> - Removes a node from the [param group]. Does nothing if the node is not in the [param group]. See notes in the description, and the group methods in [SceneTree]. + Removes the node from the given [param group]. Does nothing if the node is not in the [param group]. See also notes in the description, and the [SceneTree]'s group methods. </description> </method> <method name="reparent"> @@ -708,7 +739,7 @@ <param index="0" name="new_parent" type="Node" /> <param index="1" name="keep_global_transform" type="bool" default="true" /> <description> - Changes the parent of this [Node] to the [param new_parent]. The node needs to already have a parent. + Changes the parent of this [Node] to the [param new_parent]. The node needs to already have a parent. The node's [member owner] is preserved if its owner is still reachable from the new location (i.e., the node is still a descendant of the new parent after the operation). If [param keep_global_transform] is [code]true[/code], the node's global transform will be preserved if supported. [Node2D], [Node3D] and [Control] support this argument (but [Control] keeps only position). </description> </method> @@ -717,24 +748,25 @@ <param index="0" name="node" type="Node" /> <param index="1" name="keep_groups" type="bool" default="false" /> <description> - Replaces a node in a scene by the given one. Subscriptions that pass through this node will be lost. - If [param keep_groups] is [code]true[/code], the [param node] is added to the same groups that the replaced node is in. - [b]Note:[/b] The given node will become the new parent of any child nodes that the replaced node had. - [b]Note:[/b] The replaced node is not automatically freed, so you either need to keep it in a variable for later use or free it using [method Object.free]. + Replaces this node by the given [param node]. All children of this node are moved to [param node]. + If [param keep_groups] is [code]true[/code], the [param node] is added to the same groups that the replaced node is in (see [method add_to_group]). + [b]Warning:[/b] The replaced node is removed from the tree, but it is [b]not[/b] deleted. To prevent memory leaks, store a reference to the node in a variable, or use [method Object.free]. </description> </method> <method name="request_ready"> <return type="void" /> <description> - Requests that [method _ready] be called again. Note that the method won't be called immediately, but is scheduled for when the node is added to the scene tree again. [method _ready] is called only for the node which requested it, which means that you need to request ready for each child if you want them to call [method _ready] too (in which case, [method _ready] will be called in the same order as it would normally). + Requests [method _ready] to be called again the next time the node enters the tree. Does [b]not[/b] immediately call [method _ready]. + [b]Note:[/b] This method only affects the current node. If the node's children also need to request ready, this method needs to be called for each one of them. When the node and its children enter the tree again, the order of [method _ready] callbacks will be the same as normal. </description> </method> <method name="rpc" qualifiers="vararg"> <return type="int" enum="Error" /> <param index="0" name="method" type="StringName" /> <description> - Sends a remote procedure call request for the given [param method] to peers on the network (and locally), optionally sending all additional arguments as arguments to the method called by the RPC. The call request will only be received by nodes with the same [NodePath], including the exact same node name. Behavior depends on the RPC configuration for the given method, see [method rpc_config] and [annotation @GDScript.@rpc]. Methods are not exposed to RPCs by default. Returns [code]null[/code]. - [b]Note:[/b] You can only safely use RPCs on clients after you received the [code]connected_to_server[/code] signal from the [MultiplayerAPI]. You also need to keep track of the connection state, either by the [MultiplayerAPI] signals like [code]server_disconnected[/code] or by checking [code]get_multiplayer().peer.get_connection_status() == CONNECTION_CONNECTED[/code]. + Sends a remote procedure call request for the given [param method] to peers on the network (and locally), sending additional arguments to the method called by the RPC. The call request will only be received by nodes with the same [NodePath], including the exact same [member name]. Behavior depends on the RPC configuration for the given [param method] (see [method rpc_config] and [annotation @GDScript.@rpc]). By default, methods are not exposed to RPCs. + May return [constant OK] if the call is successful, [constant ERR_INVALID_PARAMETER] if the arguments passed in the [param method] do not match, [constant ERR_UNCONFIGURED] if the node's [member multiplayer] cannot be fetched (such as when the node is not inside the tree), [constant ERR_CONNECTION_ERROR] if [member multiplayer]'s connection is not available. + [b]Note:[/b] You can only safely use RPCs on clients after you received the [signal MultiplayerAPI.connected_to_server] signal from the [MultiplayerAPI]. You also need to keep track of the connection state, either by the [MultiplayerAPI] signals like [signal MultiplayerAPI.server_disconnected] or by checking ([code]get_multiplayer().peer.get_connection_status() == CONNECTION_CONNECTED[/code]). </description> </method> <method name="rpc_config"> @@ -742,16 +774,12 @@ <param index="0" name="method" type="StringName" /> <param index="1" name="config" type="Variant" /> <description> - Changes the RPC mode for the given [param method] with the given [param config] which should be [code]null[/code] (to disable) or a [Dictionary] in the form: - [codeblock] - { - rpc_mode = MultiplayerAPI.RPCMode, - transfer_mode = MultiplayerPeer.TransferMode, - call_local = false, - channel = 0, - } - [/codeblock] - See [enum MultiplayerAPI.RPCMode] and [enum MultiplayerPeer.TransferMode]. An alternative is annotating methods and properties with the corresponding [annotation @GDScript.@rpc] annotation ([code]@rpc("any_peer")[/code], [code]@rpc("authority")[/code]). By default, methods are not exposed to networking (and RPCs). + Changes the RPC configuration for the given [param method]. [param config] should either be [code]null[/code] to disable the feature (as by default), or a [Dictionary] containing the following entries: + - [code]rpc_mode[/code]: see [enum MultiplayerAPI.RPCMode]; + - [code]transfer_mode[/code]: see [enum MultiplayerPeer.TransferMode]; + - [code]call_local[/code]: if [code]true[/code], the method will also be called locally; + - [code]channel[/code]: an [int] representing the channel to send the RPC on. + [b]Note:[/b] In GDScript, this method corresponds to the [annotation @GDScript.@rpc] annotation, with various parameters passed ([code]@rpc(any)[/code], [code]@rpc(authority)[/code]...). See also the [url=$DOCS_URL/tutorials/networking/high_level_multiplayer.html]high-level multiplayer[/url] tutorial. </description> </method> <method name="rpc_id" qualifiers="vararg"> @@ -759,7 +787,8 @@ <param index="0" name="peer_id" type="int" /> <param index="1" name="method" type="StringName" /> <description> - Sends a [method rpc] to a specific peer identified by [param peer_id] (see [method MultiplayerPeer.set_target_peer]). Returns [code]null[/code]. + Sends a [method rpc] to a specific peer identified by [param peer_id] (see [method MultiplayerPeer.set_target_peer]). + May return [constant OK] if the call is successful, [constant ERR_INVALID_PARAMETER] if the arguments passed in the [param method] do not match, [constant ERR_UNCONFIGURED] if the node's [member multiplayer] cannot be fetched (such as when the node is not inside the tree), [constant ERR_CONNECTION_ERROR] if [member multiplayer]'s connection is not available. </description> </method> <method name="set_deferred_thread_group"> @@ -774,7 +803,7 @@ <return type="void" /> <param index="0" name="fold" type="bool" /> <description> - Sets the folded state of the node in the Scene dock. This method is only intended for use with editor tooling. + If set to [code]true[/code], the node appears folded in the Scene dock. As a result, all of its children are hidden. This method is intended to be used in editor plugins and tools, but it also works in release builds. See also [method is_displayed_folded]. </description> </method> <method name="set_editable_instance"> @@ -782,7 +811,7 @@ <param index="0" name="node" type="Node" /> <param index="1" name="is_editable" type="bool" /> <description> - Sets the editable children state of [param node] relative to this node. This method is only intended for use with editor tooling. + Set to [code]true[/code] to allow all nodes owned by [param node] to be available, and editable, in the Scene dock, even if their [member owner] is not the scene root. This method is intended to be used in editor plugins and tools, but it also works in release builds. See also [method is_editable_instance]. </description> </method> <method name="set_multiplayer_authority"> @@ -790,73 +819,74 @@ <param index="0" name="id" type="int" /> <param index="1" name="recursive" type="bool" default="true" /> <description> - Sets the node's multiplayer authority to the peer with the given peer ID. The multiplayer authority is the peer that has authority over the node on the network. Useful in conjunction with [method rpc_config] and the [MultiplayerAPI]. Defaults to peer ID 1 (the server). If [param recursive], the given peer is recursively set as the authority for all children of this node. - [b]Warning:[/b] This does [b]not[/b] automatically replicate the new authority to other peers. It is developer's responsibility to do so. You can propagate the information about the new authority using [member MultiplayerSpawner.spawn_function], an RPC, or using a [MultiplayerSynchronizer]. Also, the parent's authority does [b]not[/b] propagate to newly added children. + Sets the node's multiplayer authority to the peer with the given peer [param id]. The multiplayer authority is the peer that has authority over the node on the network. Defaults to peer ID 1 (the server). Useful in conjunction with [method rpc_config] and the [MultiplayerAPI]. + If [param recursive] is [code]true[/code], the given peer is recursively set as the authority for all children of this node. + [b]Warning:[/b] This does [b]not[/b] automatically replicate the new authority to other peers. It is the developer's responsibility to do so. You may replicate the new authority's information using [member MultiplayerSpawner.spawn_function], an RPC, or a [MultiplayerSynchronizer]. Furthermore, the parent's authority does [b]not[/b] propagate to newly added children. </description> </method> <method name="set_physics_process"> <return type="void" /> <param index="0" name="enable" type="bool" /> <description> - Enables or disables physics (i.e. fixed framerate) processing. When a node is being processed, it will receive a [constant NOTIFICATION_PHYSICS_PROCESS] at a fixed (usually 60 FPS, see [member Engine.physics_ticks_per_second] to change) interval (and the [method _physics_process] callback will be called if exists). Enabled automatically if [method _physics_process] is overridden. Any calls to this before [method _ready] will be ignored. + If set to [code]true[/code], enables physics (fixed framerate) processing. When a node is being processed, it will receive a [constant NOTIFICATION_PHYSICS_PROCESS] at a fixed (usually 60 FPS, see [member Engine.physics_ticks_per_second] to change) interval (and the [method _physics_process] callback will be called if exists). Enabled automatically if [method _physics_process] is overridden. </description> </method> <method name="set_physics_process_internal"> <return type="void" /> <param index="0" name="enable" type="bool" /> <description> - Enables or disables internal physics for this node. Internal physics processing happens in isolation from the normal [method _physics_process] calls and is used by some nodes internally to guarantee proper functioning even if the node is paused or physics processing is disabled for scripting ([method set_physics_process]). Only useful for advanced uses to manipulate built-in nodes' behavior. - [b]Warning:[/b] Built-in Nodes rely on the internal processing for their own logic, so changing this value from your code may lead to unexpected behavior. Script access to this internal logic is provided for specific advanced uses, but is unsafe and not supported. + If set to [code]true[/code], enables internal physics for this node. Internal physics processing happens in isolation from the normal [method _physics_process] calls and is used by some nodes internally to guarantee proper functioning even if the node is paused or physics processing is disabled for scripting ([method set_physics_process]). + [b]Warning:[/b] Built-in nodes rely on internal processing for their internal logic. Disabling it is unsafe and may lead to unexpected behavior. Use this method if you know what you are doing. </description> </method> <method name="set_process"> <return type="void" /> <param index="0" name="enable" type="bool" /> <description> - Enables or disables processing. When a node is being processed, it will receive a [constant NOTIFICATION_PROCESS] on every drawn frame (and the [method _process] callback will be called if exists). Enabled automatically if [method _process] is overridden. Any calls to this before [method _ready] will be ignored. + If set to [code]true[/code], enables processing. When a node is being processed, it will receive a [constant NOTIFICATION_PROCESS] on every drawn frame (and the [method _process] callback will be called if exists). Enabled automatically if [method _process] is overridden. </description> </method> <method name="set_process_input"> <return type="void" /> <param index="0" name="enable" type="bool" /> <description> - Enables or disables input processing. This is not required for GUI controls! Enabled automatically if [method _input] is overridden. Any calls to this before [method _ready] will be ignored. + If set to [code]true[/code], enables input processing. This is not required for GUI controls! Enabled automatically if [method _input] is overridden. </description> </method> <method name="set_process_internal"> <return type="void" /> <param index="0" name="enable" type="bool" /> <description> - Enables or disabled internal processing for this node. Internal processing happens in isolation from the normal [method _process] calls and is used by some nodes internally to guarantee proper functioning even if the node is paused or processing is disabled for scripting ([method set_process]). Only useful for advanced uses to manipulate built-in nodes' behavior. - [b]Warning:[/b] Built-in Nodes rely on the internal processing for their own logic, so changing this value from your code may lead to unexpected behavior. Script access to this internal logic is provided for specific advanced uses, but is unsafe and not supported. + If set to [code]true[/code], enables internal processing for this node. Internal processing happens in isolation from the normal [method _process] calls and is used by some nodes internally to guarantee proper functioning even if the node is paused or processing is disabled for scripting ([method set_process]). + [b]Warning:[/b] Built-in nodes rely on internal processing for their internal logic. Disabling it is unsafe and may lead to unexpected behavior. Use this method if you know what you are doing. </description> </method> <method name="set_process_shortcut_input"> <return type="void" /> <param index="0" name="enable" type="bool" /> <description> - Enables shortcut processing. Enabled automatically if [method _shortcut_input] is overridden. Any calls to this before [method _ready] will be ignored. + If set to [code]true[/code], enables shortcut processing for this node. Enabled automatically if [method _shortcut_input] is overridden. </description> </method> <method name="set_process_unhandled_input"> <return type="void" /> <param index="0" name="enable" type="bool" /> <description> - Enables unhandled input processing. This is not required for GUI controls! It enables the node to receive all input that was not previously handled (usually by a [Control]). Enabled automatically if [method _unhandled_input] is overridden. Any calls to this before [method _ready] will be ignored. + If set to [code]true[/code], enables unhandled input processing. This is not required for GUI controls! It enables the node to receive all input that was not previously handled (usually by a [Control]). Enabled automatically if [method _unhandled_input] is overridden. </description> </method> <method name="set_process_unhandled_key_input"> <return type="void" /> <param index="0" name="enable" type="bool" /> <description> - Enables unhandled key input processing. Enabled automatically if [method _unhandled_key_input] is overridden. Any calls to this before [method _ready] will be ignored. + If set to [code]true[/code], enables unhandled key input processing. Enabled automatically if [method _unhandled_key_input] is overridden. </description> </method> <method name="set_scene_instance_load_placeholder"> <return type="void" /> <param index="0" name="load_placeholder" type="bool" /> <description> - Sets whether this is an instance load placeholder. See [InstancePlaceholder]. + If set to [code]true[/code], the node becomes a [InstancePlaceholder] when packed and instantiated from a [PackedScene]. See also [method get_scene_instance_load_placeholder]. </description> </method> <method name="set_thread_safe"> @@ -870,35 +900,34 @@ <method name="update_configuration_warnings"> <return type="void" /> <description> - Updates the warning displayed for this node in the Scene Dock. - Use [method _get_configuration_warnings] to setup the warning message to display. + Refreshes the warnings displayed for this node in the Scene dock. Use [method _get_configuration_warnings] to customize the warning messages to display. </description> </method> </methods> <members> <member name="editor_description" type="String" setter="set_editor_description" getter="get_editor_description" default=""""> - Add a custom description to a node. It will be displayed in a tooltip when hovered in editor's scene tree. + An optional description to the node. It will be displayed as a tooltip when hovering over the node in the editor's Scene dock. </member> <member name="multiplayer" type="MultiplayerAPI" setter="" getter="get_multiplayer"> The [MultiplayerAPI] instance associated with this node. See [method SceneTree.get_multiplayer]. [b]Note:[/b] Renaming the node, or moving it in the tree, will not move the [MultiplayerAPI] to the new path, you will have to update this manually. </member> <member name="name" type="StringName" setter="set_name" getter="get_name"> - The name of the node. This name is unique among the siblings (other child nodes from the same parent). When set to an existing name, the node will be automatically renamed. - [b]Note:[/b] Auto-generated names might include the [code]@[/code] character, which is reserved for unique names when using [method add_child]. When setting the name manually, any [code]@[/code] will be removed. + The name of the node. This name must be unique among the siblings (other child nodes from the same parent). When set to an existing sibling's name, the node is automatically renamed. + [b]Note:[/b] When changing the name, the following characters will be removed: ([code].[/code] [code]:[/code] [code]@[/code] [code]/[/code] [code]"[/code] [code]%[/code]). In particular, the [code]@[/code] character is reserved for auto-generated names. See also [method String.validate_node_name]. </member> <member name="owner" type="Node" setter="set_owner" getter="get_owner"> - The node owner. A node can have any ancestor node as owner (i.e. a parent, grandparent, etc. node ascending in the tree). This implies that [method add_child] should be called before setting the owner, so that this relationship of parenting exists. When saving a node (using [PackedScene]), all the nodes it owns will be saved with it. This allows for the creation of complex scene trees, with instancing and subinstancing. - [b]Note:[/b] If you want a child to be persisted to a [PackedScene], you must set [member owner] in addition to calling [method add_child]. This is typically relevant for [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]tool scripts[/url] and [url=$DOCS_URL/tutorials/plugins/editor/index.html]editor plugins[/url]. If a new node is added to the tree without setting its owner as an ancestor in that tree, it will be visible in the 2D/3D view, but not in the scene tree (and not persisted when packing or saving). + The owner of this node. The owner must be an ancestor of this node. When packing the owner node in a [PackedScene], all the nodes it owns are also saved with it. + [b]Note:[/b] In the editor, nodes not owned by the scene root are usually not displayed in the Scene dock, and will [b]not[/b] be saved. To prevent this, remember to set the owner after calling [method add_child]. See also (see [member unique_name_in_owner]) </member> <member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="Node.ProcessMode" default="0"> - Can be used to pause or unpause the node, or make the node paused based on the [SceneTree], or make it inherit the process mode from its parent (default). + The node's processing behavior (see [enum ProcessMode]). To check if the node is able to process, with the current mode and [member SceneTree.paused], use [method can_process]. </member> <member name="process_physics_priority" type="int" setter="set_physics_process_priority" getter="get_physics_process_priority" default="0"> Similar to [member process_priority] but for [constant NOTIFICATION_PHYSICS_PROCESS], [method _physics_process] or the internal version. </member> <member name="process_priority" type="int" setter="set_process_priority" getter="get_process_priority" default="0"> - The node's priority in the execution order of the enabled processing callbacks (i.e. [constant NOTIFICATION_PROCESS], [constant NOTIFICATION_PHYSICS_PROCESS] and their internal counterparts). Nodes whose process priority value is [i]lower[/i] will have their processing callbacks executed first. + The node's execution order of the process callbacks ([method _process], [method _physics_process], and internal processing). Nodes whose priority value is [i]lower[/i] call their process callbacks first, regardless of tree order. </member> <member name="process_thread_group" type="int" setter="set_process_thread_group" getter="get_process_thread_group" enum="Node.ProcessThreadGroup" default="0"> Set the process thread group for this node (basically, whether it receives [constant NOTIFICATION_PROCESS], [constant NOTIFICATION_PHYSICS_PROCESS], [method _process] or [method _physics_process] (and the internal versions) on the main thread or in a sub-thread. @@ -913,26 +942,26 @@ Set whether the current thread group will process messages (calls to [method call_deferred_thread_group] on threads, and whether it wants to receive them during regular process or physics process callbacks. </member> <member name="scene_file_path" type="String" setter="set_scene_file_path" getter="get_scene_file_path"> - If a scene is instantiated from a file, its topmost node contains the absolute file path from which it was loaded in [member scene_file_path] (e.g. [code]res://levels/1.tscn[/code]). Otherwise, [member scene_file_path] is set to an empty string. + The original scene's file path, if the node has been instantiated from a [PackedScene] file. Only scene root nodes contains this. </member> <member name="unique_name_in_owner" type="bool" setter="set_unique_name_in_owner" getter="is_unique_name_in_owner" default="false"> - Sets this node's name as a unique name in its [member owner]. This allows the node to be accessed as [code]%Name[/code] instead of the full path, from any node within that scene. - If another node with the same owner already had that name declared as unique, that other node's name will no longer be set as having a unique name. + If [code]true[/code], the node can be accessed from any node sharing the same [member owner] or from the [member owner] itself, with special [code]%Name[/code] syntax in [method get_node]. + [b]Note:[/b] If another node with the same [member owner] shares the same [member name] as this node, the other node will no longer be accessible as unique. </member> </members> <signals> <signal name="child_entered_tree"> <param index="0" name="node" type="Node" /> <description> - Emitted when a child node enters the scene tree, either because it entered on its own or because this node entered with it. + Emitted when the child [param node] enters the [SceneTree], usually because this node entered the tree (see [signal tree_entered]), or [method add_child] has been called. This signal is emitted [i]after[/i] the child node's own [constant NOTIFICATION_ENTER_TREE] and [signal tree_entered]. </description> </signal> <signal name="child_exiting_tree"> <param index="0" name="node" type="Node" /> <description> - Emitted when a child node is about to exit the scene tree, either because it is being removed or freed directly, or because this node is exiting the tree. - When this signal is received, the child [param node] is still in the tree and valid. This signal is emitted [i]after[/i] the child node's own [signal tree_exiting] and [constant NOTIFICATION_EXIT_TREE]. + Emitted when the child [param node] is about to exit the [SceneTree], usually because this node is exiting the tree (see [signal tree_exiting]), or because the child [param node] is being removed or freed. + When this signal is received, the child [param node] is still accessible inside the tree. This signal is emitted [i]after[/i] the child node's own [signal tree_exiting] and [constant NOTIFICATION_EXIT_TREE]. </description> </signal> <signal name="child_order_changed"> @@ -940,14 +969,20 @@ Emitted when the list of children is changed. This happens when child nodes are added, moved or removed. </description> </signal> + <signal name="editor_description_changed"> + <param index="0" name="node" type="Node" /> + <description> + Emitted when the node's editor description field changed. + </description> + </signal> <signal name="ready"> <description> - Emitted when the node is ready. Comes after [method _ready] callback and follows the same rules. + Emitted when the node is considered ready, after [method _ready] is called. </description> </signal> <signal name="renamed"> <description> - Emitted when the node is renamed. + Emitted when the node's [member name] is changed, if the node is inside the tree. </description> </signal> <signal name="replacing_by"> @@ -966,23 +1001,24 @@ <signal name="tree_exited"> <description> Emitted after the node exits the tree and is no longer active. + This signal is emitted [i]after[/i] the related [constant NOTIFICATION_EXIT_TREE] notification. </description> </signal> <signal name="tree_exiting"> <description> - Emitted when the node is still active but about to exit the tree. This is the right place for de-initialization (or a "destructor", if you will). - This signal is emitted [i]before[/i] the related [constant NOTIFICATION_EXIT_TREE] notification. + Emitted when the node is just about to exit the tree. The node is still valid. As such, this is the right place for de-initialization (or a "destructor", if you will). + This signal is emitted [i]after[/i] the node's [method _exit_tree], and [i]before[/i] the related [constant NOTIFICATION_EXIT_TREE]. </description> </signal> </signals> <constants> <constant name="NOTIFICATION_ENTER_TREE" value="10"> - Notification received when the node enters a [SceneTree]. - This notification is emitted [i]before[/i] the related [signal tree_entered]. + Notification received when the node enters a [SceneTree]. See [method _enter_tree]. + This notification is received [i]before[/i] the related [signal tree_entered] signal. </constant> <constant name="NOTIFICATION_EXIT_TREE" value="11"> - Notification received when the node is about to exit a [SceneTree]. - This notification is emitted [i]after[/i] the related [signal tree_exiting]. + Notification received when the node is about to exit a [SceneTree]. See [method _exit_tree]. + This notification is received [i]after[/i] the related [signal tree_exiting] signal. </constant> <constant name="NOTIFICATION_MOVED_IN_PARENT" value="12" is_deprecated="true"> [i]Deprecated.[/i] This notification is no longer emitted. Use [constant NOTIFICATION_CHILD_ORDER_CHANGED] instead. @@ -991,26 +1027,27 @@ Notification received when the node is ready. See [method _ready]. </constant> <constant name="NOTIFICATION_PAUSED" value="14"> - Notification received when the node is paused. + Notification received when the node is paused. See [member process_mode]. </constant> <constant name="NOTIFICATION_UNPAUSED" value="15"> - Notification received when the node is unpaused. + Notification received when the node is unpaused. See [member process_mode]. </constant> <constant name="NOTIFICATION_PHYSICS_PROCESS" value="16"> - Notification received every frame when the physics process flag is set (see [method set_physics_process]). + Notification received from the tree every physics frame when [method is_physics_processing] returns [code]true[/code]. See [method _physics_process]. </constant> <constant name="NOTIFICATION_PROCESS" value="17"> - Notification received every frame when the process flag is set (see [method set_process]). + Notification received from the tree every rendered frame when [method is_processing] returns [code]true[/code]. See [method _process]. </constant> <constant name="NOTIFICATION_PARENTED" value="18"> - Notification received when a node is set as a child of another node. - [b]Note:[/b] This doesn't mean that a node entered the [SceneTree]. + Notification received when the node is set as a child of another node (see [method add_child] and [method add_sibling]). + [b]Note:[/b] This does [i]not[/i] mean that the node entered the [SceneTree]. </constant> <constant name="NOTIFICATION_UNPARENTED" value="19"> - Notification received when a node is unparented (parent removed it from the list of children). + Notification received when the parent node calls [method remove_child] on this node. + [b]Note:[/b] This does [i]not[/i] mean that the node exited the [SceneTree]. </constant> <constant name="NOTIFICATION_SCENE_INSTANTIATED" value="20"> - Notification received by scene owner when its scene is instantiated. + Notification received [i]only[/i] by the newly instantiated scene root node, when [method PackedScene.instantiate] is completed. </constant> <constant name="NOTIFICATION_DRAG_BEGIN" value="21"> Notification received when a drag operation begins. All nodes receive this notification, not only the dragged one. @@ -1022,19 +1059,19 @@ Use [method Viewport.gui_is_drag_successful] to check if the drag succeeded. </constant> <constant name="NOTIFICATION_PATH_RENAMED" value="23"> - Notification received when the node's name or one of its parents' name is changed. This notification is [i]not[/i] received when the node is removed from the scene tree to be added to another parent later on. + Notification received when the node's [member name] or one of its ancestors' [member name] is changed. This notification is [i]not[/i] received when the node is removed from the [SceneTree]. </constant> <constant name="NOTIFICATION_CHILD_ORDER_CHANGED" value="24"> Notification received when the list of children is changed. This happens when child nodes are added, moved or removed. </constant> <constant name="NOTIFICATION_INTERNAL_PROCESS" value="25"> - Notification received every frame when the internal process flag is set (see [method set_process_internal]). + Notification received from the tree every rendered frame when [method is_processing_internal] returns [code]true[/code]. </constant> <constant name="NOTIFICATION_INTERNAL_PHYSICS_PROCESS" value="26"> - Notification received every frame when the internal physics process flag is set (see [method set_physics_process_internal]). + Notification received from the tree every physics frame when [method is_physics_processing_internal] returns [code]true[/code]. </constant> <constant name="NOTIFICATION_POST_ENTER_TREE" value="27"> - Notification received when the node is ready, just before [constant NOTIFICATION_READY] is received. Unlike the latter, it's sent every time the node enters the tree, instead of only once. + Notification received when the node enters the tree, just before [constant NOTIFICATION_READY] may be received. Unlike the latter, it is sent every time the node enters tree, not just once. </constant> <constant name="NOTIFICATION_DISABLED" value="28"> Notification received when the node is disabled. See [constant PROCESS_MODE_DISABLED]. @@ -1057,11 +1094,11 @@ Implemented for embedded windows and on desktop and web platforms. </constant> <constant name="NOTIFICATION_WM_WINDOW_FOCUS_IN" value="1004"> - Notification received when the node's parent [Window] is focused. This may be a change of focus between two windows of the same engine instance, or from the OS desktop or a third-party application to a window of the game (in which case [constant NOTIFICATION_APPLICATION_FOCUS_IN] is also emitted). + Notification received from the OS when the node's [Window] ancestor is focused. This may be a change of focus between two windows of the same engine instance, or from the OS desktop or a third-party application to a window of the game (in which case [constant NOTIFICATION_APPLICATION_FOCUS_IN] is also received). A [Window] node receives this notification when it is focused. </constant> <constant name="NOTIFICATION_WM_WINDOW_FOCUS_OUT" value="1005"> - Notification received when the node's parent [Window] is defocused. This may be a change of focus between two windows of the same engine instance, or from a window of the game to the OS desktop or a third-party application (in which case [constant NOTIFICATION_APPLICATION_FOCUS_OUT] is also emitted). + Notification received from the OS when the node's [Window] ancestor is defocused. This may be a change of focus between two windows of the same engine instance, or from a window of the game to the OS desktop or a third-party application (in which case [constant NOTIFICATION_APPLICATION_FOCUS_OUT] is also received). A [Window] node receives this notification when it is defocused. </constant> <constant name="NOTIFICATION_WM_CLOSE_REQUEST" value="1006"> @@ -1070,13 +1107,14 @@ </constant> <constant name="NOTIFICATION_WM_GO_BACK_REQUEST" value="1007"> Notification received from the OS when a go back request is sent (e.g. pressing the "Back" button on Android). - Specific to the Android platform. + Implemented only on iOS. </constant> <constant name="NOTIFICATION_WM_SIZE_CHANGED" value="1008"> - Notification received from the OS when the window is resized. + Notification received when the window is resized. + [b]Note:[/b] Only the resized [Window] node receives this notification, and it's not propagated to the child nodes. </constant> <constant name="NOTIFICATION_WM_DPI_CHANGE" value="1009"> - Notification received from the OS when the screen's DPI has been changed. Only implemented on macOS. + Notification received from the OS when the screen's dots per inch (DPI) scale is changed. Only implemented on macOS. </constant> <constant name="NOTIFICATION_VP_MOUSE_ENTER" value="1010"> Notification received when the mouse cursor enters the [Viewport]'s visible area, that is not occluded behind other [Control]s or [Window]s, provided its [member Viewport.gui_disable_input] is [code]false[/code] and regardless if it's currently focused or not. @@ -1086,56 +1124,56 @@ </constant> <constant name="NOTIFICATION_OS_MEMORY_WARNING" value="2009"> Notification received from the OS when the application is exceeding its allocated memory. - Specific to the iOS platform. + Implemented only on iOS. </constant> <constant name="NOTIFICATION_TRANSLATION_CHANGED" value="2010"> Notification received when translations may have changed. Can be triggered by the user changing the locale. Can be used to respond to language changes, for example to change the UI strings on the fly. Useful when working with the built-in translation support, like [method Object.tr]. </constant> <constant name="NOTIFICATION_WM_ABOUT" value="2011"> Notification received from the OS when a request for "About" information is sent. - Specific to the macOS platform. + Implemented only on macOS. </constant> <constant name="NOTIFICATION_CRASH" value="2012"> Notification received from Godot's crash handler when the engine is about to crash. - Implemented on desktop platforms if the crash handler is enabled. + Implemented on desktop platforms, if the crash handler is enabled. </constant> <constant name="NOTIFICATION_OS_IME_UPDATE" value="2013"> Notification received from the OS when an update of the Input Method Engine occurs (e.g. change of IME cursor position or composition string). - Specific to the macOS platform. + Implemented only on macOS. </constant> <constant name="NOTIFICATION_APPLICATION_RESUMED" value="2014"> Notification received from the OS when the application is resumed. - Specific to the Android platform. + Implemented only on Android. </constant> <constant name="NOTIFICATION_APPLICATION_PAUSED" value="2015"> Notification received from the OS when the application is paused. - Specific to the Android platform. + Implemented only on Android. </constant> <constant name="NOTIFICATION_APPLICATION_FOCUS_IN" value="2016"> - Notification received from the OS when the application is focused, i.e. when changing the focus from the OS desktop or a thirdparty application to any open window of the Godot instance. + Notification received from the OS when the application is focused, i.e. when changing the focus from the OS desktop or a third-party application to any open window of the Godot instance. Implemented on desktop platforms. </constant> <constant name="NOTIFICATION_APPLICATION_FOCUS_OUT" value="2017"> - Notification received from the OS when the application is defocused, i.e. when changing the focus from any open window of the Godot instance to the OS desktop or a thirdparty application. + Notification received from the OS when the application is defocused, i.e. when changing the focus from any open window of the Godot instance to the OS desktop or a third-party application. Implemented on desktop platforms. </constant> <constant name="NOTIFICATION_TEXT_SERVER_CHANGED" value="2018"> - Notification received when text server is changed. + Notification received when the [TextServer] is changed. </constant> <constant name="PROCESS_MODE_INHERIT" value="0" enum="ProcessMode"> - Inherits process mode from the node's parent. For the root node, it is equivalent to [constant PROCESS_MODE_PAUSABLE]. Default. + Inherits [member process_mode] from the node's parent. For the root node, it is equivalent to [constant PROCESS_MODE_PAUSABLE]. This is the default for any newly created node. </constant> <constant name="PROCESS_MODE_PAUSABLE" value="1" enum="ProcessMode"> - Stops processing when the [SceneTree] is paused (process when unpaused). This is the inverse of [constant PROCESS_MODE_WHEN_PAUSED]. + Stops processing when [member SceneTree.paused] is [code]true[/code]. This is the inverse of [constant PROCESS_MODE_WHEN_PAUSED]. </constant> <constant name="PROCESS_MODE_WHEN_PAUSED" value="2" enum="ProcessMode"> - Only process when the [SceneTree] is paused (don't process when unpaused). This is the inverse of [constant PROCESS_MODE_PAUSABLE]. + Process [b]only[/b] when [member SceneTree.paused] is [code]true[/code]. This is the inverse of [constant PROCESS_MODE_PAUSABLE]. </constant> <constant name="PROCESS_MODE_ALWAYS" value="3" enum="ProcessMode"> - Always process. Continue processing always, ignoring the [SceneTree]'s paused property. This is the inverse of [constant PROCESS_MODE_DISABLED]. + Always process. Keeps processing, ignoring [member SceneTree.paused]. This is the inverse of [constant PROCESS_MODE_DISABLED]. </constant> <constant name="PROCESS_MODE_DISABLED" value="4" enum="ProcessMode"> - Never process. Completely disables processing, ignoring the [SceneTree]'s paused property. This is the inverse of [constant PROCESS_MODE_ALWAYS]. + Never process. Completely disables processing, ignoring [member SceneTree.paused]. This is the inverse of [constant PROCESS_MODE_ALWAYS]. </constant> <constant name="PROCESS_THREAD_GROUP_INHERIT" value="0" enum="ProcessThreadGroup"> If the [member process_thread_group] property is sent to this, the node will belong to any parent (or grandparent) node that has a thread group mode that is not inherit. See [member process_thread_group] for more information. @@ -1153,26 +1191,25 @@ <constant name="FLAG_PROCESS_THREAD_MESSAGES_ALL" value="3" enum="ProcessThreadMessages" is_bitfield="true"> </constant> <constant name="DUPLICATE_SIGNALS" value="1" enum="DuplicateFlags"> - Duplicate the node's signals. + Duplicate the node's signal connections. </constant> <constant name="DUPLICATE_GROUPS" value="2" enum="DuplicateFlags"> Duplicate the node's groups. </constant> <constant name="DUPLICATE_SCRIPTS" value="4" enum="DuplicateFlags"> - Duplicate the node's scripts. + Duplicate the node's script (including the ancestor's script, if combined with [constant DUPLICATE_USE_INSTANTIATION]). </constant> <constant name="DUPLICATE_USE_INSTANTIATION" value="8" enum="DuplicateFlags"> - Duplicate using instancing. - An instance stays linked to the original so when the original changes, the instance changes too. + Duplicate using [method PackedScene.instantiate]. If the node comes from a scene saved on disk, re-uses [method PackedScene.instantiate] as the base for the duplicated node and its children. </constant> <constant name="INTERNAL_MODE_DISABLED" value="0" enum="InternalMode"> - Node will not be internal. + The node will not be internal. </constant> <constant name="INTERNAL_MODE_FRONT" value="1" enum="InternalMode"> - Node will be placed at the front of parent's node list, before any non-internal sibling. + The node will be placed at the beginning of the parent's children list, before any non-internal sibling. </constant> <constant name="INTERNAL_MODE_BACK" value="2" enum="InternalMode"> - Node will be placed at the back of parent's node list, after any non-internal sibling. + The node will be placed at the end of the parent's children list, after any non-internal sibling. </constant> </constants> </class> diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml index 553a3913d8..328e572c13 100644 --- a/doc/classes/NodePath.xml +++ b/doc/classes/NodePath.xml @@ -121,13 +121,13 @@ var node_path = NodePath("Path2D/PathFollow2D/Sprite2D") print(node_path.get_name(0)) # Path2D print(node_path.get_name(1)) # PathFollow2D - print(node_path.get_name(2)) # Sprite + print(node_path.get_name(2)) # Sprite2D [/gdscript] [csharp] var nodePath = new NodePath("Path2D/PathFollow2D/Sprite2D"); GD.Print(nodePath.GetName(0)); // Path2D GD.Print(nodePath.GetName(1)); // PathFollow2D - GD.Print(nodePath.GetName(2)); // Sprite + GD.Print(nodePath.GetName(2)); // Sprite2D [/csharp] [/codeblocks] </description> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 44197dbd0c..188e846f5e 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -4,8 +4,8 @@ Provides access to common operating system functionalities. </brief_description> <description> - This class wraps the most common functionalities for communicating with the host operating system, such as the video driver, delays, environment variables, execution of binaries, command line, etc. - [b]Note:[/b] In Godot 4, [OS] functions related to window management were moved to the [DisplayServer] singleton. + The [OS] class wraps the most common functionalities for communicating with the host operating system, such as the video driver, delays, environment variables, execution of binaries, command line, etc. + [b]Note:[/b] In Godot 4, [OS] functions related to window management, clipboard, and TTS were moved to the [DisplayServer] singleton (and the [Window] class). Functions related to time were removed and are only available in the [Time] class. </description> <tutorials> <link title="OS Test Demo">https://godotengine.org/asset-library/asset/677</link> @@ -16,13 +16,13 @@ <param index="0" name="text" type="String" /> <param index="1" name="title" type="String" default=""Alert!"" /> <description> - Displays a modal dialog box using the host OS' facilities. Execution is blocked until the dialog is closed. + Displays a modal dialog box using the host platform's implementation. The engine execution is blocked until the dialog is closed. </description> </method> <method name="close_midi_inputs"> <return type="void" /> <description> - Shuts down system MIDI driver. + Shuts down the system MIDI driver. Godot will no longer receive [InputEventMIDI]. See also [method open_midi_inputs] and [method get_connected_midi_inputs]. [b]Note:[/b] This method is implemented on Linux, macOS and Windows. </description> </method> @@ -30,7 +30,8 @@ <return type="void" /> <param index="0" name="message" type="String" /> <description> - Crashes the engine (or the editor if called within a [code]@tool[/code] script). This should [i]only[/i] be used for testing the system's crash handler, not for any other purpose. For general error reporting, use (in order of preference) [method @GDScript.assert], [method @GlobalScope.push_error] or [method alert]. See also [method kill]. + Crashes the engine (or the editor if called within a [code]@tool[/code] script). See also [method kill]. + [b]Note:[/b] This method should [i]only[/i] be used for testing the system's crash handler, not for any other purpose. For general error reporting, use (in order of preference) [method @GDScript.assert], [method @GlobalScope.push_error], or [method alert]. </description> </method> <method name="create_instance"> @@ -38,8 +39,9 @@ <param index="0" name="arguments" type="PackedStringArray" /> <description> Creates a new instance of Godot that runs independently. The [param arguments] are used in the given order and separated by a space. - If the process creation succeeds, the method will return the new process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). If the process creation fails, the method will return [code]-1[/code]. - [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. + If the process is successfully created, the method will return the new process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). If the process cannot be created, the method will return [code]-1[/code]. + See [method create_process] if you wish to run a different process. + [b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows. </description> </method> <method name="create_process"> @@ -48,9 +50,9 @@ <param index="1" name="arguments" type="PackedStringArray" /> <param index="2" name="open_console" type="bool" default="false" /> <description> - Creates a new process that runs independently of Godot. It will not terminate if Godot terminates. The path specified in [param path] must exist and be executable file or macOS .app bundle. Platform path resolution will be used. The [param arguments] are used in the given order and separated by a space. - On Windows, if [param open_console] is [code]true[/code] and the process is a console app, a new terminal window will be opened. This is ignored on other platforms. - If the process creation succeeds, the method will return the new process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). If the process creation fails, the method will return [code]-1[/code]. + Creates a new process that runs independently of Godot. It will not terminate when Godot terminates. The path specified in [param path] must exist and be executable file or macOS .app bundle. Platform path resolution will be used. The [param arguments] are used in the given order and separated by a space. + On Windows, if [param open_console] is [code]true[/code] and the process is a console app, a new terminal window will be opened. + If the process is successfully created, this method returns its process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). Otherwise this method returns [code]-1[/code]. For example, running another instance of the project: [codeblocks] [gdscript] @@ -69,8 +71,8 @@ <return type="void" /> <param index="0" name="msec" type="int" /> <description> - Delays execution of the current thread by [param msec] milliseconds. [param msec] must be greater than or equal to [code]0[/code]. Otherwise, [method delay_msec] will do nothing and will print an error message. - [b]Note:[/b] [method delay_msec] is a [i]blocking[/i] way to delay code execution. To delay code execution in a non-blocking way, see [method SceneTree.create_timer]. Awaiting with [method SceneTree.create_timer] will delay the execution of code placed below the [code]await[/code] without affecting the rest of the project (or editor, for [EditorPlugin]s and [EditorScript]s). + Delays execution of the current thread by [param msec] milliseconds. [param msec] must be greater than or equal to [code]0[/code]. Otherwise, [method delay_msec] does nothing and prints an error message. + [b]Note:[/b] [method delay_msec] is a [i]blocking[/i] way to delay code execution. To delay code execution in a non-blocking way, you may use [method SceneTree.create_timer]. Awaiting with [SceneTreeTimer] delays the execution of code placed below the [code]await[/code] without affecting the rest of the project (or editor, for [EditorPlugin]s and [EditorScript]s). [b]Note:[/b] When [method delay_msec] is called on the main thread, it will freeze the project and will prevent it from redrawing and registering input until the delay has passed. When using [method delay_msec] as part of an [EditorPlugin] or [EditorScript], it will freeze the editor but won't freeze the project if it is currently running (since the project is an independent child process). </description> </method> @@ -78,8 +80,8 @@ <return type="void" /> <param index="0" name="usec" type="int" /> <description> - Delays execution of the current thread by [param usec] microseconds. [param usec] must be greater than or equal to [code]0[/code]. Otherwise, [method delay_usec] will do nothing and will print an error message. - [b]Note:[/b] [method delay_usec] is a [i]blocking[/i] way to delay code execution. To delay code execution in a non-blocking way, see [method SceneTree.create_timer]. Awaiting with [method SceneTree.create_timer] will delay the execution of code placed below the [code]await[/code] without affecting the rest of the project (or editor, for [EditorPlugin]s and [EditorScript]s). + Delays execution of the current thread by [param usec] microseconds. [param usec] must be greater than or equal to [code]0[/code]. Otherwise, [method delay_usec] does nothing and prints an error message. + [b]Note:[/b] [method delay_usec] is a [i]blocking[/i] way to delay code execution. To delay code execution in a non-blocking way, you may use [method SceneTree.create_timer]. Awaiting with a [SceneTreeTimer] delays the execution of code placed below the [code]await[/code] without affecting the rest of the project (or editor, for [EditorPlugin]s and [EditorScript]s). [b]Note:[/b] When [method delay_usec] is called on the main thread, it will freeze the project and will prevent it from redrawing and registering input until the delay has passed. When using [method delay_usec] as part of an [EditorPlugin] or [EditorScript], it will freeze the editor but won't freeze the project if it is currently running (since the project is an independent child process). </description> </method> @@ -91,10 +93,11 @@ <param index="3" name="read_stderr" type="bool" default="false" /> <param index="4" name="open_console" type="bool" default="false" /> <description> - Executes a command. The file specified in [param path] must exist and be executable. Platform path resolution will be used. The [param arguments] are used in the given order, separated by spaces, and wrapped in quotes. If an [param output] [Array] is provided, the complete shell output of the process will be appended as a single [String] element in [param output]. If [param read_stderr] is [code]true[/code], the output to the standard error stream will be included too. - On Windows, if [param open_console] is [code]true[/code] and the process is a console app, a new terminal window will be opened. This is ignored on other platforms. - If the command is successfully executed, the method will return the exit code of the command, or [code]-1[/code] if it fails. - [b]Note:[/b] The Godot thread will pause its execution until the executed command terminates. Use [Thread] to create a separate thread that will not pause the Godot thread, or use [method create_process] to create a completely independent process. + Executes the given process in a [i]blocking[/i] way. The file specified in [param path] must exist and be executable. The system path resolution will be used. The [param arguments] are used in the given order, separated by spaces, and wrapped in quotes. + If an [param output] array is provided, the complete shell output of the process is appended to [param output] as a single [String] element. If [param read_stderr] is [code]true[/code], the output to the standard error stream is also appended to the array. + On Windows, if [param open_console] is [code]true[/code] and the process is a console app, a new terminal window is opened. + This method returns the exit code of the command, or [code]-1[/code] if the process fails to execute. + [b]Note:[/b] The main thread will be blocked until the executed command terminates. Use [Thread] to create a separate thread that will not block the main thread, or use [method create_process] to create a completely independent process. For example, to retrieve a list of the working directory's contents: [codeblocks] [gdscript] @@ -128,13 +131,29 @@ <return type="int" enum="Key" /> <param index="0" name="string" type="String" /> <description> - Returns the keycode of the given string (e.g. "Escape"). + Finds the keycode for the given string. The returned values are equivalent to the [enum Key] constants. + [codeblocks] + [gdscript] + print(OS.find_keycode_from_string("C")) # Prints 67 (KEY_C) + print(OS.find_keycode_from_string("Escape")) # Prints 4194305 (KEY_ESCAPE) + print(OS.find_keycode_from_string("Shift+Tab")) # Prints 37748738 (KEY_MASK_SHIFT | KEY_TAB) + print(OS.find_keycode_from_string("Unknown")) # Prints 0 (KEY_NONE) + [/gdscript] + [csharp] + GD.Print(OS.FindKeycodeFromString("C")); // Prints C (Key.C) + GD.Print(OS.FindKeycodeFromString("Escape")); // Prints Escape (Key.Escape) + GD.Print(OS.FindKeycodeFromString("Shift+Tab")); // Prints 37748738 (KeyModifierMask.MaskShift | Key.Tab) + GD.Print(OS.FindKeycodeFromString("Unknown")); // Prints None (Key.None) + [/csharp] + [/codeblocks] + See also [method get_keycode_string]. </description> </method> <method name="get_cache_dir" qualifiers="const"> <return type="String" /> <description> - Returns the [i]global[/i] cache data directory according to the operating system's standards. On the Linux/BSD platform, this path can be overridden by setting the [code]XDG_CACHE_HOME[/code] environment variable before starting the project. See [url=$DOCS_URL/tutorials/io/data_paths.html]File paths in Godot projects[/url] in the documentation for more information. See also [method get_config_dir] and [method get_data_dir]. + Returns the [i]global[/i] cache data directory according to the operating system's standards. + On the Linux/BSD platform, this path can be overridden by setting the [code]XDG_CACHE_HOME[/code] environment variable before starting the project. See [url=$DOCS_URL/tutorials/io/data_paths.html]File paths in Godot projects[/url] in the documentation for more information. See also [method get_config_dir] and [method get_data_dir]. Not to be confused with [method get_user_data_dir], which returns the [i]project-specific[/i] user data path. </description> </method> @@ -145,12 +164,12 @@ Command-line arguments can be written in any form, including both [code]--key value[/code] and [code]--key=value[/code] forms so they can be properly parsed, as long as custom command-line arguments do not conflict with engine arguments. You can also incorporate environment variables using the [method get_environment] method. You can set [member ProjectSettings.editor/run/main_run_args] to define command-line arguments to be passed by the editor when running the project. - Here's a minimal example on how to parse command-line arguments into a dictionary using the [code]--key=value[/code] form for arguments: + Here's a minimal example on how to parse command-line arguments into a [Dictionary] using the [code]--key=value[/code] form for arguments: [codeblocks] [gdscript] var arguments = {} for argument in OS.get_cmdline_args(): - if argument.find("=") > -1: + if argument.contains("="): var key_value = argument.split("=") arguments[key_value[0].lstrip("--")] = key_value[1] else: @@ -162,7 +181,7 @@ var arguments = new Godot.Collections.Dictionary(); foreach (var argument in OS.GetCmdlineArgs()) { - if (argument.Find("=") > -1) + if (argument.Contains('=')) { string[] keyValue = argument.Split("="); arguments[keyValue[0].LStrip("--")] = keyValue[1]; @@ -176,91 +195,108 @@ } [/csharp] [/codeblocks] - [b]Note:[/b] Passing custom user arguments directly is not recommended, as the engine may discard or modify them. Instead, the best way is to use the standard UNIX double dash ([code]--[/code]) and then pass custom arguments, which the engine itself will ignore. These can be read via [method get_cmdline_user_args]. + [b]Note:[/b] Passing custom user arguments directly is not recommended, as the engine may discard or modify them. Instead, pass the standard UNIX double dash ([code]--[/code]) and then the custom arguments, which the engine will ignore by design. These can be read via [method get_cmdline_user_args]. </description> </method> <method name="get_cmdline_user_args"> <return type="PackedStringArray" /> <description> - Similar to [method get_cmdline_args], but this returns the user arguments (any argument passed after the double dash [code]--[/code] or double plus [code]++[/code] argument). These are left untouched by Godot for the user. [code]++[/code] can be used in situations where [code]--[/code] is intercepted by another program (such as [code]startx[/code]). - For example, in the command line below, [code]--fullscreen[/code] will not be returned in [method get_cmdline_user_args] and [code]--level 1[/code] will only be returned in [method get_cmdline_user_args]: + Returns the command-line user arguments passed to the engine. User arguments are ignored by the engine and reserved for the user. They are passed after the double dash [code]--[/code] argument. [code]++[/code] may be used when [code]--[/code] is intercepted by another program (such as [code]startx[/code]). [codeblock] - godot --fullscreen -- --level 1 - # Or: - godot --fullscreen ++ --level 1 + # Godot has been executed with the following command: + # godot --fullscreen -- --level=2 --hardcore + + OS.get_cmdline_args() # Returns ["--fullscreen", "--level=2", "--hardcore"] + OS.get_cmdline_user_args() # Returns ["--level=2", "--hardcore"] [/codeblock] + To get all passed arguments, use [method get_cmdline_args]. </description> </method> <method name="get_config_dir" qualifiers="const"> <return type="String" /> <description> - Returns the [i]global[/i] user configuration directory according to the operating system's standards. On the Linux/BSD platform, this path can be overridden by setting the [code]XDG_CONFIG_HOME[/code] environment variable before starting the project. See [url=$DOCS_URL/tutorials/io/data_paths.html]File paths in Godot projects[/url] in the documentation for more information. See also [method get_cache_dir] and [method get_data_dir]. + Returns the [i]global[/i] user configuration directory according to the operating system's standards. + On the Linux/BSD platform, this path can be overridden by setting the [code]XDG_CONFIG_HOME[/code] environment variable before starting the project. See [url=$DOCS_URL/tutorials/io/data_paths.html]File paths in Godot projects[/url] in the documentation for more information. See also [method get_cache_dir] and [method get_data_dir]. 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_connected_midi_inputs"> <return type="PackedStringArray" /> <description> - Returns an array of MIDI device names. - The returned array will be empty if the system MIDI driver has not previously been initialized with [method open_midi_inputs]. + Returns an array of connected MIDI device names, if they exist. Returns an empty array if the system MIDI driver has not previously been initialized with [method open_midi_inputs]. See also [method close_midi_inputs]. [b]Note:[/b] This method is implemented on Linux, macOS and Windows. </description> </method> <method name="get_data_dir" qualifiers="const"> <return type="String" /> <description> - Returns the [i]global[/i] user data directory according to the operating system's standards. On the Linux/BSD platform, this path can be overridden by setting the [code]XDG_DATA_HOME[/code] environment variable before starting the project. See [url=$DOCS_URL/tutorials/io/data_paths.html]File paths in Godot projects[/url] in the documentation for more information. See also [method get_cache_dir] and [method get_config_dir]. + Returns the [i]global[/i] user data directory according to the operating system's standards. + On the Linux/BSD platform, this path can be overridden by setting the [code]XDG_DATA_HOME[/code] environment variable before starting the project. See [url=$DOCS_URL/tutorials/io/data_paths.html]File paths in Godot projects[/url] in the documentation for more information. See also [method get_cache_dir] and [method get_config_dir]. 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 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. + [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" /> <description> - Returns the value of an environment variable. Returns an empty string if the environment variable doesn't exist. + Returns the value of the given environment variable, or an empty string if [param variable] doesn't exist. [b]Note:[/b] Double-check the casing of [param variable]. Environment variable names are case-sensitive on all platforms except Windows. + [b]Note:[/b] On macOS, applications do not have access to shell environment variables. </description> </method> <method name="get_executable_path" qualifiers="const"> <return type="String" /> <description> - Returns the path to the current engine executable. + Returns the file path to the current engine executable. [b]Note:[/b] On macOS, always use [method create_instance] instead of relying on executable path. </description> </method> <method name="get_granted_permissions" qualifiers="const"> <return type="PackedStringArray" /> <description> - On Android devices: With this function, you can get the list of dangerous permissions that have been granted. - On macOS (sandboxed applications only): This function returns the list of user selected folders accessible to the application. Use native file dialog to request folder access permission. + On Android devices: Returns the list of dangerous permissions that have been granted. + On macOS: Returns the list of user selected folders accessible to the application (sandboxed applications only). Use the native file dialog to request folder access permission. </description> </method> <method name="get_keycode_string" qualifiers="const"> <return type="String" /> <param index="0" name="code" type="int" enum="Key" /> <description> - Returns the given keycode as a string (e.g. Return values: [code]"Escape"[/code], [code]"Shift+Escape"[/code]). - See also [member InputEventKey.keycode] and [method InputEventKey.get_keycode_with_modifiers]. + Returns the given keycode as a [String]. + [codeblocks] + [gdscript] + print(OS.get_keycode_string(KEY_C)) # Prints "C" + print(OS.get_keycode_string(KEY_ESCAPE)) # Prints "Escape" + print(OS.get_keycode_string(KEY_MASK_SHIFT | KEY_TAB)) # Prints "Shift+Tab" + [/gdscript] + [csharp] + GD.Print(OS.GetKeycodeString(Key.C)); // Prints "C" + GD.Print(OS.GetKeycodeString(Key.Escape)); // Prints "Escape" + GD.Print(OS.GetKeycodeString((Key)KeyModifierMask.MaskShift | Key.Tab)); // Prints "Shift+Tab" + [/csharp] + [/codeblocks] + See also [method find_keycode_from_string], [member InputEventKey.keycode], and [method InputEventKey.get_keycode_with_modifiers]. </description> </method> <method name="get_locale" qualifiers="const"> <return type="String" /> <description> - Returns the host OS locale as a string of the form [code]language_Script_COUNTRY_VARIANT@extra[/code]. If you want only the language code and not the fully specified locale from the OS, you can use [method get_locale_language]. - [code]language[/code] - 2 or 3-letter [url=https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes]language code[/url], in lower case. - [code skip-lint]Script[/code] - optional, 4-letter [url=https://en.wikipedia.org/wiki/ISO_15924]script code[/url], in title case. - [code]COUNTRY[/code] - optional, 2 or 3-letter [url=https://en.wikipedia.org/wiki/ISO_3166-1]country code[/url], in upper case. - [code]VARIANT[/code] - optional, language variant, region and sort order. Variant can have any number of underscored keywords. - [code]extra[/code] - optional, semicolon separated list of additional key words. Currency, calendar, sort order and numbering system information. + Returns the host OS locale as a [String] of the form [code]language_Script_COUNTRY_VARIANT@extra[/code]. Every substring after [code]language[/code] is optional and may not exist. + - [code]language[/code] - 2 or 3-letter [url=https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes]language code[/url], in lower case. + - [code skip-lint]Script[/code] - 4-letter [url=https://en.wikipedia.org/wiki/ISO_15924]script code[/url], in title case. + - [code]COUNTRY[/code] - 2 or 3-letter [url=https://en.wikipedia.org/wiki/ISO_3166-1]country code[/url], in upper case. + - [code]VARIANT[/code] - language variant, region and sort order. The variant can have any number of underscored keywords. + - [code]extra[/code] - semicolon separated list of additional key words. This may include currency, calendar, sort order and numbering system information. + If you want only the language code and not the fully specified locale from the OS, you can use [method get_locale_language]. </description> </method> <method name="get_locale_language" qualifiers="const"> @@ -280,11 +316,12 @@ <method name="get_memory_info" qualifiers="const"> <return type="Dictionary" /> <description> - Returns the [Dictionary] with the following keys: - [code]"physical"[/code] - total amount of usable physical memory, in bytes or [code]-1[/code] if unknown. This value can be slightly less than the actual physical memory amount, since it does not include memory reserved by kernel and devices. - [code]"free"[/code] - amount of physical memory, that can be immediately allocated without disk access or other costly operation, in bytes or [code]-1[/code] if unknown. The process might be able to allocate more physical memory, but such allocation will require moving inactive pages to disk and can take some time. - [code]"available"[/code] - amount of memory, that can be allocated without extending the swap file(s), in bytes or [code]-1[/code] if unknown. This value include both physical memory and swap. - [code]"stack"[/code] - size of the current thread stack, in bytes or [code]-1[/code] if unknown. + Returns a [Dictionary] containing information about the current memory with the following entries: + - [code]"physical"[/code] - total amount of usable physical memory in bytes. This value can be slightly less than the actual physical memory amount, since it does not include memory reserved by the kernel and devices. + - [code]"free"[/code] - amount of physical memory, that can be immediately allocated without disk access or other costly operations, in bytes. The process might be able to allocate more physical memory, but this action will require moving inactive pages to disk, which can be expensive. + - [code]"available"[/code] - amount of memory that can be allocated without extending the swap file(s), in bytes. This value includes both physical memory and swap. + - [code]"stack"[/code] - size of the current thread stack in bytes. + [b]Note:[/b] Each entry's value may be [code]-1[/code] if it is unknown. </description> </method> <method name="get_model_name" qualifiers="const"> @@ -297,65 +334,66 @@ <method name="get_name" qualifiers="const"> <return type="String" /> <description> - Returns the name of the host OS. - On Windows, this is [code]"Windows"[/code]. - On macOS, this is [code]"macOS"[/code]. - On Linux-based operating systems, this is [code]"Linux"[/code]. - On BSD-based operating systems, this is [code]"FreeBSD"[/code], [code]"NetBSD"[/code], [code]"OpenBSD"[/code], or [code]"BSD"[/code] as a fallback. - On Android, this is [code]"Android"[/code]. - On iOS, this is [code]"iOS"[/code]. - On the web, this is [code]"Web"[/code]. - [b]Note:[/b] Custom builds of the engine may support additional platforms, such as consoles, yielding other return values. + Returns the name of the host platform. + - On Windows, this is [code]"Windows"[/code]. + - On macOS, this is [code]"macOS"[/code]. + - On Linux-based operating systems, this is [code]"Linux"[/code]. + - On BSD-based operating systems, this is [code]"FreeBSD"[/code], [code]"NetBSD"[/code], [code]"OpenBSD"[/code], or [code]"BSD"[/code] as a fallback. + - On Android, this is [code]"Android"[/code]. + - On iOS, this is [code]"iOS"[/code]. + - On the web, this is [code]"Web"[/code]. + [b]Note:[/b] Custom builds of the engine may support additional platforms, such as consoles, possibly returning other names. [codeblocks] [gdscript] match OS.get_name(): "Windows": - print("Windows") + print("Welcome to Windows!") "macOS": - print("macOS") + print("Welcome to macOS!") "Linux", "FreeBSD", "NetBSD", "OpenBSD", "BSD": - print("Linux/BSD") + print("Welcome to Linux/BSD!") "Android": - print("Android") + print("Welcome to Android!") "iOS": - print("iOS") + print("Welcome to iOS!") "Web": - print("Web") + print("Welcome to the Web!") [/gdscript] [csharp] switch (OS.GetName()) { case "Windows": - GD.Print("Windows"); + GD.Print("Welcome to Windows"); break; case "macOS": - GD.Print("macOS"); + GD.Print("Welcome to macOS!"); break; case "Linux": case "FreeBSD": case "NetBSD": case "OpenBSD": case "BSD": - GD.Print("Linux/BSD"); + GD.Print("Welcome to Linux/BSD!"); break; case "Android": - GD.Print("Android"); + GD.Print("Welcome to Android!"); break; case "iOS": - GD.Print("iOS"); + GD.Print("Welcome to iOS!"); break; case "Web": - GD.Print("Web"); + GD.Print("Welcome to the Web!"); break; } [/csharp] [/codeblocks] + [b]Note:[/b] On Web platforms, it is still possible to determine the host platform's OS with feature tags. See [method has_feature]. </description> </method> <method name="get_process_id" qualifiers="const"> <return type="int" /> <description> - Returns the project's process ID. + Returns the number used by the host machine to uniquely identify this application. [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. </description> </method> @@ -368,7 +406,7 @@ <method name="get_processor_name" qualifiers="const"> <return type="String" /> <description> - Returns the name of the CPU model on the host machine (e.g. "Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz"). + Returns the full name of the CPU model on the host machine (e.g. [code]"Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz"[/code]). [b]Note:[/b] This method is only implemented on Windows, macOS, Linux and iOS. On Android and Web, [method get_processor_name] returns an empty string. </description> </method> @@ -381,13 +419,13 @@ <method name="get_static_memory_peak_usage" qualifiers="const"> <return type="int" /> <description> - Returns the maximum amount of static memory used (only works in debug). + Returns the maximum amount of static memory used. Only works in debug builds. </description> </method> <method name="get_static_memory_usage" qualifiers="const"> <return type="int" /> <description> - Returns the amount of static memory being used by the program in bytes (only works in debug). + Returns the amount of static memory being used by the program in bytes. Only works in debug builds. </description> </method> <method name="get_system_dir" qualifiers="const"> @@ -395,9 +433,9 @@ <param index="0" name="dir" type="int" enum="OS.SystemDir" /> <param index="1" name="shared_storage" type="bool" default="true" /> <description> - Returns the actual path to commonly used folders across different platforms. Available locations are specified in [enum SystemDir]. + Returns the path to commonly used folders across different platforms, as defined by [param dir]. See the [enum SystemDir] constants for available locations. [b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows. - [b]Note:[/b] Shared storage is implemented on Android and allows to differentiate between app specific and shared directories. Shared directories have additional restrictions on Android. + [b]Note:[/b] Shared storage is implemented on Android and allows to differentiate between app specific and shared directories, if [param shared_storage] is [code]true[/code]. Shared directories have additional restrictions on Android. </description> </method> <method name="get_system_font_path" qualifiers="const"> @@ -407,7 +445,7 @@ <param index="2" name="stretch" type="int" default="100" /> <param index="3" name="italic" type="bool" default="false" /> <description> - Returns path to the system font file with [param font_name] and style. Returns empty string if no matching fonts found. + Returns the path to the system font file with [param font_name] and style. Returns an empty string if no matching fonts found. The following aliases can be used to request default fonts: "sans-serif", "serif", "monospace", "cursive", and "fantasy". [b]Note:[/b] Returned font might have different style if the requested style is not available. [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. @@ -423,7 +461,7 @@ <param index="5" name="stretch" type="int" default="100" /> <param index="6" name="italic" type="bool" default="false" /> <description> - Returns an array of the system substitute font file paths, which are similar to the font with [param font_name] and style for the specified text, locale and script. Returns empty array if no matching fonts found. + Returns an array of the system substitute font file paths, which are similar to the font with [param font_name] and style for the specified text, locale, and script. Returns an empty array if no matching fonts found. The following aliases can be used to request default fonts: "sans-serif", "serif", "monospace", "cursive", and "fantasy". [b]Note:[/b] Depending on OS, it's not guaranteed that any of the returned fonts will be suitable for rendering specified text. Fonts should be loaded and checked in the order they are returned, and the first suitable one used. [b]Note:[/b] Returned fonts might have different style if the requested style is not available or belong to a different font family. @@ -433,7 +471,7 @@ <method name="get_system_fonts" qualifiers="const"> <return type="PackedStringArray" /> <description> - Returns list of font family names available. + Returns the list of font family names available. [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. </description> </method> @@ -448,19 +486,19 @@ <return type="String" /> <description> Returns a string that is unique to the device. - [b]Note:[/b] This string may change without notice if the user reinstalls/upgrades their operating system or changes their hardware. This means it should generally not be used to encrypt persistent data as the data saved before an unexpected ID change would become inaccessible. The returned string may also be falsified using external programs, so do not rely on the string returned by [method get_unique_id] for security purposes. - [b]Note:[/b] Returns an empty string and prints an error on Web, as this method cannot be implemented on this platform. + [b]Note:[/b] This string may change without notice if the user reinstalls their operating system, upgrades it, or modifies their hardware. This means it should generally not be used to encrypt persistent data, as the data saved before an unexpected ID change would become inaccessible. The returned string may also be falsified using external programs, so do not rely on the string returned by this method for security purposes. + [b]Note:[/b] On Web, returns an empty string and generates an error, as this method cannot be implemented for security concerns. </description> </method> <method name="get_user_data_dir" qualifiers="const"> <return type="String" /> <description> - Returns the absolute directory path where user data is written ([code]user://[/code]). - On Windows, this is [code]%AppData%\Godot\app_userdata\[project_name][/code], or [code]%AppData%\[custom_name][/code] if [code]use_custom_user_dir[/code] is set. [code]%AppData%[/code] expands to [code]%UserProfile%\AppData\Roaming[/code]. - On macOS, this is [code]~/Library/Application Support/Godot/app_userdata/[project_name][/code], or [code]~/Library/Application Support/[custom_name][/code] if [code]use_custom_user_dir[/code] is set. - On Linux and BSD, this is [code]~/.local/share/godot/app_userdata/[project_name][/code], or [code]~/.local/share/[custom_name][/code] if [code]use_custom_user_dir[/code] is set. - On Android and iOS, this is a sandboxed directory in either internal or external storage, depending on the user's configuration. - On the web, this is a virtual directory managed by the browser. + Returns the absolute directory path where user data is written (the [code]user://[/code] directory in Godot). The path depends on the project name and [member ProjectSettings.application/config/use_custom_user_dir]. + - On Windows, this is [code]%AppData%\Godot\app_userdata\[project_name][/code], or [code]%AppData%\[custom_name][/code] if [code]use_custom_user_dir[/code] is set. [code]%AppData%[/code] expands to [code]%UserProfile%\AppData\Roaming[/code]. + - On macOS, this is [code]~/Library/Application Support/Godot/app_userdata/[project_name][/code], or [code]~/Library/Application Support/[custom_name][/code] if [code]use_custom_user_dir[/code] is set. + - On Linux and BSD, this is [code]~/.local/share/godot/app_userdata/[project_name][/code], or [code]~/.local/share/[custom_name][/code] if [code]use_custom_user_dir[/code] is set. + - On Android and iOS, this is a sandboxed directory in either internal or external storage, depending on the user's configuration. + - On Web, this is a virtual directory managed by the browser. If the project name is empty, [code][project_name][/code] falls back to [code][unnamed project][/code]. Not to be confused with [method get_data_dir], which returns the [i]global[/i] (non-project-specific) user home directory. </description> @@ -469,20 +507,20 @@ <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 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. + - For Windows, the major and minor version are returned, as well as the build number. For example, the returned string may look like [code]10.0.9926[/code] for a build of Windows 10, and it may 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 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="get_video_adapter_driver_info" qualifiers="const"> <return type="PackedStringArray" /> <description> - Returns the video adapter driver name and version for the user's currently active graphics card. See also [method RenderingServer.get_video_adapter_api_version]. + Returns the video adapter driver name and version for the user's currently active graphics card, as a [PackedStringArray]. See also [method RenderingServer.get_video_adapter_api_version]. The first element holds the driver name, such as [code]nvidia[/code], [code]amdgpu[/code], etc. - The second element holds the driver version. For e.g. the [code]nvidia[/code] driver on a Linux/BSD platform, the version is in the format [code]510.85.02[/code]. For Windows, the driver's format is [code]31.0.15.1659[/code]. - [b]Note:[/b] This method is only supported on the platforms Linux/BSD and Windows when not running in headless mode. It returns an empty array on other platforms. + The second element holds the driver version. For example, on the [code]nvidia[/code] driver on a Linux/BSD platform, the version is in the format [code]510.85.02[/code]. For Windows, the driver's format is [code]31.0.15.1659[/code]. + [b]Note:[/b] This method is only supported on Linux/BSD and Windows when not running in headless mode. On other platforms, it returns an empty array. </description> </method> <method name="has_environment" qualifiers="const"> @@ -499,8 +537,7 @@ <description> Returns [code]true[/code] if the feature for the given feature tag is supported in the currently running instance, depending on the platform, build, etc. Can be used to check whether you're currently running a debug build, on a certain platform or arch, etc. Refer to the [url=$DOCS_URL/tutorials/export/feature_tags.html]Feature Tags[/url] documentation for more details. [b]Note:[/b] Tag names are case-sensitive. - [b]Note:[/b] On the web platform, one of the following additional tags is defined to indicate host platform: [code]web_android[/code], [code]web_ios[/code], [code]web_linuxbsd[/code], [code]web_macos[/code], or [code]web_windows[/code]. - [b]Note:[/b] On the iOS simulator, the additional [code]simulator[/code] tag is defined. + [b]Note:[/b] On the Web platform, one of the following additional tags is defined to indicate host platform: [code]web_android[/code], [code]web_ios[/code], [code]web_linuxbsd[/code], [code]web_macos[/code], or [code]web_windows[/code]. </description> </method> <method name="is_debug_build" qualifiers="const"> @@ -508,22 +545,35 @@ <description> Returns [code]true[/code] if the Godot binary used to run the project is a [i]debug[/i] export template, or when running in the editor. Returns [code]false[/code] if the Godot binary used to run the project is a [i]release[/i] export template. - To check whether the Godot binary used to run the project is an export template (debug or release), use [code]OS.has_feature("template")[/code] instead. + [b]Note:[/b] To check whether the Godot binary used to run the project is an export template (debug or release), use [code]OS.has_feature("template")[/code] instead. </description> </method> <method name="is_keycode_unicode" qualifiers="const"> <return type="bool" /> <param index="0" name="code" type="int" /> <description> - Returns [code]true[/code] if the input keycode corresponds to a Unicode character. + Returns [code]true[/code] if the input keycode corresponds to a Unicode character. For a list of codes, see the [enum Key] constants. + [codeblocks] + [gdscript] + print(OS.is_keycode_unicode(KEY_G)) # Prints true + print(OS.is_keycode_unicode(KEY_KP_4)) # Prints true + print(OS.is_keycode_unicode(KEY_TAB)) # Prints false + print(OS.is_keycode_unicode(KEY_ESCAPE)) # Prints false + [/gdscript] + [csharp] + GD.Print(OS.IsKeycodeUnicode((long)Key.G)); // Prints true + GD.Print(OS.IsKeycodeUnicode((long)Key.Kp4)); // Prints true + GD.Print(OS.IsKeycodeUnicode((long)Key.Tab)); // Prints false + GD.Print(OS.IsKeycodeUnicode((long)Key.Escape)); // Prints false + [/csharp] + [/codeblocks] </description> </method> <method name="is_process_running" qualifiers="const"> <return type="bool" /> <param index="0" name="pid" type="int" /> <description> - Returns [code]true[/code] if the child process ID ([param pid]) is still running or [code]false[/code] if it has terminated. - Must be a valid ID generated from [method create_process]. + Returns [code]true[/code] if the child process ID ([param pid]) is still running or [code]false[/code] if it has terminated. [param pid] must be a valid ID generated from [method create_process]. [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. </description> </method> @@ -536,8 +586,8 @@ <method name="is_sandboxed" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if application is running in the sandbox. - [b]Note:[/b] This method is implemented on macOS and Linux. + Returns [code]true[/code] if the application is running in the sandbox. + [b]Note:[/b] This method is only implemented on macOS and Linux. </description> </method> <method name="is_stdout_verbose" qualifiers="const"> @@ -549,15 +599,15 @@ <method name="is_userfs_persistent" qualifiers="const"> <return type="bool" /> <description> - If [code]true[/code], the [code]user://[/code] file system is persistent, so that its state is the same after a player quits and starts the game again. Relevant to the Web platform, where this persistence may be unavailable. + Returns [code]true[/code] if the [code]user://[/code] file system is persistent, that is, its state is the same after a player quits and starts the game again. Relevant to the Web platform, where this persistence may be unavailable. </description> </method> <method name="kill"> <return type="int" enum="Error" /> <param index="0" name="pid" type="int" /> <description> - Kill (terminate) the process identified by the given process ID ([param pid]), e.g. the one returned by [method execute] in non-blocking mode. See also [method crash]. - [b]Note:[/b] This method can also be used to kill processes that were not spawned by the game. + Kill (terminate) the process identified by the given process ID ([param pid]), such as the ID returned by [method execute] in non-blocking mode. See also [method crash]. + [b]Note:[/b] This method can also be used to kill processes that were not spawned by the engine. [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. </description> </method> @@ -565,9 +615,9 @@ <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 DirAccess.remove]. + Moves the file or directory at the given [param path] 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 projects. - [b]Note:[/b] If the user has disabled the recycle bin on their system, the file will be permanently deleted instead. + Returns [constant FAILED] if the file or directory cannot be found, or the system does not support this method. [codeblocks] [gdscript] var file_to_remove = "user://slot1.save" @@ -578,12 +628,14 @@ OS.MoveToTrash(ProjectSettings.GlobalizePath(fileToRemove)); [/csharp] [/codeblocks] + [b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows. + [b]Note:[/b] If the user has disabled the recycle bin on their system, the file will be permanently deleted instead. </description> </method> <method name="open_midi_inputs"> <return type="void" /> <description> - Initializes the singleton for the system MIDI driver. + Initializes the singleton for the system MIDI driver, allowing Godot to receive [InputEventMIDI]. See also [method get_connected_midi_inputs] and [method close_midi_inputs]. [b]Note:[/b] This method is implemented on Linux, macOS and Windows. </description> </method> @@ -598,14 +650,15 @@ <return type="bool" /> <param index="0" name="name" type="String" /> <description> - At the moment this function is only used by [code]AudioDriverOpenSL[/code] to request permission for [code]RECORD_AUDIO[/code] on Android. + Requests permission from the OS for the given [param name]. Returns [code]true[/code] if the permission has been successfully granted. + [b]Note:[/b] This method is currently only implemented on Android, to specifically request permission for [code]"RECORD_AUDIO"[/code] by [code]AudioDriverOpenSL[/code]. </description> </method> <method name="request_permissions"> <return type="bool" /> <description> - With this function, you can request dangerous permissions since normal permissions are automatically granted at install time in Android applications. - [b]Note:[/b] This method is implemented only on Android. + Requests [i]dangerous[/i] permissions from the OS. Returns [code]true[/code] if permissions have been successfully granted. + [b]Note:[/b] This method is only implemented on Android. Normal permissions are automatically granted at install time in Android applications. </description> </method> <method name="revoke_granted_permissions"> @@ -628,8 +681,8 @@ <param index="0" name="restart" type="bool" /> <param index="1" name="arguments" type="PackedStringArray" default="PackedStringArray()" /> <description> - If [param restart] is [code]true[/code], restarts the project automatically when it is exited with [method SceneTree.quit] or [constant Node.NOTIFICATION_WM_CLOSE_REQUEST]. Command line [param arguments] can be supplied. To restart the project with the same command line arguments as originally used to run the project, pass [method get_cmdline_args] as the value for [param arguments]. - [method set_restart_on_exit] can be used to apply setting changes that require a restart. See also [method is_restart_on_exit_set] and [method get_restart_on_exit_arguments]. + If [param restart] is [code]true[/code], restarts the project automatically when it is exited with [method SceneTree.quit] or [constant Node.NOTIFICATION_WM_CLOSE_REQUEST]. Command-line [param arguments] can be supplied. To restart the project with the same command line arguments as originally used to run the project, pass [method get_cmdline_args] as the value for [param arguments]. + This method can be used to apply setting changes that require a restart. See also [method is_restart_on_exit_set] and [method get_restart_on_exit_arguments]. [b]Note:[/b] This method is only effective on desktop platforms, and only when the project isn't started from the editor. It will have no effect on mobile and Web platforms, or when the project is started from the editor. [b]Note:[/b] If the project process crashes or is [i]killed[/i] by the user (by sending [code]SIGKILL[/code] instead of the usual [code]SIGTERM[/code]), the project won't restart automatically. </description> @@ -638,25 +691,26 @@ <return type="int" enum="Error" /> <param index="0" name="name" type="String" /> <description> - Sets the name of the current thread. + Assigns the given name to the current thread. Returns [constant ERR_UNAVAILABLE] if unavailable on the current platform. </description> </method> <method name="set_use_file_access_save_and_swap"> <return type="void" /> <param index="0" name="enabled" type="bool" /> <description> - Enables backup saves if [param enabled] is [code]true[/code]. + If [param enabled] is [code]true[/code], when opening a file for writing, a temporary file is used in its place. When closed, it is automatically applied to the target file. + This can useful when files may be opened by other applications, such as antiviruses, text editors, or even the Godot editor itself. </description> </method> <method name="shell_open"> <return type="int" enum="Error" /> <param index="0" name="uri" type="String" /> <description> - Requests the OS to open a resource with the most appropriate program. For example: + Requests the OS to open a resource identified by [param uri] with the most appropriate program. For example: - [code]OS.shell_open("C:\\Users\name\Downloads")[/code] on Windows opens the file explorer at the user's Downloads folder. - [code]OS.shell_open("https://godotengine.org")[/code] opens the default web browser on the official Godot website. - [code]OS.shell_open("mailto:example@example.com")[/code] opens the default email client with the "To" field set to [code]example@example.com[/code]. See [url=https://datatracker.ietf.org/doc/html/rfc2368]RFC 2368 - The [code]mailto[/code] URL scheme[/url] for a list of fields that can be added. - Use [method ProjectSettings.globalize_path] to convert a [code]res://[/code] or [code]user://[/code] path into a system path for use with this method. + Use [method ProjectSettings.globalize_path] to convert a [code]res://[/code] or [code]user://[/code] project path into a system path for use with this method. [b]Note:[/b] Use [method String.uri_encode] to encode characters within URLs in a URL-safe, portable way. This is especially required for line breaks. Otherwise, [method shell_open] may not work correctly in a project exported to the Web platform. [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS and Windows. </description> @@ -666,30 +720,33 @@ <param index="0" name="file_or_dir_path" type="String" /> <param index="1" name="open_folder" type="bool" default="true" /> <description> - Requests the OS to open the file manager, then navigate to the given [param file_or_dir_path] and select the target file or folder. - If [param file_or_dir_path] is a valid directory path, and [param open_folder] is [code]true[/code], the method will open the file manager and enter the target folder without selecting anything. - Use [method ProjectSettings.globalize_path] to convert a [code]res://[/code] or [code]user://[/code] path into a system path for use with this method. - [b]Note:[/b] Currently this method is only implemented on Windows and macOS. On other platforms, it will fallback to [method shell_open] with a directory path of [param file_or_dir_path] with prefix [code]file://[/code]. + Requests the OS to open the file manager, navigate to the given [param file_or_dir_path] and select the target file or folder. + If [param open_folder] is [code]true[/code] and [param file_or_dir_path] is a valid directory path, the OS will open the file manager and navigate to the target folder without selecting anything. + Use [method ProjectSettings.globalize_path] to convert a [code]res://[/code] or [code]user://[/code] project path into a system path to use with this method. + [b]Note:[/b] This method is currently only implemented on Windows and macOS. On other platforms, it will fallback to [method shell_open] with a directory path of [param file_or_dir_path] prefixed with [code]file://[/code]. </description> </method> <method name="unset_environment" qualifiers="const"> <return type="void" /> <param index="0" name="variable" type="String" /> <description> - Removes the environment [param variable] from the current environment, if it exists. The environment variable will be removed for the Godot process and any process executed with [method execute] after running [method unset_environment]. The removal of the environment variable will [i]not[/i] persist to processes run after the Godot process was terminated. - [b]Note:[/b] Environment variable names are case-sensitive on all platforms except Windows. The [param variable] name cannot be empty or include the [code]=[/code] character. + Removes the given environment variable from the current environment, if it exists. The [param variable] name cannot be empty or include the [code]=[/code] character. The environment variable will be removed for the Godot process and any process executed with [method execute] after running [method unset_environment]. The removal of the environment variable will [i]not[/i] persist to processes run after the Godot process was terminated. + [b]Note:[/b] Environment variable names are case-sensitive on all platforms except Windows. </description> </method> </methods> <members> <member name="delta_smoothing" type="bool" setter="set_delta_smoothing" getter="is_delta_smoothing_enabled" default="true"> - If [code]true[/code], the engine filters the time delta measured between each frame, and attempts to compensate for random variation. This will only operate on systems where V-Sync is active. + If [code]true[/code], the engine filters the time delta measured between each frame, and attempts to compensate for random variation. This only works on systems where V-Sync is active. + [b]Note:[/b] On start-up, this is the same as [member ProjectSettings.application/run/delta_smoothing]. </member> <member name="low_processor_usage_mode" type="bool" setter="set_low_processor_usage_mode" getter="is_in_low_processor_usage_mode" default="false"> If [code]true[/code], the engine optimizes for low processor usage by only refreshing the screen if needed. Can improve battery consumption on mobile. + [b]Note:[/b] On start-up, this is the same as [member ProjectSettings.application/run/low_processor_mode]. </member> <member name="low_processor_usage_mode_sleep_usec" type="int" setter="set_low_processor_usage_mode_sleep_usec" getter="get_low_processor_usage_mode_sleep_usec" default="6900"> - The amount of sleeping between frames when the low-processor usage mode is enabled (in microseconds). Higher values will result in lower CPU usage. + The amount of sleeping between frames when the low-processor usage mode is enabled, in microseconds. Higher values will result in lower CPU usage. See also [member low_processor_usage_mode]. + [b]Note:[/b] On start-up, this is the same as [member ProjectSettings.application/run/low_processor_mode_sleep_usec]. </member> </members> <constants> @@ -703,28 +760,28 @@ The Direct3D 12 rendering driver. </constant> <constant name="SYSTEM_DIR_DESKTOP" value="0" enum="SystemDir"> - Desktop directory path. + Refers to the Desktop directory path. </constant> <constant name="SYSTEM_DIR_DCIM" value="1" enum="SystemDir"> - DCIM (Digital Camera Images) directory path. + Refers to the DCIM (Digital Camera Images) directory path. </constant> <constant name="SYSTEM_DIR_DOCUMENTS" value="2" enum="SystemDir"> - Documents directory path. + Refers to the Documents directory path. </constant> <constant name="SYSTEM_DIR_DOWNLOADS" value="3" enum="SystemDir"> - Downloads directory path. + Refers to the Downloads directory path. </constant> <constant name="SYSTEM_DIR_MOVIES" value="4" enum="SystemDir"> - Movies directory path. + Refers to the Movies (or Videos) directory path. </constant> <constant name="SYSTEM_DIR_MUSIC" value="5" enum="SystemDir"> - Music directory path. + Refers to the Music directory path. </constant> <constant name="SYSTEM_DIR_PICTURES" value="6" enum="SystemDir"> - Pictures directory path. + Refers to the Pictures directory path. </constant> <constant name="SYSTEM_DIR_RINGTONES" value="7" enum="SystemDir"> - Ringtones directory path. + Refers to the Ringtones directory path. </constant> </constants> </class> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index 2ffb02096d..e4f4d7682b 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -314,7 +314,7 @@ { if (property["name"].AsStringName() == PropertyName.Number && IsNumberEditable) { - var usage = property["usage"].As>PropertyUsageFlags<() | PropertyUsageFlags.ReadOnly; + var usage = property["usage"].As<PropertyUsageFlags>() | PropertyUsageFlags.ReadOnly; property["usage"] = (int)usage; } } diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml index 516cc9f020..a934d32a6d 100644 --- a/doc/classes/PackedByteArray.xml +++ b/doc/classes/PackedByteArray.xml @@ -397,7 +397,7 @@ <return type="int" /> <param index="0" name="new_size" type="int" /> <description> - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. </description> </method> <method name="reverse"> diff --git a/doc/classes/PackedColorArray.xml b/doc/classes/PackedColorArray.xml index 4908a861b3..ad96ba2490 100644 --- a/doc/classes/PackedColorArray.xml +++ b/doc/classes/PackedColorArray.xml @@ -131,7 +131,7 @@ <return type="int" /> <param index="0" name="new_size" type="int" /> <description> - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. </description> </method> <method name="reverse"> diff --git a/doc/classes/PackedFloat32Array.xml b/doc/classes/PackedFloat32Array.xml index 56f9633533..6f1ecacca4 100644 --- a/doc/classes/PackedFloat32Array.xml +++ b/doc/classes/PackedFloat32Array.xml @@ -132,7 +132,7 @@ <return type="int" /> <param index="0" name="new_size" type="int" /> <description> - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. </description> </method> <method name="reverse"> diff --git a/doc/classes/PackedFloat64Array.xml b/doc/classes/PackedFloat64Array.xml index b08bdafc83..aef5ab90ac 100644 --- a/doc/classes/PackedFloat64Array.xml +++ b/doc/classes/PackedFloat64Array.xml @@ -132,7 +132,7 @@ <return type="int" /> <param index="0" name="new_size" type="int" /> <description> - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. </description> </method> <method name="reverse"> diff --git a/doc/classes/PackedInt32Array.xml b/doc/classes/PackedInt32Array.xml index c70cadc2fe..e6396e2a93 100644 --- a/doc/classes/PackedInt32Array.xml +++ b/doc/classes/PackedInt32Array.xml @@ -128,7 +128,7 @@ <return type="int" /> <param index="0" name="new_size" type="int" /> <description> - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. </description> </method> <method name="reverse"> diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml index 339ab26a68..55024341c1 100644 --- a/doc/classes/PackedInt64Array.xml +++ b/doc/classes/PackedInt64Array.xml @@ -128,7 +128,7 @@ <return type="int" /> <param index="0" name="new_size" type="int" /> <description> - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. </description> </method> <method name="reverse"> diff --git a/doc/classes/PackedStringArray.xml b/doc/classes/PackedStringArray.xml index c2ae3cf3d3..f1b02272f3 100644 --- a/doc/classes/PackedStringArray.xml +++ b/doc/classes/PackedStringArray.xml @@ -134,7 +134,7 @@ <return type="int" /> <param index="0" name="new_size" type="int" /> <description> - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. </description> </method> <method name="reverse"> diff --git a/doc/classes/PackedVector2Array.xml b/doc/classes/PackedVector2Array.xml index 0e5bb12d02..c73fea9114 100644 --- a/doc/classes/PackedVector2Array.xml +++ b/doc/classes/PackedVector2Array.xml @@ -136,7 +136,7 @@ <return type="int" /> <param index="0" name="new_size" type="int" /> <description> - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. </description> </method> <method name="reverse"> diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml index ce7ae4f396..89f258eaea 100644 --- a/doc/classes/PackedVector3Array.xml +++ b/doc/classes/PackedVector3Array.xml @@ -135,7 +135,7 @@ <return type="int" /> <param index="0" name="new_size" type="int" /> <description> - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. </description> </method> <method name="reverse"> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index ab92916320..e80b349da9 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -810,7 +810,9 @@ Main window can't be focused. No-focus window will ignore all input, except mouse clicks. </member> <member name="display/window/size/resizable" type="bool" setter="" getter="" default="true"> - Allows the window to be resizable by default. + If [code]true[/code], allows the window to be resizable by default. + [b]Note:[/b] This property is only read when the project starts. To change whether the window is resizable at runtime, set [member Window.unresizable] instead on the root Window, which can be retrieved using [code]get_viewport().get_window()[/code]. [member Window.unresizable] takes the opposite value of this setting. + [b]Note:[/b] Certain window managers can be configured to ignore the non-resizable status of a window. Do not rely on this setting as a guarantee that the window will [i]never[/i] be resizable. [b]Note:[/b] This setting is ignored on iOS. </member> <member name="display/window/size/transparent" type="bool" setter="" getter="" default="false"> @@ -1108,7 +1110,7 @@ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. </member> <member name="input/ui_swap_input_direction" type="Dictionary" setter="" getter=""> - Default [InputEventAction] to swap input direction, i.e. change between left-to-right to right-to-left modes. Affects text-editting controls ([LineEdit], [TextEdit]). + Default [InputEventAction] to swap input direction, i.e. change between left-to-right to right-to-left modes. Affects text-editing controls ([LineEdit], [TextEdit]). </member> <member name="input/ui_text_add_selection_for_next_occurrence" type="Dictionary" setter="" getter=""> If a selection is currently active with the last caret in text fields, searches for the next occurrence of the selection, adds a caret and selects the next occurrence. @@ -1219,15 +1221,15 @@ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. </member> <member name="input/ui_text_completion_accept" type="Dictionary" setter="" getter=""> - Default [InputEventAction] to accept an autocompetion hint. + Default [InputEventAction] to accept an autocompletion hint. [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. </member> <member name="input/ui_text_completion_query" type="Dictionary" setter="" getter=""> - Default [InputEventAction] to request autocompetion. + Default [InputEventAction] to request autocompletion. [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. </member> <member name="input/ui_text_completion_replace" type="Dictionary" setter="" getter=""> - Default [InputEventAction] to accept an autocompetion hint, replacing existing text. + Default [InputEventAction] to accept an autocompletion hint, replacing existing text. [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. </member> <member name="input/ui_text_dedent" type="Dictionary" setter="" getter=""> @@ -1993,9 +1995,6 @@ <member name="memory/limits/message_queue/max_size_mb" type="int" setter="" getter="" default="32"> Godot uses a message queue to defer some function calls. If you run out of space on it (you will see an error), you can increase the size here. </member> - <member name="memory/limits/multithreaded_server/rid_pool_prealloc" type="int" setter="" getter="" default="60"> - This is used by servers when used in multi-threading mode (servers and visual). RIDs are preallocated to avoid stalling the server requesting them on threads. If servers get stalled too often when loading resources in a thread, increase this number. - </member> <member name="navigation/2d/default_cell_size" type="float" setter="" getter="" default="1.0"> Default cell size for 2D navigation maps. See [method NavigationServer2D.map_set_cell_size]. </member> @@ -2537,8 +2536,6 @@ Decreasing this value may improve GPU performance on certain setups, even if the maximum number of clustered elements is never reached in the project. [b]Note:[/b] This setting is only effective when using the Forward+ rendering method, not Mobile and Compatibility. </member> - <member name="rendering/limits/forward_renderer/threaded_render_minimum_instances" type="int" setter="" getter="" default="500"> - </member> <member name="rendering/limits/global_shader_variables/buffer_size" type="int" setter="" getter="" default="65536"> </member> <member name="rendering/limits/opengl/max_lights_per_object" type="int" setter="" getter="" default="8"> @@ -2616,6 +2613,9 @@ <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/d3d12/agility_sdk_version" type="int" setter="" getter="" default="610"> + Version code of the Direct3D 12 Agility SDK to use ([code]D3D12SDKVersion[/code]). + </member> <member name="rendering/rendering_device/d3d12/max_misc_descriptors_per_frame" type="int" setter="" getter="" default="512"> The number of entries in the miscellaneous descriptors heap the Direct3D 12 rendering driver uses each frame, used for various operations like clearing a texture. Depending on the complexity of scenes, this value may be lowered or may need to be raised. @@ -2768,8 +2768,6 @@ <member name="threading/worker_pool/max_threads" type="int" setter="" getter="" default="-1"> Maximum number of threads to be used by [WorkerThreadPool]. Value of [code]-1[/code] means no limit. </member> - <member name="threading/worker_pool/use_system_threads_for_low_priority_tasks" type="bool" setter="" getter="" default="true"> - </member> <member name="xr/openxr/default_action_map" type="String" setter="" getter="" default=""res://openxr_action_map.tres""> Action map configuration to load by default. </member> diff --git a/doc/classes/Quaternion.xml b/doc/classes/Quaternion.xml index 74dfae77fc..61bc4f4720 100644 --- a/doc/classes/Quaternion.xml +++ b/doc/classes/Quaternion.xml @@ -79,6 +79,7 @@ <method name="exp" qualifiers="const"> <return type="Quaternion" /> <description> + Returns the exponential of this quaternion. The rotation axis of the result is the normalized rotation axis of this quaternion, the angle of the result is the length of the vector part of this quaternion. </description> </method> <method name="from_euler" qualifiers="static"> @@ -91,11 +92,14 @@ <method name="get_angle" qualifiers="const"> <return type="float" /> <description> + Returns the angle of the rotation represented by this quaternion. + [b]Note:[/b] The quaternion must be normalized. </description> </method> <method name="get_axis" qualifiers="const"> <return type="Vector3" /> <description> + Returns the rotation axis of the rotation represented by this quaternion. </description> </method> <method name="get_euler" qualifiers="const"> @@ -145,6 +149,7 @@ <method name="log" qualifiers="const"> <return type="Quaternion" /> <description> + Returns the logarithm of this quaternion. The vector part of the result is the rotation axis of this quaternion multiplied by its rotation angle, the real part of the result is zero. </description> </method> <method name="normalized" qualifiers="const"> diff --git a/doc/classes/RDUniform.xml b/doc/classes/RDUniform.xml index 7aab8b2810..77aaf0aae7 100644 --- a/doc/classes/RDUniform.xml +++ b/doc/classes/RDUniform.xml @@ -13,16 +13,19 @@ <return type="void" /> <param index="0" name="id" type="RID" /> <description> + Binds the given id to the uniform. The data associated with the id is then used when the uniform is passed to a shader. </description> </method> <method name="clear_ids"> <return type="void" /> <description> + Unbinds all ids currently bound to the uniform. </description> </method> <method name="get_ids" qualifiers="const"> <return type="RID[]" /> <description> + Returns an array of all ids currently bound to the uniform. </description> </method> </methods> diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index a841453ba0..54f3281e17 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -14,12 +14,12 @@ <link title="Using compute shaders">$DOCS_URL/tutorials/shaders/compute_shaders.html</link> </tutorials> <methods> - <method name="barrier"> + <method name="barrier" is_deprecated="true"> <return type="void" /> <param index="0" name="from" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" /> <param index="1" name="to" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" /> <description> - Puts a memory barrier in place. This is used for synchronization to avoid data races. See also [method full_barrier], which may be useful for debugging. + [i]Deprecated.[/i] Barriers are automatically inserted by RenderingDevice. </description> </method> <method name="buffer_clear"> @@ -27,9 +27,8 @@ <param index="0" name="buffer" type="RID" /> <param index="1" name="offset" type="int" /> <param index="2" name="size_bytes" type="int" /> - <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" /> <description> - Clears the contents of the [param buffer], clearing [param size_bytes] bytes, starting at [param offset]. Always raises a memory barrier. + Clears the contents of the [param buffer], clearing [param size_bytes] bytes, starting at [param offset]. Prints an error if: - the size isn't a multiple of four - the region specified by [param offset] + [param size_bytes] exceeds the buffer @@ -37,6 +36,21 @@ - a compute list is currently active (created by [method compute_list_begin]) </description> </method> + <method name="buffer_copy"> + <return type="int" enum="Error" /> + <param index="0" name="src_buffer" type="RID" /> + <param index="1" name="dst_buffer" type="RID" /> + <param index="2" name="src_offset" type="int" /> + <param index="3" name="dst_offset" type="int" /> + <param index="4" name="size" type="int" /> + <description> + Copies [param size] bytes from the [param src_buffer] at [param src_offset] into [param dst_buffer] at [param dst_offset]. + Prints an error if: + - [param size] exceeds the size of either [param src_buffer] or [param dst_buffer] at their corresponding offsets + - a draw list is currently active (created by [method draw_list_begin]) + - a compute list is currently active (created by [method compute_list_begin]) + </description> + </method> <method name="buffer_get_data"> <return type="PackedByteArray" /> <param index="0" name="buffer" type="RID" /> @@ -52,9 +66,8 @@ <param index="1" name="offset" type="int" /> <param index="2" name="size_bytes" type="int" /> <param index="3" name="data" type="PackedByteArray" /> - <param index="4" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" /> <description> - Updates a region of [param size_bytes] bytes, starting at [param offset], in the buffer, with the specified [param data]. Raises a memory barrier except when [param post_barrier] is set to [constant BARRIER_MASK_NO_BARRIER]. + Updates a region of [param size_bytes] bytes, starting at [param offset], in the buffer, with the specified [param data]. Prints an error if: - the region specified by [param offset] + [param size_bytes] exceeds the buffer - a draw list is currently active (created by [method draw_list_begin]) @@ -77,10 +90,9 @@ </method> <method name="compute_list_begin"> <return type="int" /> - <param index="0" name="allow_draw_overlap" type="bool" default="false" /> <description> Starts a list of compute commands created with the [code]compute_*[/code] methods. The returned value should be passed to other [code]compute_list_*[/code] functions. - If [param allow_draw_overlap] is [code]true[/code], you may have one draw list running at the same time as one compute list. Multiple compute lists cannot be created at the same time; you must finish the previous compute list first using [method compute_list_end]. + Multiple compute lists cannot be created at the same time; you must finish the previous compute list first using [method compute_list_end]. A simple compute operation might look like this (code is not a complete example): [codeblock] var rd = RenderingDevice.new() @@ -128,7 +140,6 @@ </method> <method name="compute_list_end"> <return type="void" /> - <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" /> <description> Finishes a list of compute commands created with the [code]compute_*[/code] methods. </description> @@ -170,7 +181,7 @@ <param index="1" name="color" type="Color" /> <description> Create a command buffer debug label region that can be displayed in third-party tools such as [url=https://renderdoc.org/]RenderDoc[/url]. All regions must be ended with a [method draw_command_end_label] call. When viewed from the linear series of submissions to a single queue, calls to [method draw_command_begin_label] and [method draw_command_end_label] must be matched and balanced. - The [code]VK_EXT_DEBUG_UTILS_EXTENSION_NAME[/code] Vulkan extension must be available and enabled for command buffer debug label region to work. See also [method draw_command_insert_label] and [method draw_command_end_label]. + The [code]VK_EXT_DEBUG_UTILS_EXTENSION_NAME[/code] Vulkan extension must be available and enabled for command buffer debug label region to work. See also [method draw_command_end_label]. </description> </method> <method name="draw_command_end_label"> @@ -179,12 +190,12 @@ Ends the command buffer debug label region started by a [method draw_command_begin_label] call. </description> </method> - <method name="draw_command_insert_label"> + <method name="draw_command_insert_label" is_deprecated="true"> <return type="void" /> <param index="0" name="name" type="String" /> <param index="1" name="color" type="Color" /> <description> - Inserts a command buffer debug label region in the current command buffer. Unlike [method draw_command_begin_label], this region should not be ended with a [method draw_command_end_label] call. + [i]Deprecated.[/i] Inserting labels no longer applies due to command reordering. </description> </method> <method name="draw_list_begin"> @@ -198,14 +209,13 @@ <param index="6" name="clear_depth" type="float" default="1.0" /> <param index="7" name="clear_stencil" type="int" default="0" /> <param index="8" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" /> - <param index="9" name="storage_textures" type="RID[]" default="[]" /> <description> Starts a list of raster drawing commands created with the [code]draw_*[/code] methods. The returned value should be passed to other [code]draw_list_*[/code] functions. Multiple draw lists cannot be created at the same time; you must finish the previous draw list first using [method draw_list_end]. A simple drawing operation might look like this (code is not a complete example): [codeblock] var rd = RenderingDevice.new() - var clear_colors = PackedColorArray([Color(0, 0, 0, 0), Color(0, 0, 0, 0), Color(0, 0, 0, 0)] + var clear_colors = PackedColorArray([Color(0, 0, 0, 0), Color(0, 0, 0, 0), Color(0, 0, 0, 0)]) var draw_list = rd.draw_list_begin(framebuffers[i], RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_READ, RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_DISCARD, clear_colors) # Draw opaque. @@ -232,7 +242,7 @@ [b]Note:[/b] Cannot be used with local RenderingDevices, as these don't have a screen. If called on a local RenderingDevice, [method draw_list_begin_for_screen] returns [constant INVALID_ID]. </description> </method> - <method name="draw_list_begin_split"> + <method name="draw_list_begin_split" is_deprecated="true"> <return type="PackedInt64Array" /> <param index="0" name="framebuffer" type="RID" /> <param index="1" name="splits" type="int" /> @@ -246,7 +256,7 @@ <param index="9" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" /> <param index="10" name="storage_textures" type="RID[]" default="[]" /> <description> - Variant of [method draw_list_begin] with support for multiple splits. The [param splits] parameter determines how many splits are created. + [i]Deprecated.[/i] Split draw lists are used automatically by RenderingDevice. </description> </method> <method name="draw_list_bind_index_array"> @@ -310,7 +320,6 @@ </method> <method name="draw_list_end"> <return type="void" /> - <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" /> <description> Finishes a list of raster drawing commands created with the [code]draw_*[/code] methods. </description> @@ -335,14 +344,14 @@ <method name="draw_list_switch_to_next_pass"> <return type="int" /> <description> - Switches to the next draw pass and returns the split's ID. Equivalent to [method draw_list_switch_to_next_pass_split] with [code]splits[/code] set to [code]1[/code]. + Switches to the next draw pass. </description> </method> - <method name="draw_list_switch_to_next_pass_split"> + <method name="draw_list_switch_to_next_pass_split" is_deprecated="true"> <return type="PackedInt64Array" /> <param index="0" name="splits" type="int" /> <description> - Switches to the next draw pass, with the number of splits allocated specified in [param splits]. The return value is an array containing the ID of each split. For single-split usage, see [method draw_list_switch_to_next_pass]. + [i]Deprecated.[/i] Split draw lists are used automatically by RenderingDevice. </description> </method> <method name="framebuffer_create"> @@ -430,10 +439,10 @@ Tries to free an object in the RenderingDevice. To avoid memory leaks, this should be called after using an object as memory management does not occur automatically when using RenderingDevice directly. </description> </method> - <method name="full_barrier"> + <method name="full_barrier" is_deprecated="true"> <return type="void" /> <description> - Puts a [i]full[/i] memory barrier in place. This is a memory [method barrier] with all flags enabled. [method full_barrier] it should only be used for debugging as it can severely impact performance. + [i]Deprecated.[/i] Barriers are automatically inserted by RenderingDevice. </description> </method> <method name="get_captured_timestamp_cpu_time" qualifiers="const"> @@ -704,7 +713,6 @@ <param index="3" name="mipmap_count" type="int" /> <param index="4" name="base_layer" type="int" /> <param index="5" name="layer_count" type="int" /> - <param index="6" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" /> <description> Clears the specified [param texture] by replacing all of its pixels with the specified [param color]. [param base_mipmap] and [param mipmap_count] determine which mipmaps of the texture are affected by this clear operation, while [param base_layer] and [param layer_count] determine which layers of a 3D texture (or texture array) are affected by this clear operation. For 2D textures (which only have one layer by design), [param base_layer] must be [code]0[/code] and [param layer_count] must be [code]1[/code]. [b]Note:[/b] [param texture] can't be cleared while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to [constant FINAL_ACTION_CONTINUE]) to clear this texture. @@ -721,7 +729,6 @@ <param index="6" name="dst_mipmap" type="int" /> <param index="7" name="src_layer" type="int" /> <param index="8" name="dst_layer" type="int" /> - <param index="9" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" /> <description> Copies the [param from_texture] to [param to_texture] with the specified [param from_pos], [param to_pos] and [param size] coordinates. The Z axis of the [param from_pos], [param to_pos] and [param size] must be [code]0[/code] for 2-dimensional textures. Source and destination mipmaps/layers must also be specified, with these parameters being [code]0[/code] for textures without mipmaps or single-layer textures. Returns [constant @GlobalScope.OK] if the texture copy was successful or [constant @GlobalScope.ERR_INVALID_PARAMETER] otherwise. [b]Note:[/b] [param from_texture] texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to [constant FINAL_ACTION_CONTINUE]) to copy this texture. @@ -831,7 +838,6 @@ <return type="int" enum="Error" /> <param index="0" name="from_texture" type="RID" /> <param index="1" name="to_texture" type="RID" /> - <param index="2" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" /> <description> Resolves the [param from_texture] texture onto [param to_texture] with multisample antialiasing enabled. This must be used when rendering a framebuffer for MSAA to work. Returns [constant @GlobalScope.OK] if successful, [constant @GlobalScope.ERR_INVALID_PARAMETER] otherwise. [b]Note:[/b] [param from_texture] and [param to_texture] textures must have the same dimension, format and type (color or depth). @@ -848,7 +854,6 @@ <param index="0" name="texture" type="RID" /> <param index="1" name="layer" type="int" /> <param index="2" name="data" type="PackedByteArray" /> - <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="32767" /> <description> Updates texture data with new data, replacing the previous data in place. The updated texture data must have the same dimensions and format. For 2D textures (which only have one layer), [param layer] must be [code]0[/code]. Returns [constant @GlobalScope.OK] if the update was successful, [constant @GlobalScope.ERR_INVALID_PARAMETER] otherwise. [b]Note:[/b] Updating textures is forbidden during creation of a draw or compute list. @@ -2150,39 +2155,48 @@ </constant> <constant name="DYNAMIC_STATE_STENCIL_REFERENCE" value="64" enum="PipelineDynamicStateFlags" is_bitfield="true"> </constant> - <constant name="INITIAL_ACTION_CLEAR" value="0" enum="InitialAction"> - Start rendering and clear the whole framebuffer. + <constant name="INITIAL_ACTION_LOAD" value="0" enum="InitialAction"> + Load the previous contents of the framebuffer. </constant> - <constant name="INITIAL_ACTION_CLEAR_REGION" value="1" enum="InitialAction"> - Start rendering and clear the framebuffer in the specified region. + <constant name="INITIAL_ACTION_CLEAR" value="1" enum="InitialAction"> + Clear the whole framebuffer or its specified region. </constant> - <constant name="INITIAL_ACTION_CLEAR_REGION_CONTINUE" value="2" enum="InitialAction"> - Continue rendering and clear the framebuffer in the specified region. Framebuffer must have been left in [constant FINAL_ACTION_CONTINUE] state as the final action previously. + <constant name="INITIAL_ACTION_DISCARD" value="2" enum="InitialAction"> + Ignore the previous contents of the framebuffer. This is the fastest option if you'll overwrite all of the pixels and don't need to read any of them. </constant> - <constant name="INITIAL_ACTION_KEEP" value="3" enum="InitialAction"> - Start rendering, but keep attached color texture contents. If the framebuffer was previously used to read in a shader, this will automatically insert a layout transition. + <constant name="INITIAL_ACTION_MAX" value="3" enum="InitialAction"> + Represents the size of the [enum InitialAction] enum. </constant> - <constant name="INITIAL_ACTION_DROP" value="4" enum="InitialAction"> - Start rendering, ignore what is there; write above it. In general, this is the fastest option when you will be writing every single pixel and you don't need a clear color. + <constant name="INITIAL_ACTION_CLEAR_REGION" value="1" enum="InitialAction" is_deprecated="true"> + [i]Deprecated.[/i] Use [constant INITIAL_ACTION_CLEAR] instead. </constant> - <constant name="INITIAL_ACTION_CONTINUE" value="5" enum="InitialAction"> - Continue rendering. Framebuffer must have been left in [constant FINAL_ACTION_CONTINUE] state as the final action previously. + <constant name="INITIAL_ACTION_CLEAR_REGION_CONTINUE" value="1" enum="InitialAction" is_deprecated="true"> + [i]Deprecated.[/i] Use [constant INITIAL_ACTION_LOAD] instead. </constant> - <constant name="INITIAL_ACTION_MAX" value="6" enum="InitialAction"> - Represents the size of the [enum InitialAction] enum. + <constant name="INITIAL_ACTION_KEEP" value="0" enum="InitialAction" is_deprecated="true"> + [i]Deprecated.[/i] Use [constant INITIAL_ACTION_LOAD] instead. </constant> - <constant name="FINAL_ACTION_READ" value="0" enum="FinalAction"> - Store the texture for reading and make it read-only if it has the [constant TEXTURE_USAGE_SAMPLING_BIT] bit (only applies to color, depth and stencil attachments). + <constant name="INITIAL_ACTION_DROP" value="2" enum="InitialAction" is_deprecated="true"> + [i]Deprecated.[/i] Use [constant INITIAL_ACTION_DISCARD] instead. </constant> - <constant name="FINAL_ACTION_DISCARD" value="1" enum="FinalAction"> - Discard the texture data and make it read-only if it has the [constant TEXTURE_USAGE_SAMPLING_BIT] bit (only applies to color, depth and stencil attachments). + <constant name="INITIAL_ACTION_CONTINUE" value="0" enum="InitialAction" is_deprecated="true"> + [i]Deprecated.[/i] Use [constant INITIAL_ACTION_LOAD] instead. </constant> - <constant name="FINAL_ACTION_CONTINUE" value="2" enum="FinalAction"> - Store the texture and continue for further processing. Similar to [constant FINAL_ACTION_READ], but does not make the texture read-only if it has the [constant TEXTURE_USAGE_SAMPLING_BIT] bit. + <constant name="FINAL_ACTION_STORE" value="0" enum="FinalAction"> + Store the result of the draw list in the framebuffer. This is generally what you want to do. </constant> - <constant name="FINAL_ACTION_MAX" value="3" enum="FinalAction"> + <constant name="FINAL_ACTION_DISCARD" value="1" enum="FinalAction"> + Discard the contents of the framebuffer. This is the fastest option if you don't need to use the results of the draw list. + </constant> + <constant name="FINAL_ACTION_MAX" value="2" enum="FinalAction"> Represents the size of the [enum FinalAction] enum. </constant> + <constant name="FINAL_ACTION_READ" value="0" enum="FinalAction" is_deprecated="true"> + [i]Deprecated.[/i] Use [constant FINAL_ACTION_STORE] instead. + </constant> + <constant name="FINAL_ACTION_CONTINUE" value="0" enum="FinalAction" is_deprecated="true"> + [i]Deprecated.[/i] Use [constant FINAL_ACTION_STORE] instead. + </constant> <constant name="SHADER_STAGE_VERTEX" value="0" enum="ShaderStage"> Vertex shader stage. This can be used to manipulate vertices from a shader (but not create new vertices). </constant> diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index a3ec4d25f1..42a164bbeb 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -1556,11 +1556,11 @@ Returns [code]true[/code] if changes have been made to the RenderingServer's data. [method force_draw] is usually called if this happens. </description> </method> - <method name="has_feature" qualifiers="const"> + <method name="has_feature" qualifiers="const" is_deprecated="true"> <return type="bool" /> <param index="0" name="feature" type="int" enum="RenderingServer.Features" /> <description> - Not yet implemented. Always returns [code]false[/code]. + [i]Deprecated.[/i] This method has not been used since Godot 3.0. Always returns false. </description> </method> <method name="has_os_feature" qualifiers="const"> @@ -5332,11 +5332,11 @@ <constant name="RENDERING_INFO_VIDEO_MEM_USED" value="5" enum="RenderingInfo"> Video memory used (in bytes). When using the Forward+ or mobile rendering backends, this is always greater than the sum of [constant RENDERING_INFO_TEXTURE_MEM_USED] and [constant RENDERING_INFO_BUFFER_MEM_USED], since there is miscellaneous data not accounted for by those two metrics. When using the GL Compatibility backend, this is equal to the sum of [constant RENDERING_INFO_TEXTURE_MEM_USED] and [constant RENDERING_INFO_BUFFER_MEM_USED]. </constant> - <constant name="FEATURE_SHADERS" value="0" enum="Features"> - Hardware supports shaders. This enum is currently unused in Godot 3.x. + <constant name="FEATURE_SHADERS" value="0" enum="Features" is_deprecated="true"> + [i]Deprecated.[/i] This constant has not been used since Godot 3.0. </constant> - <constant name="FEATURE_MULTITHREADED" value="1" enum="Features"> - Hardware supports multithreading. This enum is currently unused in Godot 3.x. + <constant name="FEATURE_MULTITHREADED" value="1" enum="Features" is_deprecated="true"> + [i]Deprecated.[/i] This constant has not been used since Godot 3.0. </constant> </constants> </class> diff --git a/doc/classes/ScriptLanguageExtension.xml b/doc/classes/ScriptLanguageExtension.xml index b4e2f40612..c5248f4888 100644 --- a/doc/classes/ScriptLanguageExtension.xml +++ b/doc/classes/ScriptLanguageExtension.xml @@ -114,9 +114,10 @@ </method> <method name="_find_function" qualifiers="virtual const"> <return type="int" /> - <param index="0" name="class_name" type="String" /> - <param index="1" name="function_name" type="String" /> + <param index="0" name="function" type="String" /> + <param index="1" name="code" type="String" /> <description> + Returns the line where the function is defined in the code, or [code]-1[/code] if the function is not present. </description> </method> <method name="_finish" qualifiers="virtual"> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index af4297afae..e1b60b1656 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -96,13 +96,14 @@ [gdscript] "move_local_x".capitalize() # Returns "Move Local X" "sceneFile_path".capitalize() # Returns "Scene File Path" + "2D, FPS, PNG".capitalize() # Returns "2d, Fps, Png" [/gdscript] [csharp] "move_local_x".Capitalize(); // Returns "Move Local X" "sceneFile_path".Capitalize(); // Returns "Scene File Path" + "2D, FPS, PNG".Capitalize(); // Returns "2d, Fps, Png" [/csharp] [/codeblocks] - [b]Note:[/b] This method not the same as the default appearance of properties in the Inspector dock, as it does not capitalize acronyms ([code]"2D"[/code], [code]"FPS"[/code], [code]"PNG"[/code], etc.) as you may expect. </description> </method> <method name="casecmp_to" qualifiers="const"> @@ -318,7 +319,7 @@ <return type="int" /> <description> Returns the 32-bit hash value representing the string's contents. - [b]Note:[/b] Strings with equal hash values are [i]not[/i] guaranteed to be the same, as a result of hash collisions. On the countrary, strings with different hash values are guaranteed to be different. + [b]Note:[/b] Strings with equal hash values are [i]not[/i] guaranteed to be the same, as a result of hash collisions. On the contrary, strings with different hash values are guaranteed to be different. </description> </method> <method name="hex_decode" qualifiers="const"> @@ -949,7 +950,7 @@ <method name="to_lower" qualifiers="const"> <return type="String" /> <description> - Returns the string converted to lowercase. + Returns the string converted to [code]lowercase[/code]. </description> </method> <method name="to_pascal_case" qualifiers="const"> @@ -962,12 +963,25 @@ <return type="String" /> <description> Returns the string converted to [code]snake_case[/code]. + [b]Note:[/b] Numbers followed by a [i]single[/i] letter are not separated in the conversion to keep some words (such as "2D") together. + [codeblocks] + [gdscript] + "Node2D".to_snake_case() # Returns "node_2d" + "2nd place".to_snake_case() # Returns "2_nd_place" + "Texture3DAssetFolder".to_snake_case() # Returns "texture_3d_asset_folder" + [/gdscript] + [csharp] + "Node2D".ToSnakeCase(); // Returns "node_2d" + "2nd place".ToSnakeCase(); // Returns "2_nd_place" + "Texture3DAssetFolder".ToSnakeCase(); // Returns "texture_3d_asset_folder" + [/csharp] + [/codeblocks] </description> </method> <method name="to_upper" qualifiers="const"> <return type="String" /> <description> - Returns the string converted to uppercase. + Returns the string converted to [code]UPPERCASE[/code]. </description> </method> <method name="to_utf8_buffer" qualifiers="const"> diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml index 1c5032be9b..844782eb9a 100644 --- a/doc/classes/StringName.xml +++ b/doc/classes/StringName.xml @@ -8,6 +8,7 @@ You will usually just pass a [String] to methods expecting a [StringName] and it will be automatically converted, but you may occasionally want to construct a [StringName] ahead of time with the [StringName] constructor or, in GDScript, the literal syntax [code]&"example"[/code]. See also [NodePath], which is a similar concept specifically designed to store pre-parsed scene tree paths. All of [String]'s methods are available in this class too. They convert the [StringName] into a string, and they also return a string. This is highly inefficient and should only be used if the string is desired. + [b]Note:[/b] In C#, an explicit conversion to [code]System.String[/code] is required to use the methods listed on this page. Use the [code]ToString()[/code] method to cast a [StringName] to a string, and then use the equivalent methods in [code]System.String[/code] or [code]StringExtensions[/code]. [b]Note:[/b] In a boolean context, a [StringName] will evaluate to [code]false[/code] if it is empty ([code]StringName("")[/code]). Otherwise, a [StringName] will always evaluate to [code]true[/code]. The [code]not[/code] operator cannot be used. Instead, [method is_empty] should be used to check for empty [StringName]s. </description> <tutorials> @@ -90,13 +91,14 @@ [gdscript] "move_local_x".capitalize() # Returns "Move Local X" "sceneFile_path".capitalize() # Returns "Scene File Path" + "2D, FPS, PNG".capitalize() # Returns "2d, Fps, Png" [/gdscript] [csharp] "move_local_x".Capitalize(); // Returns "Move Local X" "sceneFile_path".Capitalize(); // Returns "Scene File Path" + "2D, FPS, PNG".Capitalize(); // Returns "2d, Fps, Png" [/csharp] [/codeblocks] - [b]Note:[/b] This method not the same as the default appearance of properties in the Inspector dock, as it does not capitalize acronyms ([code]"2D"[/code], [code]"FPS"[/code], [code]"PNG"[/code], etc.) as you may expect. </description> </method> <method name="casecmp_to" qualifiers="const"> @@ -301,7 +303,7 @@ <return type="int" /> <description> Returns the 32-bit hash value representing the string's contents. - [b]Note:[/b] Strings with equal hash values are [i]not[/i] guaranteed to be the same, as a result of hash collisions. On the countrary, strings with different hash values are guaranteed to be different. + [b]Note:[/b] Strings with equal hash values are [i]not[/i] guaranteed to be the same, as a result of hash collisions. On the contrary, strings with different hash values are guaranteed to be different. </description> </method> <method name="hex_decode" qualifiers="const"> @@ -856,7 +858,7 @@ <method name="to_lower" qualifiers="const"> <return type="String" /> <description> - Returns the string converted to lowercase. + Returns the string converted to [code]lowercase[/code]. </description> </method> <method name="to_pascal_case" qualifiers="const"> @@ -869,12 +871,25 @@ <return type="String" /> <description> Returns the string converted to [code]snake_case[/code]. + [b]Note:[/b] Numbers followed by a [i]single[/i] letter are not separated in the conversion to keep some words (such as "2D") together. + [codeblocks] + [gdscript] + "Node2D".to_snake_case() # Returns "node_2d" + "2nd place".to_snake_case() # Returns "2_nd_place" + "Texture3DAssetFolder".to_snake_case() # Returns "texture_3d_asset_folder" + [/gdscript] + [csharp] + "Node2D".ToSnakeCase(); // Returns "node_2d" + "2nd place".ToSnakeCase(); // Returns "2_nd_place" + "Texture3DAssetFolder".ToSnakeCase(); // Returns "texture_3d_asset_folder" + [/csharp] + [/codeblocks] </description> </method> <method name="to_upper" qualifiers="const"> <return type="String" /> <description> - Returns the string converted to uppercase. + Returns the string converted to [code]UPPERCASE[/code]. </description> </method> <method name="to_utf8_buffer" qualifiers="const"> diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml index b3a9264569..1f3c3531c6 100644 --- a/doc/classes/TabContainer.xml +++ b/doc/classes/TabContainer.xml @@ -193,6 +193,9 @@ <member name="tab_focus_mode" type="int" setter="set_tab_focus_mode" getter="get_tab_focus_mode" enum="Control.FocusMode" default="2"> The focus access mode for the internal [TabBar] node. </member> + <member name="tabs_position" type="int" setter="set_tabs_position" getter="get_tabs_position" enum="TabContainer.TabPosition" default="0"> + Sets the position of the tab bar. See [enum TabPosition] for details. + </member> <member name="tabs_rearrange_group" type="int" setter="set_tabs_rearrange_group" getter="get_tabs_rearrange_group" default="-1"> [TabContainer]s with the same rearrange group ID will allow dragging the tabs between them. Enable drag with [member drag_to_rearrange_enabled]. Setting this to [code]-1[/code] will disable rearranging between [TabContainer]s. @@ -247,6 +250,17 @@ </description> </signal> </signals> + <constants> + <constant name="POSITION_TOP" value="0" enum="TabPosition"> + Places the tab bar at the top. + </constant> + <constant name="POSITION_BOTTOM" value="1" enum="TabPosition"> + Places the tab bar at the bottom. The tab bar's [StyleBox] will be flipped vertically. + </constant> + <constant name="POSITION_MAX" value="2" enum="TabPosition"> + Represents the size of the [enum TabPosition] enum. + </constant> + </constants> <theme_items> <theme_item name="drop_mark_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> Modulation color for the [theme_item drop_mark] icon. diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index 09f484f523..cf4d92d119 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -1744,6 +1744,7 @@ Vertical BGR subpixel layout. </constant> <constant name="FONT_LCD_SUBPIXEL_LAYOUT_MAX" value="5" enum="FontLCDSubpixelLayout"> + Represents the size of the [enum FontLCDSubpixelLayout] enum. </constant> <constant name="DIRECTION_AUTO" value="0" enum="Direction"> Text direction is determined based on contents and current locale. @@ -1867,6 +1868,7 @@ Determines whether the ellipsis at the end of the text is enforced and may not be hidden. </constant> <constant name="OVERRUN_JUSTIFICATION_AWARE" value="16" enum="TextOverrunFlag" is_bitfield="true"> + Accounts for the text being justified before attempting to trim it (see [enum JustificationFlag]). </constant> <constant name="GRAPHEME_IS_VALID" value="1" enum="GraphemeFlag" is_bitfield="true"> Grapheme is supported by the font, and can be drawn. @@ -2005,6 +2007,7 @@ Spacing at the bottom of the line. </constant> <constant name="SPACING_MAX" value="4" enum="SpacingType"> + Represents the size of the [enum SpacingType] enum. </constant> <constant name="FONT_BOLD" value="1" enum="FontStyle" is_bitfield="true"> Font is bold. diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml index 087f3a70f8..7254a92e36 100644 --- a/doc/classes/Texture2D.xml +++ b/doc/classes/Texture2D.xml @@ -123,6 +123,7 @@ <return type="Image" /> <description> Returns an [Image] that is a copy of data from this [Texture2D] (a new [Image] is created each time). [Image]s can be accessed and manipulated directly. + [b]Note:[/b] This will return [code]null[/code] if this [Texture2D] is invalid. [b]Note:[/b] This will fetch the texture data from the GPU, which might cause performance problems when overused. </description> </method> diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml index aee70f6b59..4247ff81ee 100644 --- a/doc/classes/Transform2D.xml +++ b/doc/classes/Transform2D.xml @@ -5,7 +5,7 @@ </brief_description> <description> A 2×3 matrix (2 rows, 3 columns) used for 2D linear transformations. It can represent transformations such as translation, rotation, and scaling. It consists of three [Vector2] values: [member x], [member y], and the [member origin]. - For more information, read the "Matrices and transforms" documentation article. + For a general introduction, see the [url=$DOCS_URL/tutorials/math/matrices_and_transforms.html]Matrices and transforms[/url] tutorial. </description> <tutorials> <link title="Math documentation index">$DOCS_URL/tutorials/math/index.html</link> @@ -286,6 +286,20 @@ This operator multiplies all components of the [Transform2D], including the [member origin] vector, which scales it uniformly. </description> </operator> + <operator name="operator /"> + <return type="Transform2D" /> + <param index="0" name="right" type="float" /> + <description> + This operator divides all components of the [Transform2D], including the [member origin] vector, which inversely scales it uniformly. + </description> + </operator> + <operator name="operator /"> + <return type="Transform2D" /> + <param index="0" name="right" type="int" /> + <description> + This operator divides all components of the [Transform2D], including the [member origin] vector, which inversely scales it uniformly. + </description> + </operator> <operator name="operator =="> <return type="bool" /> <param index="0" name="right" type="Transform2D" /> diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml index 85da629d70..a1ddb75bc2 100644 --- a/doc/classes/Transform3D.xml +++ b/doc/classes/Transform3D.xml @@ -5,7 +5,7 @@ </brief_description> <description> A 3×4 matrix (3 rows, 4 columns) used for 3D linear transformations. It can represent transformations such as translation, rotation, and scaling. It consists of a [member basis] (first 3 columns) and a [Vector3] for the [member origin] (last column). - For more information, read the "Matrices and transforms" documentation article. + For a general introduction, see the [url=$DOCS_URL/tutorials/math/matrices_and_transforms.html]Matrices and transforms[/url] tutorial. </description> <tutorials> <link title="Math documentation index">$DOCS_URL/tutorials/math/index.html</link> @@ -245,6 +245,20 @@ This operator multiplies all components of the [Transform3D], including the [member origin] vector, which scales it uniformly. </description> </operator> + <operator name="operator /"> + <return type="Transform3D" /> + <param index="0" name="right" type="float" /> + <description> + This operator divides all components of the [Transform3D], including the [member origin] vector, which inversely scales it uniformly. + </description> + </operator> + <operator name="operator /"> + <return type="Transform3D" /> + <param index="0" name="right" type="int" /> + <description> + This operator divides all components of the [Transform3D], including the [member origin] vector, which inversely scales it uniformly. + </description> + </operator> <operator name="operator =="> <return type="bool" /> <param index="0" name="right" type="Transform3D" /> diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml index 2100cd7612..e004755818 100644 --- a/doc/classes/Vector2i.xml +++ b/doc/classes/Vector2i.xml @@ -64,6 +64,21 @@ Returns a new vector with all components clamped between the components of [param min] and [param max], by running [method @GlobalScope.clamp] on each component. </description> </method> + <method name="distance_squared_to" qualifiers="const"> + <return type="int" /> + <param index="0" name="to" type="Vector2i" /> + <description> + Returns the squared distance between this vector and [param to]. + This method runs faster than [method distance_to], so prefer it if you need to compare vectors or need the squared distance for some formula. + </description> + </method> + <method name="distance_to" qualifiers="const"> + <return type="float" /> + <param index="0" name="to" type="Vector2i" /> + <description> + Returns the distance between this vector and [param to]. + </description> + </method> <method name="length" qualifiers="const"> <return type="float" /> <description> diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml index 8906bf0aa7..96760ed9f9 100644 --- a/doc/classes/Vector3i.xml +++ b/doc/classes/Vector3i.xml @@ -59,6 +59,21 @@ Returns a new vector with all components clamped between the components of [param min] and [param max], by running [method @GlobalScope.clamp] on each component. </description> </method> + <method name="distance_squared_to" qualifiers="const"> + <return type="int" /> + <param index="0" name="to" type="Vector3i" /> + <description> + Returns the squared distance between this vector and [param to]. + This method runs faster than [method distance_to], so prefer it if you need to compare vectors or need the squared distance for some formula. + </description> + </method> + <method name="distance_to" qualifiers="const"> + <return type="float" /> + <param index="0" name="to" type="Vector3i" /> + <description> + Returns the distance between this vector and [param to]. + </description> + </method> <method name="length" qualifiers="const"> <return type="float" /> <description> diff --git a/doc/classes/Vector4i.xml b/doc/classes/Vector4i.xml index a612c135dd..464c19c223 100644 --- a/doc/classes/Vector4i.xml +++ b/doc/classes/Vector4i.xml @@ -57,6 +57,21 @@ Returns a new vector with all components clamped between the components of [param min] and [param max], by running [method @GlobalScope.clamp] on each component. </description> </method> + <method name="distance_squared_to" qualifiers="const"> + <return type="int" /> + <param index="0" name="to" type="Vector4i" /> + <description> + Returns the squared distance between this vector and [param to]. + This method runs faster than [method distance_to], so prefer it if you need to compare vectors or need the squared distance for some formula. + </description> + </method> + <method name="distance_to" qualifiers="const"> + <return type="float" /> + <param index="0" name="to" type="Vector4i" /> + <description> + Returns the distance between this vector and [param to]. + </description> + </method> <method name="length" qualifiers="const"> <return type="float" /> <description> diff --git a/doc/classes/VehicleWheel3D.xml b/doc/classes/VehicleWheel3D.xml index 9c7ba58534..77cb5ca9f8 100644 --- a/doc/classes/VehicleWheel3D.xml +++ b/doc/classes/VehicleWheel3D.xml @@ -81,7 +81,7 @@ This is the distance in meters the wheel is lowered from its origin point. Don't set this to 0.0 and move the wheel into position, instead move the origin point of your wheel (the gizmo in Godot) to the position the wheel will take when bottoming out, then use the rest length to move the wheel down to the position it should be in when the car is in rest. </member> <member name="wheel_roll_influence" type="float" setter="set_roll_influence" getter="get_roll_influence" default="0.1"> - This value affects the roll of your vehicle. If set to 1.0 for all wheels, your vehicle will be prone to rolling over, while a value of 0.0 will resist body roll. + This value affects the roll of your vehicle. If set to 1.0 for all wheels, your vehicle will resist body roll, while a value of 0.0 will be prone to rolling over. </member> </members> </class> diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index 5f6b1960b7..618a774aae 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -357,10 +357,11 @@ Centers a native window on the current screen and an embedded window on its embedder [Viewport]. </description> </method> - <method name="move_to_foreground"> + <method name="move_to_foreground" is_deprecated="true"> <return type="void" /> <description> Moves the [Window] on top of other windows and focuses it. + [i]Deprecated.[/i] Use [method Window.grab_focus] instead. </description> </method> <method name="popup"> @@ -668,6 +669,9 @@ If [code]true[/code], the [Window] is transient, i.e. it's considered a child of another [Window]. The transient window will be destroyed with its transient parent and will return focus to their parent when closed. The transient window is displayed on top of a non-exclusive full-screen parent window. Transient windows can't enter full-screen mode. Note that behavior might be different depending on the platform. </member> + <member name="transient_to_focused" type="bool" setter="set_transient_to_focused" getter="is_transient_to_focused" default="false"> + If [code]true[/code], and the [Window] is [member transient], this window will (at the time of becoming visible) become transient to the currently focused window instead of the immediate parent window in the hierarchy. Note that the transient parent is assigned at the time this window becomes visible, so changing it afterwards has no effect until re-shown. + </member> <member name="transparent" type="bool" setter="set_flag" getter="get_flag" default="false"> If [code]true[/code], the [Window]'s background can be transparent. This is best used with embedded windows. [b]Note:[/b] Transparency support is implemented on Linux, macOS and Windows, but availability might vary depending on GPU driver, display manager, and compositor capabilities. diff --git a/doc/classes/WorkerThreadPool.xml b/doc/classes/WorkerThreadPool.xml index d6751d31ce..fa1f08b149 100644 --- a/doc/classes/WorkerThreadPool.xml +++ b/doc/classes/WorkerThreadPool.xml @@ -106,7 +106,7 @@ Pauses the thread that calls this method until the task with the given ID is completed. Returns [constant @GlobalScope.OK] if the task could be successfully awaited. Returns [constant @GlobalScope.ERR_INVALID_PARAMETER] if a task with the passed ID does not exist (maybe because it was already awaited and disposed of). - Returns [constant @GlobalScope.ERR_BUSY] if the call is made from another running task and, due to task scheduling, the task to await is at a lower level in the call stack and therefore can't progress. This is an advanced situation that should only matter when some tasks depend on others. + Returns [constant @GlobalScope.ERR_BUSY] if the call is made from another running task and, due to task scheduling, there's potential for deadlocking (e.g., the task to await may be at a lower level in the call stack and therefore can't progress). This is an advanced situation that should only matter when some tasks depend on others (in the current implementation, the tricky case is a task trying to wait on an older one). </description> </method> </methods> diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py index c3a21f3d7b..df3e928538 100755 --- a/doc/tools/make_rst.py +++ b/doc/tools/make_rst.py @@ -105,6 +105,7 @@ EDITOR_CLASSES: List[str] = [ CLASSES_WITH_CSHARP_DIFFERENCES: List[str] = [ "@GlobalScope", "String", + "StringName", "NodePath", "Signal", "Callable", diff --git a/drivers/d3d12/SCsub b/drivers/d3d12/SCsub index 11ae52fd40..a49d55ebc0 100644 --- a/drivers/d3d12/SCsub +++ b/drivers/d3d12/SCsub @@ -5,8 +5,6 @@ from pathlib import Path Import("env") -env.Append(CPPDEFINES=["RD_ENABLED"]) - env_d3d12_rdd = env.Clone() thirdparty_obj = [] diff --git a/drivers/d3d12/d3d12_context.cpp b/drivers/d3d12/d3d12_context.cpp index 36492b198b..37066a811d 100644 --- a/drivers/d3d12/d3d12_context.cpp +++ b/drivers/d3d12/d3d12_context.cpp @@ -55,27 +55,14 @@ #include <guiddef.h> #include <dxguids.h> +#ifndef CLSID_D3D12DeviceFactory +// Note: symbol is not available in MinGW import library. +const CLSID CLSID_D3D12DeviceFactory = __uuidof(ID3D12DeviceFactory); +#endif #endif extern "C" { char godot_nir_arch_name[32]; - -#ifdef AGILITY_SDK_ENABLED -__declspec(dllexport) extern const UINT D3D12SDKVersion = 610; -#ifdef AGILITY_SDK_MULTIARCH_ENABLED -#if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) -__declspec(dllexport) extern const char *D3D12SDKPath = "\\.\\arm64"; -#elif defined(__arm__) || defined(_M_ARM) -__declspec(dllexport) extern const char *D3D12SDKPath = "\\.\\arm32"; -#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64) -__declspec(dllexport) extern const char *D3D12SDKPath = "\\.\\x86_64"; -#elif defined(__i386) || defined(__i386__) || defined(_M_IX86) -__declspec(dllexport) extern const char *D3D12SDKPath = "\\.\\x86_32"; -#endif -#else -__declspec(dllexport) extern const char *D3D12SDKPath = "\\."; -#endif // AGILITY_SDK_MULTIARCH -#endif // AGILITY_SDK_ENABLED } #ifdef PIX_ENABLED @@ -89,6 +76,8 @@ __declspec(dllexport) extern const char *D3D12SDKPath = "\\."; #endif #endif +#define D3D12_DEBUG_LAYER_BREAK_ON_ERROR 0 + void D3D12Context::_debug_message_func( D3D12_MESSAGE_CATEGORY p_category, D3D12_MESSAGE_SEVERITY p_severity, @@ -295,7 +284,12 @@ Error D3D12Context::_check_capabilities() { Error D3D12Context::_initialize_debug_layers() { ComPtr<ID3D12Debug> debug_controller; - HRESULT res = D3D12GetDebugInterface(IID_PPV_ARGS(&debug_controller)); + HRESULT res; + if (device_factory) { + res = device_factory->GetConfigurationInterface(CLSID_D3D12Debug, IID_PPV_ARGS(&debug_controller)); + } else { + res = D3D12GetDebugInterface(IID_PPV_ARGS(&debug_controller)); + } ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_QUERY_FAILED); debug_controller->EnableDebugLayer(); return OK; @@ -501,7 +495,12 @@ void D3D12Context::_dump_adapter_info(int p_index) { } Error D3D12Context::_create_device(DeviceBasics &r_basics) { - HRESULT res = D3D12CreateDevice(gpu.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(r_basics.device.GetAddressOf())); + HRESULT res; + if (device_factory) { + res = device_factory->CreateDevice(gpu.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(r_basics.device.GetAddressOf())); + } else { + res = D3D12CreateDevice(gpu.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(r_basics.device.GetAddressOf())); + } ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12CreateDevice failed with error " + vformat("0x%08ux", (uint64_t)res) + "."); // Create direct command queue. @@ -566,6 +565,11 @@ Error D3D12Context::_create_device(DeviceBasics &r_basics) { res = info_queue->PushStorageFilter(&filter); ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE); + +#if D3D12_DEBUG_LAYER_BREAK_ON_ERROR + res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true); + ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE); +#endif } return OK; @@ -808,7 +812,32 @@ Error D3D12Context::_update_swap_chain(Window *window) { return OK; } +void D3D12Context::_init_device_factory() { + uint32_t agility_sdk_version = GLOBAL_GET("rendering/rendering_device/d3d12/agility_sdk_version"); + String agility_sdk_path = String(".\\") + Engine::get_singleton()->get_architecture_name(); + + // Note: symbol is not available in MinGW import library. + PFN_D3D12_GET_INTERFACE d3d_D3D12GetInterface = (PFN_D3D12_GET_INTERFACE)GetProcAddress(LoadLibraryW(L"D3D12.dll"), "D3D12GetInterface"); + ERR_FAIL_COND(!d3d_D3D12GetInterface); + + ID3D12SDKConfiguration *sdk_config = nullptr; + if (SUCCEEDED(d3d_D3D12GetInterface(CLSID_D3D12SDKConfiguration, IID_PPV_ARGS(&sdk_config)))) { + ID3D12SDKConfiguration1 *sdk_config1 = nullptr; + if (SUCCEEDED(sdk_config->QueryInterface(&sdk_config1))) { + if (SUCCEEDED(sdk_config1->CreateDeviceFactory(agility_sdk_version, agility_sdk_path.ascii().get_data(), IID_PPV_ARGS(device_factory.GetAddressOf())))) { + d3d_D3D12GetInterface(CLSID_D3D12DeviceFactory, IID_PPV_ARGS(device_factory.GetAddressOf())); + } else if (SUCCEEDED(sdk_config1->CreateDeviceFactory(agility_sdk_version, ".\\", IID_PPV_ARGS(device_factory.GetAddressOf())))) { + d3d_D3D12GetInterface(CLSID_D3D12DeviceFactory, IID_PPV_ARGS(device_factory.GetAddressOf())); + } + sdk_config1->Release(); + } + sdk_config->Release(); + } +} + Error D3D12Context::initialize() { + _init_device_factory(); + if (_use_validation_layers()) { Error err = _initialize_debug_layers(); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); @@ -867,7 +896,9 @@ void D3D12Context::_wait_for_idle_queue(ID3D12CommandQueue *p_queue) { #endif } -void D3D12Context::flush(bool p_flush_setup, bool p_flush_pending) { +void D3D12Context::flush(bool p_flush_setup, bool p_flush_pending, bool p_sync) { + ERR_FAIL_COND_MSG(!p_sync, "Flush without sync is not supported."); // This is a special case for Vulkan on mobile XR hardware, not applicable to D3D12 + if (p_flush_setup && command_list_queue[0]) { md.queue->ExecuteCommandLists(1, command_list_queue.ptr()); command_list_queue[0] = nullptr; @@ -1032,27 +1063,6 @@ void D3D12Context::local_device_free(RID p_local_device) { local_device_owner.free(p_local_device); } -void D3D12Context::command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) { -#ifdef PIX_ENABLED - const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id; - PIXBeginEvent(cmd_buf_info->cmd_list.Get(), p_color.to_argb32(), p_label_name.utf8().get_data()); -#endif -} - -void D3D12Context::command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) { -#ifdef PIX_ENABLED - const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id; - PIXSetMarker(cmd_buf_info->cmd_list.Get(), p_color.to_argb32(), p_label_name.utf8().get_data()); -#endif -} - -void D3D12Context::command_end_label(RDD::CommandBufferID p_command_buffer) { -#ifdef PIX_ENABLED - const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id; - PIXEndEvent(cmd_buf_info->cmd_list.Get()); -#endif -} - void D3D12Context::set_object_name(ID3D12Object *p_object, String p_object_name) { ERR_FAIL_NULL(p_object); int name_len = p_object_name.size(); @@ -1101,6 +1111,14 @@ RenderingDeviceDriver *D3D12Context::get_driver(RID p_local_device) { } } +bool D3D12Context::is_debug_utils_enabled() const { +#ifdef PIX_ENABLED + return true; +#else + return false; +#endif +} + D3D12Context::D3D12Context() { command_list_queue.resize(1); // First one is always the setup command. command_list_queue[0] = nullptr; diff --git a/drivers/d3d12/d3d12_context.h b/drivers/d3d12/d3d12_context.h index ec4bc832b6..ac90d38467 100644 --- a/drivers/d3d12/d3d12_context.h +++ b/drivers/d3d12/d3d12_context.h @@ -110,6 +110,7 @@ private: IMAGE_COUNT = FRAME_LAG + 1, }; + ComPtr<ID3D12DeviceFactory> device_factory; ComPtr<IDXGIFactory2> dxgi_factory; ComPtr<IDXGIAdapter> gpu; DeviceLimits gpu_limits = {}; @@ -181,6 +182,7 @@ private: void *p_context); Error _initialize_debug_layers(); + void _init_device_factory(); Error _select_adapter(int &r_index); void _dump_adapter_info(int p_index); @@ -232,15 +234,12 @@ public: virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) override final; virtual void append_command_buffer(RDD::CommandBufferID p_command_buffer) override final; void resize_notify(); - virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false) override final; + virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false, bool p_sync = true) override final; virtual Error prepare_buffers(RDD::CommandBufferID p_command_buffer) override final; virtual void postpare_buffers(RDD::CommandBufferID p_command_buffer) override final; virtual Error swap_buffers() override final; virtual Error initialize() override final; - virtual void command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) override final; - virtual void command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) override final; - virtual void command_end_label(RDD::CommandBufferID p_command_buffer) override final; void set_object_name(ID3D12Object *p_object, String p_object_name); virtual String get_device_vendor_name() const override final; @@ -253,6 +252,7 @@ public: virtual DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const override final; virtual RenderingDeviceDriver *get_driver(RID p_local_device = RID()) override final; + virtual bool is_debug_utils_enabled() const override final; D3D12Context(); virtual ~D3D12Context(); diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index 6a2a3c32b0..d3a7344c9d 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -5162,6 +5162,20 @@ void RenderingDeviceDriverD3D12::command_timestamp_write(CommandBufferID p_cmd_b cmd_buf_info->cmd_list->ResolveQueryData(tqp_info->query_heap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, p_index, tqp_info->query_count, results_buffer, p_index * sizeof(uint64_t)); } +void RenderingDeviceDriverD3D12::command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) { +#ifdef PIX_ENABLED + const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id; + PIXBeginEvent(cmd_buf_info->cmd_list.Get(), p_color.to_argb32(), p_label_name); +#endif +} + +void RenderingDeviceDriverD3D12::command_end_label(CommandBufferID p_cmd_buffer) { +#ifdef PIX_ENABLED + const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id; + PIXEndEvent(cmd_buf_info->cmd_list.Get()); +#endif +} + /****************/ /**** SCREEN ****/ /****************/ diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index bd19572878..0da339c6fd 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -771,6 +771,13 @@ public: virtual void command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) override final; /****************/ + /**** LABELS ****/ + /****************/ + + virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) override final; + virtual void command_end_label(CommandBufferID p_cmd_buffer) override final; + + /****************/ /**** SCREEN ****/ /****************/ diff --git a/drivers/egl/egl_manager.h b/drivers/egl/egl_manager.h index c3a749cd19..61d3289b2d 100644 --- a/drivers/egl/egl_manager.h +++ b/drivers/egl/egl_manager.h @@ -45,7 +45,7 @@ class EGLManager { private: - // An EGL-side rappresentation of a display with its own rendering + // An EGL-side representation of a display with its own rendering // context. struct GLDisplay { void *display = nullptr; diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp index 996e7eee7f..c6fb6ca70b 100644 --- a/drivers/gles3/effects/copy_effects.cpp +++ b/drivers/gles3/effects/copy_effects.cpp @@ -125,6 +125,18 @@ void CopyEffects::copy_to_rect(const Rect2 &p_rect) { draw_screen_quad(); } +void CopyEffects::copy_to_and_from_rect(const Rect2 &p_rect) { + bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION_SOURCE); + if (!success) { + return; + } + + copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION_SOURCE); + copy.shader.version_set_uniform(CopyShaderGLES3::SOURCE_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION_SOURCE); + + draw_screen_quad(); +} + void CopyEffects::copy_screen() { bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT); if (!success) { diff --git a/drivers/gles3/effects/copy_effects.h b/drivers/gles3/effects/copy_effects.h index 6e2cb07382..509d07b955 100644 --- a/drivers/gles3/effects/copy_effects.h +++ b/drivers/gles3/effects/copy_effects.h @@ -62,6 +62,7 @@ public: // These functions assume that a framebuffer and texture are bound already. They only manage the shader, uniforms, and vertex array. void copy_to_rect(const Rect2 &p_rect); + void copy_to_and_from_rect(const Rect2 &p_rect); void copy_screen(); void copy_cube_to_rect(const Rect2 &p_rect); void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region); diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index c048e9bf37..6ab98a9473 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -103,6 +103,11 @@ void RasterizerGLES3::begin_frame(double frame_step) { } void RasterizerGLES3::end_frame(bool p_swap_buffers) { + GLES3::Utilities *utils = GLES3::Utilities::get_singleton(); + utils->capture_timestamps_end(); +} + +void RasterizerGLES3::end_viewport(bool p_swap_buffers) { if (p_swap_buffers) { DisplayServer::get_singleton()->swap_buffers(); } else { @@ -352,13 +357,6 @@ RasterizerGLES3::~RasterizerGLES3() { } void RasterizerGLES3::prepare_for_blitting_render_targets() { - // This is a hack, but this function is called one time after all viewports have been updated. - // So it marks the end of the frame for all viewports - // In the OpenGL renderer we have to call end_frame for each viewport so we can swap the - // buffers for each window before proceeding to the next. - // This allows us to only increment the frame after all viewports are done. - GLES3::Utilities *utils = GLES3::Utilities::get_singleton(); - utils->capture_timestamps_end(); } void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer, bool p_first) { @@ -474,7 +472,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c copy_effects->copy_to_rect(screenrect); glBindTexture(GL_TEXTURE_2D, 0); - end_frame(true); + end_viewport(true); texture_storage->texture_free(texture); } diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index b19ca0e9c9..d9f436a2ec 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -93,6 +93,7 @@ public: void prepare_for_blitting_render_targets(); void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount); + void end_viewport(bool p_swap_buffers); void end_frame(bool p_swap_buffers); void finalize(); diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 75b2662a1c..8b5aaa6b8d 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -49,7 +49,7 @@ void ShaderGLES3::_add_stage(const char *p_code, StageType p_stage_type) { String text; for (int i = 0; i < lines.size(); i++) { - String l = lines[i]; + const String &l = lines[i]; bool push_chunk = false; StageTemplate::Chunk chunk; diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index 265acc1430..f37968a4fd 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -3,6 +3,7 @@ mode_default = #define MODE_SIMPLE_COPY mode_copy_section = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY +mode_copy_section_source = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define MODE_COPY_FROM mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR mode_mipmap = #define MODE_MIPMAP mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION @@ -21,7 +22,7 @@ out vec2 uv_interp; // Defined in 0-1 coords. uniform highp vec4 copy_section; #endif -#ifdef MODE_GAUSSIAN_BLUR +#if defined(MODE_GAUSSIAN_BLUR) || defined(MODE_COPY_FROM) uniform highp vec4 source_section; #endif @@ -32,7 +33,7 @@ void main() { #if defined(USE_COPY_SECTION) || defined(MODE_GAUSSIAN_BLUR) gl_Position.xy = (copy_section.xy + uv_interp.xy * copy_section.zw) * 2.0 - 1.0; #endif -#ifdef MODE_GAUSSIAN_BLUR +#if defined(MODE_GAUSSIAN_BLUR) || defined(MODE_COPY_FROM) uv_interp = source_section.xy + uv_interp * source_section.zw; #endif } diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 1d9ba623c4..e95d684763 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -607,8 +607,7 @@ layout(std140) uniform GlobalShaderUniformData { //ubo:1 vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS]; }; - /* Material Uniforms */ - +/* Material Uniforms */ #ifdef MATERIAL_UNIFORMS_USED /* clang-format off */ diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index e5080b39a3..b4e266d976 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -1538,7 +1538,7 @@ void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const { memset(w, 0, (size_t)multimesh->instances * multimesh->stride_cache * sizeof(float)); } } - uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, MULTIMESH_DIRTY_REGION_SIZE); multimesh->data_cache_dirty_regions = memnew_arr(bool, data_cache_dirty_region_count); for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) { multimesh->data_cache_dirty_regions[i] = false; @@ -1549,7 +1549,7 @@ void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const { void MeshStorage::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) { uint32_t region_index = p_index / MULTIMESH_DIRTY_REGION_SIZE; #ifdef DEBUG_ENABLED - uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, MULTIMESH_DIRTY_REGION_SIZE); ERR_FAIL_UNSIGNED_INDEX(region_index, data_cache_dirty_region_count); //bug #endif if (!multimesh->data_cache_dirty_regions[region_index]) { @@ -1570,7 +1570,7 @@ void MeshStorage::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool void MeshStorage::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb) { if (p_data) { - uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, MULTIMESH_DIRTY_REGION_SIZE); for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) { if (!multimesh->data_cache_dirty_regions[i]) { @@ -1917,7 +1917,7 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b multimesh->data_cache = multimesh->data_cache; { //clear dirty since nothing will be dirty anymore - uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, MULTIMESH_DIRTY_REGION_SIZE); for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) { multimesh->data_cache_dirty_regions[i] = false; } @@ -2044,8 +2044,8 @@ void MeshStorage::_update_dirty_multimeshes() { uint32_t visible_instances = multimesh->visible_instances >= 0 ? multimesh->visible_instances : multimesh->instances; if (multimesh->data_cache_used_dirty_regions) { - uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; - uint32_t visible_region_count = visible_instances == 0 ? 0 : (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, (int)MULTIMESH_DIRTY_REGION_SIZE); + uint32_t visible_region_count = visible_instances == 0 ? 0 : Math::division_round_up(visible_instances, (uint32_t)MULTIMESH_DIRTY_REGION_SIZE); GLint region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float); diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 4e34fbcf0a..5a59f6c772 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -766,7 +766,7 @@ void TextureStorage::texture_2d_layered_initialize(RID p_texture, const Vector<R ERR_FAIL_COND(p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP && p_layers.size() != 6); ERR_FAIL_COND_MSG(p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP_ARRAY, "Cubemap Arrays are not supported in the GL Compatibility backend."); - Ref<Image> image = p_layers[0]; + const Ref<Image> &image = p_layers[0]; { int valid_width = 0; int valid_height = 0; @@ -1475,7 +1475,7 @@ void TextureStorage::update_texture_atlas() { //generate atlas Vector<TextureAtlas::SortItem> itemsv; itemsv.resize(texture_atlas.textures.size()); - int base_size = 8; + uint32_t base_size = 8; int idx = 0; @@ -1488,7 +1488,7 @@ void TextureStorage::update_texture_atlas() { si.size.height = (src_tex->height / border) + 1; si.pixel_size = Size2i(src_tex->width, src_tex->height); - if (base_size < si.size.width) { + if (base_size < (uint32_t)si.size.width) { base_size = nearest_power_of_2_templated(si.size.width); } @@ -1519,7 +1519,7 @@ void TextureStorage::update_texture_atlas() { TextureAtlas::SortItem &si = items[i]; int best_idx = -1; int best_height = 0x7FFFFFFF; - for (int j = 0; j <= base_size - si.size.width; j++) { + for (uint32_t j = 0; j <= base_size - si.size.width; j++) { int height = 0; for (int k = 0; k < si.size.width; k++) { int h = v_offsets[k + j]; @@ -1550,7 +1550,7 @@ void TextureStorage::update_texture_atlas() { } } - if (max_height <= base_size * 2) { + if ((uint32_t)max_height <= base_size * 2) { atlas_height = max_height; break; //good ratio, break; } @@ -2647,7 +2647,10 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, rt->color); - GLES3::CopyEffects::get_singleton()->copy_screen(); + Rect2 normalized_region = region; + normalized_region.position = normalized_region.position / Size2(rt->size); + normalized_region.size = normalized_region.size / Size2(rt->size); + GLES3::CopyEffects::get_singleton()->copy_to_and_from_rect(normalized_region); if (p_gen_mipmaps) { GLES3::CopyEffects::get_singleton()->gaussian_blur(rt->backbuffer, rt->mipmap_count, region, rt->size); diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp index cbcb54bc11..6f98f072dd 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.cpp @@ -66,12 +66,14 @@ Ref<Image> ImageLoaderPNG::load_mem_png(const uint8_t *p_png, int p_size) { return img; } +Ref<Image> ImageLoaderPNG::unpack_mem_png(const uint8_t *p_png, int p_size) { + ERR_FAIL_COND_V(p_size < 4, Ref<Image>()); + ERR_FAIL_COND_V(p_png[0] != 'P' || p_png[1] != 'N' || p_png[2] != 'G' || p_png[3] != ' ', Ref<Image>()); + return load_mem_png(&p_png[4], p_size - 4); +} + Ref<Image> ImageLoaderPNG::lossless_unpack_png(const Vector<uint8_t> &p_data) { - const int len = p_data.size(); - ERR_FAIL_COND_V(len < 4, Ref<Image>()); - const uint8_t *r = p_data.ptr(); - ERR_FAIL_COND_V(r[0] != 'P' || r[1] != 'N' || r[2] != 'G' || r[3] != ' ', Ref<Image>()); - return load_mem_png(&r[4], len - 4); + return unpack_mem_png(p_data.ptr(), p_data.size()); } Vector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) { @@ -99,6 +101,7 @@ Vector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) { ImageLoaderPNG::ImageLoaderPNG() { Image::_png_mem_loader_func = load_mem_png; + Image::_png_mem_unpacker_func = unpack_mem_png; Image::png_unpacker = lossless_unpack_png; Image::png_packer = lossless_pack_png; } diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h index d587672dd1..ecce9a405b 100644 --- a/drivers/png/image_loader_png.h +++ b/drivers/png/image_loader_png.h @@ -37,6 +37,7 @@ class ImageLoaderPNG : public ImageFormatLoader { private: static Vector<uint8_t> lossless_pack_png(const Ref<Image> &p_image); static Ref<Image> lossless_unpack_png(const Vector<uint8_t> &p_data); + static Ref<Image> unpack_mem_png(const uint8_t *p_png, int p_size); static Ref<Image> load_mem_png(const uint8_t *p_png, int p_size); public: diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index ca5a13799e..d1e4d207e7 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -228,6 +228,51 @@ uint8_t FileAccessUnix::get_8() const { return b; } +uint16_t FileAccessUnix::get_16() const { + ERR_FAIL_NULL_V_MSG(f, 0, "File must be opened before use."); + + uint16_t b = 0; + if (fread(&b, 1, 2, f) != 2) { + check_errors(); + } + + if (big_endian) { + b = BSWAP16(b); + } + + return b; +} + +uint32_t FileAccessUnix::get_32() const { + ERR_FAIL_NULL_V_MSG(f, 0, "File must be opened before use."); + + uint32_t b = 0; + if (fread(&b, 1, 4, f) != 4) { + check_errors(); + } + + if (big_endian) { + b = BSWAP32(b); + } + + return b; +} + +uint64_t FileAccessUnix::get_64() const { + ERR_FAIL_NULL_V_MSG(f, 0, "File must be opened before use."); + + uint64_t b = 0; + if (fread(&b, 1, 8, f) != 8) { + check_errors(); + } + + if (big_endian) { + b = BSWAP64(b); + } + + return b; +} + uint64_t FileAccessUnix::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); ERR_FAIL_NULL_V_MSG(f, -1, "File must be opened before use."); @@ -251,6 +296,36 @@ void FileAccessUnix::store_8(uint8_t p_dest) { ERR_FAIL_COND(fwrite(&p_dest, 1, 1, f) != 1); } +void FileAccessUnix::store_16(uint16_t p_dest) { + ERR_FAIL_NULL_MSG(f, "File must be opened before use."); + + if (big_endian) { + p_dest = BSWAP16(p_dest); + } + + ERR_FAIL_COND(fwrite(&p_dest, 1, 2, f) != 2); +} + +void FileAccessUnix::store_32(uint32_t p_dest) { + ERR_FAIL_NULL_MSG(f, "File must be opened before use."); + + if (big_endian) { + p_dest = BSWAP32(p_dest); + } + + ERR_FAIL_COND(fwrite(&p_dest, 1, 4, f) != 4); +} + +void FileAccessUnix::store_64(uint64_t p_dest) { + ERR_FAIL_NULL_MSG(f, "File must be opened before use."); + + if (big_endian) { + p_dest = BSWAP64(p_dest); + } + + ERR_FAIL_COND(fwrite(&p_dest, 1, 8, f) != 8); +} + void FileAccessUnix::store_buffer(const uint8_t *p_src, uint64_t p_length) { ERR_FAIL_NULL_MSG(f, "File must be opened before use."); ERR_FAIL_COND(!p_src && p_length > 0); diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 2bfac27c4f..553fbcf355 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -68,12 +68,18 @@ public: virtual bool eof_reached() const override; ///< reading passed EOF virtual uint8_t get_8() const override; ///< get a byte + virtual uint16_t get_16() const override; + virtual uint32_t get_32() const override; + virtual uint64_t get_64() const override; virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; virtual Error get_error() const override; ///< get last error virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte + virtual void store_16(uint16_t p_dest) override; + virtual void store_32(uint32_t p_dest) override; + virtual void store_64(uint64_t p_dest) override; virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes virtual bool file_exists(const String &p_path) override; ///< return true if a file exists diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 9a77930d75..51ea9234d4 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -656,6 +656,8 @@ Error OS_Unix::open_dynamic_library(const String p_path, void *&p_library_handle path = get_executable_path().get_base_dir().path_join("../lib").path_join(p_path.get_file()); } + ERR_FAIL_COND_V(!FileAccess::exists(path), ERR_FILE_NOT_FOUND); + p_library_handle = dlopen(path.utf8().get_data(), GODOT_DLOPEN_MODE); ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror())); @@ -751,12 +753,27 @@ String OS_Unix::get_executable_path() const { return OS::get_executable_path(); } return b; -#elif defined(__OpenBSD__) || defined(__NetBSD__) +#elif defined(__OpenBSD__) char resolved_path[MAXPATHLEN]; realpath(OS::get_executable_path().utf8().get_data(), resolved_path); return String(resolved_path); +#elif defined(__NetBSD__) + int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME }; + char buf[MAXPATHLEN]; + size_t len = sizeof(buf); + if (sysctl(mib, 4, buf, &len, nullptr, 0) != 0) { + WARN_PRINT("Couldn't get executable path from sysctl"); + return OS::get_executable_path(); + } + + // NetBSD does not always return a normalized path. For example if argv[0] is "./a.out" then executable path is "/home/netbsd/./a.out". Normalize with realpath: + char resolved_path[MAXPATHLEN]; + + realpath(buf, resolved_path); + + return String(resolved_path); #elif defined(__FreeBSD__) int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; char buf[MAXPATHLEN]; diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub index 5e4bc986b8..a076c0ac54 100644 --- a/drivers/vulkan/SCsub +++ b/drivers/vulkan/SCsub @@ -2,8 +2,6 @@ Import("env") -env.Append(CPPDEFINES=["RD_ENABLED"]) - thirdparty_obj = [] thirdparty_dir = "#thirdparty/vulkan" thirdparty_volk_dir = "#thirdparty/volk" diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index e18161c974..8378e26666 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -733,6 +733,9 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared_from_slice(Tex case TEXTURE_SLICE_2D_ARRAY: { image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; } break; + default: { + return TextureID(nullptr); + } } image_view_create_info.format = RD_TO_VK_FORMAT[p_view.format]; image_view_create_info.components.r = (VkComponentSwizzle)p_view.swizzle_r; @@ -805,8 +808,11 @@ void RenderingDeviceDriverVulkan::texture_get_copyable_layout(TextureID p_textur h = MAX(1u, h >> 1); d = MAX(1u, d >> 1); } - r_layout->size = get_image_format_required_size(tex_info->rd_format, w, h, d, 1); - r_layout->row_pitch = r_layout->size / (h * d); + uint32_t bw = 0, bh = 0; + get_compressed_image_format_block_dimensions(tex_info->rd_format, bw, bh); + uint32_t sbw = 0, sbh = 0; + r_layout->size = get_image_format_required_size(tex_info->rd_format, w, h, d, 1, &sbw, &sbh); + r_layout->row_pitch = r_layout->size / ((sbh / bh) * d); r_layout->depth_pitch = r_layout->size / d; r_layout->layer_pitch = r_layout->size / tex_info->vk_create_info.arrayLayers; } @@ -1172,7 +1178,7 @@ bool RenderingDeviceDriverVulkan::command_buffer_begin_secondary(CommandBufferID VkCommandBufferBeginInfo cmd_buf_begin_info = {}; cmd_buf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmd_buf_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; + cmd_buf_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; cmd_buf_begin_info.pInheritanceInfo = &inheritance_info; VkResult err = vkBeginCommandBuffer((VkCommandBuffer)p_cmd_buffer.id, &cmd_buf_begin_info); @@ -1557,11 +1563,9 @@ RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_bytecode(const Vec read_offset += sizeof(ShaderBinary::SpecializationConstant); } - struct Stage { - ShaderStage type = SHADER_STAGE_MAX; - Vector<uint8_t> spirv; - }; - Vector<Stage> stages; + Vector<Vector<uint8_t>> stages_spirv; + stages_spirv.resize(binary_data.stage_count); + r_shader_desc.stages.resize(binary_data.stage_count); for (uint32_t i = 0; i < binary_data.stage_count; i++) { ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) * 3 >= binsize, ShaderID()); @@ -1587,17 +1591,14 @@ RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_bytecode(const Vec src_smolv = binptr + read_offset; } - Vector<uint8_t> spirv; + Vector<uint8_t> &spirv = stages_spirv.ptrw()[i]; uint32_t spirv_size = smolv::GetDecodedBufferSize(src_smolv, smolv_size); spirv.resize(spirv_size); if (!smolv::Decode(src_smolv, smolv_size, spirv.ptrw(), spirv_size)) { ERR_FAIL_V_MSG(ShaderID(), "Malformed smolv input uncompressing shader stage:" + String(SHADER_STAGE_NAMES[stage])); } - Stage stage_entry; - stage_entry.type = ShaderStage(stage); - stage_entry.spirv = spirv; - stages.push_back(stage_entry); + r_shader_desc.stages.set(i, ShaderStage(stage)); if (buf_size % 4 != 0) { buf_size += 4 - (buf_size % 4); @@ -1614,22 +1615,22 @@ RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_bytecode(const Vec String error_text; - for (int i = 0; i < stages.size(); i++) { + for (int i = 0; i < r_shader_desc.stages.size(); i++) { VkShaderModuleCreateInfo shader_module_create_info = {}; shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - shader_module_create_info.codeSize = stages[i].spirv.size(); - shader_module_create_info.pCode = (const uint32_t *)stages[i].spirv.ptr(); + shader_module_create_info.codeSize = stages_spirv[i].size(); + shader_module_create_info.pCode = (const uint32_t *)stages_spirv[i].ptr(); VkShaderModule vk_module = VK_NULL_HANDLE; VkResult res = vkCreateShaderModule(vk_device, &shader_module_create_info, nullptr, &vk_module); if (res) { - error_text = "Error (" + itos(res) + ") creating shader module for stage: " + String(SHADER_STAGE_NAMES[stages[i].type]); + error_text = "Error (" + itos(res) + ") creating shader module for stage: " + String(SHADER_STAGE_NAMES[r_shader_desc.stages[i]]); break; } VkPipelineShaderStageCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - create_info.stage = RD_STAGE_TO_VK_SHADER_STAGE_BITS[stages[i].type]; + create_info.stage = RD_STAGE_TO_VK_SHADER_STAGE_BITS[r_shader_desc.stages[i]]; create_info.module = vk_module; create_info.pName = "main"; @@ -3054,6 +3055,26 @@ void RenderingDeviceDriverVulkan::command_timestamp_write(CommandBufferID p_cmd_ } /****************/ +/**** LABELS ****/ +/****************/ + +void RenderingDeviceDriverVulkan::command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) { + VkDebugUtilsLabelEXT label; + label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + label.pNext = nullptr; + label.pLabelName = p_label_name; + label.color[0] = p_color[0]; + label.color[1] = p_color[1]; + label.color[2] = p_color[2]; + label.color[3] = p_color[3]; + vkCmdBeginDebugUtilsLabelEXT((VkCommandBuffer)p_cmd_buffer.id, &label); +} + +void RenderingDeviceDriverVulkan::command_end_label(CommandBufferID p_cmd_buffer) { + vkCmdEndDebugUtilsLabelEXT((VkCommandBuffer)p_cmd_buffer.id); +} + +/****************/ /**** SCREEN ****/ /****************/ diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h index 6d8f6fd0e0..1edee6b76e 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.h +++ b/drivers/vulkan/rendering_device_driver_vulkan.h @@ -433,6 +433,13 @@ public: virtual void command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) override final; /****************/ + /**** LABELS ****/ + /****************/ + + virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) override final; + virtual void command_end_label(CommandBufferID p_cmd_buffer) override final; + + /****************/ /**** SCREEN ****/ /****************/ diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index 1b1d4fa50f..7db2a9cd66 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -2395,9 +2395,11 @@ void VulkanContext::append_command_buffer(RDD::CommandBufferID p_command_buffer) command_buffer_count++; } -void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) { +void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending, bool p_sync) { // Ensure everything else pending is executed. - vkDeviceWaitIdle(device); + if (p_sync) { + vkDeviceWaitIdle(device); + } // Flush the pending setup buffer. @@ -2440,7 +2442,9 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) { ERR_FAIL_COND(err); } - vkDeviceWaitIdle(device); + if (p_sync) { + vkDeviceWaitIdle(device); + } } Error VulkanContext::prepare_buffers(RDD::CommandBufferID p_command_buffer) { @@ -2504,7 +2508,7 @@ Error VulkanContext::swap_buffers() { return OK; } - // print_line("swapbuffers?"); + //print_line("swap_buffers"); VkResult err; #if 0 @@ -2818,46 +2822,6 @@ void VulkanContext::local_device_free(RID p_local_device) { local_device_owner.free(p_local_device); } -void VulkanContext::command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) { - if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { - return; - } - - CharString cs = p_label_name.utf8(); - VkDebugUtilsLabelEXT label; - label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - label.pNext = nullptr; - label.pLabelName = cs.get_data(); - label.color[0] = p_color[0]; - label.color[1] = p_color[1]; - label.color[2] = p_color[2]; - label.color[3] = p_color[3]; - CmdBeginDebugUtilsLabelEXT((VkCommandBuffer)p_command_buffer.id, &label); -} - -void VulkanContext::command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) { - if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { - return; - } - CharString cs = p_label_name.utf8(); - VkDebugUtilsLabelEXT label; - label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - label.pNext = nullptr; - label.pLabelName = cs.get_data(); - label.color[0] = p_color[0]; - label.color[1] = p_color[1]; - label.color[2] = p_color[2]; - label.color[3] = p_color[3]; - CmdInsertDebugUtilsLabelEXT((VkCommandBuffer)p_command_buffer.id, &label); -} - -void VulkanContext::command_end_label(RDD::CommandBufferID p_command_buffer) { - if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { - return; - } - CmdEndDebugUtilsLabelEXT((VkCommandBuffer)p_command_buffer.id); -} - void VulkanContext::set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name) { if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { return; @@ -2913,6 +2877,10 @@ RenderingDeviceDriver *VulkanContext::get_driver(RID p_local_device) { } } +bool VulkanContext::is_debug_utils_enabled() const { + return is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); +} + VulkanContext::VulkanContext() { command_buffer_queue.resize(1); // First one is always the setup command. command_buffer_queue[0] = nullptr; diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h index ce1299a559..cbb6cf326f 100644 --- a/drivers/vulkan/vulkan_context.h +++ b/drivers/vulkan/vulkan_context.h @@ -321,15 +321,12 @@ public: virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) override final; virtual void append_command_buffer(RDD::CommandBufferID p_command_buffer) override final; void resize_notify(); - virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false) override final; + virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false, bool p_sync = true) override final; virtual Error prepare_buffers(RDD::CommandBufferID p_command_buffer) override final; virtual void postpare_buffers(RDD::CommandBufferID p_command_buffer) override final; virtual Error swap_buffers() override final; virtual Error initialize() override final; - virtual void command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) override final; - virtual void command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) override final; - virtual void command_end_label(RDD::CommandBufferID p_command_buffer) override final; void set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name); virtual String get_device_vendor_name() const override final; @@ -342,6 +339,7 @@ public: virtual DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const override final; virtual RenderingDeviceDriver *get_driver(RID p_local_device = RID()) override final; + virtual bool is_debug_utils_enabled() const override final; VulkanContext(); virtual ~VulkanContext(); diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index e39373e7a0..64f2d1f203 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -557,13 +557,11 @@ Error AudioDriverWASAPI::init() { target_latency_ms = Engine::get_singleton()->get_audio_output_latency(); - Error err = init_output_device(); - if (err != OK) { - ERR_PRINT("WASAPI: init_output_device error"); - } - exit_thread.clear(); + Error err = init_output_device(); + ERR_FAIL_COND_V_MSG(err != OK, err, "WASAPI: init_output_device error."); + thread.start(thread_func, this); return OK; diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index 9d21073f19..1b69f5da2c 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -284,6 +284,72 @@ uint8_t FileAccessWindows::get_8() const { return b; } +uint16_t FileAccessWindows::get_16() const { + ERR_FAIL_NULL_V(f, 0); + + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == WRITE) { + fflush(f); + } + prev_op = READ; + } + + uint16_t b = 0; + if (fread(&b, 1, 2, f) != 2) { + check_errors(); + } + + if (big_endian) { + b = BSWAP16(b); + } + + return b; +} + +uint32_t FileAccessWindows::get_32() const { + ERR_FAIL_NULL_V(f, 0); + + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == WRITE) { + fflush(f); + } + prev_op = READ; + } + + uint32_t b = 0; + if (fread(&b, 1, 4, f) != 4) { + check_errors(); + } + + if (big_endian) { + b = BSWAP32(b); + } + + return b; +} + +uint64_t FileAccessWindows::get_64() const { + ERR_FAIL_NULL_V(f, 0); + + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == WRITE) { + fflush(f); + } + prev_op = READ; + } + + uint64_t b = 0; + if (fread(&b, 1, 8, f) != 8) { + check_errors(); + } + + if (big_endian) { + b = BSWAP64(b); + } + + return b; +} + uint64_t FileAccessWindows::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); ERR_FAIL_NULL_V(f, -1); @@ -326,6 +392,63 @@ void FileAccessWindows::store_8(uint8_t p_dest) { fwrite(&p_dest, 1, 1, f); } +void FileAccessWindows::store_16(uint16_t p_dest) { + ERR_FAIL_NULL(f); + + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == READ) { + if (last_error != ERR_FILE_EOF) { + fseek(f, 0, SEEK_CUR); + } + } + prev_op = WRITE; + } + + if (big_endian) { + p_dest = BSWAP16(p_dest); + } + + fwrite(&p_dest, 1, 2, f); +} + +void FileAccessWindows::store_32(uint32_t p_dest) { + ERR_FAIL_NULL(f); + + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == READ) { + if (last_error != ERR_FILE_EOF) { + fseek(f, 0, SEEK_CUR); + } + } + prev_op = WRITE; + } + + if (big_endian) { + p_dest = BSWAP32(p_dest); + } + + fwrite(&p_dest, 1, 4, f); +} + +void FileAccessWindows::store_64(uint64_t p_dest) { + ERR_FAIL_NULL(f); + + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == READ) { + if (last_error != ERR_FILE_EOF) { + fseek(f, 0, SEEK_CUR); + } + } + prev_op = WRITE; + } + + if (big_endian) { + p_dest = BSWAP64(p_dest); + } + + fwrite(&p_dest, 1, 8, f); +} + void FileAccessWindows::store_buffer(const uint8_t *p_src, uint64_t p_length) { ERR_FAIL_NULL(f); ERR_FAIL_COND(!p_src && p_length > 0); diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index 73143009fc..dabb174cb2 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -69,12 +69,18 @@ public: virtual bool eof_reached() const override; ///< reading passed EOF virtual uint8_t get_8() const override; ///< get a byte + virtual uint16_t get_16() const override; + virtual uint32_t get_32() const override; + virtual uint64_t get_64() const override; virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; virtual Error get_error() const override; ///< get last error virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte + virtual void store_16(uint16_t p_dest) override; + virtual void store_32(uint32_t p_dest) override; + virtual void store_64(uint64_t p_dest) override; virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes virtual bool file_exists(const String &p_name) override; ///< return true if a file exists diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index ab923f99fe..d7302d873f 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -36,6 +36,7 @@ #include "editor/event_listener_line_edit.h" #include "editor/input_event_configuration_dialog.h" #include "scene/gui/check_button.h" +#include "scene/gui/separator.h" #include "scene/gui/tree.h" #include "scene/scene_string_names.h" @@ -357,6 +358,7 @@ void ActionMapEditor::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { action_list_search->set_right_icon(get_editor_theme_icon(SNAME("Search"))); + add_button->set_icon(get_editor_theme_icon(SNAME("Add"))); if (!actions_cache.is_empty()) { update_action_list(); } @@ -532,7 +534,7 @@ ActionMapEditor::ActionMapEditor() { action_list_search = memnew(LineEdit); action_list_search->set_h_size_flags(Control::SIZE_EXPAND_FILL); - action_list_search->set_placeholder(TTR("Filter by name...")); + action_list_search->set_placeholder(TTR("Filter by Name")); action_list_search->set_clear_button_enabled(true); action_list_search->connect("text_changed", callable_mp(this, &ActionMapEditor::_search_term_updated)); top_hbox->add_child(action_list_search); @@ -570,6 +572,8 @@ ActionMapEditor::ActionMapEditor() { // Disable the button and set its tooltip. _add_edit_text_changed(add_edit->get_text()); + add_hbox->add_child(memnew(VSeparator)); + show_builtin_actions_checkbutton = memnew(CheckButton); show_builtin_actions_checkbutton->set_text(TTR("Show Built-in Actions")); show_builtin_actions_checkbutton->connect("toggled", callable_mp(this, &ActionMapEditor::set_show_builtin_actions)); diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 08306256f1..4849a6824c 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -908,7 +908,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (Math::is_finite(minimum_time) && Math::is_finite(maximum_time) && maximum_time - minimum_time > CMP_EPSILON) { timeline->get_zoom()->set_value(zoom_value); - timeline->call_deferred("set_value", minimum_time); + callable_mp((Range *)timeline, &Range::set_value).call_deferred(minimum_time); } if (Math::is_finite(minimum_value) && Math::is_finite(maximum_value)) { @@ -1520,7 +1520,7 @@ void AnimationBezierTrackEdit::_zoom_callback(float p_zoom_factor, Vector2 p_ori // Alternate zoom (doesn't affect timeline). timeline_v_zoom = CLAMP(timeline_v_zoom * p_zoom_factor, 0.000001, 100000); } else { - timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / p_zoom_factor); + timeline->_zoom_callback(p_zoom_factor, p_origin, p_event); } timeline_v_scroll = timeline_v_scroll + (p_origin.y - get_size().y / 2.0) * (timeline_v_zoom - v_zoom_orig); queue_redraw(); @@ -1688,6 +1688,7 @@ void AnimationBezierTrackEdit::_bind_methods() { AnimationBezierTrackEdit::AnimationBezierTrackEdit() { panner.instantiate(); panner->set_callbacks(callable_mp(this, &AnimationBezierTrackEdit::_pan_callback), callable_mp(this, &AnimationBezierTrackEdit::_zoom_callback)); + panner->set_scroll_zoom_factor(AnimationTimelineEdit::SCROLL_ZOOM_FACTOR); play_position = memnew(Control); play_position->set_mouse_filter(MOUSE_FILTER_PASS); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 8268cf10ae..41a6d77860 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1247,6 +1247,58 @@ void AnimationMultiTrackKeyEdit::set_use_fps(bool p_enable) { } void AnimationTimelineEdit::_zoom_changed(double) { + double zoom_pivot = 0; // Point on timeline to stay fixed. + double zoom_pivot_delta = 0; // Delta seconds from left-most point on timeline to zoom pivot. + + int timeline_width_pixels = get_size().width - get_buttons_width() - get_name_limit(); + double timeline_width_seconds = timeline_width_pixels / last_zoom_scale; // Length (in seconds) of visible part of timeline before zoom. + double updated_timeline_width_seconds = timeline_width_pixels / get_zoom_scale(); // Length after zoom. + double updated_timeline_half_width = updated_timeline_width_seconds / 2.0; + bool zooming = updated_timeline_width_seconds < timeline_width_seconds; + + double timeline_left = get_value(); + double timeline_right = timeline_left + timeline_width_seconds; + double timeline_center = timeline_left + timeline_width_seconds / 2.0; + + if (zoom_callback_occured) { // Zooming with scroll wheel will focus on the position of the mouse. + double zoom_scroll_origin_norm = (zoom_scroll_origin.x - get_name_limit()) / timeline_width_pixels; + zoom_scroll_origin_norm = MAX(zoom_scroll_origin_norm, 0); + zoom_pivot = timeline_left + timeline_width_seconds * zoom_scroll_origin_norm; + zoom_pivot_delta = updated_timeline_width_seconds * zoom_scroll_origin_norm; + zoom_callback_occured = false; + } else { // Zooming with slider will depend on the current play position. + // If the play position is not in range, or exactly in the center, zoom in on the center. + if (get_play_position() < timeline_left || get_play_position() > timeline_left + timeline_width_seconds || get_play_position() == timeline_center) { + zoom_pivot = timeline_center; + zoom_pivot_delta = updated_timeline_half_width; + } + // Zoom from right if play position is right of center, + // and shrink from right if play position is left of center. + else if ((get_play_position() > timeline_center) == zooming) { + // If play position crosses to other side of center, center it. + bool center_passed = (get_play_position() < timeline_right - updated_timeline_half_width) == zooming; + zoom_pivot = center_passed ? get_play_position() : timeline_right; + double center_offset = CMP_EPSILON * (zooming ? 1 : -1); // Small offset to prevent crossover. + zoom_pivot_delta = center_passed ? updated_timeline_half_width + center_offset : updated_timeline_width_seconds; + } + // Zoom from left if play position is left of center, + // and shrink from left if play position is right of center. + else if ((get_play_position() <= timeline_center) == zooming) { + // If play position crosses to other side of center, center it. + bool center_passed = (get_play_position() > timeline_left + updated_timeline_half_width) == zooming; + zoom_pivot = center_passed ? get_play_position() : timeline_left; + double center_offset = CMP_EPSILON * (zooming ? -1 : 1); // Small offset to prevent crossover. + zoom_pivot_delta = center_passed ? updated_timeline_half_width + center_offset : 0; + } + } + + double hscroll_pos = zoom_pivot - zoom_pivot_delta; + hscroll_pos = CLAMP(hscroll_pos, hscroll->get_min(), hscroll->get_max()); + + hscroll->set_value(hscroll_pos); + hscroll_on_zoom_buffer = hscroll_pos; // In case of page update. + last_zoom_scale = get_zoom_scale(); + queue_redraw(); play_position->queue_redraw(); emit_signal(SNAME("zoom_changed")); @@ -1428,6 +1480,11 @@ void AnimationTimelineEdit::_notification(int p_what) { set_page(zoomw / scale); + if (hscroll->is_visible() && hscroll_on_zoom_buffer >= 0) { + hscroll->set_value(hscroll_on_zoom_buffer); + hscroll_on_zoom_buffer = -1.0; + } + int end_px = (l - get_value()) * scale; int begin_px = -get_value() * scale; Color notimecol = get_theme_color(SNAME("dark_color_2"), EditorStringName(Editor)); @@ -1733,7 +1790,9 @@ void AnimationTimelineEdit::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> void AnimationTimelineEdit::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) { double current_zoom_value = get_zoom()->get_value(); - get_zoom()->set_value(MAX(0.01, current_zoom_value * p_zoom_factor)); + zoom_scroll_origin = p_origin; + zoom_callback_occured = true; + get_zoom()->set_value(MAX(0.01, current_zoom_value - (1.0 - p_zoom_factor))); } void AnimationTimelineEdit::set_use_fps(bool p_use_fps) { @@ -1809,6 +1868,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() { len_hb->hide(); panner.instantiate(); + panner->set_scroll_zoom_factor(SCROLL_ZOOM_FACTOR); panner->set_callbacks(callable_mp(this, &AnimationTimelineEdit::_pan_callback), callable_mp(this, &AnimationTimelineEdit::_zoom_callback)); panner->set_pan_axis(ViewPanner::PAN_AXIS_HORIZONTAL); @@ -2718,9 +2778,9 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { PropertyInfo prop_info; ClassDB::get_property_info(nd->get_class(), prop, &prop_info); #ifdef DISABLE_DEPRECATED - bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians_as_degrees") != -1; + bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.contains("radians_as_degrees"); #else - bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians") != -1; + bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.contains("radians"); #endif // DISABLE_DEPRECATED if (is_angle) { menu->add_icon_item(get_editor_theme_icon(SNAME("InterpLinearAngle")), TTR("Linear Angle"), MENU_INTERPOLATION_LINEAR_ANGLE); @@ -4190,27 +4250,11 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD bool create_reset_track = p_reset_wanted && track_type_is_resettable(p_id.type); Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE; + Animation::InterpolationType interp_type = Animation::INTERPOLATION_LINEAR; + bool loop_wrap = true; if (create_normal_track || create_reset_track) { if (p_id.type == Animation::TYPE_VALUE || p_id.type == Animation::TYPE_BEZIER) { - // Hack. - NodePath np; - animation->add_track(p_id.type); - animation->track_set_path(animation->get_track_count() - 1, p_id.path); - PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np); - animation->remove_track(animation->get_track_count() - 1); // Hack. - - if (h.type == Variant::FLOAT || - h.type == Variant::VECTOR2 || - h.type == Variant::RECT2 || - h.type == Variant::VECTOR3 || - h.type == Variant::AABB || - h.type == Variant::QUATERNION || - h.type == Variant::COLOR || - h.type == Variant::PLANE || - h.type == Variant::TRANSFORM2D || - h.type == Variant::TRANSFORM3D) { - update_mode = Animation::UPDATE_CONTINUOUS; - } + _fetch_value_track_options(p_id.path, &update_mode, &interp_type, &loop_wrap); } } @@ -4237,6 +4281,8 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD undo_redo->add_do_method(animation.ptr(), "add_track", p_id.type); undo_redo->add_do_method(animation.ptr(), "track_set_path", p_id.track_idx, p_id.path); + undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", p_id.track_idx, interp_type); + undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", p_id.track_idx, loop_wrap); if (p_id.type == Animation::TYPE_VALUE) { undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", p_id.track_idx, update_mode); } @@ -4567,7 +4613,7 @@ void AnimationTrackEditor::_animation_changed() { } animation_changing_awaiting_update = true; - call_deferred(SNAME("_animation_update")); + callable_mp(this, &AnimationTrackEditor::_animation_update).call_deferred(); } void AnimationTrackEditor::_snap_mode_changed(int p_mode) { @@ -4824,36 +4870,82 @@ void AnimationTrackEditor::_add_track(int p_type) { pick_track->get_filter_line_edit()->grab_focus(); } +void AnimationTrackEditor::_fetch_value_track_options(const NodePath &p_path, Animation::UpdateMode *r_update_mode, Animation::InterpolationType *r_interpolation_type, bool *r_loop_wrap) { + AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player(); + if (player->has_animation(SceneStringNames::get_singleton()->RESET)) { + Ref<Animation> reset_anim = player->get_animation(SceneStringNames::get_singleton()->RESET); + int rt = reset_anim->find_track(p_path, Animation::TrackType::TYPE_VALUE); + if (rt >= 0) { + *r_update_mode = reset_anim->value_track_get_update_mode(rt); + *r_interpolation_type = reset_anim->track_get_interpolation_type(rt); + *r_loop_wrap = reset_anim->track_get_interpolation_loop_wrap(rt); + return; + } + rt = reset_anim->find_track(p_path, Animation::TrackType::TYPE_BEZIER); + if (rt >= 0) { + *r_interpolation_type = reset_anim->track_get_interpolation_type(rt); + *r_loop_wrap = reset_anim->track_get_interpolation_loop_wrap(rt); + return; + } + } + + // Hack. + NodePath np; + animation->add_track(Animation::TYPE_VALUE); + animation->track_set_path(animation->get_track_count() - 1, p_path); + PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np); + animation->remove_track(animation->get_track_count() - 1); // Hack. + switch (h.type) { + case Variant::FLOAT: { +#ifdef DISABLE_DEPRECATED + bool is_angle = h.type == Variant::FLOAT && h.hint_string.contains("radians_as_degrees"); +#else + bool is_angle = h.type == Variant::FLOAT && h.hint_string.contains("radians"); +#endif // DISABLE_DEPRECATED + if (is_angle) { + *r_interpolation_type = Animation::INTERPOLATION_LINEAR_ANGLE; + } + [[fallthrough]]; + } + case Variant::VECTOR2: + case Variant::RECT2: + case Variant::VECTOR3: + case Variant::TRANSFORM2D: + case Variant::VECTOR4: + case Variant::PLANE: + case Variant::QUATERNION: + case Variant::AABB: + case Variant::BASIS: + case Variant::TRANSFORM3D: + case Variant::PROJECTION: + case Variant::COLOR: + case Variant::PACKED_FLOAT32_ARRAY: + case Variant::PACKED_FLOAT64_ARRAY: + case Variant::PACKED_VECTOR2_ARRAY: + case Variant::PACKED_VECTOR3_ARRAY: + case Variant::PACKED_COLOR_ARRAY: { + *r_update_mode = Animation::UPDATE_CONTINUOUS; + } break; + default: { + } + } +} + void AnimationTrackEditor::_new_track_property_selected(String p_name) { String full_path = String(adding_track_path) + ":" + p_name; EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - if (adding_track_type == Animation::TYPE_VALUE) { - Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE; - { - // Hack. - NodePath np; - animation->add_track(Animation::TYPE_VALUE); - animation->track_set_path(animation->get_track_count() - 1, full_path); - PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np); - animation->remove_track(animation->get_track_count() - 1); // Hack. - if (h.type == Variant::FLOAT || - h.type == Variant::VECTOR2 || - h.type == Variant::RECT2 || - h.type == Variant::VECTOR3 || - h.type == Variant::AABB || - h.type == Variant::QUATERNION || - h.type == Variant::COLOR || - h.type == Variant::PLANE || - h.type == Variant::TRANSFORM2D || - h.type == Variant::TRANSFORM3D) { - update_mode = Animation::UPDATE_CONTINUOUS; - } - } + Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE; + Animation::InterpolationType interp_type = Animation::INTERPOLATION_LINEAR; + bool loop_wrap = true; + _fetch_value_track_options(full_path, &update_mode, &interp_type, &loop_wrap); + if (adding_track_type == Animation::TYPE_VALUE) { undo_redo->create_action(TTR("Add Track")); undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type); undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), full_path); + undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", animation->get_track_count(), interp_type); + undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", animation->get_track_count(), loop_wrap); undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", animation->get_track_count(), update_mode); undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count()); undo_redo->commit_action(); @@ -4877,8 +4969,11 @@ void AnimationTrackEditor::_new_track_property_selected(String p_name) { undo_redo->create_action(TTR("Add Bezier Track")); int base_track = animation->get_track_count(); for (int i = 0; i < subindices.size(); i++) { + int track_idx = base_track + i; undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type); - undo_redo->add_do_method(animation.ptr(), "track_set_path", base_track + i, full_path + subindices[i]); + undo_redo->add_do_method(animation.ptr(), "track_set_path", track_idx, full_path + subindices[i]); + undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", track_idx, interp_type); + undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", track_idx, loop_wrap); undo_redo->add_undo_method(animation.ptr(), "remove_track", base_track); } undo_redo->commit_action(); @@ -5458,8 +5553,7 @@ void AnimationTrackEditor::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p } void AnimationTrackEditor::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) { - double current_zoom_value = timeline->get_zoom()->get_value(); - timeline->get_zoom()->set_value(MAX(0.01, current_zoom_value * p_zoom_factor)); + timeline->_zoom_callback(p_zoom_factor, p_origin, p_event); } void AnimationTrackEditor::_cancel_bezier_edit() { @@ -6038,6 +6132,15 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { existing_idx = reset->track_find_key(dst_track, 0, Animation::FIND_MODE_APPROX); } + if (animation->track_get_type(sk.track) == Animation::TYPE_VALUE) { + undo_redo->add_do_method(reset.ptr(), "value_track_set_update_mode", dst_track, animation->value_track_get_update_mode(sk.track)); + } + if (animation->track_get_type(sk.track) == Animation::TYPE_AUDIO) { + undo_redo->add_do_method(reset.ptr(), "audio_track_set_use_blend", dst_track, animation->audio_track_is_use_blend(sk.track)); + } + undo_redo->add_do_method(reset.ptr(), "track_set_interpolation_type", dst_track, animation->track_get_interpolation_type(sk.track)); + undo_redo->add_do_method(reset.ptr(), "track_set_interpolation_loop_wrap", dst_track, animation->track_get_interpolation_loop_wrap(sk.track)); + undo_redo->add_do_method(reset.ptr(), "track_insert_key", dst_track, 0, animation->track_get_key_value(sk.track, sk.key), animation->track_get_key_transition(sk.track, sk.key)); undo_redo->add_undo_method(reset.ptr(), "track_remove_key_at_time", dst_track, 0); @@ -6375,7 +6478,6 @@ void AnimationTrackEditor::_select_all_tracks_for_copy() { } void AnimationTrackEditor::_bind_methods() { - ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update); ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus); ClassDB::bind_method("_redraw_tracks", &AnimationTrackEditor::_redraw_tracks); ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim); @@ -6489,6 +6591,7 @@ AnimationTrackEditor::AnimationTrackEditor() { timeline->connect("length_changed", callable_mp(this, &AnimationTrackEditor::_update_length)); panner.instantiate(); + panner->set_scroll_zoom_factor(AnimationTimelineEdit::SCROLL_ZOOM_FACTOR); panner->set_callbacks(callable_mp(this, &AnimationTrackEditor::_pan_callback), callable_mp(this, &AnimationTrackEditor::_zoom_callback)); scroll = memnew(ScrollContainer); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 4b9849b26c..b5242e2f67 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -131,6 +131,11 @@ protected: class AnimationTimelineEdit : public Range { GDCLASS(AnimationTimelineEdit, Range); + friend class AnimationBezierTrackEdit; + friend class AnimationTrackEditor; + + static constexpr float SCROLL_ZOOM_FACTOR = 1.02f; // Zoom factor per mouse scroll in the animation editor. The closer to 1.0, the finer the control. + Ref<Animation> animation; bool read_only = false; @@ -167,6 +172,11 @@ class AnimationTimelineEdit : public Range { bool dragging_hsize = false; float dragging_hsize_from = 0.0f; float dragging_hsize_at = 0.0f; + double last_zoom_scale = 1.0; + double hscroll_on_zoom_buffer = -1.0; + + Vector2 zoom_scroll_origin; + bool zoom_callback_occured = false; virtual void gui_input(const Ref<InputEvent> &p_event) override; void _track_added(int p_track); @@ -481,6 +491,8 @@ class AnimationTrackEditor : public VBoxContainer { void _insert_key_from_track(float p_ofs, int p_track); void _add_method_key(const String &p_method); + void _fetch_value_track_options(const NodePath &p_path, Animation::UpdateMode *r_update_mode, Animation::InterpolationType *r_interpolation_type, bool *r_loop_wrap); + 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); diff --git a/editor/audio_stream_preview.cpp b/editor/audio_stream_preview.cpp index c1935b4844..0b9289ff06 100644 --- a/editor/audio_stream_preview.cpp +++ b/editor/audio_stream_preview.cpp @@ -158,7 +158,7 @@ void AudioStreamPreviewGenerator::_preview_thread(void *p_preview) { } frames_todo -= to_read; - singleton->call_deferred(SNAME("_update_emit"), preview->id); + callable_mp(singleton, &AudioStreamPreviewGenerator::_update_emit).call_deferred(preview->id); } preview->preview->version++; @@ -216,7 +216,6 @@ Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref< } void AudioStreamPreviewGenerator::_bind_methods() { - ClassDB::bind_method("_update_emit", &AudioStreamPreviewGenerator::_update_emit); ClassDB::bind_method(D_METHOD("generate_preview", "stream"), &AudioStreamPreviewGenerator::generate_preview); ADD_SIGNAL(MethodInfo("preview_updated", PropertyInfo(Variant::INT, "obj_id"))); diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 9a10766900..d9101466fc 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -336,7 +336,7 @@ void FindReplaceBar::_replace_all() { matches_label->add_theme_color_override("font_color", rc > 0 ? get_theme_color(SNAME("font_color"), SNAME("Label")) : get_theme_color(SNAME("error_color"), EditorStringName(Editor))); matches_label->set_text(vformat(TTR("%d replaced."), rc)); - text_editor->call_deferred(SNAME("connect"), "text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed)); + callable_mp((Object *)text_editor, &Object::connect).call_deferred("text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed), 0U); results_count = -1; results_count_to_current = -1; needs_to_count_results = true; @@ -517,10 +517,10 @@ void FindReplaceBar::_show_search(bool p_focus_replace, bool p_show_only) { if (p_focus_replace) { search_text->deselect(); - replace_text->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)replace_text, &Control::grab_focus).call_deferred(); } else { replace_text->deselect(); - search_text->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)search_text, &Control::grab_focus).call_deferred(); } if (text_editor->has_selection(0) && !is_selection_only()) { @@ -1277,7 +1277,7 @@ void CodeTextEditor::move_lines_up() { for (int j = 0; j < caret_groups[i].size(); j++) { int c = caret_groups[i][j]; - Vector<int> caret_parameters = caret_group_parameters[j]; + const Vector<int> &caret_parameters = caret_group_parameters[j]; text_editor->set_caret_line(caret_parameters[4] - 1, c == 0, true, 0, c); text_editor->set_caret_column(caret_parameters[5], c == 0, c); @@ -1374,7 +1374,7 @@ void CodeTextEditor::move_lines_down() { for (int j = 0; j < caret_groups[i].size(); j++) { int c = caret_groups[i][j]; - Vector<int> caret_parameters = caret_group_parameters[j]; + const Vector<int> &caret_parameters = caret_group_parameters[j]; text_editor->set_caret_line(caret_parameters[4] + 1, c == 0, true, 0, c); text_editor->set_caret_column(caret_parameters[5], c == 0, c); @@ -1572,20 +1572,20 @@ void CodeTextEditor::goto_line(int p_line) { text_editor->remove_secondary_carets(); text_editor->deselect(); text_editor->unfold_line(p_line); - text_editor->call_deferred(SNAME("set_caret_line"), p_line); + callable_mp((TextEdit *)text_editor, &TextEdit::set_caret_line).call_deferred(p_line, true, true, 0, 0); } void CodeTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { text_editor->remove_secondary_carets(); text_editor->unfold_line(p_line); - text_editor->call_deferred(SNAME("set_caret_line"), p_line); - text_editor->call_deferred(SNAME("set_caret_column"), p_begin); + callable_mp((TextEdit *)text_editor, &TextEdit::set_caret_line).call_deferred(p_line, true, true, 0, 0); + callable_mp((TextEdit *)text_editor, &TextEdit::set_caret_column).call_deferred(p_begin, true, 0); text_editor->select(p_line, p_begin, p_line, p_end); } void CodeTextEditor::goto_line_centered(int p_line) { goto_line(p_line); - text_editor->call_deferred(SNAME("center_viewport_to_caret")); + callable_mp((TextEdit *)text_editor, &TextEdit::center_viewport_to_caret).call_deferred(0); } void CodeTextEditor::set_executing_line(int p_line) { diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index e37035f5eb..49d997fc6a 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -474,7 +474,7 @@ void CreateDialog::_notification(int p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { if (is_visible()) { - search_box->call_deferred(SNAME("grab_focus")); // still not visible + callable_mp((Control *)search_box, &Control::grab_focus).call_deferred(); // Still not visible. search_box->select_all(); } else { EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "create_new_node", Rect2(get_position(), get_size())); @@ -794,6 +794,7 @@ CreateDialog::CreateDialog() { rec_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL); recent = memnew(ItemList); + recent->set_auto_translate(false); rec_vb->add_margin_child(TTR("Recent:"), recent, true); recent->set_allow_reselect(true); recent->connect("item_selected", callable_mp(this, &CreateDialog::_history_selected)); diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp index 929f323e80..e854681010 100644 --- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp +++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp @@ -44,7 +44,7 @@ void DebugAdapterParser::_bind_methods() { ClassDB::bind_method(D_METHOD("req_attach", "params"), &DebugAdapterParser::req_attach); ClassDB::bind_method(D_METHOD("req_restart", "params"), &DebugAdapterParser::req_restart); ClassDB::bind_method(D_METHOD("req_terminate", "params"), &DebugAdapterParser::req_terminate); - ClassDB::bind_method(D_METHOD("req_configurationDone", "params"), &DebugAdapterParser::prepare_success_response); + ClassDB::bind_method(D_METHOD("req_configurationDone", "params"), &DebugAdapterParser::req_configurationDone); ClassDB::bind_method(D_METHOD("req_pause", "params"), &DebugAdapterParser::req_pause); ClassDB::bind_method(D_METHOD("req_continue", "params"), &DebugAdapterParser::req_continue); ClassDB::bind_method(D_METHOD("req_threads", "params"), &DebugAdapterParser::req_threads); @@ -180,6 +180,13 @@ Dictionary DebugAdapterParser::req_launch(const Dictionary &p_params) const { DebugAdapterProtocol::get_singleton()->get_current_peer()->supportsCustomData = args["godot/custom_data"]; } + DebugAdapterProtocol::get_singleton()->get_current_peer()->pending_launch = p_params; + + return Dictionary(); +} + +Dictionary DebugAdapterParser::_launch_process(const Dictionary &p_params) const { + Dictionary args = p_params["arguments"]; ScriptEditorDebugger *dbg = EditorDebuggerNode::get_singleton()->get_default_debugger(); if ((bool)args["noDebug"] != dbg->is_skip_breakpoints()) { dbg->debug_skip_breakpoints(); @@ -246,7 +253,7 @@ Dictionary DebugAdapterParser::req_restart(const Dictionary &p_params) const { args = args["arguments"]; params["arguments"] = args; - Dictionary response = DebugAdapterProtocol::get_singleton()->get_current_peer()->attached ? req_attach(params) : req_launch(params); + Dictionary response = DebugAdapterProtocol::get_singleton()->get_current_peer()->attached ? req_attach(params) : _launch_process(params); if (!response["success"]) { response["command"] = p_params["command"]; return response; @@ -261,6 +268,16 @@ Dictionary DebugAdapterParser::req_terminate(const Dictionary &p_params) const { return prepare_success_response(p_params); } +Dictionary DebugAdapterParser::req_configurationDone(const Dictionary &p_params) const { + Ref<DAPeer> peer = DebugAdapterProtocol::get_singleton()->get_current_peer(); + if (!peer->pending_launch.is_empty()) { + peer->res_queue.push_back(_launch_process(peer->pending_launch)); + peer->pending_launch.clear(); + } + + return prepare_success_response(p_params); +} + Dictionary DebugAdapterParser::req_pause(const Dictionary &p_params) const { EditorRunBar::get_singleton()->get_pause_button()->set_pressed(true); EditorDebuggerNode::get_singleton()->_paused(); diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.h b/editor/debugger/debug_adapter/debug_adapter_parser.h index 9995066ab4..e5493a4b9f 100644 --- a/editor/debugger/debug_adapter/debug_adapter_parser.h +++ b/editor/debugger/debug_adapter/debug_adapter_parser.h @@ -71,6 +71,7 @@ public: Dictionary req_attach(const Dictionary &p_params) const; Dictionary req_restart(const Dictionary &p_params) const; Dictionary req_terminate(const Dictionary &p_params) const; + Dictionary req_configurationDone(const Dictionary &p_params) const; Dictionary req_pause(const Dictionary &p_params) const; Dictionary req_continue(const Dictionary &p_params) const; Dictionary req_threads(const Dictionary &p_params) const; @@ -84,6 +85,9 @@ public: Dictionary req_evaluate(const Dictionary &p_params) const; Dictionary req_godot_put_msg(const Dictionary &p_params) const; + // Internal requests + Dictionary _launch_process(const Dictionary &p_params) const; + // Events Dictionary ev_initialized() const; Dictionary ev_process(const String &p_command) const; diff --git a/editor/debugger/debug_adapter/debug_adapter_protocol.cpp b/editor/debugger/debug_adapter/debug_adapter_protocol.cpp index 26fb73570e..7417a3d8f7 100644 --- a/editor/debugger/debug_adapter/debug_adapter_protocol.cpp +++ b/editor/debugger/debug_adapter/debug_adapter_protocol.cpp @@ -678,7 +678,10 @@ bool DebugAdapterProtocol::process_message(const String &p_text) { if (!response.is_empty()) { _current_peer->res_queue.push_front(response); } else { - completed = false; + // Launch request needs to be deferred until we receive a configurationDone request. + if (command != "req_launch") { + completed = false; + } } } diff --git a/editor/debugger/debug_adapter/debug_adapter_protocol.h b/editor/debugger/debug_adapter/debug_adapter_protocol.h index ddc55816db..fb1c533bbb 100644 --- a/editor/debugger/debug_adapter/debug_adapter_protocol.h +++ b/editor/debugger/debug_adapter/debug_adapter_protocol.h @@ -63,6 +63,7 @@ struct DAPeer : RefCounted { // Internal client info bool attached = false; + Dictionary pending_launch; Error handle_data(); Error send_data(); diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index 8229abb5a0..372d558aab 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -455,7 +455,7 @@ void EditorDebuggerNode::_debugger_wants_stop(int p_id) { // Ask editor to kill PID. int pid = get_debugger(p_id)->get_remote_pid(); if (pid) { - EditorNode::get_singleton()->call_deferred(SNAME("stop_child_process"), pid); + callable_mp(EditorNode::get_singleton(), &EditorNode::stop_child_process).call_deferred(pid); } } diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp index 6305b7435a..7d3ea33fb5 100644 --- a/editor/debugger/editor_debugger_tree.cpp +++ b/editor/debugger/editor_debugger_tree.cpp @@ -253,7 +253,7 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int } debugger_id = p_debugger; // Needed by hook, could be avoided if every debugger had its own tree if (scroll_item) { - call_deferred(SNAME("scroll_to_item"), scroll_item); + callable_mp((Tree *)this, &Tree::scroll_to_item).call_deferred(scroll_item, false); } last_filter = filter; updating_scene_tree = false; diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 7077bce9f7..d926bd0f12 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -1687,7 +1687,7 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) { // Parse back the `file:line @ method()` string. const Vector<String> file_line_number = ci->get_text(1).split("@")[0].strip_edges().split(":"); ERR_FAIL_COND_MSG(file_line_number.size() < 2, "Incorrect C++ source stack trace file:line format (please report)."); - const String file = file_line_number[0]; + const String &file = file_line_number[0]; const int line_number = file_line_number[1].to_int(); // Construct a GitHub repository URL and open it in the user's default web browser. diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index 26779f5b52..a891491339 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -398,6 +398,7 @@ DependencyEditorOwners::DependencyEditorOwners() { file_options->connect("id_pressed", callable_mp(this, &DependencyEditorOwners::_file_option)); owners = memnew(ItemList); + owners->set_auto_translate(false); owners->set_select_mode(ItemList::SELECT_MULTI); owners->connect("item_clicked", callable_mp(this, &DependencyEditorOwners::_list_rmb_clicked)); owners->connect("item_activated", callable_mp(this, &DependencyEditorOwners::_select_file)); diff --git a/editor/directory_create_dialog.cpp b/editor/directory_create_dialog.cpp index 0efd11a6c1..aacd718fde 100644 --- a/editor/directory_create_dialog.cpp +++ b/editor/directory_create_dialog.cpp @@ -110,7 +110,7 @@ void DirectoryCreateDialog::ok_pressed() { err = da->make_dir_recursive(path); if (err == OK) { - emit_signal(SNAME("dir_created")); + emit_signal(SNAME("dir_created"), base_dir.path_join(path)); } else { EditorNode::get_singleton()->show_warning(TTR("Could not create folder.")); } @@ -131,7 +131,7 @@ void DirectoryCreateDialog::config(const String &p_base_dir) { } void DirectoryCreateDialog::_bind_methods() { - ADD_SIGNAL(MethodInfo("dir_created")); + ADD_SIGNAL(MethodInfo("dir_created", PropertyInfo(Variant::STRING, "path"))); } DirectoryCreateDialog::DirectoryCreateDialog() { diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index a7e3c03250..9c1fc2a8bf 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -382,7 +382,7 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) { continue; } - String cname = name; + const String &cname = name; // Property setters and getters do not get exposed as individual methods. HashSet<StringName> setters_getters; diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index 672697bab0..1f9911f31e 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -99,6 +99,7 @@ ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<St vbc->add_child(lbl); ItemList *il = memnew(ItemList); + il->set_auto_translate(false); il->set_h_size_flags(Control::SIZE_EXPAND_FILL); il->set_same_column_width(true); il->set_auto_height(true); diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index f4a9e0a2ef..c1183c8d66 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -1234,7 +1234,7 @@ void EditorAudioBuses::_load_default_layout() { AudioServer::get_singleton()->set_bus_layout(state); _rebuild_buses(); EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); - call_deferred(SNAME("_select_layout")); + callable_mp(this, &EditorAudioBuses::_select_layout).call_deferred(); } void EditorAudioBuses::_file_dialog_callback(const String &p_string) { @@ -1250,7 +1250,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) { AudioServer::get_singleton()->set_bus_layout(state); _rebuild_buses(); EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); - call_deferred(SNAME("_select_layout")); + callable_mp(this, &EditorAudioBuses::_select_layout).call_deferred(); } else if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) { if (new_layout) { @@ -1270,14 +1270,13 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) { file->set_text(String(TTR("Layout:")) + " " + p_string.get_file()); _rebuild_buses(); EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); - call_deferred(SNAME("_select_layout")); + callable_mp(this, &EditorAudioBuses::_select_layout).call_deferred(); } } void EditorAudioBuses::_bind_methods() { ClassDB::bind_method("_update_bus", &EditorAudioBuses::_update_bus); ClassDB::bind_method("_update_sends", &EditorAudioBuses::_update_sends); - ClassDB::bind_method("_select_layout", &EditorAudioBuses::_select_layout); } EditorAudioBuses::EditorAudioBuses() { @@ -1370,7 +1369,7 @@ void EditorAudioBuses::open_layout(const String &p_path) { AudioServer::get_singleton()->set_bus_layout(state); _rebuild_buses(); EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); - call_deferred(SNAME("_select_layout")); + callable_mp(this, &EditorAudioBuses::_select_layout).call_deferred(); } void AudioBusesEditorPlugin::edit(Object *p_node) { diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 204b717296..45de4a54ae 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -57,7 +57,7 @@ void EditorAutoloadSettings::_notification(int p_what) { for (const AutoloadInfo &info : autoload_cache) { if (info.node && info.in_editor) { - get_tree()->get_root()->call_deferred(SNAME("add_child"), info.node); + callable_mp((Node *)get_tree()->get_root(), &Node::add_child).call_deferred(info.node, false, Node::INTERNAL_MODE_DISABLED); } } browse_button->set_icon(get_editor_theme_icon(SNAME("Folder"))); @@ -65,6 +65,7 @@ void EditorAutoloadSettings::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { browse_button->set_icon(get_editor_theme_icon(SNAME("Folder"))); + add_autoload->set_icon(get_editor_theme_icon(SNAME("Add"))); } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -533,7 +534,7 @@ void EditorAutoloadSettings::update_autoload() { } if (info.in_editor) { ERR_CONTINUE(!info.node); - get_tree()->get_root()->call_deferred(SNAME("remove_child"), info.node); + callable_mp((Node *)get_tree()->get_root(), &Node::remove_child).call_deferred(info.node); } if (info.node) { diff --git a/editor/editor_build_profile.cpp b/editor/editor_build_profile.cpp index c4a5fbd939..8ab8bc4a52 100644 --- a/editor/editor_build_profile.cpp +++ b/editor/editor_build_profile.cpp @@ -481,7 +481,7 @@ void EditorBuildProfileManager::_detect_classes() { String l = f->get_line(); Vector<String> fields = l.split("::"); if (fields.size() == 4) { - String path = fields[0]; + const String &path = fields[0]; DetectedFile df; df.timestamp = fields[1].to_int(); df.md5 = fields[2]; @@ -597,7 +597,7 @@ void EditorBuildProfileManager::_fill_classes_from(TreeItem *p_parent, const Str TreeItem *class_item = class_list->create_item(p_parent); class_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); class_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_class)); - String text = p_class; + const String &text = p_class; bool disabled = edited->is_class_disabled(p_class); if (disabled) { @@ -888,7 +888,7 @@ EditorBuildProfileManager::EditorBuildProfileManager() { export_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM); force_detect_classes = memnew(LineEdit); - main_vbc->add_margin_child(TTR("Forced classes on detect:"), force_detect_classes); + main_vbc->add_margin_child(TTR("Forced Classes on Detect:"), force_detect_classes); force_detect_classes->connect("text_changed", callable_mp(this, &EditorBuildProfileManager::_force_detect_classes_changed)); set_title(TTR("Edit Build Configuration Profile")); diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp index 6626251ee6..ce5d8619e1 100644 --- a/editor/editor_command_palette.cpp +++ b/editor/editor_command_palette.cpp @@ -74,7 +74,7 @@ void EditorCommandPalette::_update_command_search(const String &search_text) { CommandEntry r; r.key_name = E.key; r.display_name = E.value.name; - r.shortcut_text = E.value.shortcut; + r.shortcut_text = E.value.shortcut_text; r.last_used = E.value.last_used; bool is_subsequence_of_key_name = search_text.is_subsequence_ofn(r.key_name); @@ -92,8 +92,6 @@ void EditorCommandPalette::_update_command_search(const String &search_text) { } } - command_keys.clear(); - TreeItem *root = search_options->get_root(); root->clear_children(); @@ -168,6 +166,19 @@ void EditorCommandPalette::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { command_search_box->set_right_icon(get_editor_theme_icon(SNAME("Search"))); } break; + + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + if (!EditorSettings::get_singleton()->check_changed_settings_in_group("shortcuts")) { + break; + } + + for (KeyValue<String, Command> &kv : commands) { + Command &c = kv.value; + if (c.shortcut.is_valid()) { + c.shortcut_text = c.shortcut->get_as_text(); + } + } + } break; } } @@ -221,7 +232,7 @@ void EditorCommandPalette::remove_command(String p_key_name) { commands.erase(p_key_name); } -void EditorCommandPalette::add_command(String p_command_name, String p_key_name, Callable p_action, Vector<Variant> arguments, String p_shortcut_text) { +void EditorCommandPalette::add_command(String p_command_name, String p_key_name, Callable p_action, Vector<Variant> arguments, const Ref<Shortcut> &p_shortcut) { ERR_FAIL_COND_MSG(commands.has(p_key_name), "The Command '" + String(p_command_name) + "' already exists. Unable to add it."); const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * arguments.size()); @@ -231,7 +242,12 @@ void EditorCommandPalette::add_command(String p_command_name, String p_key_name, Command command; command.name = p_command_name; command.callable = p_action.bindp(argptrs, arguments.size()); - command.shortcut = p_shortcut_text; + if (p_shortcut.is_null()) { + command.shortcut_text = "None"; + } else { + command.shortcut = p_shortcut; + command.shortcut_text = p_shortcut->get_as_text(); + } commands[p_key_name] = command; } @@ -242,7 +258,7 @@ void EditorCommandPalette::_add_command(String p_command_name, String p_key_name Command command; command.name = p_command_name; command.callable = p_binded_action; - command.shortcut = p_shortcut_text; + command.shortcut_text = p_shortcut_text; // Commands added from plugins don't exist yet when the history is loaded, so we assign the last use time here if it was recorded. Dictionary command_history = EditorSettings::get_singleton()->get_project_metadata("command_palette", "command_history", Dictionary()); @@ -275,8 +291,7 @@ void EditorCommandPalette::register_shortcuts_as_command() { Ref<InputEventShortcut> ev; ev.instantiate(); ev->set_shortcut(shortcut); - String shortcut_text = String(shortcut->get_as_text()); - add_command(command_name, E.key, callable_mp(EditorNode::get_singleton()->get_viewport(), &Viewport::push_input), varray(ev, false), shortcut_text); + add_command(command_name, E.key, callable_mp(EditorNode::get_singleton()->get_viewport(), &Viewport::push_input), varray(ev, false), shortcut); } unregistered_shortcuts.clear(); @@ -296,8 +311,7 @@ Ref<Shortcut> EditorCommandPalette::add_shortcut_command(const String &p_command Ref<InputEventShortcut> ev; ev.instantiate(); ev->set_shortcut(p_shortcut); - String shortcut_text = String(p_shortcut->get_as_text()); - add_command(p_command, p_key, callable_mp(EditorNode::get_singleton()->get_viewport(), &Viewport::push_input), varray(ev, false), shortcut_text); + add_command(p_command, p_key, callable_mp(EditorNode::get_singleton()->get_viewport(), &Viewport::push_input), varray(ev, false), p_shortcut); } else { const String key_name = String(p_key); const String command_name = String(p_command); diff --git a/editor/editor_command_palette.h b/editor/editor_command_palette.h index 01fa6896a9..cc0f726b3a 100644 --- a/editor/editor_command_palette.h +++ b/editor/editor_command_palette.h @@ -46,7 +46,8 @@ class EditorCommandPalette : public ConfirmationDialog { struct Command { Callable callable; String name; - String shortcut; + Ref<Shortcut> shortcut; + String shortcut_text; int last_used = 0; // Store time as int, because doubles have problems with text serialization. }; @@ -77,8 +78,6 @@ class EditorCommandPalette : public ConfirmationDialog { HashMap<String, Command> commands; HashMap<String, Pair<String, Ref<Shortcut>>> unregistered_shortcuts; - List<String> command_keys; - void _update_command_search(const String &search_text); float _score_path(const String &p_search, const String &p_path); void _sbox_input(const Ref<InputEvent> &p_ie); @@ -95,7 +94,7 @@ protected: public: void open_popup(); void get_actions_list(List<String> *p_list) const; - void add_command(String p_command_name, String p_key_name, Callable p_action, Vector<Variant> arguments, String p_shortcut_text = "None"); + void add_command(String p_command_name, String p_key_name, Callable p_action, Vector<Variant> arguments, const Ref<Shortcut> &p_shortcut); void execute_command(const String &p_command_name); void register_shortcuts_as_command(); Ref<Shortcut> add_shortcut_command(const String &p_command, const String &p_key, Ref<Shortcut> p_shortcut); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index fe8c42ea3b..5f77959127 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -1242,7 +1242,6 @@ void EditorSelection::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_node", "node"), &EditorSelection::remove_node); ClassDB::bind_method(D_METHOD("get_selected_nodes"), &EditorSelection::get_selected_nodes); ClassDB::bind_method(D_METHOD("get_transformable_selected_nodes"), &EditorSelection::_get_transformable_selected_nodes); - ClassDB::bind_method(D_METHOD("_emit_change"), &EditorSelection::_emit_change); ADD_SIGNAL(MethodInfo("selection_changed")); } @@ -1290,7 +1289,7 @@ void EditorSelection::update() { changed = false; if (!emitted) { emitted = true; - call_deferred(SNAME("_emit_change")); + callable_mp(this, &EditorSelection::_emit_change).call_deferred(); } } diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 807f0c8eb7..aab433ac27 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -257,7 +257,7 @@ void EditorFileSystem::_scan_filesystem() { if (l.begins_with("::")) { Vector<String> split = l.split("::"); ERR_CONTINUE(split.size() != 3); - String name = split[1]; + const String &name = split[1]; cpath = name; @@ -290,7 +290,7 @@ void EditorFileSystem::_scan_filesystem() { if (deps.length()) { Vector<String> dp = deps.split("<>"); for (int i = 0; i < dp.size(); i++) { - String path = dp[i]; + const String &path = dp[i]; fc.deps.push_back(path); } } @@ -2436,7 +2436,13 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) { Error EditorFileSystem::reimport_append(const String &p_file, const HashMap<StringName, Variant> &p_custom_options, const String &p_custom_importer, Variant p_generator_parameters) { ERR_FAIL_COND_V_MSG(!importing, ERR_INVALID_PARAMETER, "Can only append files to import during a current reimport process."); - return _reimport_file(p_file, p_custom_options, p_custom_importer, &p_generator_parameters); + Error ret = _reimport_file(p_file, p_custom_options, p_custom_importer, &p_generator_parameters); + + // Emit the resource_reimported signal for the single file we just reimported. + Vector<String> reloads; + reloads.append(p_file); + emit_signal(SNAME("resources_reimported"), reloads); + return ret; } Error EditorFileSystem::_resource_import(const String &p_path) { @@ -2687,7 +2693,7 @@ EditorFileSystem::EditorFileSystem() { using_fat32_or_exfat = (da->get_filesystem_type() == "FAT32" || da->get_filesystem_type() == "exFAT"); scan_total = 0; - MessageQueue::get_singleton()->push_callable(callable_mp(ResourceUID::get_singleton(), &ResourceUID::clear)); // Will be updated on scan. + callable_mp(ResourceUID::get_singleton(), &ResourceUID::clear).call_deferred(); // Will be updated on scan. ResourceSaver::set_get_resource_id_for_path(_resource_saver_get_resource_id_for_path); } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 2b1ab4ca02..6e448d8866 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1966,7 +1966,7 @@ void EditorHelp::_help_callback(const String &p_topic) { } if (class_desc->is_ready()) { - class_desc->call_deferred(SNAME("scroll_to_paragraph"), line); + callable_mp(class_desc, &RichTextLabel::scroll_to_paragraph).call_deferred(line); } else { scroll_to = line; } @@ -2867,10 +2867,10 @@ void EditorHelpTooltip::parse_tooltip(const String &p_text) { PackedStringArray slices = p_text.split("|", true, 3); ERR_FAIL_COND_MSG(slices.size() < 4, "Invalid tooltip formatting. The expect string should be formatted as 'type|class|property|args'."); - String type = slices[0]; - String class_name = slices[1]; - String property_name = slices[2]; - String property_args = slices[3]; + const String &type = slices[0]; + const String &class_name = slices[1]; + const String &property_name = slices[2]; + const String &property_args = slices[3]; String title; String description; diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index 44698d93f6..64bd209d4d 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -96,7 +96,7 @@ void EditorHelpSearch::_notification(int p_what) { switch (p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { if (!is_visible()) { - results_tree->call_deferred(SNAME("clear")); // Wait for the Tree's mouse event propagation. + callable_mp(results_tree, &Tree::clear).call_deferred(); // Wait for the Tree's mouse event propagation. get_ok_button()->set_disabled(true); EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "search_help", Rect2(get_position(), get_size())); } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 59816a0eca..6809739dc1 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -695,15 +695,14 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) { new_coords.y++; } if (new_coords.x < int64_t(object->get("hframes")) && new_coords.y < int64_t(object->get("vframes"))) { - call_deferred(SNAME("emit_changed"), property, new_coords, "", false); + callable_mp(this, &EditorProperty::emit_changed).call_deferred(property, new_coords, "", false); } } else { if (int64_t(object->get(property)) + 1 < (int64_t(object->get("hframes")) * int64_t(object->get("vframes")))) { - call_deferred(SNAME("emit_changed"), property, object->get(property).operator int64_t() + 1, "", false); + callable_mp(this, &EditorProperty::emit_changed).call_deferred(property, object->get(property).operator int64_t() + 1, "", false); } } - - call_deferred(SNAME("update_property")); + callable_mp(this, &EditorProperty::update_property).call_deferred(); } } if (delete_rect.has_point(mpos)) { @@ -3021,7 +3020,7 @@ void EditorInspector::update_tree() { Vector<String> components = path.split("/"); for (int i = 0; i < components.size(); i++) { - String component = components[i]; + const String &component = components[i]; acc_path += (i > 0) ? "/" + component : component; if (!vbox_per_path[root_vbox].has(acc_path)) { @@ -3980,7 +3979,7 @@ void EditorInspector::_notification(int p_what) { case NOTIFICATION_PROCESS: { if (update_scroll_request >= 0) { - get_v_scroll_bar()->call_deferred(SNAME("set_value"), update_scroll_request); + callable_mp((Range *)get_v_scroll_bar(), &Range::set_value).call_deferred(update_scroll_request); update_scroll_request = -1; } if (update_tree_pending) { @@ -4209,6 +4208,7 @@ EditorInspector::EditorInspector() { main_vbox->add_theme_constant_override("separation", 0); add_child(main_vbox); set_horizontal_scroll_mode(SCROLL_MODE_DISABLED); + set_follow_focus(true); changing = 0; search_box = nullptr; diff --git a/editor/editor_interface.cpp b/editor/editor_interface.cpp index e179a0e18a..b007f6d530 100644 --- a/editor/editor_interface.cpp +++ b/editor/editor_interface.cpp @@ -127,7 +127,7 @@ Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh Vector<Ref<Texture2D>> textures; for (int i = 0; i < p_meshes.size(); i++) { - Ref<Mesh> mesh = p_meshes[i]; + const Ref<Mesh> &mesh = p_meshes[i]; if (!mesh.is_valid()) { textures.push_back(Ref<Texture2D>()); continue; @@ -400,6 +400,21 @@ bool EditorInterface::is_movie_maker_enabled() const { } // Base. +void EditorInterface::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { + String pf = p_function; + if (p_idx == 0) { + if (pf == "set_main_screen_editor") { + for (String E : { "\"2D\"", "\"3D\"", "\"Script\"", "\"AssetLib\"" }) { + r_options->push_back(E); + } + } else if (pf == "get_editor_viewport_3d") { + for (uint32_t i = 0; i < Node3DEditor::VIEWPORTS_COUNT; i++) { + r_options->push_back(String::num_int64(i)); + } + } + } + Object::get_argument_options(p_function, p_idx, r_options); +} void EditorInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("restart_editor", "save"), &EditorInterface::restart_editor, DEFVAL(true)); diff --git a/editor/editor_interface.h b/editor/editor_interface.h index 079fc169f2..73e89ae2f2 100644 --- a/editor/editor_interface.h +++ b/editor/editor_interface.h @@ -152,6 +152,8 @@ public: // Base. + virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; + static void create(); static void free(); diff --git a/editor/editor_layouts_dialog.cpp b/editor/editor_layouts_dialog.cpp index dce61f66d3..c6f518d4c1 100644 --- a/editor/editor_layouts_dialog.cpp +++ b/editor/editor_layouts_dialog.cpp @@ -114,6 +114,7 @@ EditorLayoutsDialog::EditorLayoutsDialog() { add_child(makevb); layout_names = memnew(ItemList); + layout_names->set_auto_translate(false); layout_names->set_auto_height(true); layout_names->set_custom_minimum_size(Size2(300 * EDSCALE, 50 * EDSCALE)); layout_names->set_visible(true); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index bd09019671..fd1d598f90 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -38,7 +38,6 @@ #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/object/class_db.h" -#include "core/object/message_queue.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/os/time.h" @@ -113,9 +112,12 @@ #include "editor/gui/editor_title_bar.h" #include "editor/gui/editor_toaster.h" #include "editor/history_dock.h" +#include "editor/import/3d/editor_import_collada.h" +#include "editor/import/3d/resource_importer_obj.h" +#include "editor/import/3d/resource_importer_scene.h" +#include "editor/import/3d/scene_import_settings.h" #include "editor/import/audio_stream_import_settings.h" #include "editor/import/dynamic_font_import_settings.h" -#include "editor/import/editor_import_collada.h" #include "editor/import/resource_importer_bitmask.h" #include "editor/import/resource_importer_bmfont.h" #include "editor/import/resource_importer_csv_translation.h" @@ -123,12 +125,10 @@ #include "editor/import/resource_importer_image.h" #include "editor/import/resource_importer_imagefont.h" #include "editor/import/resource_importer_layered_texture.h" -#include "editor/import/resource_importer_obj.h" #include "editor/import/resource_importer_shader_file.h" #include "editor/import/resource_importer_texture.h" #include "editor/import/resource_importer_texture_atlas.h" #include "editor/import/resource_importer_wav.h" -#include "editor/import/scene_import_settings.h" #include "editor/import_dock.h" #include "editor/inspector_dock.h" #include "editor/multi_node_edit.h" @@ -177,7 +177,7 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto Vector<RBSet<int>> index_sets; HashMap<String, int> scene_name_to_set_index; for (int i = 0; i < r_filenames.size(); i++) { - String scene_name = r_filenames[i]; + const String &scene_name = r_filenames[i]; if (!scene_name_to_set_index.has(scene_name)) { index_sets.append(RBSet<int>()); scene_name_to_set_index.insert(r_filenames[i], index_sets.size() - 1); @@ -233,7 +233,7 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto if (E->get() == F) { continue; } - String other_scene_name = r_filenames[F]; + const String &other_scene_name = r_filenames[F]; if (other_scene_name == scene_name) { duplicate_found = true; break; @@ -667,7 +667,7 @@ void EditorNode::_notification(int p_what) { command_palette->register_shortcuts_as_command(); - MessageQueue::get_singleton()->push_callable(callable_mp(this, &EditorNode::_begin_first_scan)); + callable_mp(this, &EditorNode::_begin_first_scan).call_deferred(); /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ } break; @@ -1106,7 +1106,7 @@ void EditorNode::_scan_external_changes() { } if (need_reload) { - disk_changed->call_deferred(SNAME("popup_centered_ratio"), 0.3); + callable_mp((Window *)disk_changed, &Window::popup_centered_ratio).call_deferred(0.3); } } @@ -3012,6 +3012,16 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case SET_RENDERER_NAME_SAVE_AND_RESTART: { ProjectSettings::get_singleton()->set("rendering/renderer/rendering_method", renderer_request); + if (renderer_request == "mobile" || renderer_request == "gl_compatibility") { + // Also change the mobile override if changing to a compatible rendering method. + // This prevents visual discrepancies between desktop and mobile platforms. + ProjectSettings::get_singleton()->set("rendering/renderer/rendering_method.mobile", renderer_request); + } else if (renderer_request == "forward_plus") { + // Use the equivalent mobile rendering method. This prevents the rendering method from staying + // on its old choice if moving from `gl_compatibility` to `forward_plus`. + ProjectSettings::get_singleton()->set("rendering/renderer/rendering_method.mobile", "mobile"); + } + ProjectSettings::get_singleton()->save(); save_all_scenes(); @@ -3696,7 +3706,7 @@ void EditorNode::_set_current_scene_nocheck(int p_idx) { callable_mp(scene_tabs, &EditorSceneTabs::update_scene_tabs).call_deferred(); if (tabs_to_close.is_empty()) { - call_deferred(SNAME("_set_main_scene_state"), state, get_edited_scene()); // Do after everything else is done setting up. + callable_mp(this, &EditorNode::_set_main_scene_state).call_deferred(state, get_edited_scene()); // Do after everything else is done setting up. } } @@ -4086,7 +4096,7 @@ bool EditorNode::has_previous_scenes() const { void EditorNode::edit_foreign_resource(Ref<Resource> p_resource) { load_scene(p_resource->get_path().get_slice("::", 0)); - InspectorDock::get_singleton()->call_deferred("edit_resource", p_resource); + callable_mp(InspectorDock::get_singleton(), &InspectorDock::edit_resource).call_deferred(p_resource); } bool EditorNode::is_resource_read_only(Ref<Resource> p_resource, bool p_foreign_resources_are_writable) { @@ -4165,7 +4175,7 @@ void EditorNode::_add_to_recent_scenes(const String &p_scene) { void EditorNode::_open_recent_scene(int p_idx) { if (p_idx == recent_scenes->get_item_count() - 1) { EditorSettings::get_singleton()->set_project_metadata("recent_files", "scenes", Array()); - call_deferred(SNAME("_update_recent_scenes")); + callable_mp(this, &EditorNode::_update_recent_scenes).call_deferred(); } else { Array rc = EditorSettings::get_singleton()->get_project_metadata("recent_files", "scenes", Array()); ERR_FAIL_INDEX(p_idx, rc.size()); @@ -4198,7 +4208,7 @@ void EditorNode::_quick_opened() { bool open_scene_dialog = quick_open->get_base_type() == "PackedScene"; for (int i = 0; i < files.size(); i++) { - String res_path = files[i]; + const String &res_path = files[i]; if (open_scene_dialog || ClassDB::is_parent_class(ResourceLoader::get_resource_type(res_path), "PackedScene")) { open_request(res_path); } else { @@ -4596,8 +4606,8 @@ String EditorNode::_get_system_info() const { } graphics += rendering_device_name; if (video_adapter_driver_info.size() == 2) { // This vector is always either of length 0 or 2. - String vad_name = video_adapter_driver_info[0]; - String vad_version = video_adapter_driver_info[1]; // Version could be potentially empty on Linux/BSD. + const String &vad_name = video_adapter_driver_info[0]; + const String &vad_version = video_adapter_driver_info[1]; // Version could be potentially empty on Linux/BSD. if (!vad_version.is_empty()) { graphics += vformat(" (%s; %s)", vad_name, vad_version); } else { @@ -5047,7 +5057,8 @@ void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String &p // Save FileSystemDock state. - p_layout->set_value(p_section, "dock_filesystem_split", FileSystemDock::get_singleton()->get_split_offset()); + p_layout->set_value(p_section, "dock_filesystem_h_split_offset", FileSystemDock::get_singleton()->get_h_split_offset()); + p_layout->set_value(p_section, "dock_filesystem_v_split_offset", FileSystemDock::get_singleton()->get_v_split_offset()); p_layout->set_value(p_section, "dock_filesystem_display_mode", FileSystemDock::get_singleton()->get_display_mode()); p_layout->set_value(p_section, "dock_filesystem_file_sort", FileSystemDock::get_singleton()->get_file_sort()); p_layout->set_value(p_section, "dock_filesystem_file_list_display_mode", FileSystemDock::get_singleton()->get_file_list_display_mode()); @@ -5188,7 +5199,7 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String Vector<String> names = String(p_layout->get_value(p_section, "dock_" + itos(i + 1))).split(","); for (int j = names.size() - 1; j >= 0; j--) { - String name = names[j]; + const String &name = names[j]; // FIXME: Find it, in a horribly inefficient way. int atidx = -1; @@ -5247,7 +5258,7 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String int selected_tab_idx = p_layout->get_value(p_section, "dock_" + itos(i + 1) + "_selected_tab_idx"); if (selected_tab_idx >= 0 && selected_tab_idx < dock_slot[i]->get_tab_count()) { - dock_slot[i]->call_deferred("set_current_tab", selected_tab_idx); + callable_mp(dock_slot[i], &TabContainer::set_current_tab).call_deferred(selected_tab_idx); } } @@ -5272,9 +5283,14 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String // FileSystemDock. - if (p_layout->has_section_key(p_section, "dock_filesystem_split")) { - int fs_split_ofs = p_layout->get_value(p_section, "dock_filesystem_split"); - FileSystemDock::get_singleton()->set_split_offset(fs_split_ofs); + if (p_layout->has_section_key(p_section, "dock_filesystem_h_split_offset")) { + int fs_h_split_ofs = p_layout->get_value(p_section, "dock_filesystem_h_split_offset"); + FileSystemDock::get_singleton()->set_h_split_offset(fs_h_split_ofs); + } + + if (p_layout->has_section_key(p_section, "dock_filesystem_v_split_offset")) { + int fs_v_split_ofs = p_layout->get_value(p_section, "dock_filesystem_v_split_offset"); + FileSystemDock::get_singleton()->set_v_split_offset(fs_v_split_ofs); } if (p_layout->has_section_key(p_section, "dock_filesystem_display_mode")) { @@ -6004,7 +6020,7 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str ERR_FAIL_COND(dir.is_null()); for (int i = 0; i < p_files.size(); i++) { - String from = p_files[i]; + const String &from = p_files[i]; String to = to_path.path_join(from.get_file()); if (dir->dir_exists(from)) { @@ -6153,7 +6169,8 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins if (edited_scene_map.size() > 0) { // Reload the new instance. Error err; - Ref<PackedScene> instance_scene_packed_scene = ResourceLoader::load(p_instance_path, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err); + Ref<PackedScene> instance_scene_packed_scene = ResourceLoader::load(p_instance_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE, &err); + instance_scene_packed_scene->set_path(p_instance_path, true); ERR_FAIL_COND(err != OK); ERR_FAIL_COND(instance_scene_packed_scene.is_null()); @@ -6260,7 +6277,8 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins // be properly updated. for (String path : required_load_paths) { if (!local_scene_cache.find(path)) { - current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err); + current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_IGNORE, &err); + current_packed_scene->set_path(path, true); local_scene_cache[path] = current_packed_scene; } else { current_packed_scene = local_scene_cache[path]; @@ -6569,6 +6587,9 @@ void EditorNode::_renderer_selected(int p_which) { } renderer_request = rendering_method; + video_restart_dialog->set_text( + vformat(TTR("Changing the renderer requires restarting the editor.\n\nChoosing Save & Restart will change the rendering method to:\n- Desktop platforms: %s\n- Mobile platforms: %s\n- Web platform: gl_compatibility"), + renderer_request, renderer_request.replace("forward_plus", "mobile"))); video_restart_dialog->popup_centered(); renderer->select(renderer_current); _update_renderer_color(); @@ -6655,15 +6676,9 @@ void EditorNode::_bind_methods() { ClassDB::bind_method(D_METHOD("push_item", "object", "property", "inspector_only"), &EditorNode::push_item, DEFVAL(""), DEFVAL(false)); 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("stop_child_process", &EditorNode::stop_child_process); - ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state); - ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes); - ADD_SIGNAL(MethodInfo("request_help_search")); ADD_SIGNAL(MethodInfo("script_add_function_request", PropertyInfo(Variant::OBJECT, "obj"), PropertyInfo(Variant::STRING, "function"), PropertyInfo(Variant::PACKED_STRING_ARRAY, "args"))); ADD_SIGNAL(MethodInfo("resource_saved", PropertyInfo(Variant::OBJECT, "obj"))); @@ -7546,7 +7561,7 @@ EditorNode::EditorNode() { renderer->set_focus_mode(Control::FOCUS_NONE); renderer->add_theme_font_override("font", theme->get_font(SNAME("bold"), EditorStringName(EditorFonts))); renderer->add_theme_font_size_override("font_size", theme->get_font_size(SNAME("bold_size"), EditorStringName(EditorFonts))); - renderer->set_tooltip_text(TTR("Choose a renderer.")); + renderer->set_tooltip_text(TTR("Choose a rendering method.\n\nNotes:\n- On mobile platforms, the Mobile rendering method is used if Forward+ is selected here.\n- On the web platform, the Compatibility rendering method is always used.")); right_menu_hb->add_child(renderer); @@ -7588,7 +7603,6 @@ EditorNode::EditorNode() { _update_renderer_color(); video_restart_dialog = memnew(ConfirmationDialog); - 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_RENDERER_NAME_SAVE_AND_RESTART)); gui_base->add_child(video_restart_dialog); @@ -7803,6 +7817,7 @@ EditorNode::EditorNode() { file = memnew(EditorFileDialog); gui_base->add_child(file); file->set_current_dir("res://"); + file->set_transient_to_focused(true); file_export_lib = memnew(EditorFileDialog); file_export_lib->set_title(TTR("Export Library")); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 94a49166b8..49c62a3a6c 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -39,8 +39,8 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/export/editor_export.h" #include "editor/gui/editor_title_bar.h" +#include "editor/import/3d/resource_importer_scene.h" #include "editor/import/editor_import_plugin.h" -#include "editor/import/resource_importer_scene.h" #include "editor/inspector_dock.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/editor_debugger_plugin.h" @@ -402,13 +402,13 @@ void EditorPlugin::remove_translation_parser_plugin(const Ref<EditorTranslationP void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin> &p_importer, bool p_first_priority) { ERR_FAIL_COND(!p_importer.is_valid()); ResourceFormatImporter::get_singleton()->add_importer(p_importer, p_first_priority); - EditorFileSystem::get_singleton()->call_deferred(SNAME("scan")); + callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::scan).call_deferred(); } void EditorPlugin::remove_import_plugin(const Ref<EditorImportPlugin> &p_importer) { ERR_FAIL_COND(!p_importer.is_valid()); ResourceFormatImporter::get_singleton()->remove_importer(p_importer); - EditorFileSystem::get_singleton()->call_deferred(SNAME("scan")); + callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::scan).call_deferred(); } void EditorPlugin::add_export_plugin(const Ref<EditorExportPlugin> &p_exporter) { diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index ef8730cabf..6c38d9de58 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -64,7 +64,7 @@ void EditorPluginSettings::update_plugins() { for (int i = 0; i < plugins.size(); i++) { Ref<ConfigFile> cf; cf.instantiate(); - const String path = plugins[i]; + const String &path = plugins[i]; Error err2 = cf->load(path); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 27530dc641..404f1151f1 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -3013,7 +3013,7 @@ void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource, if (extensions.find(parent.get_extension()) && (!EditorNode::get_singleton()->get_edited_scene() || EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path() != parent)) { // If the resource belongs to another (non-imported) scene, edit it in that scene instead. if (!FileAccess::exists(parent + ".import")) { - EditorNode::get_singleton()->call_deferred("edit_foreign_resource", p_resource); + callable_mp(EditorNode::get_singleton(), &EditorNode::edit_foreign_resource).call_deferred(p_resource); return; } } diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 0a9d35fe64..7f9d80961b 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -202,22 +202,16 @@ void EditorPropertyArray::_property_changed(const String &p_property, Variant p_ p_value = Variant(); // `EditorResourcePicker` resets to `Ref<Resource>()`. See GH-82716. } - int index; - if (p_property.begins_with("metadata/")) { - index = p_property.get_slice("/", 2).to_int(); - } else { - index = p_property.get_slice("/", 1).to_int(); - } + int index = p_property.get_slice("/", 1).to_int(); Variant array = object->get_array().duplicate(); array.set(index, p_value); - object->set_array(array); - emit_changed(get_edited_property(), array, "", true); + emit_changed(get_edited_property(), array, p_name, p_changing); } -void EditorPropertyArray::_change_type(Object *p_button, int p_index) { +void EditorPropertyArray::_change_type(Object *p_button, int p_slot_index) { Button *button = Object::cast_to<Button>(p_button); - changing_type_index = p_index; + changing_type_index = slots[p_slot_index].index; Rect2 rect = button->get_screen_rect(); change_type->reset_size(); change_type->set_position(rect.get_end() - Vector2(change_type->get_contents_minimum_size().x, 0)); @@ -244,6 +238,48 @@ void EditorPropertyArray::_object_id_selected(const StringName &p_property, Obje emit_signal(SNAME("object_id_selected"), p_property, p_id); } +void EditorPropertyArray::create_new_property_slot() { + int idx = slots.size(); + HBoxContainer *hbox = memnew(HBoxContainer); + + Button *reorder_button = memnew(Button); + reorder_button->set_icon(get_editor_theme_icon(SNAME("TripleBar"))); + reorder_button->set_default_cursor_shape(Control::CURSOR_MOVE); + reorder_button->set_disabled(is_read_only()); + reorder_button->connect(SNAME("gui_input"), callable_mp(this, &EditorPropertyArray::_reorder_button_gui_input)); + reorder_button->connect(SNAME("button_up"), callable_mp(this, &EditorPropertyArray::_reorder_button_up)); + reorder_button->connect(SNAME("button_down"), callable_mp(this, &EditorPropertyArray::_reorder_button_down).bind(idx)); + + hbox->add_child(reorder_button); + EditorProperty *prop = memnew(EditorPropertyNil); + hbox->add_child(prop); + + bool is_untyped_array = object->get_array().get_type() == Variant::ARRAY && subtype == Variant::NIL; + + if (is_untyped_array) { + Button *edit_btn = memnew(Button); + edit_btn->set_icon(get_editor_theme_icon(SNAME("Edit"))); + edit_btn->set_disabled(is_read_only()); + edit_btn->connect("pressed", callable_mp(this, &EditorPropertyArray::_change_type).bind(edit_btn, idx)); + hbox->add_child(edit_btn); + } else { + Button *remove_btn = memnew(Button); + remove_btn->set_icon(get_editor_theme_icon(SNAME("Remove"))); + remove_btn->set_disabled(is_read_only()); + remove_btn->connect("pressed", callable_mp(this, &EditorPropertyArray::_remove_pressed).bind(idx)); + hbox->add_child(remove_btn); + } + property_vbox->add_child(hbox); + + Slot slot; + slot.prop = prop; + slot.object = object; + slot.container = hbox; + slot.reorder_button = reorder_button; + slot.set_index(idx + page_index * page_length); + slots.push_back(slot); +} + void EditorPropertyArray::update_property() { Variant array = get_edited_property_value(); @@ -276,7 +312,6 @@ void EditorPropertyArray::update_property() { int size = array.call("size"); int max_page = MAX(0, size - 1) / page_length; page_index = MIN(page_index, max_page); - int offset = page_index * page_length; edit->set_text(vformat(TTR("%s (size %s)"), array_type_name, itos(size))); @@ -326,16 +361,9 @@ void EditorPropertyArray::update_property() { paginator = memnew(EditorPaginator); paginator->connect("page_changed", callable_mp(this, &EditorPropertyArray::_page_changed)); vbox->add_child(paginator); - } else { - // Bye bye children of the box. - for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) { - Node *child = property_vbox->get_child(i); - if (child == reorder_selected_element_hbox) { - continue; // Don't remove the property that the user is moving. - } - child->queue_free(); // Button still needed after pressed is called. - property_vbox->remove_child(child); + for (int i = 0; i < page_length; i++) { + create_new_property_slot(); } } @@ -345,81 +373,46 @@ void EditorPropertyArray::update_property() { paginator->update(page_index, max_page); paginator->set_visible(max_page > 0); - int amount = MIN(size - offset, page_length); - for (int i = 0; i < amount; i++) { - bool reorder_is_from_current_page = reorder_from_index / page_length == page_index; - if (reorder_is_from_current_page && i == reorder_from_index % page_length) { - // Don't duplicate the property that the user is moving. - continue; - } - if (!reorder_is_from_current_page && i == reorder_to_index % page_length) { - // Don't create the property the moving property will take the place of, - // e.g. (if page_length == 20) don't create element 20 if dragging an item from - // the first page to the second page because element 20 would become element 19. + for (Slot &slot : slots) { + bool slot_visible = &slot != &reorder_slot && slot.index < size; + slot.container->set_visible(slot_visible); + // If not visible no need to update it + if (!slot_visible) { continue; } - HBoxContainer *hbox = memnew(HBoxContainer); - property_vbox->add_child(hbox); - - Button *reorder_button = memnew(Button); - reorder_button->set_icon(get_editor_theme_icon(SNAME("TripleBar"))); - reorder_button->set_default_cursor_shape(Control::CURSOR_MOVE); - reorder_button->set_disabled(is_read_only()); - reorder_button->connect("gui_input", callable_mp(this, &EditorPropertyArray::_reorder_button_gui_input)); - reorder_button->connect("button_down", callable_mp(this, &EditorPropertyArray::_reorder_button_down).bind(i + offset)); - reorder_button->connect("button_up", callable_mp(this, &EditorPropertyArray::_reorder_button_up)); - hbox->add_child(reorder_button); - - String prop_name = "indices/" + itos(i + offset); + int idx = slot.index; + Variant::Type value_type = subtype; - EditorProperty *prop = nullptr; - Variant value = array.get(i + offset); - Variant::Type value_type = value.get_type(); - - if (value_type == Variant::NIL && subtype != Variant::NIL) { - value_type = subtype; + if (value_type == Variant::NIL) { + value_type = array.get(idx).get_type(); } - if (value_type == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(value)) { - EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID); - editor->setup("Object"); - prop = editor; - } else { - prop = EditorInspector::instantiate_property_editor(nullptr, value_type, "", subtype_hint, subtype_hint_string, PROPERTY_USAGE_NONE); - } - - prop->set_object_and_property(object.ptr(), prop_name); - prop->set_label(itos(i + offset)); - prop->set_selectable(false); - prop->set_use_folding(is_using_folding()); - prop->connect("property_changed", callable_mp(this, &EditorPropertyArray::_property_changed)); - prop->connect("object_id_selected", callable_mp(this, &EditorPropertyArray::_object_id_selected)); - prop->set_h_size_flags(SIZE_EXPAND_FILL); - prop->set_read_only(is_read_only()); - hbox->add_child(prop); - - bool is_untyped_array = array.get_type() == Variant::ARRAY && subtype == Variant::NIL; - - if (is_untyped_array) { - Button *edit_btn = memnew(Button); - edit_btn->set_icon(get_editor_theme_icon(SNAME("Edit"))); - hbox->add_child(edit_btn); - edit_btn->set_disabled(is_read_only()); - edit_btn->connect("pressed", callable_mp(this, &EditorPropertyArray::_change_type).bind(edit_btn, i + offset)); - } else { - Button *remove_btn = memnew(Button); - remove_btn->set_icon(get_editor_theme_icon(SNAME("Remove"))); - remove_btn->set_disabled(is_read_only()); - remove_btn->connect("pressed", callable_mp(this, &EditorPropertyArray::_remove_pressed).bind(i + offset)); - hbox->add_child(remove_btn); + // Check if the editor property needs to be updated. + bool value_as_id = Object::cast_to<EncodedObjectAsID>(array.get(idx)); + if (value_type != slot.type || (value_type == Variant::OBJECT && (value_as_id != slot.as_id))) { + slot.as_id = value_as_id; + slot.type = value_type; + EditorProperty *new_prop = nullptr; + if (value_type == Variant::OBJECT && value_as_id) { + EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID); + editor->setup("Object"); + new_prop = editor; + } else { + new_prop = EditorInspector::instantiate_property_editor(nullptr, value_type, "", subtype_hint, subtype_hint_string, PROPERTY_USAGE_NONE); + } + new_prop->set_selectable(false); + new_prop->set_use_folding(is_using_folding()); + new_prop->connect(SNAME("property_changed"), callable_mp(this, &EditorPropertyArray::_property_changed)); + new_prop->connect(SNAME("object_id_selected"), callable_mp(this, &EditorPropertyArray::_object_id_selected)); + new_prop->set_h_size_flags(SIZE_EXPAND_FILL); + new_prop->set_read_only(is_read_only()); + callable_mp((Node *)slot.prop, &Node::add_sibling).call_deferred(new_prop, false); + callable_mp((Node *)slot.prop, &Node::queue_free).call_deferred(); + slot.prop = new_prop; + slot.set_index(idx); } - - prop->update_property(); - } - - if (reorder_to_index % page_length > 0) { - property_vbox->move_child(property_vbox->get_child(0), reorder_to_index % page_length); + slot.prop->update_property(); } updating = false; @@ -430,13 +423,14 @@ void EditorPropertyArray::update_property() { memdelete(container); button_add_item = nullptr; container = nullptr; + slots.clear(); } } } -void EditorPropertyArray::_remove_pressed(int p_index) { +void EditorPropertyArray::_remove_pressed(int p_slot_index) { Variant array = object->get_array().duplicate(); - array.call("remove_at", p_index); + array.call("remove_at", slots[p_slot_index].index); emit_changed(get_edited_property(), array, "", false); update_property(); @@ -468,7 +462,7 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const { Vector<String> files = drag_data["files"]; for (int i = 0; i < files.size(); i++) { - String file = files[i]; + const String &file = files[i]; String ftype = EditorFileSystem::get_singleton()->get_file_type(file); for (int j = 0; j < allowed_type.get_slice_count(","); j++) { @@ -510,7 +504,7 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d // Loop the file array and add to existing array. for (int i = 0; i < files.size(); i++) { - String file = files[i]; + const String &file = files[i]; Ref<Resource> res = ResourceLoader::load(file); if (res.is_valid()) { @@ -579,6 +573,27 @@ void EditorPropertyArray::_page_changed(int p_page) { return; } page_index = p_page; + int i = p_page * page_length; + + if (reorder_slot.index < 0) { + for (Slot &slot : slots) { + slot.set_index(i); + i++; + } + } else { + int reorder_from_page = reorder_slot.index / page_length; + if (reorder_from_page < p_page) { + i++; + } + for (Slot &slot : slots) { + if (slot.index != reorder_slot.index) { + slot.set_index(i); + i++; + } else if (i == reorder_slot.index) { + i++; + } + } + } update_property(); } @@ -620,7 +635,7 @@ void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint } void EditorPropertyArray::_reorder_button_gui_input(const Ref<InputEvent> &p_event) { - if (reorder_from_index < 0 || is_read_only()) { + if (reorder_slot.index < 0 || is_read_only()) { return; } @@ -645,26 +660,25 @@ void EditorPropertyArray::_reorder_button_gui_input(const Ref<InputEvent> &p_eve reorder_mouse_y_delta -= required_y_distance * direction; reorder_to_index += direction; + + property_vbox->move_child(reorder_slot.container, reorder_to_index % page_length); + if ((direction < 0 && reorder_to_index % page_length == page_length - 1) || (direction > 0 && reorder_to_index % page_length == 0)) { // Automatically move to the next/previous page. _page_changed(page_index + direction); } - property_vbox->move_child(reorder_selected_element_hbox, reorder_to_index % page_length); // Ensure the moving element is visible. - InspectorDock::get_inspector_singleton()->ensure_control_visible(reorder_selected_element_hbox); + InspectorDock::get_inspector_singleton()->ensure_control_visible(reorder_slot.container); } } } -void EditorPropertyArray::_reorder_button_down(int p_index) { +void EditorPropertyArray::_reorder_button_down(int p_slot_index) { if (is_read_only()) { return; } - - reorder_from_index = p_index; - reorder_to_index = p_index; - reorder_selected_element_hbox = Object::cast_to<HBoxContainer>(property_vbox->get_child(p_index % page_length)); - reorder_selected_button = Object::cast_to<Button>(reorder_selected_element_hbox->get_child(0)); + reorder_slot = slots[p_slot_index]; + reorder_to_index = reorder_slot.index; // Ideally it'd to be able to show the mouse but I had issues with // Control's `mouse_exit()`/`mouse_entered()` signals not getting called. Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); @@ -675,29 +689,27 @@ void EditorPropertyArray::_reorder_button_up() { return; } - if (reorder_from_index != reorder_to_index) { + if (reorder_slot.index != reorder_to_index) { // Move the element. Variant array = object->get_array().duplicate(); - Variant value_to_move = array.get(reorder_from_index); - array.call("remove_at", reorder_from_index); + property_vbox->move_child(reorder_slot.container, reorder_slot.index % page_length); + Variant value_to_move = array.get(reorder_slot.index); + array.call("remove_at", reorder_slot.index); array.call("insert", reorder_to_index, value_to_move); + reorder_slot.index = reorder_slot.index % page_length + page_index * page_length; emit_changed(get_edited_property(), array, "", false); - update_property(); } - reorder_from_index = -1; - reorder_to_index = -1; - reorder_mouse_y_delta = 0.0f; - Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); - ERR_FAIL_NULL(reorder_selected_button); - reorder_selected_button->warp_mouse(reorder_selected_button->get_size() / 2.0f); - - reorder_selected_element_hbox = nullptr; - reorder_selected_button = nullptr; + ERR_FAIL_NULL(reorder_slot.reorder_button); + reorder_slot.reorder_button->warp_mouse(reorder_slot.reorder_button->get_size() / 2.0f); + reorder_to_index = -1; + reorder_mouse_y_delta = 0.0f; + reorder_slot = Slot(); + _page_changed(page_index); } void EditorPropertyArray::_bind_methods() { diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index 2ca1931f85..f157da00c2 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -81,6 +81,23 @@ public: class EditorPropertyArray : public EditorProperty { GDCLASS(EditorPropertyArray, EditorProperty); + struct Slot { + Ref<EditorPropertyArrayObject> object; + HBoxContainer *container = nullptr; + int index = -1; + Variant::Type type = Variant::VARIANT_MAX; + bool as_id = false; + EditorProperty *prop = nullptr; + Button *reorder_button = nullptr; + + void set_index(int p_idx) { + String prop_name = "indices/" + itos(p_idx); + prop->set_object_and_property(object.ptr(), prop_name); + prop->set_label(itos(p_idx)); + index = p_idx; + } + }; + PopupMenu *change_type = nullptr; int page_length = 20; @@ -96,13 +113,11 @@ class EditorPropertyArray : public EditorProperty { Variant::Type subtype; PropertyHint subtype_hint; String subtype_hint_string; + LocalVector<Slot> slots; - int reorder_from_index = -1; + Slot reorder_slot; int reorder_to_index = -1; float reorder_mouse_y_delta = 0.0f; - HBoxContainer *reorder_selected_element_hbox = nullptr; - Button *reorder_selected_button = nullptr; - void initialize_array(Variant &p_array); void _page_changed(int p_page); @@ -110,6 +125,7 @@ class EditorPropertyArray : public EditorProperty { void _reorder_button_gui_input(const Ref<InputEvent> &p_event); void _reorder_button_down(int p_index); void _reorder_button_up(); + void create_new_property_slot(); protected: Ref<EditorPropertyArrayObject> object; @@ -124,7 +140,7 @@ protected: virtual void _length_changed(double p_page); virtual void _edit_pressed(); virtual void _property_changed(const String &p_property, Variant p_value, const String &p_name = "", bool p_changing = false); - virtual void _change_type(Object *p_button, int p_index); + virtual void _change_type(Object *p_button, int p_slot_index); virtual void _change_type_menu(int p_index); virtual void _object_id_selected(const StringName &p_property, ObjectID p_id); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index ed20e50685..011cb26621 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -675,7 +675,7 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const { return false; } -bool EditorResourcePicker::_is_type_valid(const String p_type_name, HashSet<StringName> p_allowed_types) const { +bool EditorResourcePicker::_is_type_valid(const String p_type_name, const HashSet<StringName> &p_allowed_types) const { for (const StringName &E : p_allowed_types) { String at = E; if (p_type_name == at || ClassDB::is_parent_class(p_type_name, at) || EditorNode::get_editor_data().script_class_is_parent(p_type_name, at)) { diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h index 35703bcbeb..fb54455e89 100644 --- a/editor/editor_resource_picker.h +++ b/editor/editor_resource_picker.h @@ -99,7 +99,7 @@ class EditorResourcePicker : public HBoxContainer { String _get_resource_type(const Ref<Resource> &p_resource) const; void _get_allowed_types(bool p_with_convert, HashSet<StringName> *p_vector) const; bool _is_drop_valid(const Dictionary &p_drag_data) const; - bool _is_type_valid(const String p_type_name, HashSet<StringName> p_allowed_types) const; + bool _is_type_valid(const String p_type_name, const HashSet<StringName> &p_allowed_types) const; Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index b3340dffc1..f21f0ac216 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -34,7 +34,6 @@ #include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/object/message_queue.h" #include "core/variant/variant_utility.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" @@ -123,7 +122,7 @@ void EditorResourcePreview::_preview_ready(const String &p_path, int p_hash, con cache[p_path] = item; } - MessageQueue::get_singleton()->push_call(id, p_func, p_path, p_texture, p_small_texture, p_ud); + Callable(id, p_func).call_deferred(p_path, p_texture, p_small_texture, p_ud); } void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<ImageTexture> &r_small_texture, const QueueItem &p_item, const String &cache_base, Dictionary &p_metadata) { diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index a5e70c5b6c..33a176499d 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -92,9 +92,6 @@ void EditorSettingsDialog::popup_edit_settings() { inspector->edit(EditorSettings::get_singleton()); inspector->get_inspector()->update_tree(); - search_box->select_all(); - search_box->grab_focus(); - _update_shortcuts(); set_process_shortcut_input(true); @@ -762,7 +759,7 @@ EditorSettingsDialog::EditorSettingsDialog() { tab_shortcuts->add_child(top_hbox); shortcut_search_box = memnew(LineEdit); - shortcut_search_box->set_placeholder(TTR("Filter by name...")); + shortcut_search_box->set_placeholder(TTR("Filter by Name")); shortcut_search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); top_hbox->add_child(shortcut_search_box); shortcut_search_box->connect("text_changed", callable_mp(this, &EditorSettingsDialog::_filter_shortcuts)); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index ef68554a3d..da5eecfb73 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -2176,6 +2176,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_icon("shape_rect_wheel", "ColorPicker", theme->get_icon(SNAME("PickerShapeRectangleWheel"), EditorStringName(EditorIcons))); theme->set_icon("add_preset", "ColorPicker", theme->get_icon(SNAME("Add"), EditorStringName(EditorIcons))); theme->set_icon("sample_bg", "ColorPicker", theme->get_icon(SNAME("GuiMiniCheckerboard"), EditorStringName(EditorIcons))); + theme->set_icon("sample_revert", "ColorPicker", theme->get_icon(SNAME("Reload"), EditorStringName(EditorIcons))); theme->set_icon("overbright_indicator", "ColorPicker", theme->get_icon(SNAME("OverbrightIndicator"), EditorStringName(EditorIcons))); theme->set_icon("bar_arrow", "ColorPicker", theme->get_icon(SNAME("ColorPickerBarArrow"), EditorStringName(EditorIcons))); theme->set_icon("picker_cursor", "ColorPicker", theme->get_icon(SNAME("PickerCursor"), EditorStringName(EditorIcons))); diff --git a/editor/event_listener_line_edit.cpp b/editor/event_listener_line_edit.cpp index e51808c78c..2c46e1c20a 100644 --- a/editor/event_listener_line_edit.cpp +++ b/editor/event_listener_line_edit.cpp @@ -175,12 +175,12 @@ void EventListenerLineEdit::_on_text_changed(const String &p_text) { } void EventListenerLineEdit::_on_focus() { - set_placeholder(TTR("Listening for input...")); + set_placeholder(TTR("Listening for Input")); } void EventListenerLineEdit::_on_unfocus() { ignore_next_event = true; - set_placeholder(TTR("Filter by event...")); + set_placeholder(TTR("Filter by Event")); } Ref<InputEvent> EventListenerLineEdit::get_event() const { @@ -227,5 +227,5 @@ void EventListenerLineEdit::_bind_methods() { EventListenerLineEdit::EventListenerLineEdit() { set_caret_blink_enabled(false); - set_placeholder(TTR("Filter by event...")); + set_placeholder(TTR("Filter by Event")); } diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index ab2ada9ae4..855d610d72 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -456,7 +456,7 @@ void EditorExportPlatform::_edit_files_with_filter(Ref<DirAccess> &da, const Vec da->list_dir_end(); for (int i = 0; i < dirs.size(); ++i) { - String dir = dirs[i]; + const String &dir = dirs[i]; if (dir.begins_with(".")) { continue; } @@ -547,8 +547,10 @@ EditorExportPlatform::ExportNotifier::~ExportNotifier() { for (int i = 0; i < export_plugins.size(); i++) { if (GDVIRTUAL_IS_OVERRIDDEN_PTR(export_plugins[i], _export_end)) { export_plugins.write[i]->_export_end_script(); + } else { + export_plugins.write[i]->_export_end(); } - export_plugins.write[i]->_export_end(); + export_plugins.write[i]->_export_end_clear(); export_plugins.write[i]->set_export_preset(Ref<EditorExportPlugin>()); } } @@ -899,7 +901,7 @@ Vector<String> EditorExportPlatform::get_forced_export_files() { if (FileAccess::exists(abs_path)) { files.push_back(ts_data); // Remove the file later. - MessageQueue::get_singleton()->push_callable(callable_mp_static(DirAccess::remove_absolute), abs_path); + callable_mp_static(DirAccess::remove_absolute).call_deferred(abs_path); } } } @@ -1096,7 +1098,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & Vector<String> fields = l.split("::"); if (fields.size() == 4) { FileExportCache fec; - String path = fields[0]; + const String &path = fields[0]; fec.source_md5 = fields[1].strip_edges(); fec.source_modified_time = fields[2].strip_edges().to_int(); fec.saved_path = fields[3]; @@ -1364,8 +1366,8 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & if (path_remaps.size()) { if (true) { //new remap mode, use always as it's friendlier with multiple .pck exports for (int i = 0; i < path_remaps.size(); i += 2) { - String from = path_remaps[i]; - String to = path_remaps[i + 1]; + const String &from = path_remaps[i]; + const String &to = path_remaps[i + 1]; String remap_file = "[remap]\n\npath=\"" + to.c_escape() + "\"\n"; CharString utf8 = remap_file.utf8(); Vector<uint8_t> new_file; diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp index 6576960b9a..ec8c8c7b69 100644 --- a/editor/export/editor_export_plugin.cpp +++ b/editor/export/editor_export_plugin.cpp @@ -291,6 +291,8 @@ void EditorExportPlugin::_export_file(const String &p_path, const String &p_type void EditorExportPlugin::_export_begin(const HashSet<String> &p_features, bool p_debug, const String &p_path, int p_flags) { } +void EditorExportPlugin::_export_end() {} + void EditorExportPlugin::skip() { skipped = true; } diff --git a/editor/export/editor_export_plugin.h b/editor/export/editor_export_plugin.h index 7d866ce37e..fe97d2e04f 100644 --- a/editor/export/editor_export_plugin.h +++ b/editor/export/editor_export_plugin.h @@ -71,7 +71,7 @@ class EditorExportPlugin : public RefCounted { skipped = false; } - _FORCE_INLINE_ void _export_end() { + _FORCE_INLINE_ void _export_end_clear() { ios_frameworks.clear(); ios_embedded_frameworks.clear(); ios_bundle_files.clear(); @@ -108,6 +108,7 @@ protected: virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features); virtual void _export_begin(const HashSet<String> &p_features, bool p_debug, const String &p_path, int p_flags); + virtual void _export_end(); static void _bind_methods(); diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index f2c5eeb2ed..4c0efde4c5 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -1191,6 +1191,7 @@ ProjectExportDialog::ProjectExportDialog() { preset_vb->add_child(mc); mc->set_v_size_flags(Control::SIZE_EXPAND_FILL); presets = memnew(ItemList); + presets->set_auto_translate(false); SET_DRAG_FORWARDING_GCD(presets, ProjectExportDialog); mc->add_child(presets); presets->connect("item_selected", callable_mp(this, &ProjectExportDialog::_edit_preset)); @@ -1276,6 +1277,7 @@ ProjectExportDialog::ProjectExportDialog() { server_strip_message = memnew(Label); server_strip_message->set_visible(false); server_strip_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + server_strip_message->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); resources_vb->add_child(server_strip_message); { @@ -1283,7 +1285,7 @@ ProjectExportDialog::ProjectExportDialog() { ClassDB::get_inheriters_from_class("Resource", &resource_names); PackedStringArray strippable; - for (StringName resource_name : resource_names) { + for (const StringName &resource_name : resource_names) { if (ClassDB::has_method(resource_name, "create_placeholder", true)) { strippable.push_back(resource_name); } diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index e5d03942e3..4e94ff1129 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -47,7 +47,7 @@ #include "editor/editor_string_names.h" #include "editor/gui/editor_dir_dialog.h" #include "editor/gui/editor_scene_tabs.h" -#include "editor/import/scene_import_settings.h" +#include "editor/import/3d/scene_import_settings.h" #include "editor/import_dock.h" #include "editor/plugins/editor_resource_tooltip_plugins.h" #include "editor/scene_create_dialog.h" @@ -388,7 +388,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo const Color default_folder_color = get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog")); for (int i = 0; i < favorite_paths.size(); i++) { - String favorite = favorite_paths[i]; + const String &favorite = favorite_paths[i]; if (!favorite.begins_with("res://")) { continue; } @@ -470,8 +470,6 @@ void FileSystemDock::_update_display_mode(bool p_force) { case DISPLAY_MODE_HSPLIT: case DISPLAY_MODE_VSPLIT: const bool is_vertical = display_mode == DISPLAY_MODE_VSPLIT; - const int split_offset = split_box->get_split_offset(); - is_vertical ? split_box_offset_h = split_offset : split_box_offset_v = split_offset; split_box->set_vertical(is_vertical); const int actual_offset = is_vertical ? split_box_offset_v : split_box_offset_h; @@ -653,7 +651,7 @@ void FileSystemDock::_notification(int p_what) { void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_selected) { // Update the import dock. import_dock_needs_update = true; - call_deferred(SNAME("_update_import_dock")); + callable_mp(this, &FileSystemDock::_update_import_dock).call_deferred(); // Return if we don't select something new. if (!p_selected) { @@ -1883,10 +1881,6 @@ Vector<String> FileSystemDock::_check_existing() { return conflicting_items; } -void FileSystemDock::_move_dialog_confirm(const String &p_path) { - _move_operation_confirm(p_path, move_dialog->is_copy_pressed()); -} - void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_copy, Overwrite p_overwrite) { if (p_overwrite == OVERWRITE_UNDECIDED) { to_move_path = p_to_path; @@ -2301,7 +2295,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected // Instantiate all selected scenes. Vector<String> paths; for (int i = 0; i < p_selected.size(); i++) { - String fpath = p_selected[i]; + const String &fpath = p_selected[i]; if (EditorFileSystem::get_singleton()->get_file_type(fpath) == "PackedScene") { paths.push_back(fpath); } @@ -2339,7 +2333,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected case FILE_DEPENDENCIES: { // Checkout the file dependencies. if (!p_selected.is_empty()) { - String fpath = p_selected[0]; + const String &fpath = p_selected[0]; deps_editor->edit(fpath); } } break; @@ -2347,7 +2341,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected case FILE_OWNERS: { // Checkout the file owners. if (!p_selected.is_empty()) { - String fpath = p_selected[0]; + const String &fpath = p_selected[0]; owners_editor->show(fpath); } } break; @@ -2357,12 +2351,13 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected to_move.clear(); Vector<String> collapsed_paths = _remove_self_included_paths(p_selected); for (int i = collapsed_paths.size() - 1; i >= 0; i--) { - String fpath = collapsed_paths[i]; + const String &fpath = collapsed_paths[i]; if (fpath != "res://") { to_move.push_back(FileOrFolder(fpath, !fpath.ends_with("/"))); } } if (to_move.size() > 0) { + move_dialog->config(p_selected); move_dialog->popup_centered_ratio(0.4); } } break; @@ -2404,7 +2399,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected Vector<String> collapsed_paths = _remove_self_included_paths(p_selected); for (int i = 0; i < collapsed_paths.size(); i++) { - String fpath = collapsed_paths[i]; + const String &fpath = collapsed_paths[i]; if (fpath != "res://") { if (fpath.ends_with("/")) { remove_folders.push_back(fpath); @@ -2476,7 +2471,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected case FILE_COPY_PATH: { if (!p_selected.is_empty()) { - String fpath = p_selected[0]; + const String &fpath = p_selected[0]; DisplayServer::get_singleton()->clipboard_set(fpath); } } break; @@ -2588,6 +2583,14 @@ void FileSystemDock::_change_split_mode() { emit_signal(SNAME("display_mode_changed")); } +void FileSystemDock::_split_dragged(int p_offset) { + if (split_box->is_vertical()) { + split_box_offset_v = p_offset; + } else { + split_box_offset_h = p_offset; + } +} + void FileSystemDock::fix_dependencies(const String &p_for_file) { deps_editor->edit(p_for_file); } @@ -2988,7 +2991,7 @@ void FileSystemDock::_folder_color_index_pressed(int p_index, PopupMenu *p_menu) // Update project settings with new folder colors. for (int i = 0; i < selected.size(); i++) { - String fpath = selected[i]; + const String &fpath = selected[i]; if (chosen_color_name) { assigned_folder_colors[fpath] = chosen_color_name; @@ -3019,7 +3022,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str bool all_not_favorites = true; for (int i = 0; i < p_paths.size(); i++) { - String fpath = p_paths[i]; + const String &fpath = p_paths[i]; if (fpath.ends_with("/")) { foldernames.push_back(fpath); all_files = false; @@ -3177,7 +3180,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str } if (p_paths.size() == 1) { - const String fpath = p_paths[0]; + const String &fpath = p_paths[0]; #if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED) p_popup->add_separator(); @@ -3326,7 +3329,7 @@ void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) { // Update the import dock. import_dock_needs_update = true; - call_deferred(SNAME("_update_import_dock")); + callable_mp(this, &FileSystemDock::_update_import_dock).call_deferred(); } void FileSystemDock::_tree_mouse_exited() { @@ -3562,7 +3565,7 @@ void FileSystemDock::_update_import_dock() { Vector<String> imports; String import_type; for (int i = 0; i < efiles.size(); i++) { - String fpath = efiles[i]; + const String &fpath = efiles[i]; Ref<ConfigFile> cf; cf.instantiate(); Error err = cf->load(fpath + ".import"); @@ -3642,16 +3645,11 @@ MenuButton *FileSystemDock::_create_file_menu_button() { } void FileSystemDock::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update_tree"), &FileSystemDock::_update_tree); - ClassDB::bind_method(D_METHOD("_file_list_thumbnail_done"), &FileSystemDock::_file_list_thumbnail_done); ClassDB::bind_method(D_METHOD("_tree_thumbnail_done"), &FileSystemDock::_tree_thumbnail_done); - ClassDB::bind_method(D_METHOD("_select_file"), &FileSystemDock::_select_file); ClassDB::bind_method(D_METHOD("navigate_to_path", "path"), &FileSystemDock::navigate_to_path); - ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock); - ClassDB::bind_method(D_METHOD("add_resource_tooltip_plugin", "plugin"), &FileSystemDock::add_resource_tooltip_plugin); ClassDB::bind_method(D_METHOD("remove_resource_tooltip_plugin", "plugin"), &FileSystemDock::remove_resource_tooltip_plugin); @@ -3767,6 +3765,8 @@ FileSystemDock::FileSystemDock() { split_box = memnew(SplitContainer); split_box->set_v_size_flags(SIZE_EXPAND_FILL); + split_box->connect("dragged", callable_mp(this, &FileSystemDock::_split_dragged)); + split_box_offset_h = 240 * EDSCALE; add_child(split_box); tree = memnew(FileSystemTree); @@ -3847,7 +3847,8 @@ FileSystemDock::FileSystemDock() { move_dialog = memnew(EditorDirDialog); add_child(move_dialog); - move_dialog->connect("dir_selected", callable_mp(this, &FileSystemDock::_move_dialog_confirm)); + move_dialog->connect("move_pressed", callable_mp(this, &FileSystemDock::_move_operation_confirm).bind(false, OVERWRITE_UNDECIDED)); + move_dialog->connect("copy_pressed", callable_mp(this, &FileSystemDock::_move_operation_confirm).bind(true, OVERWRITE_UNDECIDED)); overwrite_dialog = memnew(ConfirmationDialog); add_child(overwrite_dialog); @@ -3884,7 +3885,7 @@ FileSystemDock::FileSystemDock() { make_dir_dialog = memnew(DirectoryCreateDialog); add_child(make_dir_dialog); - make_dir_dialog->connect("dir_created", callable_mp(this, &FileSystemDock::_rescan)); + make_dir_dialog->connect("dir_created", callable_mp(this, &FileSystemDock::_rescan).unbind(1)); make_scene_dialog = memnew(SceneCreateDialog); add_child(make_scene_dialog); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index d7203c15bd..5fe1389e2a 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -102,6 +102,12 @@ public: FILE_SORT_MAX, }; + enum Overwrite { + OVERWRITE_UNDECIDED, + OVERWRITE_REPLACE, + OVERWRITE_RENAME, + }; + private: enum FileMenu { FILE_OPEN, @@ -133,12 +139,6 @@ private: FILE_NEW_SCENE, }; - enum Overwrite { - OVERWRITE_UNDECIDED, - OVERWRITE_REPLACE, - OVERWRITE_RENAME, - }; - HashMap<String, Color> folder_colors; Dictionary assigned_folder_colors; @@ -290,7 +290,6 @@ private: void _duplicate_operation_confirm(); void _overwrite_dialog_action(bool p_overwrite); Vector<String> _check_existing(); - void _move_dialog_confirm(const String &p_path); void _move_operation_confirm(const String &p_to_path, bool p_copy = false, Overwrite p_overwrite = OVERWRITE_UNDECIDED); void _tree_rmb_option(int p_option); @@ -306,6 +305,7 @@ private: void _rescan(); void _change_split_mode(); + void _split_dragged(int p_offset); void _search_changed(const String &p_text, const Control *p_from); @@ -387,8 +387,10 @@ public: void fix_dependencies(const String &p_for_file); - int get_split_offset() { return split_box->get_split_offset(); } - void set_split_offset(int p_offset) { split_box->set_split_offset(p_offset); } + int get_h_split_offset() const { return split_box_offset_h; } + void set_h_split_offset(int p_offset) { split_box_offset_h = p_offset; } + int get_v_split_offset() const { return split_box_offset_v; } + void set_v_split_offset(int p_offset) { split_box_offset_v = p_offset; } void select_file(const String &p_file); void set_display_mode(DisplayMode p_display_mode); @@ -410,4 +412,6 @@ public: ~FileSystemDock(); }; +VARIANT_ENUM_CAST(FileSystemDock::Overwrite); + #endif // FILESYSTEM_DOCK_H diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index a14df01858..a81aa971f3 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -172,9 +172,11 @@ void FindInFiles::_iterate() { _current_dir = _current_dir.path_join(folder_name); PackedStringArray sub_dirs; - _scan_dir("res://" + _current_dir, sub_dirs); + PackedStringArray files_to_scan; + _scan_dir("res://" + _current_dir, sub_dirs, files_to_scan); _folders_stack.push_back(sub_dirs); + _files_to_scan.append_array(files_to_scan); } else { // Go back one level. @@ -211,7 +213,7 @@ float FindInFiles::get_progress() const { return 0; } -void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) { +void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders, PackedStringArray &out_files_to_scan) { Ref<DirAccess> dir = DirAccess::open(path); if (dir.is_null()) { print_verbose("Cannot open directory! " + path); @@ -227,8 +229,11 @@ void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) { break; } - // If there is a .gdignore file in the directory, skip searching the directory. + // If there is a .gdignore file in the directory, clear all the files/folders + // to be searched on this path and skip searching the directory. if (file == ".gdignore") { + out_folders.clear(); + out_files_to_scan.clear(); break; } @@ -247,7 +252,7 @@ void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) { } else { String file_ext = file.get_extension(); if (_extension_filter.has(file_ext)) { - _files_to_scan.push_back(path.path_join(file)); + out_files_to_scan.push_back(path.path_join(file)); } } } @@ -460,7 +465,7 @@ void FindInFilesDialog::_notification(int p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { if (is_visible()) { // Doesn't work more than once if not deferred... - _search_text_line_edit->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)_search_text_line_edit, &Control::grab_focus).call_deferred(); _search_text_line_edit->select_all(); // Extensions might have changed in the meantime, we clean them and instance them again. for (int i = 0; i < _filters_container->get_child_count(); i++) { diff --git a/editor/find_in_files.h b/editor/find_in_files.h index 25ce2b0415..fcf5dd6281 100644 --- a/editor/find_in_files.h +++ b/editor/find_in_files.h @@ -67,7 +67,7 @@ protected: private: void _process(); void _iterate(); - void _scan_dir(String path, PackedStringArray &out_folders); + void _scan_dir(String path, PackedStringArray &out_folders, PackedStringArray &out_files_to_scan); void _scan_file(String fpath); // Config diff --git a/editor/group_settings_editor.cpp b/editor/group_settings_editor.cpp index a91154ae36..42e117f4c1 100644 --- a/editor/group_settings_editor.cpp +++ b/editor/group_settings_editor.cpp @@ -45,6 +45,9 @@ void GroupSettingsEditor::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { update_groups(); } break; + case NOTIFICATION_THEME_CHANGED: { + add_button->set_icon(get_editor_theme_icon(SNAME("Add"))); + } break; } } diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index 9fa9fe5a9d..77a867f34b 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -274,20 +274,22 @@ void GroupsEditor::_update_groups_and_tree() { _update_tree(); } -void GroupsEditor::_update_scene_groups(Node *p_node) { - if (scene_groups_cache.has(p_node)) { - scene_groups = scene_groups_cache[p_node]; - scene_groups_cache.erase(p_node); +void GroupsEditor::_update_scene_groups(const ObjectID &p_id) { + HashMap<ObjectID, HashMap<StringName, bool>>::Iterator I = scene_groups_cache.find(p_id); + if (I) { + scene_groups = I->value; + scene_groups_cache.remove(I); } else { scene_groups = HashMap<StringName, bool>(); } } -void GroupsEditor::_cache_scene_groups(Node *p_node) { +void GroupsEditor::_cache_scene_groups(const ObjectID &p_id) { const int edited_scene_count = EditorNode::get_editor_data().get_edited_scene_count(); for (int i = 0; i < edited_scene_count; i++) { - if (p_node == EditorNode::get_editor_data().get_edited_scene_root(i)) { - scene_groups_cache[p_node] = scene_groups_for_caching; + Node *edited_scene_root = EditorNode::get_editor_data().get_edited_scene_root(i); + if (edited_scene_root && p_id == edited_scene_root->get_instance_id()) { + scene_groups_cache[p_id] = scene_groups_for_caching; break; } } @@ -305,7 +307,7 @@ void GroupsEditor::set_current(Node *p_node) { if (scene_tree->get_edited_scene_root() != scene_root_node) { scene_root_node = scene_tree->get_edited_scene_root(); - _update_scene_groups(scene_root_node); + _update_scene_groups(scene_root_node->get_instance_id()); _update_groups(); } @@ -803,7 +805,7 @@ void GroupsEditor::_bind_methods() { void GroupsEditor::_node_removed(Node *p_node) { if (scene_root_node == p_node) { scene_groups_for_caching = scene_groups; - callable_mp(this, &GroupsEditor::_cache_scene_groups).call_deferred(p_node); + callable_mp(this, &GroupsEditor::_cache_scene_groups).call_deferred(p_node->get_instance_id()); scene_root_node = nullptr; } diff --git a/editor/groups_editor.h b/editor/groups_editor.h index cf74470b1b..8a0ca067de 100644 --- a/editor/groups_editor.h +++ b/editor/groups_editor.h @@ -78,14 +78,14 @@ class GroupsEditor : public VBoxContainer { Button *add = nullptr; Tree *tree = nullptr; - HashMap<Node *, HashMap<StringName, bool>> scene_groups_cache; + HashMap<ObjectID, HashMap<StringName, bool>> scene_groups_cache; HashMap<StringName, bool> scene_groups_for_caching; HashMap<StringName, bool> scene_groups; HashMap<StringName, String> global_groups; - void _update_scene_groups(Node *p_node); - void _cache_scene_groups(Node *p_node); + void _update_scene_groups(const ObjectID &p_id); + void _cache_scene_groups(const ObjectID &p_id); void _show_add_group_dialog(); void _show_rename_group_dialog(); diff --git a/editor/gui/editor_dir_dialog.cpp b/editor/gui/editor_dir_dialog.cpp index fada434a03..8821a0eeae 100644 --- a/editor/gui/editor_dir_dialog.cpp +++ b/editor/gui/editor_dir_dialog.cpp @@ -30,22 +30,18 @@ #include "editor_dir_dialog.h" -#include "core/io/dir_access.h" -#include "core/os/keyboard.h" -#include "core/os/os.h" +#include "editor/directory_create_dialog.h" #include "editor/editor_file_system.h" -#include "editor/editor_scale.h" -#include "editor/editor_settings.h" -#include "scene/gui/check_box.h" +#include "scene/gui/box_container.h" #include "scene/gui/tree.h" #include "servers/display_server.h" void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p_dir, const String &p_select_path) { updating = true; - String path = p_dir->get_path(); + const String path = p_dir->get_path(); - p_item->set_metadata(0, p_dir->get_path()); + p_item->set_metadata(0, path); p_item->set_icon(0, tree->get_editor_theme_icon(SNAME("Folder"))); p_item->set_icon_modulate(0, tree->get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog"))); @@ -59,6 +55,10 @@ void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p p_item->set_text(0, p_dir->get_name()); } + if (path == new_dir_path || !p_item->get_parent()) { + p_item->select(0); + } + updating = false; for (int i = 0; i < p_dir->get_subdir_count(); i++) { TreeItem *ti = tree->create_item(p_item); @@ -66,6 +66,22 @@ void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p } } +void EditorDirDialog::config(const Vector<String> &p_paths) { + ERR_FAIL_COND(p_paths.is_empty()); + + if (p_paths.size() == 1) { + String path = p_paths[0]; + if (path.ends_with("/")) { + path = path.substr(0, path.length() - 1); + } + // TRANSLATORS: %s is the file name that will be moved or duplicated. + set_title(vformat(TTR("Move/Duplicate: %s"), path.get_file())); + } else { + // TRANSLATORS: %d is the number of files that will be moved or duplicated. + set_title(vformat(TTRN("Move/Duplicate %d Item", "Move/Duplicate %d Items", p_paths.size()), p_paths.size())); + } +} + void EditorDirDialog::reload(const String &p_path) { if (!is_visible()) { must_reload = true; @@ -76,13 +92,10 @@ void EditorDirDialog::reload(const String &p_path) { TreeItem *root = tree->create_item(); _update_dir(root, EditorFileSystem::get_singleton()->get_filesystem(), p_path); _item_collapsed(root); + new_dir_path.clear(); must_reload = false; } -bool EditorDirDialog::is_copy_pressed() const { - return copy->is_pressed(); -} - void EditorDirDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -112,14 +125,6 @@ void EditorDirDialog::_notification(int p_what) { } } -void EditorDirDialog::_copy_toggled(bool p_pressed) { - if (p_pressed) { - set_ok_button_text(TTR("Copy")); - } else { - set_ok_button_text(TTR("Move")); - } -} - void EditorDirDialog::_item_collapsed(Object *p_item) { TreeItem *item = Object::cast_to<TreeItem>(p_item); @@ -135,100 +140,83 @@ void EditorDirDialog::_item_collapsed(Object *p_item) { } void EditorDirDialog::_item_activated() { - _ok_pressed(); // From AcceptDialog. + TreeItem *ti = tree->get_selected(); + ERR_FAIL_NULL(ti); + if (ti->get_child_count() > 0) { + ti->set_collapsed(!ti->is_collapsed()); + } } -void EditorDirDialog::ok_pressed() { +void EditorDirDialog::_copy_pressed() { TreeItem *ti = tree->get_selected(); - if (!ti) { - return; - } + ERR_FAIL_NULL(ti); - String dir = ti->get_metadata(0); - emit_signal(SNAME("dir_selected"), dir); hide(); + emit_signal(SNAME("copy_pressed"), ti->get_metadata(0)); } -void EditorDirDialog::_make_dir() { +void EditorDirDialog::ok_pressed() { TreeItem *ti = tree->get_selected(); - if (!ti) { - mkdirerr->set_text(TTR("Please select a base directory first.")); - mkdirerr->popup_centered(); - return; - } + ERR_FAIL_NULL(ti); - makedialog->popup_centered(Size2(250, 80)); - makedirname->grab_focus(); + hide(); + emit_signal(SNAME("move_pressed"), ti->get_metadata(0)); } -void EditorDirDialog::_make_dir_confirm() { +void EditorDirDialog::_make_dir() { TreeItem *ti = tree->get_selected(); - if (!ti) { - return; - } - - String dir = ti->get_metadata(0); - - Ref<DirAccess> d = DirAccess::open(dir); - ERR_FAIL_COND_MSG(d.is_null(), "Cannot open directory '" + dir + "'."); - - const String stripped_dirname = makedirname->get_text().strip_edges(); + ERR_FAIL_NULL(ti); + makedialog->config(ti->get_metadata(0)); + makedialog->popup_centered(); +} - if (d->dir_exists(stripped_dirname)) { - mkdirerr->set_text(TTR("Could not create folder. File with that name already exists.")); - mkdirerr->popup_centered(); - return; +void EditorDirDialog::_make_dir_confirm(const String &p_path) { + // Multiple level of directories can be created at once. + String base_dir = p_path.get_base_dir(); + while (true) { + opened_paths.insert(base_dir + "/"); + if (base_dir == "res://") { + break; + } + base_dir = base_dir.get_base_dir(); } - Error err = d->make_dir(stripped_dirname); - if (err != OK) { - mkdirerr->popup_centered(Size2(250, 80) * EDSCALE); - } else { - opened_paths.insert(dir); - EditorFileSystem::get_singleton()->scan_changes(); // We created a dir, so rescan changes. - } - makedirname->set_text(""); // reset label + new_dir_path = p_path + "/"; + EditorFileSystem::get_singleton()->scan_changes(); // We created a dir, so rescan changes. } void EditorDirDialog::_bind_methods() { - ADD_SIGNAL(MethodInfo("dir_selected", PropertyInfo(Variant::STRING, "dir"))); + ADD_SIGNAL(MethodInfo("copy_pressed", PropertyInfo(Variant::STRING, "dir"))); + ADD_SIGNAL(MethodInfo("move_pressed", PropertyInfo(Variant::STRING, "dir"))); } EditorDirDialog::EditorDirDialog() { - set_title(TTR("Choose a Directory")); set_hide_on_ok(false); VBoxContainer *vb = memnew(VBoxContainer); add_child(vb); + HBoxContainer *hb = memnew(HBoxContainer); + vb->add_child(hb); + + hb->add_child(memnew(Label(TTR("Choose target directory:")))); + hb->add_spacer(); + + makedir = memnew(Button(TTR("Create Folder"))); + hb->add_child(makedir); + makedir->connect("pressed", callable_mp(this, &EditorDirDialog::_make_dir)); + tree = memnew(Tree); vb->add_child(tree); tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); tree->connect("item_activated", callable_mp(this, &EditorDirDialog::_item_activated)); - copy = memnew(CheckBox); - vb->add_child(copy); - copy->set_text(TTR("Copy File(s)")); - copy->connect("toggled", callable_mp(this, &EditorDirDialog::_copy_toggled)); + set_ok_button_text(TTR("Move")); - makedir = add_button(TTR("Create Folder"), DisplayServer::get_singleton()->get_swap_cancel_ok(), "makedir"); - makedir->connect("pressed", callable_mp(this, &EditorDirDialog::_make_dir)); + copy = add_button(TTR("Copy"), !DisplayServer::get_singleton()->get_swap_cancel_ok()); + copy->connect("pressed", callable_mp(this, &EditorDirDialog::_copy_pressed)); - makedialog = memnew(ConfirmationDialog); - makedialog->set_title(TTR("Create Folder")); + makedialog = memnew(DirectoryCreateDialog); add_child(makedialog); - - VBoxContainer *makevb = memnew(VBoxContainer); - makedialog->add_child(makevb); - - makedirname = memnew(LineEdit); - makevb->add_margin_child(TTR("Name:"), makedirname); - makedialog->register_text_enter(makedirname); - makedialog->connect("confirmed", callable_mp(this, &EditorDirDialog::_make_dir_confirm)); - - mkdirerr = memnew(AcceptDialog); - mkdirerr->set_text(TTR("Could not create folder.")); - add_child(mkdirerr); - - set_ok_button_text(TTR("Move")); + makedialog->connect("dir_created", callable_mp(this, &EditorDirDialog::_make_dir_confirm)); } diff --git a/editor/gui/editor_dir_dialog.h b/editor/gui/editor_dir_dialog.h index 9f2b48c164..40badec212 100644 --- a/editor/gui/editor_dir_dialog.h +++ b/editor/gui/editor_dir_dialog.h @@ -33,7 +33,7 @@ #include "scene/gui/dialogs.h" -class CheckBox; +class DirectoryCreateDialog; class EditorFileSystemDirectory; class Tree; class TreeItem; @@ -41,25 +41,24 @@ class TreeItem; class EditorDirDialog : public ConfirmationDialog { GDCLASS(EditorDirDialog, ConfirmationDialog); - ConfirmationDialog *makedialog = nullptr; - LineEdit *makedirname = nullptr; - AcceptDialog *mkdirerr = nullptr; + DirectoryCreateDialog *makedialog = nullptr; Button *makedir = nullptr; + Button *copy = nullptr; HashSet<String> opened_paths; + String new_dir_path; Tree *tree = nullptr; bool updating = false; - CheckBox *copy = nullptr; - void _copy_toggled(bool p_pressed); void _item_collapsed(Object *p_item); void _item_activated(); void _update_dir(TreeItem *p_item, EditorFileSystemDirectory *p_dir, const String &p_select_path = String()); void _make_dir(); - void _make_dir_confirm(); + void _make_dir_confirm(const String &p_path); + void _copy_pressed(); void ok_pressed() override; bool must_reload = false; @@ -69,8 +68,8 @@ protected: static void _bind_methods(); public: + void config(const Vector<String> &p_paths); void reload(const String &p_path = ""); - bool is_copy_pressed() const; EditorDirDialog(); }; diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp index fad7e29be7..9764574d04 100644 --- a/editor/gui/editor_file_dialog.cpp +++ b/editor/gui/editor_file_dialog.cpp @@ -1909,6 +1909,7 @@ EditorFileDialog::EditorFileDialog() { fav_down->connect("pressed", callable_mp(this, &EditorFileDialog::_favorite_move_down)); favorites = memnew(ItemList); + favorites->set_auto_translate(false); fav_vb->add_child(favorites); favorites->set_v_size_flags(Control::SIZE_EXPAND_FILL); favorites->connect("item_selected", callable_mp(this, &EditorFileDialog::_favorite_selected)); @@ -1918,6 +1919,7 @@ EditorFileDialog::EditorFileDialog() { rec_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE); rec_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL); recent = memnew(ItemList); + recent->set_auto_translate(false); recent->set_allow_reselect(true); rec_vb->add_margin_child(TTR("Recent:"), recent, true); recent->connect("item_selected", callable_mp(this, &EditorFileDialog::_recent_selected)); @@ -1941,6 +1943,7 @@ EditorFileDialog::EditorFileDialog() { // Item (files and folders) list with context menu. item_list = memnew(ItemList); + item_list->set_auto_translate(false); item_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); item_list->connect("item_clicked", callable_mp(this, &EditorFileDialog::_item_list_item_rmb_clicked)); item_list->connect("empty_clicked", callable_mp(this, &EditorFileDialog::_item_list_empty_clicked)); diff --git a/editor/gui/editor_spin_slider.cpp b/editor/gui/editor_spin_slider.cpp index 750837cce9..051e4340bc 100644 --- a/editor/gui/editor_spin_slider.cpp +++ b/editor/gui/editor_spin_slider.cpp @@ -92,7 +92,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) { } } else if (mb->get_button_index() == MouseButton::WHEEL_UP || mb->get_button_index() == MouseButton::WHEEL_DOWN) { if (grabber->is_visible()) { - call_deferred(SNAME("queue_redraw")); + callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw).call_deferred(); } } } @@ -637,11 +637,11 @@ void EditorSpinSlider::_focus_entered() { _ensure_input_popup(); value_input->set_text(get_text_value()); value_input_popup->set_size(get_size()); - value_input_popup->call_deferred(SNAME("show")); - value_input->call_deferred(SNAME("grab_focus")); - value_input->call_deferred(SNAME("select_all")); value_input->set_focus_next(find_next_valid_focus()->get_path()); value_input->set_focus_previous(find_prev_valid_focus()->get_path()); + callable_mp((CanvasItem *)value_input_popup, &CanvasItem::show).call_deferred(); + callable_mp((Control *)value_input, &Control::grab_focus).call_deferred(); + callable_mp(value_input, &LineEdit ::select_all).call_deferred(); emit_signal("value_focus_entered"); } diff --git a/editor/gui/editor_toaster.cpp b/editor/gui/editor_toaster.cpp index 1abb591508..ac54a5a371 100644 --- a/editor/gui/editor_toaster.cpp +++ b/editor/gui/editor_toaster.cpp @@ -406,7 +406,7 @@ void EditorToaster::popup_str(String p_message, Severity p_severity, String p_to // Since "_popup_str" adds nodes to the tree, and since the "add_child" method is not // thread-safe, it's better to defer the call to the next cycle to be thread-safe. is_processing_error = true; - call_deferred(SNAME("_popup_str"), p_message, p_severity, p_tooltip); + callable_mp(this, &EditorToaster::_popup_str).call_deferred(p_message, p_severity, p_tooltip); is_processing_error = false; } @@ -499,11 +499,6 @@ EditorToaster *EditorToaster::get_singleton() { return singleton; } -void EditorToaster::_bind_methods() { - // Binding method to make it defer-able. - ClassDB::bind_method(D_METHOD("_popup_str", "message", "severity", "tooltip"), &EditorToaster::_popup_str); -} - EditorToaster::EditorToaster() { set_notify_transform(true); set_process_internal(true); diff --git a/editor/gui/editor_toaster.h b/editor/gui/editor_toaster.h index 3e39d9d519..5034cb66fc 100644 --- a/editor/gui/editor_toaster.h +++ b/editor/gui/editor_toaster.h @@ -105,7 +105,6 @@ private: protected: static EditorToaster *singleton; - static void _bind_methods(); void _notification(int p_what); diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp index 475d81101b..766a507260 100644 --- a/editor/gui/scene_tree_editor.cpp +++ b/editor/gui/scene_tree_editor.cpp @@ -31,7 +31,6 @@ #include "scene_tree_editor.h" #include "core/config/project_settings.h" -#include "core/object/message_queue.h" #include "core/object/script_language.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" @@ -361,33 +360,12 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { } { - // Display the node name in all tooltips so that long node names can be previewed - // without having to rename them. - String tooltip = String(p_node->get_name()); - - if (p_node == get_scene_node() && p_node->get_scene_inherited_state().is_valid()) { - item->add_button(0, get_editor_theme_icon(SNAME("InstanceOptions")), BUTTON_SUBSCENE, false, TTR("Open in Editor")); - tooltip += String("\n" + TTR("Inherits:") + " " + p_node->get_scene_inherited_state()->get_path()); - } else if (p_node != get_scene_node() && !p_node->get_scene_file_path().is_empty() && can_open_instance) { - item->add_button(0, get_editor_theme_icon(SNAME("InstanceOptions")), BUTTON_SUBSCENE, false, TTR("Open in Editor")); - tooltip += String("\n" + TTR("Instance:") + " " + p_node->get_scene_file_path()); + _update_node_tooltip(p_node, item); + Callable delay_update_tooltip = callable_mp(this, &SceneTreeEditor::_queue_update_node_tooltip); + if (p_node->is_connected("editor_description_changed", delay_update_tooltip)) { + p_node->disconnect("editor_description_changed", delay_update_tooltip); } - - StringName custom_type = EditorNode::get_singleton()->get_object_custom_type_name(p_node); - tooltip += String("\n" + TTR("Type:") + " " + (custom_type != StringName() ? String(custom_type) : p_node->get_class())); - - if (!p_node->get_editor_description().is_empty()) { - const PackedInt32Array boundaries = TS->string_get_word_breaks(p_node->get_editor_description(), "", 80); - tooltip += "\n"; - - for (int i = 0; i < boundaries.size(); i += 2) { - const int start = boundaries[i]; - const int end = boundaries[i + 1]; - tooltip += "\n" + p_node->get_editor_description().substr(start, end - start + 1).rstrip("\n"); - } - } - - item->set_tooltip_text(0, tooltip); + p_node->connect("editor_description_changed", delay_update_tooltip.bind(item)); } if (can_open_instance && is_scene_tree_dock) { // Show buttons only when necessary (SceneTreeDock) to avoid crashes. @@ -520,6 +498,46 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { } } +void SceneTreeEditor::_queue_update_node_tooltip(Node *p_node, TreeItem *p_item) { + Callable update_tooltip = callable_mp(this, &SceneTreeEditor::_update_node_tooltip); + if (update_node_tooltip_delay->is_connected("timeout", update_tooltip)) { + update_node_tooltip_delay->disconnect("timeout", update_tooltip); + } + + update_node_tooltip_delay->connect("timeout", update_tooltip.bind(p_node, p_item)); + update_node_tooltip_delay->start(); +} + +void SceneTreeEditor::_update_node_tooltip(Node *p_node, TreeItem *p_item) { + // Display the node name in all tooltips so that long node names can be previewed + // without having to rename them. + String tooltip = p_node->get_name(); + + if (p_node == get_scene_node() && p_node->get_scene_inherited_state().is_valid()) { + p_item->add_button(0, get_editor_theme_icon(SNAME("InstanceOptions")), BUTTON_SUBSCENE, false, TTR("Open in Editor")); + tooltip += String("\n" + TTR("Inherits:") + " " + p_node->get_scene_inherited_state()->get_path()); + } else if (p_node != get_scene_node() && !p_node->get_scene_file_path().is_empty() && can_open_instance) { + p_item->add_button(0, get_editor_theme_icon(SNAME("InstanceOptions")), BUTTON_SUBSCENE, false, TTR("Open in Editor")); + tooltip += String("\n" + TTR("Instance:") + " " + p_node->get_scene_file_path()); + } + + StringName custom_type = EditorNode::get_singleton()->get_object_custom_type_name(p_node); + tooltip += "\n" + TTR("Type:") + " " + (custom_type != StringName() ? String(custom_type) : p_node->get_class()); + + if (!p_node->get_editor_description().is_empty()) { + const PackedInt32Array boundaries = TS->string_get_word_breaks(p_node->get_editor_description(), "", 80); + tooltip += "\n"; + + for (int i = 0; i < boundaries.size(); i += 2) { + const int start = boundaries[i]; + const int end = boundaries[i + 1]; + tooltip += "\n" + p_node->get_editor_description().substr(start, end - start + 1).rstrip("\n"); + } + } + + p_item->set_tooltip_text(0, tooltip); +} + void SceneTreeEditor::_node_visibility_changed(Node *p_node) { if (!p_node || (p_node != get_scene_node() && !p_node->get_owner())) { return; @@ -574,7 +592,7 @@ void SceneTreeEditor::_node_script_changed(Node *p_node) { return; } - MessageQueue::get_singleton()->push_call(this, "_update_tree"); + callable_mp(this, &SceneTreeEditor::_update_tree).call_deferred(false); tree_dirty = true; } @@ -607,7 +625,7 @@ void SceneTreeEditor::_node_renamed(Node *p_node) { emit_signal(SNAME("node_renamed")); if (!tree_dirty) { - MessageQueue::get_singleton()->push_call(this, "_update_tree"); + callable_mp(this, &SceneTreeEditor::_update_tree).call_deferred(false); tree_dirty = true; } } @@ -728,7 +746,7 @@ bool SceneTreeEditor::_item_matches_all_terms(TreeItem *p_item, PackedStringArra } for (int i = 0; i < p_terms.size(); i++) { - String term = p_terms[i]; + const String &term = p_terms[i]; // Recognize special filter. if (term.contains(":") && !term.get_slicec(':', 0).is_empty()) { @@ -824,12 +842,12 @@ void SceneTreeEditor::_test_update_tree() { return; // did not change } - MessageQueue::get_singleton()->push_call(this, "_update_tree"); + callable_mp(this, &SceneTreeEditor::_update_tree).call_deferred(false); tree_dirty = true; } void SceneTreeEditor::_tree_process_mode_changed() { - MessageQueue::get_singleton()->push_call(this, "_update_tree"); + callable_mp(this, &SceneTreeEditor::_update_tree).call_deferred(false); tree_dirty = true; } @@ -844,7 +862,7 @@ void SceneTreeEditor::_tree_changed() { return; } - MessageQueue::get_singleton()->push_call(this, "_test_update_tree"); + callable_mp(this, &SceneTreeEditor::_test_update_tree).call_deferred(); pending_test_update = true; } @@ -1465,7 +1483,6 @@ 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 UndoRedo. ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node); - ClassDB::bind_method("_test_update_tree", &SceneTreeEditor::_test_update_tree); ClassDB::bind_method(D_METHOD("update_tree"), &SceneTreeEditor::update_tree); @@ -1538,6 +1555,11 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope update_timer->set_wait_time(0.5); add_child(update_timer); + update_node_tooltip_delay = memnew(Timer); + update_node_tooltip_delay->set_wait_time(0.5); + update_node_tooltip_delay->set_one_shot(true); + add_child(update_node_tooltip_delay); + script_types = memnew(List<StringName>); ClassDB::get_inheriters_from_class("Script", script_types); } @@ -1618,7 +1640,7 @@ void SceneTreeDialog::_notification(int p_what) { tree->update_tree(); // Select the search bar by default. - filter->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)filter, &Control::grab_focus).call_deferred(); } } break; diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h index 96d6d065f6..179050daeb 100644 --- a/editor/gui/scene_tree_editor.h +++ b/editor/gui/scene_tree_editor.h @@ -37,6 +37,7 @@ class EditorSelection; class TextureRect; +class Timer; class SceneTreeEditor : public Control { GDCLASS(SceneTreeEditor, Control); @@ -108,6 +109,8 @@ class SceneTreeEditor : public Control { bool display_foreign = false; bool tree_dirty = true; bool pending_test_update = false; + Timer *update_node_tooltip_delay = nullptr; + static void _bind_methods(); void _cell_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button); @@ -118,6 +121,8 @@ class SceneTreeEditor : public Control { void _node_visibility_changed(Node *p_node); void _update_visibility_color(Node *p_node, TreeItem *p_item); void _set_item_custom_color(TreeItem *p_item, Color p_color); + void _update_node_tooltip(Node *p_node, TreeItem *p_item); + void _queue_update_node_tooltip(Node *p_node, TreeItem *p_item); void _selection_changed(); Node *get_scene_node() const; diff --git a/editor/history_dock.cpp b/editor/history_dock.cpp index 0ec840b8f1..6ec240fdf0 100644 --- a/editor/history_dock.cpp +++ b/editor/history_dock.cpp @@ -248,6 +248,7 @@ HistoryDock::HistoryDock() { global_history_checkbox->connect("toggled", callable_mp(this, &HistoryDock::refresh_history).unbind(1)); action_list = memnew(ItemList); + action_list->set_auto_translate(false); add_child(action_list); action_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); action_list->connect("item_selected", callable_mp(this, &HistoryDock::seek_history)); diff --git a/editor/icons/PhysicsMaterial.svg b/editor/icons/PhysicsMaterial.svg new file mode 100644 index 0000000000..bdb41a1d27 --- /dev/null +++ b/editor/icons/PhysicsMaterial.svg @@ -0,0 +1 @@ +<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#e0e0e0"><path d="M14 8.5v4L8 15l-6-2.5v-4M8 11v4" stroke-opacity=".6" stroke-linejoin="round" stroke-width="2"/><path d="m8 6 6 2.5L8 11 2 8.5z" stroke-linejoin="round" stroke-width="2"/><path d="M3.5 2l1 1.8M8 1v2m4.5-1-1 1.8" stroke-linecap="round" stroke-width="1.75"/></g></svg> diff --git a/editor/import/collada.cpp b/editor/import/3d/collada.cpp index be63973ea7..ae8041d6fe 100644 --- a/editor/import/collada.cpp +++ b/editor/import/3d/collada.cpp @@ -1718,7 +1718,7 @@ void Collada::_parse_animation(XMLParser &p_parser) { for (int i = 0; i < channel_sources.size(); i++) { String source = _uri_to_id(channel_sources[i]); - String target = channel_targets[i]; + const String &target = channel_targets[i]; ERR_CONTINUE(!samplers.has(source)); HashMap<String, String> &sampler = samplers[source]; diff --git a/editor/import/collada.h b/editor/import/3d/collada.h index 7877b1e86d..7877b1e86d 100644 --- a/editor/import/collada.h +++ b/editor/import/3d/collada.h diff --git a/editor/import/editor_import_collada.cpp b/editor/import/3d/editor_import_collada.cpp index 3f7ed8ab8b..49fec679bf 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/3d/editor_import_collada.cpp @@ -32,7 +32,7 @@ #include "core/os/os.h" #include "editor/editor_node.h" -#include "editor/import/collada.h" +#include "editor/import/3d/collada.h" #include "scene/3d/camera_3d.h" #include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/light_3d.h" @@ -1151,7 +1151,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres ERR_FAIL_COND_V(skeletons.is_empty(), ERR_INVALID_DATA); - String skname = skeletons[0]; + const String &skname = skeletons[0]; ERR_FAIL_COND_V(!node_map.has(skname), ERR_INVALID_DATA); NodeMap nmsk = node_map[skname]; Skeleton3D *sk = Object::cast_to<Skeleton3D>(nmsk.node); @@ -1205,7 +1205,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres valid = true; Vector<String> names = morph->sources[target].sarray; for (int i = 0; i < names.size(); i++) { - String meshid2 = names[i]; + const String &meshid2 = names[i]; if (collada.state.mesh_data_map.has(meshid2)) { Ref<ImporterMesh> mesh = Ref<ImporterMesh>(memnew(ImporterMesh)); const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid2]; diff --git a/editor/import/editor_import_collada.h b/editor/import/3d/editor_import_collada.h index 2950f499cb..e0214c2fd0 100644 --- a/editor/import/editor_import_collada.h +++ b/editor/import/3d/editor_import_collada.h @@ -31,7 +31,7 @@ #ifndef EDITOR_IMPORT_COLLADA_H #define EDITOR_IMPORT_COLLADA_H -#include "editor/import/resource_importer_scene.h" +#include "editor/import/3d/resource_importer_scene.h" class EditorSceneFormatImporterCollada : public EditorSceneFormatImporter { GDCLASS(EditorSceneFormatImporterCollada, EditorSceneFormatImporter); diff --git a/editor/import/post_import_plugin_skeleton_renamer.cpp b/editor/import/3d/post_import_plugin_skeleton_renamer.cpp index adeea51dae..ffe75f189c 100644 --- a/editor/import/post_import_plugin_skeleton_renamer.cpp +++ b/editor/import/3d/post_import_plugin_skeleton_renamer.cpp @@ -30,7 +30,7 @@ #include "post_import_plugin_skeleton_renamer.h" -#include "editor/import/scene_import_settings.h" +#include "editor/import/3d/scene_import_settings.h" #include "scene/3d/bone_attachment_3d.h" #include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/skeleton_3d.h" @@ -45,7 +45,7 @@ void PostImportPluginSkeletonRenamer::get_internal_import_options(InternalImport } } -void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options, HashMap<String, String> p_rename_map) { +void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options, const HashMap<String, String> &p_rename_map) { // Prepare objects. Object *map = p_options["retarget/bone_map"].get_validated_object(); if (!map || !bool(p_options["retarget/bone_renamer/rename_bones"])) { @@ -121,7 +121,7 @@ void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p // Rename bones in all Nodes by calling method. { Dictionary rename_map_dict; - for (HashMap<String, String>::Iterator E = p_rename_map.begin(); E; ++E) { + for (HashMap<String, String>::ConstIterator E = p_rename_map.begin(); E; ++E) { rename_map_dict[E->key] = E->value; } diff --git a/editor/import/post_import_plugin_skeleton_renamer.h b/editor/import/3d/post_import_plugin_skeleton_renamer.h index 98f778f6c2..a977117374 100644 --- a/editor/import/post_import_plugin_skeleton_renamer.h +++ b/editor/import/3d/post_import_plugin_skeleton_renamer.h @@ -40,7 +40,7 @@ public: virtual void get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) override; virtual void internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options) override; - void _internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options, HashMap<String, String> p_rename_map); + void _internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options, const HashMap<String, String> &p_rename_map); PostImportPluginSkeletonRenamer(); }; diff --git a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp index 3390bf4ed4..53bf24fb7e 100644 --- a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp +++ b/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp @@ -30,7 +30,7 @@ #include "post_import_plugin_skeleton_rest_fixer.h" -#include "editor/import/scene_import_settings.h" +#include "editor/import/3d/scene_import_settings.h" #include "scene/3d/bone_attachment_3d.h" #include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/skeleton_3d.h" diff --git a/editor/import/post_import_plugin_skeleton_rest_fixer.h b/editor/import/3d/post_import_plugin_skeleton_rest_fixer.h index c765169fd0..c765169fd0 100644 --- a/editor/import/post_import_plugin_skeleton_rest_fixer.h +++ b/editor/import/3d/post_import_plugin_skeleton_rest_fixer.h diff --git a/editor/import/post_import_plugin_skeleton_track_organizer.cpp b/editor/import/3d/post_import_plugin_skeleton_track_organizer.cpp index e5a8e879fc..53bcc59fcb 100644 --- a/editor/import/post_import_plugin_skeleton_track_organizer.cpp +++ b/editor/import/3d/post_import_plugin_skeleton_track_organizer.cpp @@ -30,7 +30,7 @@ #include "post_import_plugin_skeleton_track_organizer.h" -#include "editor/import/scene_import_settings.h" +#include "editor/import/3d/scene_import_settings.h" #include "scene/3d/skeleton_3d.h" #include "scene/animation/animation_player.h" #include "scene/resources/bone_map.h" diff --git a/editor/import/post_import_plugin_skeleton_track_organizer.h b/editor/import/3d/post_import_plugin_skeleton_track_organizer.h index 24a4f70aa9..24a4f70aa9 100644 --- a/editor/import/post_import_plugin_skeleton_track_organizer.h +++ b/editor/import/3d/post_import_plugin_skeleton_track_organizer.h diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/3d/resource_importer_obj.cpp index 082e78fdbe..a5e51636af 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/3d/resource_importer_obj.cpp @@ -202,7 +202,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S return OK; } -static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, bool p_disable_compression, List<String> *r_missing_deps) { +static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, bool p_disable_compression, List<String> *r_missing_deps) { Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path)); @@ -220,7 +220,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ ERR_FAIL_COND_V_MSG(coff_header_machines.find(first_bytes) != -1, ERR_FILE_CORRUPT, vformat("Couldn't read OBJ file '%s', it seems to be binary, corrupted, or empty.", p_path)); f->seek(0); - Ref<ArrayMesh> mesh; + Ref<ImporterMesh> mesh; mesh.instantiate(); bool generate_tangents = p_generate_tangents; @@ -400,24 +400,24 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ print_verbose("OBJ: Current material library " + current_material_library + " has " + itos(material_map.has(current_material_library))); print_verbose("OBJ: Current material " + current_material + " has " + itos(material_map.has(current_material_library) && material_map[current_material_library].has(current_material))); - + Ref<StandardMaterial3D> material; if (material_map.has(current_material_library) && material_map[current_material_library].has(current_material)) { - Ref<StandardMaterial3D> &material = material_map[current_material_library][current_material]; + material = material_map[current_material_library][current_material]; if (!colors.is_empty()) { material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); } surf_tool->set_material(material); } - mesh = surf_tool->commit(mesh, mesh_flags); - if (!current_material.is_empty()) { - mesh->surface_set_name(mesh->get_surface_count() - 1, current_material.get_basename()); + mesh->set_surface_name(mesh->get_surface_count() - 1, current_material.get_basename()); } else if (!current_group.is_empty()) { - mesh->surface_set_name(mesh->get_surface_count() - 1, current_group); + mesh->set_surface_name(mesh->get_surface_count() - 1, current_group); } + Array array = surf_tool->commit_to_arrays(); + mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, array, TypedArray<Array>(), Dictionary(), material, name, mesh_flags); + print_verbose("OBJ: Added surface :" + mesh->get_surface_name(mesh->get_surface_count() - 1)); - print_verbose("OBJ: Added surface :" + mesh->surface_get_name(mesh->get_surface_count() - 1)); surf_tool->clear(); surf_tool->begin(Mesh::PRIMITIVE_TRIANGLES); } @@ -476,7 +476,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ } Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { - List<Ref<Mesh>> meshes; + List<Ref<ImporterMesh>> meshes; Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, false, Vector3(1, 1, 1), Vector3(0, 0, 0), p_flags & IMPORT_FORCE_DISABLE_MESH_COMPRESSION, r_missing_deps); @@ -489,16 +489,9 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, co Node3D *scene = memnew(Node3D); - for (const Ref<Mesh> &m : meshes) { - Ref<ImporterMesh> mesh; - mesh.instantiate(); - mesh->set_name(m->get_name()); - for (int i = 0; i < m->get_surface_count(); i++) { - mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i), String(), m->surface_get_format(i)); - } - + for (Ref<ImporterMesh> m : meshes) { ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D); - mi->set_mesh(mesh); + mi->set_mesh(m); mi->set_name(m->get_name()); scene->add_child(mi, true); mi->set_owner(scene); @@ -565,7 +558,7 @@ bool ResourceImporterOBJ::get_option_visibility(const String &p_path, const Stri } Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { - List<Ref<Mesh>> meshes; + List<Ref<ImporterMesh>> meshes; Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["optimize_mesh"], p_options["scale_mesh"], p_options["offset_mesh"], p_options["force_disable_mesh_compression"], nullptr); @@ -574,7 +567,7 @@ Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_s String save_path = p_save_path + ".mesh"; - err = ResourceSaver::save(meshes.front()->get(), save_path); + err = ResourceSaver::save(meshes.front()->get()->get_mesh(), save_path); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save Mesh to file '" + save_path + "'."); diff --git a/editor/import/resource_importer_obj.h b/editor/import/3d/resource_importer_obj.h index faf0f336c0..faf0f336c0 100644 --- a/editor/import/resource_importer_obj.h +++ b/editor/import/3d/resource_importer_obj.h diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp index 80dc3f194c..dfb14c6741 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/3d/resource_importer_scene.cpp @@ -35,7 +35,7 @@ #include "core/object/script_language.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" -#include "editor/import/scene_import_settings.h" +#include "editor/import/3d/scene_import_settings.h" #include "scene/3d/area_3d.h" #include "scene/3d/collision_shape_3d.h" #include "scene/3d/importer_mesh_instance_3d.h" @@ -2377,9 +2377,8 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file, const HashM ERR_FAIL_COND_V(!importer.is_valid(), nullptr); Error err = OK; - HashMap<StringName, Variant> options_dupe = p_options; - Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS | EditorSceneFormatImporter::IMPORT_FORCE_DISABLE_MESH_COMPRESSION, options_dupe, nullptr, &err); + Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS | EditorSceneFormatImporter::IMPORT_FORCE_DISABLE_MESH_COMPRESSION, p_options, nullptr, &err); if (!scene || err != OK) { return nullptr; } diff --git a/editor/import/resource_importer_scene.h b/editor/import/3d/resource_importer_scene.h index 6ea4d1af7d..6ea4d1af7d 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/3d/resource_importer_scene.h diff --git a/editor/import/scene_import_settings.cpp b/editor/import/3d/scene_import_settings.cpp index 4ecc6dedbd..4ecc6dedbd 100644 --- a/editor/import/scene_import_settings.cpp +++ b/editor/import/3d/scene_import_settings.cpp diff --git a/editor/import/scene_import_settings.h b/editor/import/3d/scene_import_settings.h index 3e71d5da17..c6c416daba 100644 --- a/editor/import/scene_import_settings.h +++ b/editor/import/3d/scene_import_settings.h @@ -31,7 +31,7 @@ #ifndef SCENE_IMPORT_SETTINGS_H #define SCENE_IMPORT_SETTINGS_H -#include "editor/import/resource_importer_scene.h" +#include "editor/import/3d/resource_importer_scene.h" #include "scene/3d/camera_3d.h" #include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" diff --git a/editor/import/SCsub b/editor/import/SCsub index 359d04e5df..a8c06cc406 100644 --- a/editor/import/SCsub +++ b/editor/import/SCsub @@ -3,3 +3,4 @@ Import("env") env.add_source_files(env.editor_sources, "*.cpp") +env.add_source_files(env.editor_sources, "3d/*.cpp") diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp index 5414c6e74b..bc96191d33 100644 --- a/editor/import/audio_stream_import_settings.cpp +++ b/editor/import/audio_stream_import_settings.cpp @@ -277,6 +277,8 @@ void AudioStreamImportSettingsDialog::_draw_indicator() { rect.size.height -= y_ofs; } + _current_label->set_text(String::num(_current, 2).pad_decimals(2) + " /"); + float ofs_x = (_current - zoom_bar->get_value()) * rect.size.width / zoom_bar->get_page(); if (ofs_x < 0 || ofs_x >= rect.size.width) { return; @@ -310,8 +312,6 @@ void AudioStreamImportSettingsDialog::_draw_indicator() { } } } - - _current_label->set_text(String::num(_current, 2).pad_decimals(2) + " /"); } void AudioStreamImportSettingsDialog::_on_indicator_mouse_exited() { diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index 5564726594..ad65fcebd7 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -1345,6 +1345,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() { page2_description->set_text(TTR("Add font size, and variation coordinates, and select glyphs to pre-render:")); page2_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); page2_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + page2_description->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); page2_vb->add_child(page2_description); HSplitContainer *page2_hb = memnew(HSplitContainer); @@ -1418,6 +1419,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() { page2_0_description->set_text(TTR("Select translations to add all required glyphs to pre-render list:")); page2_0_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); page2_0_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + page2_0_description->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); page2_0_vb->add_child(page2_0_description); locale_tree = memnew(Tree); @@ -1449,6 +1451,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() { page2_1_description->set_text(TTR("Enter a text and select OpenType features to shape and add all required glyphs to pre-render list:")); page2_1_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); page2_1_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + page2_1_description->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); page2_1_vb->add_child(page2_1_description); HSplitContainer *page2_1_hb = memnew(HSplitContainer); @@ -1486,6 +1489,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() { page2_2_description->set_text(TTR("Add or remove glyphs from the character map to pre-render list:\nNote: Some stylistic alternatives and glyph variants do not have one-to-one correspondence to character, and not shown in this map, use \"Glyphs from the text\" tab to add these.")); page2_2_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); page2_2_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + page2_2_description->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); page2_2_vb->add_child(page2_2_description); HSplitContainer *glyphs_split = memnew(HSplitContainer); diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp index 7afce116b8..3243dcf256 100644 --- a/editor/import/editor_import_plugin.cpp +++ b/editor/import/editor_import_plugin.cpp @@ -186,6 +186,15 @@ Error EditorImportPlugin::import(const String &p_source_file, const String &p_sa ERR_FAIL_V_MSG(ERR_METHOD_NOT_FOUND, "Unimplemented _import in add-on."); } +bool EditorImportPlugin::can_import_threaded() const { + bool ret = false; + if (GDVIRTUAL_CALL(_can_import_threaded, ret)) { + return ret; + } else { + return ResourceImporter::can_import_threaded(); + } +} + Error EditorImportPlugin::_append_import_external_resource(const String &p_file, const Dictionary &p_custom_options, const String &p_custom_importer, Variant p_generator_parameters) { HashMap<StringName, Variant> options; List<Variant> keys; @@ -213,5 +222,6 @@ void EditorImportPlugin::_bind_methods() { GDVIRTUAL_BIND(_get_import_order) GDVIRTUAL_BIND(_get_option_visibility, "path", "option_name", "options") GDVIRTUAL_BIND(_import, "source_file", "save_path", "options", "platform_variants", "gen_files"); + GDVIRTUAL_BIND(_can_import_threaded); ClassDB::bind_method(D_METHOD("append_import_external_resource", "path", "custom_options", "custom_importer", "generator_parameters"), &EditorImportPlugin::_append_import_external_resource, DEFVAL(Dictionary()), DEFVAL(String()), DEFVAL(Variant())); } diff --git a/editor/import/editor_import_plugin.h b/editor/import/editor_import_plugin.h index fb164c7f15..ea5cfc2682 100644 --- a/editor/import/editor_import_plugin.h +++ b/editor/import/editor_import_plugin.h @@ -52,6 +52,7 @@ protected: GDVIRTUAL0RC(int, _get_import_order) GDVIRTUAL3RC(bool, _get_option_visibility, String, StringName, Dictionary) GDVIRTUAL5RC(Error, _import, String, String, Dictionary, TypedArray<String>, TypedArray<String>) + GDVIRTUAL0RC(bool, _can_import_threaded) Error _append_import_external_resource(const String &p_file, const Dictionary &p_custom_options = Dictionary(), const String &p_custom_importer = String(), Variant p_generator_parameters = Variant()); @@ -69,6 +70,7 @@ public: virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const override; virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override; virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata = nullptr) override; + virtual bool can_import_threaded() const override; Error append_import_external_resource(const String &p_file, const HashMap<StringName, Variant> &p_custom_options = HashMap<StringName, Variant>(), const String &p_custom_importer = String(), Variant p_generator_parameters = Variant()); }; diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 1ee273f64b..1b413c0978 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -461,15 +461,6 @@ void InspectorDock::_notification(int p_what) { } void InspectorDock::_bind_methods() { - ClassDB::bind_method("_unref_resource", &InspectorDock::_unref_resource); - ClassDB::bind_method("_paste_resource", &InspectorDock::_paste_resource); - ClassDB::bind_method("_copy_resource", &InspectorDock::_copy_resource); - - ClassDB::bind_method("_menu_collapseall", &InspectorDock::_menu_collapseall); - ClassDB::bind_method("_menu_expandall", &InspectorDock::_menu_expandall); - - ClassDB::bind_method("edit_resource", &InspectorDock::edit_resource); - ClassDB::bind_method("store_script_properties", &InspectorDock::store_script_properties); ClassDB::bind_method("apply_script_properties", &InspectorDock::apply_script_properties); diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp index fb34740318..46c6ef5712 100644 --- a/editor/localization_editor.cpp +++ b/editor/localization_editor.cpp @@ -189,7 +189,7 @@ void LocalizationEditor::_translation_res_select() { if (updating_translations) { return; } - call_deferred(SNAME("update_translations")); + callable_mp(this, &LocalizationEditor::update_translations).call_deferred(); } void LocalizationEditor::_translation_res_option_popup(bool p_arrow_clicked) { @@ -545,7 +545,7 @@ void LocalizationEditor::update_translations() { PackedStringArray selected = remaps[keys[i]]; for (int j = 0; j < selected.size(); j++) { - String s2 = selected[j]; + const String &s2 = selected[j]; int qp = s2.rfind(":"); String path = s2.substr(0, qp); String locale = s2.substr(qp + 1, s2.length()); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 4a17fd89ff..5ffb89ac65 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -41,6 +41,7 @@ #include "editor/editor_string_names.h" #include "editor/editor_undo_redo_manager.h" #include "editor/gui/editor_file_dialog.h" +#include "scene/3d/skeleton_3d.h" #include "scene/animation/animation_player.h" #include "scene/gui/check_box.h" #include "scene/gui/menu_button.h" @@ -623,6 +624,111 @@ void AnimationNodeBlendTreeEditor::_filter_edited() { updating = false; } +void AnimationNodeBlendTreeEditor::_filter_fill_selection() { + TreeItem *ti = filters->get_root(); + if (!ti) { + return; + } + + updating = true; + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + undo_redo->create_action(TTR("Fill Selected Filter Children")); + + _filter_fill_selection_recursive(undo_redo, ti, false); + + undo_redo->add_do_method(this, "_update_filters", _filter_edit); + undo_redo->add_undo_method(this, "_update_filters", _filter_edit); + undo_redo->commit_action(); + updating = false; + + _update_filters(_filter_edit); +} + +void AnimationNodeBlendTreeEditor::_filter_invert_selection() { + TreeItem *ti = filters->get_root(); + if (!ti) { + return; + } + + updating = true; + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + undo_redo->create_action(TTR("Invert Filter Selection")); + + _filter_invert_selection_recursive(undo_redo, ti); + + undo_redo->add_do_method(this, "_update_filters", _filter_edit); + undo_redo->add_undo_method(this, "_update_filters", _filter_edit); + undo_redo->commit_action(); + updating = false; + + _update_filters(_filter_edit); +} + +void AnimationNodeBlendTreeEditor::_filter_clear_selection() { + TreeItem *ti = filters->get_root(); + if (!ti) { + return; + } + + updating = true; + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + undo_redo->create_action(TTR("Clear Filter Selection")); + + _filter_clear_selection_recursive(undo_redo, ti); + + undo_redo->add_do_method(this, "_update_filters", _filter_edit); + undo_redo->add_undo_method(this, "_update_filters", _filter_edit); + undo_redo->commit_action(); + updating = false; + + _update_filters(_filter_edit); +} + +void AnimationNodeBlendTreeEditor::_filter_fill_selection_recursive(EditorUndoRedoManager *p_undo_redo, TreeItem *p_item, bool p_parent_filtered) { + TreeItem *ti = p_item->get_first_child(); + bool parent_filtered = p_parent_filtered; + while (ti) { + NodePath item_path = ti->get_metadata(0); + bool filtered = _filter_edit->is_path_filtered(item_path); + parent_filtered |= filtered; + + p_undo_redo->add_do_method(_filter_edit.ptr(), "set_filter_path", item_path, parent_filtered); + p_undo_redo->add_undo_method(_filter_edit.ptr(), "set_filter_path", item_path, filtered); + + _filter_fill_selection_recursive(p_undo_redo, ti, parent_filtered); + ti = ti->get_next(); + parent_filtered = p_parent_filtered; + } +} + +void AnimationNodeBlendTreeEditor::_filter_invert_selection_recursive(EditorUndoRedoManager *p_undo_redo, TreeItem *p_item) { + TreeItem *ti = p_item->get_first_child(); + while (ti) { + NodePath item_path = ti->get_metadata(0); + bool filtered = _filter_edit->is_path_filtered(item_path); + + p_undo_redo->add_do_method(_filter_edit.ptr(), "set_filter_path", item_path, !filtered); + p_undo_redo->add_undo_method(_filter_edit.ptr(), "set_filter_path", item_path, filtered); + + _filter_invert_selection_recursive(p_undo_redo, ti); + ti = ti->get_next(); + } +} + +void AnimationNodeBlendTreeEditor::_filter_clear_selection_recursive(EditorUndoRedoManager *p_undo_redo, TreeItem *p_item) { + TreeItem *ti = p_item->get_first_child(); + while (ti) { + NodePath item_path = ti->get_metadata(0); + bool filtered = _filter_edit->is_path_filtered(item_path); + + p_undo_redo->add_do_method(_filter_edit.ptr(), "set_filter_path", item_path, false); + p_undo_redo->add_undo_method(_filter_edit.ptr(), "set_filter_path", item_path, filtered); + + _filter_clear_selection_recursive(p_undo_redo, ti); + ti = ti->get_next(); + } +} + bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &anode) { if (updating || _filter_edit != anode) { return false; @@ -1121,10 +1227,28 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { VBoxContainer *filter_vbox = memnew(VBoxContainer); filter_dialog->add_child(filter_vbox); + HBoxContainer *filter_hbox = memnew(HBoxContainer); + filter_vbox->add_child(filter_hbox); + filter_enabled = memnew(CheckBox); filter_enabled->set_text(TTR("Enable Filtering")); filter_enabled->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_filter_toggled)); - filter_vbox->add_child(filter_enabled); + filter_hbox->add_child(filter_enabled); + + filter_fill_selection = memnew(Button); + filter_fill_selection->set_text(TTR("Fill Selected Children")); + filter_fill_selection->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_filter_fill_selection)); + filter_hbox->add_child(filter_fill_selection); + + filter_invert_selection = memnew(Button); + filter_invert_selection->set_text(TTR("Invert")); + filter_invert_selection->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_filter_invert_selection)); + filter_hbox->add_child(filter_invert_selection); + + filter_clear_selection = memnew(Button); + filter_clear_selection->set_text(TTR("Clear")); + filter_clear_selection->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_filter_clear_selection)); + filter_hbox->add_child(filter_clear_selection); filters = memnew(Tree); filter_vbox->add_child(filters); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h index 1f7a33e02a..690b127938 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.h +++ b/editor/plugins/animation_blend_tree_editor_plugin.h @@ -66,6 +66,9 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { AcceptDialog *filter_dialog = nullptr; Tree *filters = nullptr; CheckBox *filter_enabled = nullptr; + Button *filter_fill_selection = nullptr; + Button *filter_invert_selection = nullptr; + Button *filter_clear_selection = nullptr; HashMap<StringName, ProgressBar *> animations; Vector<EditorProperty *> visible_properties; @@ -116,6 +119,12 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { void _inspect_filters(const String &p_which); void _filter_edited(); void _filter_toggled(); + void _filter_fill_selection(); + void _filter_invert_selection(); + void _filter_clear_selection(); + void _filter_fill_selection_recursive(EditorUndoRedoManager *p_undo_redo, TreeItem *p_item, bool p_parent_filtered); + void _filter_invert_selection_recursive(EditorUndoRedoManager *p_undo_redo, TreeItem *p_item); + void _filter_clear_selection_recursive(EditorUndoRedoManager *p_undo_redo, TreeItem *p_item); Ref<AnimationNode> _filter_edit; void _popup(bool p_has_input_ports, const Vector2 &p_node_position); diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index e3b2154e37..c302226357 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -137,7 +137,7 @@ void AnimationLibraryEditor::_load_library() { file_dialog->add_filter("*." + K); } - file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES); file_dialog->set_current_file(""); file_dialog->popup_centered_ratio(); @@ -299,85 +299,9 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { } break; } } + void AnimationLibraryEditor::_load_file(String p_path) { switch (file_dialog_action) { - case FILE_DIALOG_ACTION_OPEN_LIBRARY: { - Ref<AnimationLibrary> al = ResourceLoader::load(p_path); - if (al.is_null()) { - error_dialog->set_text(TTR("Invalid AnimationLibrary file.")); - error_dialog->popup_centered(); - return; - } - - List<StringName> libs; - mixer->get_animation_library_list(&libs); - for (const StringName &K : libs) { - Ref<AnimationLibrary> al2 = mixer->get_animation_library(K); - if (al2 == al) { - error_dialog->set_text(TTR("This library is already added to the mixer.")); - error_dialog->popup_centered(); - - return; - } - } - - String name = AnimationLibrary::validate_library_name(p_path.get_file().get_basename()); - - int attempt = 1; - - while (bool(mixer->has_animation_library(name))) { - attempt++; - name = p_path.get_file().get_basename() + " " + itos(attempt); - } - - EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - - undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), name)); - undo_redo->add_do_method(mixer, "add_animation_library", name, al); - undo_redo->add_undo_method(mixer, "remove_animation_library", name); - undo_redo->add_do_method(this, "_update_editor", mixer); - undo_redo->add_undo_method(this, "_update_editor", mixer); - undo_redo->commit_action(); - } break; - case FILE_DIALOG_ACTION_OPEN_ANIMATION: { - Ref<Animation> anim = ResourceLoader::load(p_path); - if (anim.is_null()) { - error_dialog->set_text(TTR("Invalid Animation file.")); - error_dialog->popup_centered(); - return; - } - - Ref<AnimationLibrary> al = mixer->get_animation_library(adding_animation_to_library); - List<StringName> anims; - al->get_animation_list(&anims); - for (const StringName &K : anims) { - Ref<Animation> a2 = al->get_animation(K); - if (a2 == anim) { - error_dialog->set_text(TTR("This animation is already added to the library.")); - error_dialog->popup_centered(); - return; - } - } - - String name = p_path.get_file().get_basename(); - - int attempt = 1; - - while (al->has_animation(name)) { - attempt++; - name = p_path.get_file().get_basename() + " " + itos(attempt); - } - - EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - - undo_redo->create_action(vformat(TTR("Load Animation into Library: %s"), name)); - undo_redo->add_do_method(al.ptr(), "add_animation", name, anim); - undo_redo->add_undo_method(al.ptr(), "remove_animation", name); - undo_redo->add_do_method(this, "_update_editor", mixer); - undo_redo->add_undo_method(this, "_update_editor", mixer); - undo_redo->commit_action(); - } break; - case FILE_DIALOG_ACTION_SAVE_LIBRARY: { Ref<AnimationLibrary> al = mixer->get_animation_library(file_dialog_library); String prev_path = al->get_path(); @@ -415,6 +339,121 @@ void AnimationLibraryEditor::_load_file(String p_path) { undo_redo->commit_action(); } } break; + default: { + } + } +} + +void AnimationLibraryEditor::_load_files(const PackedStringArray &p_paths) { + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + bool has_created_action = false; + bool show_error_diag = false; + List<String> name_list; + + switch (file_dialog_action) { + case FILE_DIALOG_ACTION_OPEN_LIBRARY: { + for (const String &path : p_paths) { + Ref<AnimationLibrary> al = ResourceLoader::load(path); + if (al.is_null()) { + show_error_diag = true; + error_dialog->set_text(TTR("Some AnimationLibrary files were invalid.")); + continue; + } + + List<StringName> libs; + mixer->get_animation_library_list(&libs); + bool is_already_added = false; + for (const StringName &K : libs) { + if (mixer->get_animation_library(K) == al) { + // Prioritize the "invalid" error message. + if (!show_error_diag) { + show_error_diag = true; + error_dialog->set_text(TTR("Some of the selected libraries were already added to the mixer.")); + } + + is_already_added = true; + break; + } + } + + if (is_already_added) { + continue; + } + + String name = AnimationLibrary::validate_library_name(path.get_file().get_basename()); + int attempt = 1; + while (bool(mixer->has_animation_library(name)) || name_list.find(name)) { + attempt++; + name = path.get_file().get_basename() + " " + itos(attempt); + } + name_list.push_back(name); + + if (!has_created_action) { + has_created_action = true; + undo_redo->create_action(p_paths.size() > 1 ? TTR("Add Animation Libraries") : vformat(TTR("Add Animation Library: %s"), name)); + } + undo_redo->add_do_method(mixer, "add_animation_library", name, al); + undo_redo->add_undo_method(mixer, "remove_animation_library", name); + } + } break; + case FILE_DIALOG_ACTION_OPEN_ANIMATION: { + Ref<AnimationLibrary> al = mixer->get_animation_library(adding_animation_to_library); + for (const String &path : p_paths) { + Ref<Animation> anim = ResourceLoader::load(path); + if (anim.is_null()) { + show_error_diag = true; + error_dialog->set_text(TTR("Some Animation files were invalid.")); + continue; + } + + List<StringName> anims; + al->get_animation_list(&anims); + bool is_already_added = false; + for (const StringName &K : anims) { + if (al->get_animation(K) == anim) { + // Prioritize the "invalid" error message. + if (!show_error_diag) { + show_error_diag = true; + error_dialog->set_text(TTR("Some of the selected animations were already added to the library.")); + } + + is_already_added = true; + break; + } + } + + if (is_already_added) { + continue; + } + + String name = path.get_file().get_basename(); + int attempt = 1; + while (al->has_animation(name) || name_list.find(name)) { + attempt++; + name = path.get_file().get_basename() + " " + itos(attempt); + } + name_list.push_back(name); + + if (!has_created_action) { + has_created_action = true; + undo_redo->create_action(p_paths.size() > 1 ? TTR("Load Animations into Library") : vformat(TTR("Load Animation into Library: %s"), name)); + } + undo_redo->add_do_method(al.ptr(), "add_animation", name, anim); + undo_redo->add_undo_method(al.ptr(), "remove_animation", name); + } + } break; + default: { + } + } + + if (has_created_action) { + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); + undo_redo->commit_action(); + } + + if (show_error_diag) { + error_dialog->popup_centered(); } } @@ -506,7 +545,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int } file_dialog->set_title(TTR("Load Animation")); - file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES); file_dialog->set_current_file(""); file_dialog->popup_centered_ratio(); @@ -673,12 +712,12 @@ void AnimationLibraryEditor::update_tree() { libitem->set_metadata(0, K); libitem->set_icon(0, get_editor_theme_icon("AnimationLibrary")); - libitem->add_button(0, get_editor_theme_icon("Add"), LIB_BUTTON_ADD, animation_library_is_foreign, TTR("Add Animation to Library")); - libitem->add_button(0, get_editor_theme_icon("Load"), LIB_BUTTON_LOAD, animation_library_is_foreign, TTR("Load animation from file and add to library")); - libitem->add_button(0, get_editor_theme_icon("ActionPaste"), LIB_BUTTON_PASTE, animation_library_is_foreign, TTR("Paste Animation to Library from clipboard")); + libitem->add_button(0, get_editor_theme_icon("Add"), LIB_BUTTON_ADD, animation_library_is_foreign, TTR("Add animation to library.")); + libitem->add_button(0, get_editor_theme_icon("Load"), LIB_BUTTON_LOAD, animation_library_is_foreign, TTR("Load animation from file and add to library.")); + libitem->add_button(0, get_editor_theme_icon("ActionPaste"), LIB_BUTTON_PASTE, animation_library_is_foreign, TTR("Paste animation to library from clipboard.")); - libitem->add_button(1, get_editor_theme_icon("Save"), LIB_BUTTON_FILE, false, TTR("Save animation library to resource on disk")); - libitem->add_button(1, get_editor_theme_icon("Remove"), LIB_BUTTON_DELETE, false, TTR("Remove animation library")); + libitem->add_button(1, get_editor_theme_icon("Save"), LIB_BUTTON_FILE, false, TTR("Save animation library to resource on disk.")); + libitem->add_button(1, get_editor_theme_icon("Remove"), LIB_BUTTON_DELETE, false, TTR("Remove animation library.")); libitem->set_custom_bg_color(0, ss_color); @@ -690,7 +729,7 @@ void AnimationLibraryEditor::update_tree() { anitem->set_editable(0, !animation_library_is_foreign); anitem->set_metadata(0, L); anitem->set_icon(0, get_editor_theme_icon("Animation")); - anitem->add_button(0, get_editor_theme_icon("ActionCopy"), ANIM_BUTTON_COPY, animation_library_is_foreign, TTR("Copy animation to clipboard")); + anitem->add_button(0, get_editor_theme_icon("ActionCopy"), ANIM_BUTTON_COPY, animation_library_is_foreign, TTR("Copy animation to clipboard.")); Ref<Animation> anim = al->get_animation(L); String anim_path = anim->get_path(); @@ -717,8 +756,8 @@ void AnimationLibraryEditor::update_tree() { anitem->set_text(1, anim_path.get_file()); } } - anitem->add_button(1, get_editor_theme_icon("Save"), ANIM_BUTTON_FILE, animation_library_is_foreign, TTR("Save animation to resource on disk")); - anitem->add_button(1, get_editor_theme_icon("Remove"), ANIM_BUTTON_DELETE, animation_library_is_foreign, TTR("Remove animation from Library")); + anitem->add_button(1, get_editor_theme_icon("Save"), ANIM_BUTTON_FILE, animation_library_is_foreign, TTR("Save animation to resource on disk.")); + anitem->add_button(1, get_editor_theme_icon("Remove"), ANIM_BUTTON_DELETE, animation_library_is_foreign, TTR("Remove animation from Library.")); } } } @@ -728,6 +767,15 @@ void AnimationLibraryEditor::show_dialog() { popup_centered_ratio(0.5); } +void AnimationLibraryEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_THEME_CHANGED: { + new_library_button->set_icon(get_editor_theme_icon(SNAME("Add"))); + load_library_button->set_icon(get_editor_theme_icon(SNAME("Load"))); + } + } +} + void AnimationLibraryEditor::_update_editor(Object *p_mixer) { emit_signal("update_editor", p_mixer); } @@ -743,6 +791,7 @@ AnimationLibraryEditor::AnimationLibraryEditor() { file_dialog = memnew(EditorFileDialog); add_child(file_dialog); file_dialog->connect("file_selected", callable_mp(this, &AnimationLibraryEditor::_load_file)); + file_dialog->connect("files_selected", callable_mp(this, &AnimationLibraryEditor::_load_files)); add_library_dialog = memnew(ConfirmationDialog); VBoxContainer *dialog_vb = memnew(VBoxContainer); @@ -760,12 +809,14 @@ AnimationLibraryEditor::AnimationLibraryEditor() { VBoxContainer *vb = memnew(VBoxContainer); HBoxContainer *hb = memnew(HBoxContainer); hb->add_spacer(true); - Button *b = memnew(Button(TTR("Add Library"))); - b->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_add_library)); - hb->add_child(b); - b = memnew(Button(TTR("Load Library"))); - b->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_load_library)); - hb->add_child(b); + new_library_button = memnew(Button(TTR("New Library"))); + new_library_button->set_tooltip_text(TTR("Create new empty animation library.")); + new_library_button->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_add_library)); + hb->add_child(new_library_button); + load_library_button = memnew(Button(TTR("Load Library"))); + load_library_button->set_tooltip_text(TTR("Load animation library from disk.")); + load_library_button->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_load_library)); + hb->add_child(load_library_button); vb->add_child(hb); tree = memnew(Tree); vb->add_child(tree); diff --git a/editor/plugins/animation_library_editor.h b/editor/plugins/animation_library_editor.h index b656642a7c..c003e9a10b 100644 --- a/editor/plugins/animation_library_editor.h +++ b/editor/plugins/animation_library_editor.h @@ -80,6 +80,9 @@ class AnimationLibraryEditor : public AcceptDialog { StringName file_dialog_animation; StringName file_dialog_library; + Button *new_library_button = nullptr; + Button *load_library_button = nullptr; + AcceptDialog *error_dialog = nullptr; bool adding_animation = false; StringName adding_animation_to_library; @@ -98,6 +101,7 @@ class AnimationLibraryEditor : public AcceptDialog { void _add_library_confirm(); void _load_library(); void _load_file(String p_path); + void _load_files(const PackedStringArray &p_paths); void _item_renamed(); void _button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button); @@ -107,6 +111,7 @@ class AnimationLibraryEditor : public AcceptDialog { bool updating = false; protected: + void _notification(int p_what); void _update_editor(Object *p_mixer); static void _bind_methods(); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 84251e1476..fe2ce70735 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -2139,7 +2139,7 @@ void AnimationPlayerEditorPlugin::_clear_dummy_player() { } Node *parent = dummy_player->get_parent(); if (parent) { - parent->call_deferred("remove_child", dummy_player); + callable_mp(parent, &Node::remove_child).call_deferred(dummy_player); } dummy_player->queue_free(); dummy_player = nullptr; diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index e9c8b0c610..0e61a7e29f 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -203,7 +203,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv } if (node_rects[i].edit.has_point(mb->get_position())) { //edit name - call_deferred(SNAME("_open_editor"), node_rects[i].node_name); + callable_mp(this, &AnimationNodeStateMachineEditor::_open_editor).call_deferred(node_rects[i].node_name); return; } @@ -1610,12 +1610,6 @@ void AnimationNodeStateMachineEditor::_update_mode() { void AnimationNodeStateMachineEditor::_bind_methods() { ClassDB::bind_method("_update_graph", &AnimationNodeStateMachineEditor::_update_graph); - ClassDB::bind_method("_open_editor", &AnimationNodeStateMachineEditor::_open_editor); - ClassDB::bind_method("_connect_to", &AnimationNodeStateMachineEditor::_connect_to); - ClassDB::bind_method("_stop_connecting", &AnimationNodeStateMachineEditor::_stop_connecting); - ClassDB::bind_method("_delete_selected", &AnimationNodeStateMachineEditor::_delete_selected); - ClassDB::bind_method("_delete_all", &AnimationNodeStateMachineEditor::_delete_all); - ClassDB::bind_method("_delete_tree_draw", &AnimationNodeStateMachineEditor::_delete_tree_draw); BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, panel_style, "panel", "GraphStateMachine"); BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, error_panel_style, "error_panel", "GraphStateMachine"); diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp index db61c95474..153f192838 100644 --- a/editor/plugins/bone_map_editor_plugin.cpp +++ b/editor/plugins/bone_map_editor_plugin.cpp @@ -32,10 +32,10 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" -#include "editor/import/post_import_plugin_skeleton_renamer.h" -#include "editor/import/post_import_plugin_skeleton_rest_fixer.h" -#include "editor/import/post_import_plugin_skeleton_track_organizer.h" -#include "editor/import/scene_import_settings.h" +#include "editor/import/3d/post_import_plugin_skeleton_renamer.h" +#include "editor/import/3d/post_import_plugin_skeleton_rest_fixer.h" +#include "editor/import/3d/post_import_plugin_skeleton_track_organizer.h" +#include "editor/import/3d/scene_import_settings.h" #include "scene/gui/aspect_ratio_container.h" #include "scene/gui/separator.h" #include "scene/gui/texture_rect.h" @@ -95,7 +95,7 @@ void BoneMapperButton::_notification(int p_what) { } } -BoneMapperButton::BoneMapperButton(const StringName p_profile_bone_name, bool p_require, bool p_selected) { +BoneMapperButton::BoneMapperButton(const StringName &p_profile_bone_name, bool p_require, bool p_selected) { profile_bone_name = p_profile_bone_name; require = p_require; selected = p_selected; diff --git a/editor/plugins/bone_map_editor_plugin.h b/editor/plugins/bone_map_editor_plugin.h index 9ff32707c7..9479ed3730 100644 --- a/editor/plugins/bone_map_editor_plugin.h +++ b/editor/plugins/bone_map_editor_plugin.h @@ -78,7 +78,7 @@ public: bool is_require() const; - BoneMapperButton(const StringName p_profile_bone_name, bool p_require, bool p_selected); + BoneMapperButton(const StringName &p_profile_bone_name, bool p_require, bool p_selected); ~BoneMapperButton(); }; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index bac2a4909f..f16aff555c 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -345,7 +345,7 @@ void CanvasItemEditor::_snap_other_nodes( } } -Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsigned int p_forced_modes, const CanvasItem *p_self_canvas_item, List<CanvasItem *> p_other_nodes_exceptions) { +Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsigned int p_forced_modes, const CanvasItem *p_self_canvas_item, const List<CanvasItem *> &p_other_nodes_exceptions) { snap_target[0] = SNAP_TARGET_NONE; snap_target[1] = SNAP_TARGET_NONE; @@ -535,7 +535,7 @@ void CanvasItemEditor::_keying_changed() { } } -Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_list) { +Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(const List<CanvasItem *> &p_list) { ERR_FAIL_COND_V(p_list.is_empty(), Rect2()); // Handles the first element @@ -830,7 +830,7 @@ Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2 return output; } -void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones) { +void CanvasItemEditor::_save_canvas_item_state(const List<CanvasItem *> &p_canvas_items, bool save_bones) { original_transform = Transform2D(); bool transform_stored = false; @@ -853,14 +853,14 @@ void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items } } -void CanvasItemEditor::_restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones) { +void CanvasItemEditor::_restore_canvas_item_state(const List<CanvasItem *> &p_canvas_items, bool restore_bones) { for (CanvasItem *ci : drag_selection) { CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci); ci->_edit_set_state(se->undo_state); } } -void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_items, String action_name, bool commit_bones) { +void CanvasItemEditor::_commit_canvas_item_state(const List<CanvasItem *> &p_canvas_items, String action_name, bool commit_bones) { List<CanvasItem *> modified_canvas_items; for (CanvasItem *ci : p_canvas_items) { Dictionary old_state = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci)->undo_state; @@ -976,7 +976,7 @@ void CanvasItemEditor::_node_created(Node *p_node) { c->_edit_set_position(xform.xform(node_create_position)); } - call_deferred(SNAME("_reset_create_position")); // Defer the call in case more than one node is added. + callable_mp(this, &CanvasItemEditor::_reset_create_position).call_deferred(); // Defer the call in case more than one node is added. } void CanvasItemEditor::_reset_create_position() { @@ -2014,14 +2014,14 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { if ((b->is_alt_pressed() && !b->is_command_or_control_pressed()) || tool == TOOL_MOVE) { List<CanvasItem *> selection = _get_edited_canvas_items(); - drag_selection.clear(); - for (int i = 0; i < selection.size(); i++) { - if (_is_node_movable(selection[i], true)) { - drag_selection.push_back(selection[i]); + if (selection.size() > 0) { + drag_selection.clear(); + for (int i = 0; i < selection.size(); i++) { + if (_is_node_movable(selection[i], true)) { + drag_selection.push_back(selection[i]); + } } - } - if (selection.size() > 0) { drag_type = DRAG_MOVE; CanvasItem *ci = selection[0]; @@ -2043,8 +2043,9 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { drag_from = transform.affine_inverse().xform(b->get_position()); _save_canvas_item_state(drag_selection); + + return true; } - return true; } } } @@ -2344,7 +2345,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { return true; } - if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && tool == TOOL_SELECT && !panner->is_panning()) { + if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && !panner->is_panning() && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE)) { // Single item selection Point2 click = transform.affine_inverse().xform(b->get_position()); @@ -2379,7 +2380,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { } else { bool still_selected = _select_click_on_item(ci, click, b->is_shift_pressed()); // Start dragging - if (still_selected) { + if (still_selected && (tool == TOOL_SELECT || tool == TOOL_MOVE)) { // Drag the node(s) if requested drag_start_origin = click; drag_type = DRAG_QUEUED; @@ -2463,7 +2464,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { } } - if (k.is_valid() && k->is_action_pressed(SNAME("ui_cancel"), false, true) && drag_type == DRAG_NONE && tool == TOOL_SELECT) { + if (k.is_valid() && k->is_action_pressed(SNAME("ui_cancel"), false, true) && drag_type == DRAG_NONE) { // Unselect everything editor_selection->clear(); viewport->queue_redraw(); @@ -2609,7 +2610,7 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { // Grab focus if (!viewport->has_focus() && (!get_viewport()->gui_get_focus_owner() || !get_viewport()->gui_get_focus_owner()->is_text_field())) { - viewport->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)viewport, &Control::grab_focus).call_deferred(); } } @@ -3638,7 +3639,7 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans _draw_invisible_nodes_positions(p_node->get_child(i), parent_xform, canvas_xform); } - if (ci && !ci->_edit_use_rect() && (!editor_selection->is_selected(ci) || _is_node_locked(ci))) { + if (show_position_gizmos && ci && !ci->_edit_use_rect() && (!editor_selection->is_selected(ci) || _is_node_locked(ci))) { Transform2D xform = transform * canvas_xform * parent_xform; // Draw the node's position @@ -3775,13 +3776,13 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p real_t offset = 0; Ref<Texture2D> lock = get_editor_theme_icon(SNAME("LockViewport")); - if (p_node->has_meta("_edit_lock_") && show_edit_locks) { + if (show_lock_gizmos && p_node->has_meta("_edit_lock_")) { lock->draw(viewport_ci, (transform * canvas_xform * parent_xform).xform(Point2(0, 0)) + Point2(offset, 0)); offset += lock->get_size().x; } Ref<Texture2D> group = get_editor_theme_icon(SNAME("GroupViewport")); - if (ci->has_meta("_edit_group_") && show_edit_locks) { + if (show_group_gizmos && ci->has_meta("_edit_group_")) { group->draw(viewport_ci, (transform * canvas_xform * parent_xform).xform(Point2(0, 0)) + Point2(offset, 0)); //offset += group->get_size().x; } @@ -3910,6 +3911,11 @@ void CanvasItemEditor::_update_editor_settings() { void CanvasItemEditor::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_READY: { + EditorRunBar::get_singleton()->connect("play_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true)); + EditorRunBar::get_singleton()->connect("stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false)); + } break; + case NOTIFICATION_PHYSICS_PROCESS: { EditorNode::get_singleton()->get_scene_root()->set_snap_controls_to_pixels(GLOBAL_GET("gui/common/snap_controls_to_pixels")); @@ -4289,16 +4295,28 @@ void CanvasItemEditor::_popup_callback(int p_op) { view_menu->get_popup()->set_item_checked(idx, show_viewport); viewport->queue_redraw(); } break; - case SHOW_EDIT_LOCKS: { - show_edit_locks = !show_edit_locks; - int idx = view_menu->get_popup()->get_item_index(SHOW_EDIT_LOCKS); - view_menu->get_popup()->set_item_checked(idx, show_edit_locks); + case SHOW_POSITION_GIZMOS: { + show_position_gizmos = !show_position_gizmos; + int idx = gizmos_menu->get_item_index(SHOW_POSITION_GIZMOS); + gizmos_menu->set_item_checked(idx, show_position_gizmos); + viewport->queue_redraw(); + } break; + case SHOW_LOCK_GIZMOS: { + show_lock_gizmos = !show_lock_gizmos; + int idx = gizmos_menu->get_item_index(SHOW_LOCK_GIZMOS); + gizmos_menu->set_item_checked(idx, show_lock_gizmos); + viewport->queue_redraw(); + } break; + case SHOW_GROUP_GIZMOS: { + show_group_gizmos = !show_group_gizmos; + int idx = gizmos_menu->get_item_index(SHOW_GROUP_GIZMOS); + gizmos_menu->set_item_checked(idx, show_group_gizmos); viewport->queue_redraw(); } break; case SHOW_TRANSFORMATION_GIZMOS: { show_transformation_gizmos = !show_transformation_gizmos; - int idx = view_menu->get_popup()->get_item_index(SHOW_TRANSFORMATION_GIZMOS); - view_menu->get_popup()->set_item_checked(idx, show_transformation_gizmos); + int idx = gizmos_menu->get_item_index(SHOW_TRANSFORMATION_GIZMOS); + gizmos_menu->set_item_checked(idx, show_transformation_gizmos); viewport->queue_redraw(); } break; case SNAP_USE_NODE_PARENT: { @@ -4710,7 +4728,7 @@ void CanvasItemEditor::_focus_selection(int p_op) { zoom *= 0.90; zoom_widget->set_zoom(zoom); viewport->queue_redraw(); // Redraw to update the global canvas transform after zoom changes. - call_deferred(SNAME("center_at"), rect.get_center()); // Defer because the updated transform is needed. + callable_mp(this, &CanvasItemEditor::center_at).call_deferred(rect.get_center()); // Defer because the updated transform is needed. } else { center_at(rect.get_center()); } @@ -4759,7 +4777,9 @@ Dictionary CanvasItemEditor::get_state() const { state["show_guides"] = show_guides; state["show_helpers"] = show_helpers; state["show_zoom_control"] = zoom_widget->is_visible(); - state["show_edit_locks"] = show_edit_locks; + state["show_position_gizmos"] = show_position_gizmos; + state["show_lock_gizmos"] = show_lock_gizmos; + state["show_group_gizmos"] = show_group_gizmos; state["show_transformation_gizmos"] = show_transformation_gizmos; state["snap_rotation"] = snap_rotation; state["snap_scale"] = snap_scale; @@ -4896,16 +4916,28 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { view_menu->get_popup()->set_item_checked(idx, show_helpers); } - if (state.has("show_edit_locks")) { - show_edit_locks = state["show_edit_locks"]; - int idx = view_menu->get_popup()->get_item_index(SHOW_EDIT_LOCKS); - view_menu->get_popup()->set_item_checked(idx, show_edit_locks); + if (state.has("show_position_gizmos")) { + show_position_gizmos = state["show_position_gizmos"]; + int idx = gizmos_menu->get_item_index(SHOW_POSITION_GIZMOS); + gizmos_menu->set_item_checked(idx, show_position_gizmos); + } + + if (state.has("show_lock_gizmos")) { + show_lock_gizmos = state["show_lock_gizmos"]; + int idx = gizmos_menu->get_item_index(SHOW_LOCK_GIZMOS); + gizmos_menu->set_item_checked(idx, show_lock_gizmos); + } + + if (state.has("show_group_gizmos")) { + show_group_gizmos = state["show_group_gizmos"]; + int idx = gizmos_menu->get_item_index(SHOW_GROUP_GIZMOS); + gizmos_menu->set_item_checked(idx, show_group_gizmos); } if (state.has("show_transformation_gizmos")) { show_transformation_gizmos = state["show_transformation_gizmos"]; - int idx = view_menu->get_popup()->get_item_index(SHOW_TRANSFORMATION_GIZMOS); - view_menu->get_popup()->set_item_checked(idx, show_transformation_gizmos); + int idx = gizmos_menu->get_item_index(SHOW_TRANSFORMATION_GIZMOS); + gizmos_menu->set_item_checked(idx, show_transformation_gizmos); } if (state.has("show_zoom_control")) { @@ -5053,9 +5085,6 @@ 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)); - EditorRunBar::get_singleton()->call_deferred(SNAME("connect"), "play_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true)); - EditorRunBar::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false)); - // Add some margin to the sides for better esthetics. // This prevents the first button's hover/pressed effect from "touching" the panel's border, // which looks ugly. @@ -5323,7 +5352,7 @@ CanvasItemEditor::CanvasItemEditor() { group_button->set_theme_type_variation("FlatButton"); main_menu_hbox->add_child(group_button); group_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(GROUP_SELECTED)); - group_button->set_tooltip_text(TTR("Make selected node's children not selectable.")); + group_button->set_tooltip_text(TTR("Groups the selected node with its children. This causes the parent to be selected when any child node is clicked in 2D and 3D view.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. group_button->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::G)); @@ -5331,7 +5360,7 @@ CanvasItemEditor::CanvasItemEditor() { ungroup_button->set_theme_type_variation("FlatButton"); main_menu_hbox->add_child(ungroup_button); ungroup_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(UNGROUP_SELECTED)); - ungroup_button->set_tooltip_text(TTR("Make selected node's children selectable.")); + ungroup_button->set_tooltip_text(TTR("Ungroups the selected node from its children. Child nodes will be individual items in 2D and 3D view.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. ungroup_button->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::G)); @@ -5394,8 +5423,18 @@ CanvasItemEditor::CanvasItemEditor() { p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_guides", TTR("Show Guides"), Key::Y), SHOW_GUIDES); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_origin", TTR("Show Origin")), SHOW_ORIGIN); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_viewport", TTR("Show Viewport")), SHOW_VIEWPORT); - p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_edit_locks", TTR("Show Group And Lock Icons")), SHOW_EDIT_LOCKS); - p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_transformation_gizmos", TTR("Show Transformation Gizmos")), SHOW_TRANSFORMATION_GIZMOS); + p->add_separator(); + + gizmos_menu = memnew(PopupMenu); + gizmos_menu->set_name("GizmosMenu"); + gizmos_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); + gizmos_menu->set_hide_on_checkable_item_selection(false); + gizmos_menu->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_position_gizmos", TTR("Position")), SHOW_POSITION_GIZMOS); + gizmos_menu->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_lock_gizmos", TTR("Lock")), SHOW_LOCK_GIZMOS); + gizmos_menu->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_group_gizmos", TTR("Group")), SHOW_GROUP_GIZMOS); + gizmos_menu->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_transformation_gizmos", TTR("Transformation")), SHOW_TRANSFORMATION_GIZMOS); + p->add_child(gizmos_menu); + p->add_submenu_item(TTR("Gizmos"), "GizmosMenu"); p->add_separator(); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), Key::F), VIEW_CENTER_TO_SELECTION); @@ -5806,7 +5845,7 @@ void CanvasItemEditorViewport::_perform_drop_data() { Vector<String> error_files; EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Create Node")); + undo_redo->create_action_for_history(TTR("Create Node"), EditorNode::get_editor_data().get_current_edited_scene_history_id()); for (int i = 0; i < selected_files.size(); i++) { String path = selected_files[i]; diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 9aac6e44df..7fe63e6282 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -126,7 +126,9 @@ private: SHOW_GUIDES, SHOW_ORIGIN, SHOW_VIEWPORT, - SHOW_EDIT_LOCKS, + SHOW_POSITION_GIZMOS, + SHOW_LOCK_GIZMOS, + SHOW_GROUP_GIZMOS, SHOW_TRANSFORMATION_GIZMOS, LOCK_SELECTED, UNLOCK_SELECTED, @@ -209,7 +211,9 @@ private: bool show_origin = true; bool show_viewport = true; bool show_helpers = false; - bool show_edit_locks = true; + bool show_position_gizmos = true; + bool show_lock_gizmos = true; + bool show_group_gizmos = true; bool show_transformation_gizmos = true; real_t zoom = 1.0; @@ -331,6 +335,7 @@ private: MenuButton *view_menu = nullptr; PopupMenu *grid_menu = nullptr; PopupMenu *theme_menu = nullptr; + PopupMenu *gizmos_menu = nullptr; HBoxContainer *animation_hb = nullptr; MenuButton *animation_menu = nullptr; @@ -388,9 +393,9 @@ private: CanvasItem *ref_item = nullptr; - void _save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones = false); - void _restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones = false); - void _commit_canvas_item_state(List<CanvasItem *> p_canvas_items, String action_name, bool commit_bones = false); + void _save_canvas_item_state(const List<CanvasItem *> &p_canvas_items, bool save_bones = false); + void _restore_canvas_item_state(const List<CanvasItem *> &p_canvas_items, bool restore_bones = false); + void _commit_canvas_item_state(const List<CanvasItem *> &p_canvas_items, String action_name, bool commit_bones = false); Vector2 _anchor_to_position(const Control *p_control, Vector2 anchor); Vector2 _position_to_anchor(const Control *p_control, Vector2 position); @@ -424,7 +429,7 @@ private: void _switch_theme_preview(int p_mode); List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true) const; - Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list); + Rect2 _get_encompassing_rect_from_list(const List<CanvasItem *> &p_list); void _expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D(), bool include_locked_nodes = true); Rect2 _get_encompassing_rect(const Node *p_node); @@ -540,7 +545,7 @@ public: SNAP_DEFAULT = SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL, }; - Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, unsigned int p_forced_modes = 0, const CanvasItem *p_self_canvas_item = nullptr, List<CanvasItem *> p_other_nodes_exceptions = List<CanvasItem *>()); + Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, unsigned int p_forced_modes = 0, const CanvasItem *p_self_canvas_item = nullptr, const List<CanvasItem *> &p_other_nodes_exceptions = List<CanvasItem *>()); real_t snap_angle(real_t p_target, real_t p_start = 0) const; Transform2D get_canvas_transform() const { return transform; } diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp index a0539c401d..0688ed959e 100644 --- a/editor/plugins/control_editor_plugin.cpp +++ b/editor/plugins/control_editor_plugin.cpp @@ -189,7 +189,7 @@ void EditorPropertyAnchorsPreset::setup(const Vector<String> &p_options) { Vector<String> text_split = p_options[i].split(":"); int64_t current_val = text_split[1].to_int(); - String option_name = text_split[0]; + const String &option_name = text_split[0]; if (option_name.begins_with("Preset")) { String preset_name = option_name.trim_prefix("Preset"); String humanized_name = preset_name.capitalize(); diff --git a/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp index 1fce7f5efb..3a8a0cff96 100644 --- a/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp @@ -284,7 +284,7 @@ Joint3DGizmoPlugin::Joint3DGizmoPlugin() { update_timer->set_wait_time(1.0 / 120.0); update_timer->connect("timeout", callable_mp(this, &Joint3DGizmoPlugin::incremental_update_gizmos)); update_timer->set_autostart(true); - EditorNode::get_singleton()->call_deferred(SNAME("add_child"), update_timer); + callable_mp((Node *)EditorNode::get_singleton(), &Node::add_child).call_deferred(update_timer, false, Node::INTERNAL_MODE_DISABLED); } void Joint3DGizmoPlugin::incremental_update_gizmos() { diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp index 11f60a166c..335498dff9 100644 --- a/editor/plugins/lightmap_gi_editor_plugin.cpp +++ b/editor/plugins/lightmap_gi_editor_plugin.cpp @@ -105,7 +105,10 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) { EditorNode::get_singleton()->show_warning(TTR("Lightmap data is not local to the scene.")); } break; case LightmapGI::BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL: { - EditorNode::get_singleton()->show_warning(TTR("Maximum texture size is too small for the lightmap images.")); + EditorNode::get_singleton()->show_warning(TTR("Maximum texture size is too small for the lightmap images.\nWhile this can be fixed by increasing the maximum texture size, it is recommended you split the scene into more objects instead.")); + } break; + case LightmapGI::BAKE_ERROR_LIGHTMAP_TOO_SMALL: { + EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images. Make sure all meshes selected to bake have `lightmap_size_hint` value set high enough, and `texel_scale` value of LightmapGI is not too low.")); } break; default: { } break; diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 3bd786c04f..a427d0359d 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -825,6 +825,7 @@ void EditorNode3DGizmo::_bind_methods() { GDVIRTUAL_BIND(_is_handle_highlighted, "id", "secondary"); GDVIRTUAL_BIND(_get_handle_value, "id", "secondary"); + GDVIRTUAL_BIND(_begin_handle_action, "id", "secondary"); GDVIRTUAL_BIND(_set_handle, "id", "secondary", "camera", "point"); GDVIRTUAL_BIND(_commit_handle, "id", "secondary", "restore", "cancel"); @@ -1045,6 +1046,7 @@ void EditorNode3DGizmoPlugin::_bind_methods() { GDVIRTUAL_BIND(_is_handle_highlighted, "gizmo", "handle_id", "secondary"); GDVIRTUAL_BIND(_get_handle_value, "gizmo", "handle_id", "secondary"); + GDVIRTUAL_BIND(_begin_handle_action, "gizmo", "handle_id", "secondary"); GDVIRTUAL_BIND(_set_handle, "gizmo", "handle_id", "secondary", "camera", "screen_pos"); GDVIRTUAL_BIND(_commit_handle, "gizmo", "handle_id", "secondary", "restore", "cancel"); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 52f17c4a45..e4d24832bf 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -1839,17 +1839,17 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { clicked = ObjectID(); - if ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->is_command_or_control_pressed()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) { + if (can_select_gizmos && ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->is_command_or_control_pressed()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE)) { begin_transform(TRANSFORM_ROTATE, false); break; } - if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) { + if (can_select_gizmos && spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) { begin_transform(TRANSFORM_TRANSLATE, false); break; } - if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) { + if (can_select_gizmos && spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) { begin_transform(TRANSFORM_SCALE, false); break; } @@ -2734,11 +2734,11 @@ void Node3DEditorViewport::_notification(int p_what) { } else { set_freelook_active(false); } - call_deferred(SNAME("update_transform_gizmo_view")); + callable_mp(this, &Node3DEditorViewport::update_transform_gizmo_view).call_deferred(); } break; case NOTIFICATION_RESIZED: { - call_deferred(SNAME("update_transform_gizmo_view")); + callable_mp(this, &Node3DEditorViewport::update_transform_gizmo_view).call_deferred(); } break; case NOTIFICATION_PROCESS: { @@ -3355,7 +3355,7 @@ void Node3DEditorViewport::_menu_option(int p_option) { view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), false); orthogonal = false; auto_orthogonal = false; - call_deferred(SNAME("update_transform_gizmo_view")); + callable_mp(this, &Node3DEditorViewport::update_transform_gizmo_view).call_deferred(); _update_camera(0); _update_name(); @@ -3365,7 +3365,7 @@ void Node3DEditorViewport::_menu_option(int p_option) { view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), true); orthogonal = true; auto_orthogonal = false; - call_deferred(SNAME("update_transform_gizmo_view")); + callable_mp(this, &Node3DEditorViewport::update_transform_gizmo_view).call_deferred(); _update_camera(0); _update_name(); } break; @@ -3985,8 +3985,6 @@ Dictionary Node3DEditorViewport::get_state() const { } void Node3DEditorViewport::_bind_methods() { - ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &Node3DEditorViewport::update_transform_gizmo_view); // Used by call_deferred. - ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport"))); ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport"))); } @@ -4247,17 +4245,16 @@ bool Node3DEditorViewport::_apply_preview_material(ObjectID p_target, const Poin return false; } - if (spatial_editor->get_preview_material() != mesh_instance->get_surface_override_material(closest_surface)) { - spatial_editor->set_preview_material_surface(closest_surface); - spatial_editor->set_preview_reset_material(mesh_instance->get_surface_override_material(closest_surface)); - mesh_instance->set_surface_override_material(closest_surface, spatial_editor->get_preview_material()); - } + spatial_editor->set_preview_material_surface(closest_surface); + spatial_editor->set_preview_reset_material(mesh_instance->get_surface_override_material(closest_surface)); + mesh_instance->set_surface_override_material(closest_surface, spatial_editor->get_preview_material()); return true; } GeometryInstance3D *geometry_instance = Object::cast_to<GeometryInstance3D>(target_inst); - if (geometry_instance && spatial_editor->get_preview_material() != geometry_instance->get_material_override()) { + if (geometry_instance) { + spatial_editor->set_preview_material_surface(-1); spatial_editor->set_preview_reset_material(geometry_instance->get_material_override()); geometry_instance->set_material_override(spatial_editor->get_preview_material()); return true; @@ -4277,7 +4274,6 @@ void Node3DEditorViewport::_reset_preview_material() const { GeometryInstance3D *geometry_instance = Object::cast_to<GeometryInstance3D>(last_target_inst); if (mesh_instance && spatial_editor->get_preview_material_surface() != -1) { mesh_instance->set_surface_override_material(spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_reset_material()); - spatial_editor->set_preview_material_surface(-1); } else if (geometry_instance) { geometry_instance->set_material_override(spatial_editor->get_preview_reset_material()); } @@ -6489,25 +6485,91 @@ void Node3DEditor::_init_indicators() { origin_enabled = true; grid_enabled = true; - indicator_mat.instantiate(); - indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); - indicator_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); - indicator_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true); - indicator_mat->set_transparency(StandardMaterial3D::Transparency::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS); + Ref<Shader> origin_shader = memnew(Shader); + origin_shader->set_code(R"( +// 3D editor origin line shader. + +shader_type spatial; +render_mode blend_mix,cull_disabled,unshaded, fog_disabled; + +void vertex() { + vec3 point_a = MODEL_MATRIX[3].xyz; + // Encoded in scale. + vec3 point_b = vec3(MODEL_MATRIX[0].x, MODEL_MATRIX[1].y, MODEL_MATRIX[2].z); + + // Points are already in world space, so no need for MODEL_MATRIX anymore. + vec4 clip_a = PROJECTION_MATRIX * (VIEW_MATRIX * vec4(point_a, 1.0)); + vec4 clip_b = PROJECTION_MATRIX * (VIEW_MATRIX * vec4(point_b, 1.0)); + + vec2 screen_a = VIEWPORT_SIZE * (0.5 * clip_a.xy / clip_a.w + 0.5); + vec2 screen_b = VIEWPORT_SIZE * (0.5 * clip_b.xy / clip_b.w + 0.5); + + vec2 x_basis = normalize(screen_b - screen_a); + vec2 y_basis = vec2(-x_basis.y, x_basis.x); + + float width = 3.0; + vec2 screen_point_a = screen_a + width * (VERTEX.x * x_basis + VERTEX.y * y_basis); + vec2 screen_point_b = screen_b + width * (VERTEX.x * x_basis + VERTEX.y * y_basis); + vec2 screen_point_final = mix(screen_point_a, screen_point_b, VERTEX.z); + + vec4 clip_final = mix(clip_a, clip_b, VERTEX.z); + + POSITION = vec4(clip_final.w * ((2.0 * screen_point_final) / VIEWPORT_SIZE - 1.0), clip_final.z, clip_final.w); + UV = VERTEX.yz * clip_final.w; + + if (!OUTPUT_IS_SRGB) { + COLOR.rgb = mix(pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb * (1.0 / 12.92), lessThan(COLOR.rgb, vec3(0.04045))); + } +} + +void fragment() { + // Multiply by 0.5 since UV is actually UV is [-1, 1]. + float line_width = fwidth(UV.x * 0.5); + float line_uv = abs(UV.x * 0.5); + float line = smoothstep(line_width * 1.0, line_width * 0.25, line_uv); + + ALBEDO = COLOR.rgb; + ALPHA *= COLOR.a * line; +} +)"); + + origin_mat.instantiate(); + origin_mat->set_shader(origin_shader); - Vector<Color> origin_colors; Vector<Vector3> origin_points; + origin_points.resize(6); + + origin_points.set(0, Vector3(0.0, -0.5, 0.0)); + origin_points.set(1, Vector3(0.0, -0.5, 1.0)); + origin_points.set(2, Vector3(0.0, 0.5, 1.0)); + + origin_points.set(3, Vector3(0.0, -0.5, 0.0)); + origin_points.set(4, Vector3(0.0, 0.5, 1.0)); + origin_points.set(5, Vector3(0.0, 0.5, 0.0)); + + Array d; + d.resize(RS::ARRAY_MAX); + d[RenderingServer::ARRAY_VERTEX] = origin_points; - const int count_of_elements = 3 * 6; - origin_colors.resize(count_of_elements); - origin_points.resize(count_of_elements); + origin_mesh = RenderingServer::get_singleton()->mesh_create(); - int x = 0; + RenderingServer::get_singleton()->mesh_add_surface_from_arrays(origin_mesh, RenderingServer::PRIMITIVE_TRIANGLES, d); + RenderingServer::get_singleton()->mesh_surface_set_material(origin_mesh, 0, origin_mat->get_rid()); + + origin_multimesh = RenderingServer::get_singleton()->multimesh_create(); + RenderingServer::get_singleton()->multimesh_set_mesh(origin_multimesh, origin_mesh); + RenderingServer::get_singleton()->multimesh_allocate_data(origin_multimesh, 12, RS::MultimeshTransformFormat::MULTIMESH_TRANSFORM_3D, true, false); + RenderingServer::get_singleton()->multimesh_set_visible_instances(origin_multimesh, -1); + + LocalVector<float> distances; + distances.resize(5); + distances[0] = -1000000.0; + distances[1] = -1000.0; + distances[2] = 0.0; + distances[3] = 1000.0; + distances[4] = 1000000.0; for (int i = 0; i < 3; i++) { - Vector3 axis; - axis[i] = 1; Color origin_color; switch (i) { case 0: @@ -6524,27 +6586,26 @@ void Node3DEditor::_init_indicators() { break; } - grid_enable[i] = false; - grid_visible[i] = false; + Vector3 axis; + axis[i] = 1; - origin_colors.set(x, origin_color); - origin_colors.set(x + 1, origin_color); - origin_colors.set(x + 2, origin_color); - origin_colors.set(x + 3, origin_color); - origin_colors.set(x + 4, origin_color); - origin_colors.set(x + 5, origin_color); - // To both allow having a large origin size and avoid jitter - // at small scales, we should segment the line into pieces. - // 3 pieces seems to do the trick, and let's use powers of 2. - origin_points.set(x, axis * 1048576); - origin_points.set(x + 1, axis * 1024); - origin_points.set(x + 2, axis * 1024); - origin_points.set(x + 3, axis * -1024); - origin_points.set(x + 4, axis * -1024); - origin_points.set(x + 5, axis * -1048576); - x += 6; + for (int j = 0; j < 4; j++) { + Transform3D t = Transform3D(); + t = t.scaled(axis * distances[j + 1]); + t = t.translated(axis * distances[j]); + RenderingServer::get_singleton()->multimesh_instance_set_transform(origin_multimesh, i * 4 + j, t); + RenderingServer::get_singleton()->multimesh_instance_set_color(origin_multimesh, i * 4 + j, origin_color); + } } + origin_instance = RenderingServer::get_singleton()->instance_create2(origin_multimesh, get_tree()->get_root()->get_world_3d()->get_scenario()); + RS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << Node3DEditorViewport::GIZMO_GRID_LAYER); + RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true); + RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false); + RS::get_singleton()->instance_set_ignore_culling(origin_instance, true); + + RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, RS::SHADOW_CASTING_SETTING_OFF); + Ref<Shader> grid_shader = memnew(Shader); grid_shader->set_code(R"( // 3D editor grid shader. @@ -6593,22 +6654,6 @@ void fragment() { grid_visible[2] = grid_enable[2]; _init_grid(); - - origin = RenderingServer::get_singleton()->mesh_create(); - Array d; - d.resize(RS::ARRAY_MAX); - d[RenderingServer::ARRAY_VERTEX] = origin_points; - d[RenderingServer::ARRAY_COLOR] = origin_colors; - - RenderingServer::get_singleton()->mesh_add_surface_from_arrays(origin, RenderingServer::PRIMITIVE_LINES, d); - RenderingServer::get_singleton()->mesh_surface_set_material(origin, 0, indicator_mat->get_rid()); - - origin_instance = RenderingServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world_3d()->get_scenario()); - RS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << Node3DEditorViewport::GIZMO_GRID_LAYER); - RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true); - RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false); - - RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, RS::SHADOW_CASTING_SETTING_OFF); } { @@ -7226,7 +7271,8 @@ void Node3DEditor::_init_grid() { void Node3DEditor::_finish_indicators() { RenderingServer::get_singleton()->free(origin_instance); - RenderingServer::get_singleton()->free(origin); + RenderingServer::get_singleton()->free(origin_multimesh); + RenderingServer::get_singleton()->free(origin_mesh); _finish_grid(); } @@ -8013,6 +8059,8 @@ void Node3DEditor::_bind_methods() { ClassDB::bind_method("_clear_subgizmo_selection", &Node3DEditor::_clear_subgizmo_selection); ClassDB::bind_method("_refresh_menu_icons", &Node3DEditor::_refresh_menu_icons); + ClassDB::bind_method("update_all_gizmos", &Node3DEditor::update_all_gizmos); + ADD_SIGNAL(MethodInfo("transform_key_request")); ADD_SIGNAL(MethodInfo("item_lock_status_changed")); ADD_SIGNAL(MethodInfo("item_group_status_changed")); @@ -8300,7 +8348,7 @@ Node3DEditor::Node3DEditor() { main_menu_hbox->add_child(tool_button[TOOL_GROUP_SELECTED]); tool_button[TOOL_GROUP_SELECTED]->set_theme_type_variation("FlatButton"); tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_GROUP_SELECTED)); - tool_button[TOOL_GROUP_SELECTED]->set_tooltip_text(TTR("Make selected node's children not selectable.")); + tool_button[TOOL_GROUP_SELECTED]->set_tooltip_text(TTR("Groups the selected node with its children. This selects the parent when any child node is clicked in 2D and 3D view.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::G)); @@ -8308,7 +8356,7 @@ Node3DEditor::Node3DEditor() { main_menu_hbox->add_child(tool_button[TOOL_UNGROUP_SELECTED]); tool_button[TOOL_UNGROUP_SELECTED]->set_theme_type_variation("FlatButton"); tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNGROUP_SELECTED)); - tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip_text(TTR("Make selected node's children selectable.")); + tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip_text(TTR("Ungroups the selected node from its children. Child nodes will be individual items in 2D and 3D view.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::G)); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 1ce09a2bcb..0f6ea71571 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -597,7 +597,8 @@ private: ToolMode tool_mode; - RID origin; + RID origin_mesh; + RID origin_multimesh; RID origin_instance; bool origin_enabled = false; RID grid[3]; @@ -631,7 +632,7 @@ private: RID indicators_instance; RID cursor_mesh; RID cursor_instance; - Ref<StandardMaterial3D> indicator_mat; + Ref<ShaderMaterial> origin_mat; Ref<ShaderMaterial> grid_mat[3]; Ref<StandardMaterial3D> cursor_material; diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index 0d6086bb4d..6f44dfc755 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -37,6 +37,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "scene/gui/dialogs.h" #include "scene/gui/menu_button.h" void Path2DEditor::_notification(int p_what) { @@ -48,6 +49,7 @@ void Path2DEditor::_notification(int p_what) { curve_create->set_icon(get_editor_theme_icon(SNAME("CurveCreate"))); curve_del->set_icon(get_editor_theme_icon(SNAME("CurveDelete"))); curve_close->set_icon(get_editor_theme_icon(SNAME("CurveClose"))); + curve_clear_points->set_icon(get_editor_theme_icon(SNAME("Clear"))); } break; } } @@ -68,7 +70,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { return false; } - if (!node->get_curve().is_valid()) { + if (node->get_curve().is_null()) { return false; } @@ -121,7 +123,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { // Check for point deletion. EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - if ((mb->get_button_index() == MouseButton::RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == MouseButton::LEFT && mode == MODE_DELETE)) { + if ((mb->get_button_index() == MouseButton::RIGHT && (mode == MODE_EDIT || mode == MODE_CREATE)) || (mb->get_button_index() == MouseButton::LEFT && mode == MODE_DELETE)) { if (dist_to_p < grab_threshold) { undo_redo->create_action(TTR("Remove Point from Curve")); undo_redo->add_do_method(curve.ptr(), "remove_point", i); @@ -154,16 +156,14 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { // Check for point creation. if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && ((mb->is_command_or_control_pressed() && mode == MODE_EDIT) || mode == MODE_CREATE)) { Ref<Curve2D> curve = node->get_curve(); + curve->add_point(cpoint); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Point to Curve")); undo_redo->add_do_method(curve.ptr(), "add_point", cpoint); - undo_redo->add_undo_method(curve.ptr(), "remove_point", curve->get_point_count()); - undo_redo->add_do_method(canvas_item_editor, "update_viewport"); - undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); - undo_redo->commit_action(); + undo_redo->add_undo_method(curve.ptr(), "remove_point", curve->get_point_count() - 1); - action = ACTION_MOVING_POINT; + action = ACTION_MOVING_NEW_POINT; action_point = curve->get_point_count() - 1; moving_from = curve->get_point_position(action_point); moving_screen_from = gpoint; @@ -191,15 +191,15 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { insertion_point = curve->get_point_count() - 2; } + const Vector2 new_point = xform.affine_inverse().xform(gpoint2); + curve->add_point(new_point, Vector2(0, 0), Vector2(0, 0), insertion_point + 1); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Split Curve")); - undo_redo->add_do_method(curve.ptr(), "add_point", xform.affine_inverse().xform(gpoint2), Vector2(0, 0), Vector2(0, 0), insertion_point + 1); + undo_redo->add_do_method(curve.ptr(), "add_point", new_point, Vector2(0, 0), Vector2(0, 0), insertion_point + 1); undo_redo->add_undo_method(curve.ptr(), "remove_point", insertion_point + 1); - undo_redo->add_do_method(canvas_item_editor, "update_viewport"); - undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); - undo_redo->commit_action(); - action = ACTION_MOVING_POINT; + action = ACTION_MOVING_NEW_POINT; action_point = insertion_point + 1; moving_from = curve->get_point_position(action_point); moving_screen_from = gpoint2; @@ -222,13 +222,16 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { // N/A, handled in above condition. break; - case ACTION_MOVING_POINT: { - undo_redo->create_action(TTR("Move Point in Curve")); + case ACTION_MOVING_POINT: + case ACTION_MOVING_NEW_POINT: { + if (action == ACTION_MOVING_POINT) { + undo_redo->create_action(TTR("Move Point in Curve")); + undo_redo->add_undo_method(curve.ptr(), "set_point_position", action_point, moving_from); + } undo_redo->add_do_method(curve.ptr(), "set_point_position", action_point, cpoint); - undo_redo->add_undo_method(curve.ptr(), "set_point_position", action_point, moving_from); undo_redo->add_do_method(canvas_item_editor, "update_viewport"); undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); - undo_redo->commit_action(); + undo_redo->commit_action(false); } break; @@ -334,7 +337,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { // N/A, handled in above condition. break; - case ACTION_MOVING_POINT: { + case ACTION_MOVING_POINT: + case ACTION_MOVING_NEW_POINT: { curve->set_point_position(action_point, cpoint); } break; @@ -364,7 +368,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { - if (!node || !node->is_visible_in_tree() || !node->get_curve().is_valid()) { + if (!node || !node->is_visible_in_tree() || node->get_curve().is_null()) { return; } @@ -437,12 +441,12 @@ void Path2DEditor::edit(Node *p_path2d) { if (p_path2d) { node = Object::cast_to<Path2D>(p_path2d); + if (!node->is_connected("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed))) { node->connect("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed)); } - } else { - // node may have been deleted at this point + // The node may have been deleted at this point. if (node && node->is_connected("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed))) { node->disconnect("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed)); } @@ -452,6 +456,8 @@ void Path2DEditor::edit(Node *p_path2d) { void Path2DEditor::_bind_methods() { //ClassDB::bind_method(D_METHOD("_menu_option"),&Path2DEditor::_menu_option); + ClassDB::bind_method(D_METHOD("_clear_curve_points"), &Path2DEditor::_clear_curve_points); + ClassDB::bind_method(D_METHOD("_restore_curve_points"), &Path2DEditor::_restore_curve_points); } void Path2DEditor::_mode_selected(int p_mode) { @@ -475,32 +481,46 @@ void Path2DEditor::_mode_selected(int p_mode) { curve_edit->set_pressed(false); curve_edit_curve->set_pressed(false); curve_del->set_pressed(true); - } else if (p_mode == ACTION_CLOSE) { - //? - - if (!node->get_curve().is_valid()) { + } else if (p_mode == MODE_CLOSE) { + if (node->get_curve().is_null()) { return; } if (node->get_curve()->get_point_count() < 3) { return; } - Vector2 begin = node->get_curve()->get_point_position(0); Vector2 end = node->get_curve()->get_point_position(node->get_curve()->get_point_count() - 1); + if (begin.is_equal_approx(end)) { return; } - EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Remove Point from Curve")); + + undo_redo->create_action(TTR("Close the Curve")); undo_redo->add_do_method(node->get_curve().ptr(), "add_point", begin); undo_redo->add_undo_method(node->get_curve().ptr(), "remove_point", node->get_curve()->get_point_count()); undo_redo->add_do_method(canvas_item_editor, "update_viewport"); undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); undo_redo->commit_action(); return; - } + } else if (p_mode == MODE_CLEAR_POINTS) { + if (node->get_curve().is_null()) { + return; + } + if (node->get_curve()->get_point_count() == 0) { + return; + } + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + PackedVector2Array points = node->get_curve()->get_points().duplicate(); + undo_redo->create_action(TTR("Clear Curve Points"), UndoRedo::MERGE_DISABLE, node); + undo_redo->add_do_method(this, "_clear_curve_points", node); + undo_redo->add_undo_method(this, "_restore_curve_points", node, points); + undo_redo->add_do_method(canvas_item_editor, "update_viewport"); + undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); + undo_redo->commit_action(); + return; + } mode = Mode(p_mode); } @@ -523,6 +543,52 @@ void Path2DEditor::_handle_option_pressed(int p_option) { } } +void Path2DEditor::_confirm_clear_points() { + if (!node || node->get_curve().is_null()) { + return; + } + if (node->get_curve()->get_point_count() == 0) { + return; + } + clear_points_dialog->reset_size(); + clear_points_dialog->popup_centered(); +} + +void Path2DEditor::_clear_curve_points(Path2D *p_path2d) { + if (!p_path2d || p_path2d->get_curve().is_null()) { + return; + } + Ref<Curve2D> curve = p_path2d->get_curve(); + + if (curve->get_point_count() == 0) { + return; + } + curve->clear_points(); + + if (node == p_path2d) { + _mode_selected(MODE_CREATE); + } +} + +void Path2DEditor::_restore_curve_points(Path2D *p_path2d, const PackedVector2Array &p_points) { + if (!p_path2d || p_path2d->get_curve().is_null()) { + return; + } + Ref<Curve2D> curve = p_path2d->get_curve(); + + if (curve->get_point_count() > 0) { + curve->clear_points(); + } + + for (int i = 0; i < p_points.size(); i += 3) { + curve->add_point(p_points[i + 2], p_points[i], p_points[i + 1]); // The Curve2D::points pattern is [point_in, point_out, point_position]. + } + + if (node == p_path2d) { + _mode_selected(MODE_EDIT); + } +} + Path2DEditor::Path2DEditor() { canvas_item_editor = nullptr; mirror_handle_angle = true; @@ -553,7 +619,7 @@ Path2DEditor::Path2DEditor() { curve_create->set_theme_type_variation("FlatButton"); curve_create->set_toggle_mode(true); curve_create->set_focus_mode(Control::FOCUS_NONE); - curve_create->set_tooltip_text(TTR("Add Point (in empty space)")); + curve_create->set_tooltip_text(TTR("Add Point (in empty space)") + "\n" + TTR("Right Click: Delete Point")); curve_create->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_CREATE)); add_child(curve_create); @@ -569,9 +635,22 @@ Path2DEditor::Path2DEditor() { curve_close->set_theme_type_variation("FlatButton"); curve_close->set_focus_mode(Control::FOCUS_NONE); curve_close->set_tooltip_text(TTR("Close Curve")); - curve_close->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(ACTION_CLOSE)); + curve_close->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_CLOSE)); add_child(curve_close); + curve_clear_points = memnew(Button); + curve_clear_points->set_theme_type_variation("FlatButton"); + curve_clear_points->set_focus_mode(Control::FOCUS_NONE); + curve_clear_points->set_tooltip_text(TTR("Clear Points")); + curve_clear_points->connect("pressed", callable_mp(this, &Path2DEditor::_confirm_clear_points)); + add_child(curve_clear_points); + + clear_points_dialog = memnew(ConfirmationDialog); + clear_points_dialog->set_title(TTR("Please Confirm...")); + clear_points_dialog->set_text(TTR("Remove all curve points?")); + clear_points_dialog->connect("confirmed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_CLEAR_POINTS)); + add_child(clear_points_dialog); + PopupMenu *menu; handle_menu = memnew(MenuButton); diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h index b8816d9b1e..af9f307cc8 100644 --- a/editor/plugins/path_2d_editor_plugin.h +++ b/editor/plugins/path_2d_editor_plugin.h @@ -36,45 +36,51 @@ #include "scene/gui/box_container.h" class CanvasItemEditor; +class ConfirmationDialog; class MenuButton; class Path2DEditor : public HBoxContainer { GDCLASS(Path2DEditor, HBoxContainer); + friend class Path2DEditorPlugin; + CanvasItemEditor *canvas_item_editor = nullptr; Panel *panel = nullptr; Path2D *node = nullptr; - HBoxContainer *base_hb = nullptr; - enum Mode { MODE_CREATE, MODE_EDIT, MODE_EDIT_CURVE, MODE_DELETE, - ACTION_CLOSE + MODE_CLOSE, + MODE_CLEAR_POINTS, }; Mode mode; + Button *curve_clear_points = nullptr; + Button *curve_close = nullptr; Button *curve_create = nullptr; + Button *curve_del = nullptr; Button *curve_edit = nullptr; Button *curve_edit_curve = nullptr; - Button *curve_del = nullptr; - Button *curve_close = nullptr; MenuButton *handle_menu = nullptr; + ConfirmationDialog *clear_points_dialog = nullptr; + bool mirror_handle_angle; bool mirror_handle_length; bool on_edge; enum HandleOption { HANDLE_OPTION_ANGLE, - HANDLE_OPTION_LENGTH + HANDLE_OPTION_LENGTH, }; enum Action { ACTION_NONE, ACTION_MOVING_POINT, + ACTION_MOVING_NEW_POINT, ACTION_MOVING_IN, ACTION_MOVING_OUT, }; @@ -91,7 +97,10 @@ class Path2DEditor : public HBoxContainer { void _handle_option_pressed(int p_option); void _node_visibility_changed(); - friend class Path2DEditorPlugin; + + void _confirm_clear_points(); + void _clear_curve_points(Path2D *p_path2d); + void _restore_curve_points(Path2D *p_path2d, const PackedVector2Array &p_points); protected: void _notification(int p_what); diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index f8e6c71a4c..148ba7d7ca 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -36,6 +36,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/gui/editor_zoom_widget.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/2d/skeleton_2d.h" #include "scene/gui/check_box.h" @@ -96,10 +97,14 @@ void Polygon2DEditor::_notification(int p_what) { b_snap_grid->set_icon(get_editor_theme_icon(SNAME("Grid"))); b_snap_enable->set_icon(get_editor_theme_icon(SNAME("SnapGrid"))); - uv_icon_zoom->set_texture(get_editor_theme_icon(SNAME("Zoom"))); uv_vscroll->set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE); uv_hscroll->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE); + // Avoid scrollbar overlapping. + Size2 hmin = uv_hscroll->get_combined_minimum_size(); + Size2 vmin = uv_vscroll->get_combined_minimum_size(); + uv_hscroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -vmin.width); + uv_vscroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -hmin.height); [[fallthrough]]; } case NOTIFICATION_THEME_CHANGED: { @@ -317,6 +322,7 @@ void Polygon2DEditor::_menu_option(int p_option) { uv_edit->popup_centered_ratio(0.85); } _update_bone_list(); + get_tree()->connect("process_frame", callable_mp(this, &Polygon2DEditor::_center_view), CONNECT_ONE_SHOT); } break; case UVEDIT_POLYGON_TO_UV: { Vector<Vector2> points = node->get_polygon(); @@ -470,7 +476,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } Transform2D mtx; - mtx.columns[2] = -uv_draw_ofs; + mtx.columns[2] = -uv_draw_ofs * uv_draw_zoom; mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom)); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); @@ -941,36 +947,79 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_edit_draw->queue_redraw(); } } +} - Ref<InputEventMagnifyGesture> magnify_gesture = p_input; - if (magnify_gesture.is_valid()) { - uv_zoom->set_value(uv_zoom->get_value() * magnify_gesture->get_factor()); +void Polygon2DEditor::_center_view() { + Size2 texture_size; + if (node->get_texture().is_valid()) { + texture_size = node->get_texture()->get_size(); + Vector2 zoom_factor = (uv_edit_draw->get_size() - Vector2(1, 1) * 50 * EDSCALE) / texture_size; + zoom_widget->set_zoom(MIN(zoom_factor.x, zoom_factor.y)); + } else { + zoom_widget->set_zoom(EDSCALE); } + // Recalculate scroll limits. + _update_zoom_and_pan(false); - Ref<InputEventPanGesture> pan_gesture = p_input; - if (pan_gesture.is_valid()) { - uv_hscroll->set_value(uv_hscroll->get_value() + uv_hscroll->get_page() * pan_gesture->get_delta().x / 8); - uv_vscroll->set_value(uv_vscroll->get_value() + uv_vscroll->get_page() * pan_gesture->get_delta().y / 8); - } + Size2 offset = (texture_size - uv_edit_draw->get_size() / uv_draw_zoom) / 2; + uv_hscroll->set_value_no_signal(offset.x); + uv_vscroll->set_value_no_signal(offset.y); + _update_zoom_and_pan(false); } void Polygon2DEditor::_uv_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) { - uv_hscroll->set_value(uv_hscroll->get_value() - p_scroll_vec.x); - uv_vscroll->set_value(uv_vscroll->get_value() - p_scroll_vec.y); + uv_hscroll->set_value_no_signal(uv_hscroll->get_value() - p_scroll_vec.x / uv_draw_zoom); + uv_vscroll->set_value_no_signal(uv_vscroll->get_value() - p_scroll_vec.y / uv_draw_zoom); + _update_zoom_and_pan(false); } void Polygon2DEditor::_uv_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) { - uv_zoom->set_value(uv_zoom->get_value() * p_zoom_factor); + zoom_widget->set_zoom(uv_draw_zoom * p_zoom_factor); + uv_draw_ofs += p_origin / uv_draw_zoom - p_origin / zoom_widget->get_zoom(); + uv_hscroll->set_value_no_signal(uv_draw_ofs.x); + uv_vscroll->set_value_no_signal(uv_draw_ofs.y); + _update_zoom_and_pan(false); } -void Polygon2DEditor::_uv_scroll_changed(real_t) { - if (updating_uv_scroll) { - return; +void Polygon2DEditor::_update_zoom_and_pan(bool p_zoom_at_center) { + uv_draw_ofs = Vector2(uv_hscroll->get_value(), uv_vscroll->get_value()); + real_t previous_zoom = uv_draw_zoom; + uv_draw_zoom = zoom_widget->get_zoom(); + if (p_zoom_at_center) { + Vector2 center = uv_edit_draw->get_size() / 2; + uv_draw_ofs += center / previous_zoom - center / uv_draw_zoom; + } + + Point2 min_corner; + Point2 max_corner; + if (node->get_texture().is_valid()) { + max_corner += node->get_texture()->get_size(); + } + + Vector<Vector2> points = uv_edit_mode[0]->is_pressed() ? node->get_uv() : node->get_polygon(); + for (int i = 0; i < points.size(); i++) { + min_corner = min_corner.min(points[i]); + max_corner = max_corner.max(points[i]); } + Size2 page_size = uv_edit_draw->get_size() / uv_draw_zoom; + Vector2 margin = Vector2(50, 50) * EDSCALE / uv_draw_zoom; + min_corner -= page_size - margin; + max_corner += page_size - margin; + + uv_hscroll->set_block_signals(true); + uv_hscroll->set_min(min_corner.x); + uv_hscroll->set_max(max_corner.x); + uv_hscroll->set_page(page_size.x); + uv_hscroll->set_value(uv_draw_ofs.x); + uv_hscroll->set_block_signals(false); + + uv_vscroll->set_block_signals(true); + uv_vscroll->set_min(min_corner.y); + uv_vscroll->set_max(max_corner.y); + uv_vscroll->set_page(page_size.y); + uv_vscroll->set_value(uv_draw_ofs.y); + uv_vscroll->set_block_signals(false); - uv_draw_ofs.x = uv_hscroll->get_value(); - uv_draw_ofs.y = uv_vscroll->get_value(); - uv_draw_zoom = uv_zoom->get_value(); uv_edit_draw->queue_redraw(); } @@ -987,7 +1036,7 @@ void Polygon2DEditor::_uv_draw() { String warning; Transform2D mtx; - mtx.columns[2] = -uv_draw_ofs; + mtx.columns[2] = -uv_draw_ofs * uv_draw_zoom; mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom)); // Draw texture as a background if editing uvs or no uv mapping exist. @@ -1094,7 +1143,6 @@ void Polygon2DEditor::_uv_draw() { polygon_fill_color.push_back(pf); } Color prev_color = Color(0.5, 0.5, 0.5); - Rect2 rect; int uv_draw_max = uvs.size(); @@ -1222,40 +1270,6 @@ void Polygon2DEditor::_uv_draw() { //draw paint circle uv_edit_draw->draw_circle(bone_paint_pos, bone_paint_radius->get_value() * EDSCALE, Color(1, 1, 1, 0.1)); } - - rect.position = -uv_edit_draw->get_size(); - rect.size = uv_edit_draw->get_size() * 2.0 + base_tex->get_size() * uv_draw_zoom; - - updating_uv_scroll = true; - - uv_hscroll->set_min(rect.position.x); - uv_hscroll->set_max(rect.position.x + rect.size.x); - if (ABS(rect.position.x - (rect.position.x + rect.size.x)) <= uv_edit_draw->get_size().x) { - uv_hscroll->hide(); - } else { - uv_hscroll->show(); - uv_hscroll->set_page(uv_edit_draw->get_size().x); - uv_hscroll->set_value(uv_draw_ofs.x); - } - - uv_vscroll->set_min(rect.position.y); - uv_vscroll->set_max(rect.position.y + rect.size.y); - if (ABS(rect.position.y - (rect.position.y + rect.size.y)) <= uv_edit_draw->get_size().y) { - uv_vscroll->hide(); - } else { - uv_vscroll->show(); - uv_vscroll->set_page(uv_edit_draw->get_size().y); - uv_vscroll->set_value(uv_draw_ofs.y); - } - - Size2 hmin = uv_hscroll->get_combined_minimum_size(); - Size2 vmin = uv_vscroll->get_combined_minimum_size(); - - // Avoid scrollbar overlapping. - uv_hscroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, uv_vscroll->is_visible() ? -vmin.width : 0); - uv_vscroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, uv_hscroll->is_visible() ? -hmin.height : 0); - - updating_uv_scroll = false; } void Polygon2DEditor::_bind_methods() { @@ -1480,33 +1494,20 @@ Polygon2DEditor::Polygon2DEditor() { sb_step_y->connect("value_changed", callable_mp(this, &Polygon2DEditor::_set_snap_step_y)); grid_settings_vb->add_margin_child(TTR("Grid Step Y:"), sb_step_y); - uv_mode_hb->add_child(memnew(VSeparator)); - uv_icon_zoom = memnew(TextureRect); - uv_icon_zoom->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); - uv_mode_hb->add_child(uv_icon_zoom); - uv_zoom = memnew(HSlider); - uv_zoom->set_min(0.01); - uv_zoom->set_max(16); - uv_zoom->set_value(1); - uv_zoom->set_step(0.01); - uv_zoom->set_v_size_flags(SIZE_SHRINK_CENTER); - - uv_mode_hb->add_child(uv_zoom); - uv_zoom->set_custom_minimum_size(Size2(80 * EDSCALE, 0)); - uv_zoom_value = memnew(SpinBox); - uv_zoom->share(uv_zoom_value); - uv_zoom_value->set_custom_minimum_size(Size2(50, 0)); - uv_mode_hb->add_child(uv_zoom_value); - uv_zoom->connect("value_changed", callable_mp(this, &Polygon2DEditor::_uv_scroll_changed)); + zoom_widget = memnew(EditorZoomWidget); + uv_edit_draw->add_child(zoom_widget); + zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE); + zoom_widget->connect("zoom_changed", callable_mp(this, &Polygon2DEditor::_update_zoom_and_pan).unbind(1).bind(true)); + zoom_widget->set_shortcut_context(nullptr); uv_vscroll = memnew(VScrollBar); uv_vscroll->set_step(0.001); uv_edit_draw->add_child(uv_vscroll); - uv_vscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_uv_scroll_changed)); + uv_vscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_update_zoom_and_pan).unbind(1).bind(false)); uv_hscroll = memnew(HScrollBar); uv_hscroll->set_step(0.001); uv_edit_draw->add_child(uv_hscroll); - uv_hscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_uv_scroll_changed)); + uv_hscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_update_zoom_and_pan).unbind(1).bind(false)); bone_scroll_main_vb = memnew(VBoxContainer); bone_scroll_main_vb->hide(); @@ -1535,7 +1536,6 @@ Polygon2DEditor::Polygon2DEditor() { point_drag_index = -1; uv_drag = false; uv_create = false; - updating_uv_scroll = false; bone_painting = false; error = memnew(AcceptDialog); diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h index 8c52984b59..164aa3eccc 100644 --- a/editor/plugins/polygon_2d_editor_plugin.h +++ b/editor/plugins/polygon_2d_editor_plugin.h @@ -35,6 +35,7 @@ class AcceptDialog; class ButtonGroup; +class EditorZoomWidget; class HScrollBar; class HSlider; class Label; @@ -85,12 +86,10 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { Panel *uv_edit_background = nullptr; Polygon2D *preview_polygon = nullptr; Control *uv_edit_draw = nullptr; - HSlider *uv_zoom = nullptr; - SpinBox *uv_zoom_value = nullptr; + EditorZoomWidget *zoom_widget = nullptr; HScrollBar *uv_hscroll = nullptr; VScrollBar *uv_vscroll = nullptr; MenuButton *uv_menu = nullptr; - TextureRect *uv_icon_zoom = nullptr; Ref<ViewPanner> uv_panner; void _uv_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event); @@ -129,7 +128,6 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { Vector<int> polygon_create; UVMode uv_move_current; Vector2 uv_drag_from; - bool updating_uv_scroll; AcceptDialog *error = nullptr; @@ -145,7 +143,8 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { void _cancel_editing(); void _update_polygon_editing_state(); - void _uv_scroll_changed(real_t); + void _center_view(); + void _update_zoom_and_pan(bool p_zoom_at_center); void _uv_input(const Ref<InputEvent> &p_input); void _uv_draw(); void _uv_mode(int p_mode); diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index ee7ad739b8..d9f5aee82c 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -50,7 +50,7 @@ void ResourcePreloaderEditor::_notification(int p_what) { void ResourcePreloaderEditor::_files_load_request(const Vector<String> &p_paths) { for (int i = 0; i < p_paths.size(); i++) { - String path = p_paths[i]; + const String &path = p_paths[i]; Ref<Resource> resource; resource = ResourceLoader::load(path); diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp index bc6507155a..b54a2f717d 100644 --- a/editor/plugins/root_motion_editor_plugin.cpp +++ b/editor/plugins/root_motion_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "scene/3d/skeleton_3d.h" #include "scene/animation/animation_mixer.h" #include "scene/gui/button.h" #include "scene/gui/dialogs.h" diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index c1a65b7bb7..9a8164a3cf 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -733,7 +733,7 @@ void ScriptEditor::_open_recent_script(int p_idx) { // clear button if (p_idx == recent_scripts->get_item_count() - 1) { EditorSettings::get_singleton()->set_project_metadata("recent_files", "scripts", Array()); - call_deferred(SNAME("_update_recent_scripts")); + callable_mp(this, &ScriptEditor::_update_recent_scripts).call_deferred(); return; } @@ -1031,7 +1031,7 @@ void ScriptEditor::_scene_saved_callback(const String &p_path) { void ScriptEditor::trigger_live_script_reload() { if (!pending_auto_reload && auto_reload_running_scripts) { - call_deferred(SNAME("_live_auto_reload_running_scripts")); + callable_mp(this, &ScriptEditor::_live_auto_reload_running_scripts).call_deferred(); pending_auto_reload = true; } } @@ -1082,7 +1082,7 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Resource> p_for_script) { script_editor->reload_scripts(); need_reload = false; } else { - disk_changed->call_deferred(SNAME("popup_centered_ratio"), 0.3); + callable_mp((Window *)disk_changed, &Window::popup_centered_ratio).call_deferred(0.3); } } @@ -2873,7 +2873,7 @@ void ScriptEditor::_tree_changed() { } waiting_update_names = true; - call_deferred(SNAME("_update_script_names")); + callable_mp(this, &ScriptEditor::_update_script_names).call_deferred(); } void ScriptEditor::_split_dragged(float) { @@ -2963,7 +2963,7 @@ bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data } for (int i = 0; i < files.size(); i++) { - String file = files[i]; + const String &file = files[i]; if (file.is_empty() || !FileAccess::exists(file)) { continue; } @@ -3043,7 +3043,7 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co } int num_tabs_before = tab_container->get_tab_count(); for (int i = 0; i < files.size(); i++) { - String file = files[i]; + const String &file = files[i]; if (file.is_empty() || !FileAccess::exists(file)) { continue; } @@ -3386,7 +3386,6 @@ void ScriptEditor::_help_class_goto(const String &p_desc) { eh->set_name(cname); tab_container->add_child(eh); - _go_to_tab(tab_container->get_tab_count() - 1); eh->go_to_help(p_desc); eh->connect("go_to_help", callable_mp(this, &ScriptEditor::_help_class_goto)); _add_recent_script(eh->get_class()); @@ -3394,7 +3393,7 @@ void ScriptEditor::_help_class_goto(const String &p_desc) { _update_script_names(); _save_layout(); - call_deferred("_help_tab_goto", cname, p_desc); + callable_mp(this, &ScriptEditor::_help_tab_goto).call_deferred(cname, p_desc); } bool ScriptEditor::_help_tab_goto(const String &p_name, const String &p_desc) { @@ -3792,18 +3791,7 @@ void ScriptEditor::_filter_methods_text_changed(const String &p_newtext) { } void ScriptEditor::_bind_methods() { - ClassDB::bind_method("_close_docs_tab", &ScriptEditor::_close_docs_tab); - ClassDB::bind_method("_close_all_tabs", &ScriptEditor::_close_all_tabs); - ClassDB::bind_method("_close_other_tabs", &ScriptEditor::_close_other_tabs); - ClassDB::bind_method("_goto_script_line2", &ScriptEditor::_goto_script_line2); - ClassDB::bind_method("_copy_script_path", &ScriptEditor::_copy_script_path); - - ClassDB::bind_method("_help_class_open", &ScriptEditor::_help_class_open); ClassDB::bind_method("_help_tab_goto", &ScriptEditor::_help_tab_goto); - ClassDB::bind_method("_live_auto_reload_running_scripts", &ScriptEditor::_live_auto_reload_running_scripts); - ClassDB::bind_method("_update_members_overview", &ScriptEditor::_update_members_overview); - ClassDB::bind_method("_update_recent_scripts", &ScriptEditor::_update_recent_scripts); - ClassDB::bind_method("get_current_editor", &ScriptEditor::_get_current_editor); ClassDB::bind_method("get_open_script_editors", &ScriptEditor::_get_open_script_editors); @@ -3860,6 +3848,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { scripts_vbox->add_child(filter_scripts); script_list = memnew(ItemList); + script_list->set_auto_translate(false); scripts_vbox->add_child(script_list); script_list->set_custom_minimum_size(Size2(150, 60) * EDSCALE); //need to give a bit of limit to avoid it from disappearing script_list->set_v_size_flags(SIZE_EXPAND_FILL); @@ -3904,6 +3893,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { overview_vbox->add_child(filter_methods); members_overview = memnew(ItemList); + members_overview->set_auto_translate(false); overview_vbox->add_child(members_overview); members_overview->set_allow_reselect(true); @@ -3912,6 +3902,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { members_overview->set_allow_rmb_select(true); help_overview = memnew(ItemList); + help_overview->set_auto_translate(false); overview_vbox->add_child(help_overview); help_overview->set_allow_reselect(true); help_overview->set_custom_minimum_size(Size2(0, 60) * EDSCALE); //need to give a bit of limit to avoid it from disappearing diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index eb934da4dd..38f3d865d4 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -788,9 +788,7 @@ static void _find_changed_scripts_for_external_editor(Node *p_base, Node *p_curr } void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_for_script) { - if (!bool(EDITOR_GET("text_editor/external/use_external_editor"))) { - return; - } + bool use_external_editor = bool(EDITOR_GET("text_editor/external/use_external_editor")); ERR_FAIL_NULL(get_tree()); @@ -804,6 +802,10 @@ void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_fo for (const Ref<Script> &E : scripts) { Ref<Script> scr = E; + if (!use_external_editor && !scr->get_language()->overrides_external_editor()) { + continue; // We're not using an external editor for this script. + } + if (p_for_script.is_valid() && p_for_script != scr) { continue; } @@ -884,7 +886,7 @@ void ScriptTextEditor::_breakpoint_item_pressed(int p_idx) { _edit_option(breakpoints_menu->get_item_id(p_idx)); } else { code_editor->goto_line(breakpoints_menu->get_item_metadata(p_idx)); - code_editor->get_text_editor()->call_deferred(SNAME("center_viewport_to_caret")); //Need to be deferred, because goto uses call_deferred(). + callable_mp((TextEdit *)code_editor->get_text_editor(), &TextEdit::center_viewport_to_caret).call_deferred(0); // Needs to be deferred, because goto uses call_deferred(). } } @@ -1271,27 +1273,27 @@ void ScriptTextEditor::_edit_option(int p_op) { switch (p_op) { case EDIT_UNDO: { tx->undo(); - tx->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)tx, &Control::grab_focus).call_deferred(); } break; case EDIT_REDO: { tx->redo(); - tx->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)tx, &Control::grab_focus).call_deferred(); } break; case EDIT_CUT: { tx->cut(); - tx->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)tx, &Control::grab_focus).call_deferred(); } break; case EDIT_COPY: { tx->copy(); - tx->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)tx, &Control::grab_focus).call_deferred(); } break; case EDIT_PASTE: { tx->paste(); - tx->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)tx, &Control::grab_focus).call_deferred(); } break; case EDIT_SELECT_ALL: { tx->select_all(); - tx->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)tx, &Control::grab_focus).call_deferred(); } break; case EDIT_MOVE_LINE_UP: { code_editor->move_lines_up(); @@ -1409,7 +1411,7 @@ void ScriptTextEditor::_edit_option(int p_op) { PackedStringArray results; for (int i = 0; i < lines.size(); i++) { - String line = lines[i]; + const String &line = lines[i]; String whitespace = line.substr(0, line.size() - line.strip_edges(true, false).size()); // Extract the whitespace at the beginning. if (expression.parse(line) == OK) { Variant result = expression.execute(Array(), Variant(), false, true); @@ -2447,7 +2449,7 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/indent", TTR("Indent"), Key::NONE); ED_SHORTCUT("script_text_editor/unindent", TTR("Unindent"), KeyModifierMask::SHIFT | Key::TAB); - ED_SHORTCUT_ARRAY("script_text_editor/toggle_comment", TTR("Toggle Comment"), { int32_t(KeyModifierMask::CMD_OR_CTRL | Key::K), int32_t(KeyModifierMask::CMD_OR_CTRL | Key::SLASH) }); + ED_SHORTCUT_ARRAY("script_text_editor/toggle_comment", TTR("Toggle Comment"), { int32_t(KeyModifierMask::CMD_OR_CTRL | Key::K), int32_t(KeyModifierMask::CMD_OR_CTRL | Key::SLASH), int32_t(KeyModifierMask::CMD_OR_CTRL | Key::KP_DIVIDE), int32_t(KeyModifierMask::CMD_OR_CTRL | Key::NUMBERSIGN) }); ED_SHORTCUT("script_text_editor/toggle_fold_line", TTR("Fold/Unfold Line"), KeyModifierMask::ALT | Key::F); ED_SHORTCUT_OVERRIDE("script_text_editor/toggle_fold_line", "macos", KeyModifierMask::CTRL | KeyModifierMask::META | Key::F); ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), Key::NONE); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 9da201f9f1..6d6da69405 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -84,7 +84,8 @@ void ShaderEditorPlugin::_update_shader_list() { Ref<Texture2D> icon = shader_list->get_editor_theme_icon(_class); shader_list->add_item(text, icon); - shader_list->set_item_tooltip(shader_list->get_item_count() - 1, path); + shader_list->set_item_tooltip(-1, path); + edited_shader.name = text; } if (shader_tabs->get_tab_count()) { @@ -292,11 +293,6 @@ void ShaderEditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) { } String ShaderEditorPlugin::get_unsaved_status(const String &p_for_scene) const { - if (!p_for_scene.is_empty()) { - // TODO: handle built-in shaders. - return String(); - } - // TODO: This should also include visual shaders and shader includes, but save_external_data() doesn't seem to save them... PackedStringArray unsaved_shaders; for (uint32_t i = 0; i < edited_shaders.size(); i++) { @@ -305,10 +301,30 @@ String ShaderEditorPlugin::get_unsaved_status(const String &p_for_scene) const { if (unsaved_shaders.is_empty()) { unsaved_shaders.append(TTR("Save changes to the following shaders(s) before quitting?")); } - unsaved_shaders.append(edited_shaders[i].shader_editor->get_name()); + unsaved_shaders.append(edited_shaders[i].name.trim_suffix("(*)")); + } + } + } + + if (!p_for_scene.is_empty()) { + PackedStringArray unsaved_built_in_shaders; + + const String scene_file = p_for_scene.get_file(); + for (const String &E : unsaved_shaders) { + if (!E.is_resource_file() && E.contains(scene_file)) { + if (unsaved_built_in_shaders.is_empty()) { + unsaved_built_in_shaders.append(TTR("There are unsaved changes in the following built-in shaders(s):")); + } + unsaved_built_in_shaders.append(E); } } + + if (!unsaved_built_in_shaders.is_empty()) { + return String("\n").join(unsaved_built_in_shaders); + } + return String(); } + return String("\n").join(unsaved_shaders); } @@ -517,7 +533,7 @@ bool ShaderEditorPlugin::can_drop_data_fw(const Point2 &p_point, const Variant & } for (int i = 0; i < files.size(); i++) { - String file = files[i]; + const String &file = files[i]; if (ResourceLoader::exists(file, "Shader")) { Ref<Shader> shader = ResourceLoader::load(file); if (shader.is_valid()) { @@ -558,7 +574,7 @@ void ShaderEditorPlugin::drop_data_fw(const Point2 &p_point, const Variant &p_da Vector<String> files = d["files"]; for (int i = 0; i < files.size(); i++) { - String file = files[i]; + const String &file = files[i]; Ref<Resource> res; if (ResourceLoader::exists(file, "Shader") || ResourceLoader::exists(file, "ShaderInclude")) { res = ResourceLoader::load(file); @@ -586,6 +602,7 @@ void ShaderEditorPlugin::_file_removed(const String &p_removed_file) { void ShaderEditorPlugin::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { + EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &ShaderEditorPlugin::_resource_saved), CONNECT_DEFERRED); EditorNode::get_singleton()->connect("scene_closed", callable_mp(this, &ShaderEditorPlugin::_close_builtin_shaders_from_scene)); FileSystemDock::get_singleton()->connect("file_removed", callable_mp(this, &ShaderEditorPlugin::_file_removed)); } break; @@ -641,6 +658,7 @@ ShaderEditorPlugin::ShaderEditorPlugin() { } shader_list = memnew(ItemList); + shader_list->set_auto_translate(false); shader_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); vb->add_child(shader_list); shader_list->connect("item_selected", callable_mp(this, &ShaderEditorPlugin::_shader_selected)); @@ -660,9 +678,6 @@ ShaderEditorPlugin::ShaderEditorPlugin() { button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Shader Editor"), window_wrapper); - // Defer connect because Editor class is not in the binding system yet. - EditorNode::get_singleton()->call_deferred("connect", "resource_saved", callable_mp(this, &ShaderEditorPlugin::_resource_saved), CONNECT_DEFERRED); - shader_create_dialog = memnew(ShaderCreateDialog); vb->add_child(shader_create_dialog); shader_create_dialog->connect("shader_created", callable_mp(this, &ShaderEditorPlugin::_shader_created)); diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h index 073b0ee192..ea50d62b8f 100644 --- a/editor/plugins/shader_editor_plugin.h +++ b/editor/plugins/shader_editor_plugin.h @@ -55,6 +55,7 @@ class ShaderEditorPlugin : public EditorPlugin { TextShaderEditor *shader_editor = nullptr; VisualShaderEditor *visual_shader_editor = nullptr; String path; + String name; }; LocalVector<EditedShader> edited_shaders; diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp index 11bec4f61c..d68b3bde14 100644 --- a/editor/plugins/shader_file_editor_plugin.cpp +++ b/editor/plugins/shader_file_editor_plugin.cpp @@ -256,6 +256,7 @@ ShaderFileEditor::ShaderFileEditor() { add_child(main_hs); versions = memnew(ItemList); + versions->set_auto_translate(false); versions->connect("item_selected", callable_mp(this, &ShaderFileEditor::_version_selected)); versions->set_custom_minimum_size(Size2i(200 * EDSCALE, 0)); main_hs->add_child(versions); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 9a709e8dda..c816220bd2 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -837,10 +837,10 @@ void Skeleton3DEditor::_notification(int p_what) { joint_tree->connect("item_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_selection_changed)); joint_tree->connect("item_mouse_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_rmb_select)); #ifdef TOOLS_ENABLED - skeleton->connect("pose_updated", callable_mp(this, &Skeleton3DEditor::_draw_gizmo)); - skeleton->connect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties)); - skeleton->connect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed)); - skeleton->connect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible)); + skeleton->connect(SceneStringNames::get_singleton()->pose_updated, callable_mp(this, &Skeleton3DEditor::_draw_gizmo)); + skeleton->connect(SceneStringNames::get_singleton()->pose_updated, callable_mp(this, &Skeleton3DEditor::_update_properties)); + skeleton->connect(SceneStringNames::get_singleton()->bone_enabled_changed, callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed)); + skeleton->connect(SceneStringNames::get_singleton()->show_rest_only_changed, callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible)); #endif get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Object::CONNECT_ONE_SHOT); @@ -865,10 +865,10 @@ void Skeleton3DEditor::_notification(int p_what) { if (skeleton) { select_bone(-1); // Requires that the joint_tree has not been deleted. #ifdef TOOLS_ENABLED - skeleton->disconnect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible)); - skeleton->disconnect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed)); - skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_draw_gizmo)); - skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties)); + skeleton->disconnect(SceneStringNames::get_singleton()->show_rest_only_changed, callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible)); + skeleton->disconnect(SceneStringNames::get_singleton()->bone_enabled_changed, callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed)); + skeleton->disconnect(SceneStringNames::get_singleton()->pose_updated, callable_mp(this, &Skeleton3DEditor::_draw_gizmo)); + skeleton->disconnect(SceneStringNames::get_singleton()->pose_updated, callable_mp(this, &Skeleton3DEditor::_update_properties)); skeleton->set_transform_gizmo_visible(true); #endif if (handles_mesh_instance->get_parent()) { @@ -889,18 +889,6 @@ void Skeleton3DEditor::_node_removed(Node *p_node) { _update_properties(); } -void Skeleton3DEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_node_removed"), &Skeleton3DEditor::_node_removed); - ClassDB::bind_method(D_METHOD("_joint_tree_selection_changed"), &Skeleton3DEditor::_joint_tree_selection_changed); - ClassDB::bind_method(D_METHOD("_joint_tree_rmb_select"), &Skeleton3DEditor::_joint_tree_rmb_select); - ClassDB::bind_method(D_METHOD("_update_properties"), &Skeleton3DEditor::_update_properties); - ClassDB::bind_method(D_METHOD("_on_click_skeleton_option"), &Skeleton3DEditor::_on_click_skeleton_option); - - ClassDB::bind_method(D_METHOD("move_skeleton_bone"), &Skeleton3DEditor::move_skeleton_bone); - - ClassDB::bind_method(D_METHOD("_draw_gizmo"), &Skeleton3DEditor::_draw_gizmo); -} - void Skeleton3DEditor::edit_mode_toggled(const bool pressed) { edit_mode = pressed; _update_gizmo_visible(); diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h index 3cc7c85492..839061a2fe 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.h +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -198,7 +198,6 @@ class Skeleton3DEditor : public VBoxContainer { protected: void _notification(int p_what); void _node_removed(Node *p_node); - static void _bind_methods(); public: static Skeleton3DEditor *get_singleton() { return singleton; } diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index 7c1c6a8f82..d343f80420 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -34,7 +34,9 @@ #include "core/math/geometry_2d.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/gui/editor_zoom_widget.h" #include "editor/scene_tree_dock.h" #include "scene/2d/collision_polygon_2d.h" #include "scene/2d/light_occluder_2d.h" @@ -42,6 +44,8 @@ #include "scene/2d/polygon_2d.h" #include "scene/gui/box_container.h" #include "scene/gui/menu_button.h" +#include "scene/gui/panel.h" +#include "scene/gui/view_panner.h" #include "thirdparty/misc/clipper.hpp" void Sprite2DEditor::_node_removed(Node *p_node) { @@ -168,6 +172,8 @@ void Sprite2DEditor::_popup_debug_uv_dialog() { _update_mesh_data(); debug_uv_dialog->popup_centered(); + get_tree()->connect("process_frame", callable_mp(this, &Sprite2DEditor::_center_view), CONNECT_ONE_SHOT); + debug_uv->set_texture_filter(node->get_texture_filter_in_tree()); debug_uv->queue_redraw(); } @@ -460,17 +466,19 @@ void Sprite2DEditor::_add_as_sibling_or_child(Node *p_own_node, Node *p_new_node p_new_node->set_owner(this->get_tree()->get_edited_scene_root()); } +void Sprite2DEditor::_debug_uv_input(const Ref<InputEvent> &p_input) { + if (panner->gui_input(p_input)) { + accept_event(); + } +} + void Sprite2DEditor::_debug_uv_draw() { + debug_uv->draw_set_transform(-draw_offset * draw_zoom, 0, Vector2(draw_zoom, draw_zoom)); + Ref<Texture2D> tex = node->get_texture(); ERR_FAIL_COND(!tex.is_valid()); - Point2 draw_pos_offset = Point2(1.0, 1.0); - Size2 draw_size_offset = Size2(2.0, 2.0); - - debug_uv->set_clip_contents(true); - debug_uv->draw_texture(tex, draw_pos_offset); - debug_uv->set_custom_minimum_size(tex->get_size() + draw_size_offset); - debug_uv->draw_set_transform(draw_pos_offset, 0, Size2(1.0, 1.0)); + debug_uv->draw_texture(tex, Point2()); Color color = Color(1.0, 0.8, 0.7); @@ -487,8 +495,86 @@ void Sprite2DEditor::_debug_uv_draw() { } } +void Sprite2DEditor::_center_view() { + Ref<Texture2D> tex = node->get_texture(); + ERR_FAIL_COND(!tex.is_valid()); + Vector2 zoom_factor = (debug_uv->get_size() - Vector2(1, 1) * 50 * EDSCALE) / tex->get_size(); + zoom_widget->set_zoom(MIN(zoom_factor.x, zoom_factor.y)); + // Recalculate scroll limits. + _update_zoom_and_pan(false); + + Vector2 offset = (tex->get_size() - debug_uv->get_size() / zoom_widget->get_zoom()) / 2; + h_scroll->set_value_no_signal(offset.x); + v_scroll->set_value_no_signal(offset.y); + _update_zoom_and_pan(false); +} + +void Sprite2DEditor::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) { + h_scroll->set_value_no_signal(h_scroll->get_value() - p_scroll_vec.x / draw_zoom); + v_scroll->set_value_no_signal(v_scroll->get_value() - p_scroll_vec.y / draw_zoom); + _update_zoom_and_pan(false); +} + +void Sprite2DEditor::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) { + const real_t prev_zoom = draw_zoom; + zoom_widget->set_zoom(draw_zoom * p_zoom_factor); + draw_offset += p_origin / prev_zoom - p_origin / zoom_widget->get_zoom(); + h_scroll->set_value_no_signal(draw_offset.x); + v_scroll->set_value_no_signal(draw_offset.y); + _update_zoom_and_pan(false); +} + +void Sprite2DEditor::_update_zoom_and_pan(bool p_zoom_at_center) { + real_t previous_zoom = draw_zoom; + draw_zoom = zoom_widget->get_zoom(); + draw_offset = Vector2(h_scroll->get_value(), v_scroll->get_value()); + if (p_zoom_at_center) { + Vector2 center = debug_uv->get_size() / 2; + draw_offset += center / previous_zoom - center / draw_zoom; + } + + Ref<Texture2D> tex = node->get_texture(); + ERR_FAIL_COND(!tex.is_valid()); + + Point2 min_corner; + Point2 max_corner = tex->get_size(); + Size2 page_size = debug_uv->get_size() / draw_zoom; + Vector2 margin = Vector2(50, 50) * EDSCALE / draw_zoom; + min_corner -= page_size - margin; + max_corner += page_size - margin; + + h_scroll->set_block_signals(true); + h_scroll->set_min(min_corner.x); + h_scroll->set_max(max_corner.x); + h_scroll->set_page(page_size.x); + h_scroll->set_value(draw_offset.x); + h_scroll->set_block_signals(false); + + v_scroll->set_block_signals(true); + v_scroll->set_min(min_corner.y); + v_scroll->set_max(max_corner.y); + v_scroll->set_page(page_size.y); + v_scroll->set_value(draw_offset.y); + v_scroll->set_block_signals(false); + + debug_uv->queue_redraw(); +} + void Sprite2DEditor::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_READY: { + v_scroll->set_anchors_and_offsets_preset(Control::PRESET_RIGHT_WIDE); + h_scroll->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_WIDE); + // Avoid scrollbar overlapping. + Size2 hmin = h_scroll->get_combined_minimum_size(); + Size2 vmin = v_scroll->get_combined_minimum_size(); + h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -vmin.width); + v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -hmin.height); + [[fallthrough]]; + } + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning"))); + } break; case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { options->set_icon(get_editor_theme_icon(SNAME("Sprite2D"))); @@ -526,12 +612,29 @@ Sprite2DEditor::Sprite2DEditor() { debug_uv_dialog = memnew(ConfirmationDialog); VBoxContainer *vb = memnew(VBoxContainer); debug_uv_dialog->add_child(vb); - ScrollContainer *scroll = memnew(ScrollContainer); - scroll->set_custom_minimum_size(Size2(800, 500) * EDSCALE); - vb->add_margin_child(TTR("Preview:"), scroll, true); - debug_uv = memnew(Control); + debug_uv = memnew(Panel); + debug_uv->connect("gui_input", callable_mp(this, &Sprite2DEditor::_debug_uv_input)); debug_uv->connect("draw", callable_mp(this, &Sprite2DEditor::_debug_uv_draw)); - scroll->add_child(debug_uv); + debug_uv->set_custom_minimum_size(Size2(800, 500) * EDSCALE); + debug_uv->set_clip_contents(true); + vb->add_margin_child(TTR("Preview:"), debug_uv, true); + + panner.instantiate(); + panner->set_callbacks(callable_mp(this, &Sprite2DEditor::_pan_callback), callable_mp(this, &Sprite2DEditor::_zoom_callback)); + + zoom_widget = memnew(EditorZoomWidget); + debug_uv->add_child(zoom_widget); + zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE); + zoom_widget->connect("zoom_changed", callable_mp(this, &Sprite2DEditor::_update_zoom_and_pan).unbind(1).bind(true)); + zoom_widget->set_shortcut_context(nullptr); + + v_scroll = memnew(VScrollBar); + debug_uv->add_child(v_scroll); + v_scroll->connect("value_changed", callable_mp(this, &Sprite2DEditor::_update_zoom_and_pan).unbind(1).bind(false)); + h_scroll = memnew(HScrollBar); + debug_uv->add_child(h_scroll); + h_scroll->connect("value_changed", callable_mp(this, &Sprite2DEditor::_update_zoom_and_pan).unbind(1).bind(false)); + debug_uv_dialog->connect("confirmed", callable_mp(this, &Sprite2DEditor::_create_node)); HBoxContainer *hb = memnew(HBoxContainer); diff --git a/editor/plugins/sprite_2d_editor_plugin.h b/editor/plugins/sprite_2d_editor_plugin.h index 52e4b2b264..1121481341 100644 --- a/editor/plugins/sprite_2d_editor_plugin.h +++ b/editor/plugins/sprite_2d_editor_plugin.h @@ -37,7 +37,10 @@ class AcceptDialog; class ConfirmationDialog; +class EditorZoomWidget; class MenuButton; +class Panel; +class ViewPanner; class Sprite2DEditor : public Control { GDCLASS(Sprite2DEditor, Control); @@ -60,7 +63,7 @@ class Sprite2DEditor : public Control { AcceptDialog *err_dialog = nullptr; ConfirmationDialog *debug_uv_dialog = nullptr; - Control *debug_uv = nullptr; + Panel *debug_uv = nullptr; Vector<Vector2> uv_lines; Vector<Vector<Vector2>> outline_lines; Vector<Vector<Vector2>> computed_outline_lines; @@ -68,6 +71,13 @@ class Sprite2DEditor : public Control { Vector<Vector2> computed_uv; Vector<int> computed_indices; + HScrollBar *h_scroll = nullptr; + VScrollBar *v_scroll = nullptr; + EditorZoomWidget *zoom_widget = nullptr; + Ref<ViewPanner> panner; + Vector2 draw_offset; + real_t draw_zoom = 1.0; + SpinBox *simplification = nullptr; SpinBox *grow_pixels = nullptr; SpinBox *shrink_pixels = nullptr; @@ -78,8 +88,13 @@ class Sprite2DEditor : public Control { //void _create_uv_lines(); friend class Sprite2DEditorPlugin; + void _debug_uv_input(const Ref<InputEvent> &p_input); void _debug_uv_draw(); void _popup_debug_uv_dialog(); + void _center_view(); + void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event); + void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event); + void _update_zoom_and_pan(bool p_zoom_at_center); void _update_mesh_data(); void _create_node(); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index a1241ae662..f4fa4b14bb 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -1425,7 +1425,7 @@ bool SpriteFramesEditor::can_drop_data_fw(const Point2 &p_point, const Variant & } for (int i = 0; i < files.size(); i++) { - String f = files[i]; + const String &f = files[i]; String ftype = EditorFileSystem::get_singleton()->get_file_type(f); if (!ClassDB::is_parent_class(ftype, "Texture2D")) { @@ -1880,6 +1880,7 @@ SpriteFramesEditor::SpriteFramesEditor() { add_child(file); frame_list = memnew(ItemList); + frame_list->set_auto_translate(false); frame_list->set_v_size_flags(SIZE_EXPAND_FILL); frame_list->set_icon_mode(ItemList::ICON_MODE_TOP); frame_list->set_texture_filter(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index c7945e44f0..475aba0eeb 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -352,27 +352,27 @@ void TextEditor::_edit_option(int p_op) { switch (p_op) { case EDIT_UNDO: { tx->undo(); - tx->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)tx, &Control::grab_focus).call_deferred(); } break; case EDIT_REDO: { tx->redo(); - tx->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)tx, &Control::grab_focus).call_deferred(); } break; case EDIT_CUT: { tx->cut(); - tx->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)tx, &Control::grab_focus).call_deferred(); } break; case EDIT_COPY: { tx->copy(); - tx->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)tx, &Control::grab_focus).call_deferred(); } break; case EDIT_PASTE: { tx->paste(); - tx->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)tx, &Control::grab_focus).call_deferred(); } break; case EDIT_SELECT_ALL: { tx->select_all(); - tx->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)tx, &Control::grab_focus).call_deferred(); } break; case EDIT_MOVE_LINE_UP: { code_editor->move_lines_up(); diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp index 3a2ddeb94e..e5b9e3854f 100644 --- a/editor/plugins/text_shader_editor.cpp +++ b/editor/plugins/text_shader_editor.cpp @@ -170,8 +170,8 @@ void ShaderTextEditor::set_edited_code(const String &p_code) { get_text_editor()->set_text(p_code); get_text_editor()->clear_undo_history(); - get_text_editor()->call_deferred(SNAME("set_h_scroll"), 0); - get_text_editor()->call_deferred(SNAME("set_v_scroll"), 0); + callable_mp((TextEdit *)get_text_editor(), &TextEdit::set_h_scroll).call_deferred(0); + callable_mp((TextEdit *)get_text_editor(), &TextEdit::set_v_scroll).call_deferred(0); get_text_editor()->tag_saved_version(); _validate_script(); @@ -719,7 +719,7 @@ void TextShaderEditor::_menu_option(int p_option) { } break; } if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) { - shader_editor->get_text_editor()->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)shader_editor->get_text_editor(), &Control::grab_focus).call_deferred(); } } @@ -820,7 +820,7 @@ void TextShaderEditor::_check_for_external_edit() { if (use_autoreload) { _reload_shader_include_from_disk(); } else { - disk_changed->call_deferred(SNAME("popup_centered")); + callable_mp((Window *)disk_changed, &Window::popup_centered).call_deferred(Size2i()); } } return; @@ -834,7 +834,7 @@ void TextShaderEditor::_check_for_external_edit() { if (use_autoreload) { _reload_shader_from_disk(); } else { - disk_changed->call_deferred(SNAME("popup_centered")); + callable_mp((Window *)disk_changed, &Window::popup_centered).call_deferred(Size2i()); } } } diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index ec5785e605..9d640bf0dc 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -38,6 +38,7 @@ #include "scene/resources/atlas_texture.h" #include "scene/resources/compressed_texture.h" #include "scene/resources/image_texture.h" +#include "scene/resources/portable_compressed_texture.h" TextureRect *TexturePreview::get_texture_display() { return texture_display; @@ -158,7 +159,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) { } bool EditorInspectorPluginTexture::can_handle(Object *p_object) { - return Object::cast_to<ImageTexture>(p_object) != nullptr || Object::cast_to<AtlasTexture>(p_object) != nullptr || Object::cast_to<CompressedTexture2D>(p_object) != nullptr || Object::cast_to<AnimatedTexture>(p_object) != nullptr || Object::cast_to<Image>(p_object) != nullptr; + return Object::cast_to<ImageTexture>(p_object) != nullptr || Object::cast_to<AtlasTexture>(p_object) != nullptr || Object::cast_to<CompressedTexture2D>(p_object) != nullptr || Object::cast_to<PortableCompressedTexture2D>(p_object) != nullptr || Object::cast_to<AnimatedTexture>(p_object) != nullptr || Object::cast_to<Image>(p_object) != nullptr; } void EditorInspectorPluginTexture::parse_begin(Object *p_object) { diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 6c153f6113..cbe0f115d3 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -2247,6 +2247,7 @@ ThemeTypeDialog::ThemeTypeDialog() { add_type_vb->add_child(add_type_options_label); add_type_options = memnew(ItemList); + add_type_options->set_auto_translate(false); add_type_options->set_v_size_flags(Control::SIZE_EXPAND_FILL); add_type_vb->add_child(add_type_options); add_type_options->connect("item_selected", callable_mp(this, &ThemeTypeDialog::_add_type_options_cbk)); @@ -2373,7 +2374,7 @@ void ThemeTypeEditor::_update_type_list_debounced() { update_debounce_timer->start(); } -HashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) const, bool include_default) { +HashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, void (Theme::*get_list_func)(const StringName &, List<StringName> *) const, bool include_default) { HashMap<StringName, bool> items; List<StringName> names; diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h index cf8c5ceb28..8ad262da55 100644 --- a/editor/plugins/theme_editor_plugin.h +++ b/editor/plugins/theme_editor_plugin.h @@ -373,7 +373,7 @@ class ThemeTypeEditor : public MarginContainer { VBoxContainer *_create_item_list(Theme::DataType p_data_type); void _update_type_list(); void _update_type_list_debounced(); - HashMap<StringName, bool> _get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) const, bool include_default); + HashMap<StringName, bool> _get_type_items(String p_type_name, void (Theme::*get_list_func)(const StringName &, List<StringName> *) const, bool include_default); HBoxContainer *_create_property_control(Theme::DataType p_data_type, String p_item_name, bool p_editable); void _add_focusable(Control *p_control); void _update_type_items(); diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp index b91f32775f..62b4993947 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.cpp +++ b/editor/plugins/tiles/atlas_merging_dialog.cpp @@ -52,7 +52,7 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla // Compute the new texture region size. Vector2i new_texture_region_size; for (int source_index = 0; source_index < p_atlas_sources.size(); source_index++) { - Ref<TileSetAtlasSource> atlas_source = p_atlas_sources[source_index]; + const Ref<TileSetAtlasSource> &atlas_source = p_atlas_sources[source_index]; new_texture_region_size = new_texture_region_size.max(atlas_source->get_texture_region_size()); } @@ -60,7 +60,7 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla Vector2i atlas_offset; int line_height = 0; for (int source_index = 0; source_index < p_atlas_sources.size(); source_index++) { - Ref<TileSetAtlasSource> atlas_source = p_atlas_sources[source_index]; + const Ref<TileSetAtlasSource> &atlas_source = p_atlas_sources[source_index]; Ref<Image> input_image = atlas_source->get_texture()->get_image(); if (input_image->get_format() != Image::FORMAT_RGBA8) { input_image->convert(Image::FORMAT_RGBA8); @@ -111,7 +111,7 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla // Copy the tiles to the merged TileSetAtlasSource. for (int source_index = 0; source_index < p_atlas_sources.size(); source_index++) { - Ref<TileSetAtlasSource> atlas_source = p_atlas_sources[source_index]; + const Ref<TileSetAtlasSource> &atlas_source = p_atlas_sources[source_index]; for (KeyValue<Vector2i, Vector2i> tile_mapping : merged_mapping[source_index]) { // Create tiles and alternatives, then copy their properties. for (int alternative_index = 0; alternative_index < atlas_source->get_alternative_tiles_count(tile_mapping.key); alternative_index++) { @@ -311,6 +311,7 @@ AtlasMergingDialog::AtlasMergingDialog() { // Atlas sources item list. atlas_merging_atlases_list = memnew(ItemList); + atlas_merging_atlases_list->set_auto_translate(false); atlas_merging_atlases_list->set_fixed_icon_size(Size2(60, 60) * EDSCALE); atlas_merging_atlases_list->set_h_size_flags(Control::SIZE_EXPAND_FILL); atlas_merging_atlases_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index 221833d450..8e4c26bd15 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -53,7 +53,7 @@ void TileDataEditor::_tile_set_changed_plan_update() { _tile_set_changed_update_needed = true; - call_deferred(SNAME("_tile_set_changed_deferred_update")); + callable_mp(this, &TileDataEditor::_tile_set_changed_deferred_update).call_deferred(); } void TileDataEditor::_tile_set_changed_deferred_update() { @@ -80,8 +80,6 @@ TileData *TileDataEditor::_get_tile_data(TileMapCell p_cell) { } void TileDataEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_tile_set_changed_deferred_update"), &TileDataEditor::_tile_set_changed_deferred_update); - ADD_SIGNAL(MethodInfo("needs_redraw")); } @@ -112,16 +110,16 @@ bool DummyObject::_get(const StringName &p_name, Variant &r_ret) const { return false; } -bool DummyObject::has_dummy_property(StringName p_name) { +bool DummyObject::has_dummy_property(const StringName &p_name) { return properties.has(p_name); } -void DummyObject::add_dummy_property(StringName p_name) { +void DummyObject::add_dummy_property(const StringName &p_name) { ERR_FAIL_COND(properties.has(p_name)); properties[p_name] = Variant(); } -void DummyObject::remove_dummy_property(StringName p_name) { +void DummyObject::remove_dummy_property(const StringName &p_name) { ERR_FAIL_COND(!properties.has(p_name)); properties.erase(p_name); } @@ -719,11 +717,19 @@ void GenericTilePolygonEditor::set_tile_set(Ref<TileSet> p_tile_set) { Vector2 zoomed_tile = editor_zoom_widget->get_zoom() * tile_set->get_tile_size(); while (zoomed_tile.y < default_control_y_size) { editor_zoom_widget->set_zoom_by_increments(6, false); - zoomed_tile = editor_zoom_widget->get_zoom() * tile_set->get_tile_size(); + float current_zoom = editor_zoom_widget->get_zoom(); + zoomed_tile = current_zoom * tile_set->get_tile_size(); + if (Math::is_equal_approx(current_zoom, editor_zoom_widget->get_max_zoom())) { + break; + } } while (zoomed_tile.y > default_control_y_size) { editor_zoom_widget->set_zoom_by_increments(-6, false); - zoomed_tile = editor_zoom_widget->get_zoom() * tile_set->get_tile_size(); + float current_zoom = editor_zoom_widget->get_zoom(); + zoomed_tile = current_zoom * tile_set->get_tile_size(); + if (Math::is_equal_approx(current_zoom, editor_zoom_widget->get_min_zoom())) { + break; + } } editor_zoom_widget->set_zoom_by_increments(-6, false); _zoom_changed(); @@ -948,7 +954,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() { _set_snap_option(EditorSettings::get_singleton()->get_project_metadata("editor_metadata", "tile_snap_option", SNAP_NONE)); } -void TileDataDefaultEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) { +void TileDataDefaultEditor::_property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field) { ERR_FAIL_NULL(dummy_object); dummy_object->set(p_property, p_value); emit_signal(SNAME("needs_redraw")); @@ -981,7 +987,7 @@ Variant TileDataDefaultEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_s return tile_data->get(property); } -void TileDataDefaultEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) { +void TileDataDefaultEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) { Vector2i coords = E.key.get_atlas_coords(); @@ -1455,7 +1461,7 @@ Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_ return tile_data->get_occluder(occlusion_layer); } -void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) { +void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) { Vector2i coords = E.key.get_atlas_coords(); @@ -1481,11 +1487,11 @@ TileDataOcclusionShapeEditor::TileDataOcclusionShapeEditor() { add_child(polygon_editor); } -void TileDataCollisionEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) { +void TileDataCollisionEditor::_property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field) { dummy_object->set(p_property, p_value); } -void TileDataCollisionEditor::_property_selected(StringName p_path, int p_focusable) { +void TileDataCollisionEditor::_property_selected(const StringName &p_path, int p_focusable) { // Deselect all other properties for (KeyValue<StringName, EditorProperty *> &editor : property_editors) { if (editor.key != p_path) { @@ -1634,10 +1640,10 @@ Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas return dict; } -void TileDataCollisionEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) { +void TileDataCollisionEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) { Dictionary new_dict = p_new_value; EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - for (KeyValue<TileMapCell, Variant> &E : p_previous_values) { + for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) { Vector2i coords = E.key.get_atlas_coords(); Dictionary old_dict = E.value; @@ -1802,7 +1808,7 @@ void TileDataTerrainsEditor::_update_terrain_selector() { } } -void TileDataTerrainsEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) { +void TileDataTerrainsEditor::_property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field) { Variant old_value = dummy_object->get(p_property); dummy_object->set(p_property, p_value); if (p_property == "terrain_set") { @@ -2871,7 +2877,7 @@ Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atla return tile_data->get_navigation_polygon(navigation_layer); } -void TileDataNavigationEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) { +void TileDataNavigationEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) { Vector2i coords = E.key.get_atlas_coords(); diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h index 4bba5bb467..27fe4316a0 100644 --- a/editor/plugins/tiles/tile_data_editors.h +++ b/editor/plugins/tiles/tile_data_editors.h @@ -82,9 +82,9 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; public: - bool has_dummy_property(StringName p_name); - void add_dummy_property(StringName p_name); - void remove_dummy_property(StringName p_name); + bool has_dummy_property(const StringName &p_name); + void add_dummy_property(const StringName &p_name); + void remove_dummy_property(const StringName &p_name); void clear_dummy_properties(); }; @@ -224,7 +224,7 @@ private: HashMap<TileMapCell, Variant, TileMapCell> drag_modified; Variant drag_painted_value; - void _property_value_changed(StringName p_property, Variant p_value, StringName p_field); + void _property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field); protected: DummyObject *dummy_object = memnew(DummyObject); @@ -238,7 +238,7 @@ protected: virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile); virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value); virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile); - virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value); + virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value); public: virtual Control *get_toolbar() override { return toolbar; }; @@ -291,7 +291,7 @@ private: virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override; virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; - virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override; + virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) override; protected: virtual void _tile_set_changed() override; @@ -316,15 +316,15 @@ class TileDataCollisionEditor : public TileDataDefaultEditor { DummyObject *dummy_object = memnew(DummyObject); HashMap<StringName, EditorProperty *> property_editors; - void _property_value_changed(StringName p_property, Variant p_value, StringName p_field); - void _property_selected(StringName p_path, int p_focusable); + void _property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field); + void _property_selected(const StringName &p_path, int p_focusable); void _polygons_changed(); virtual Variant _get_painted_value() override; virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override; virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; - virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override; + virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) override; protected: virtual void _tile_set_changed() override; @@ -368,7 +368,7 @@ private: EditorPropertyEnum *terrain_set_property_editor = nullptr; EditorPropertyEnum *terrain_property_editor = nullptr; - void _property_value_changed(StringName p_property, Variant p_value, StringName p_field); + void _property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field); void _update_terrain_selector(); @@ -405,7 +405,7 @@ private: virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override; virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; - virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override; + virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) override; protected: virtual void _tile_set_changed() override; diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 661af16ce8..c0aa5b8efa 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -2421,6 +2421,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { sources_bottom_actions->add_child(source_sort_button); sources_list = memnew(ItemList); + sources_list->set_auto_translate(false); sources_list->set_fixed_icon_size(Size2(60, 60) * EDSCALE); sources_list->set_h_size_flags(Control::SIZE_EXPAND_FILL); sources_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -2460,6 +2461,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { // Scenes collection source. scene_tiles_list = memnew(ItemList); + scene_tiles_list->set_auto_translate(false); scene_tiles_list->set_h_size_flags(Control::SIZE_EXPAND_FILL); scene_tiles_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); scene_tiles_list->set_select_mode(ItemList::SELECT_MULTI); @@ -2485,6 +2487,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { int thumbnail_size = 64; patterns_item_list = memnew(ItemList); + patterns_item_list->set_auto_translate(false); patterns_item_list->set_max_columns(0); patterns_item_list->set_icon_mode(ItemList::ICON_MODE_TOP); patterns_item_list->set_fixed_column_width(thumbnail_size * 3 / 2); @@ -3560,6 +3563,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() { tilemap_tab_terrains->add_child(terrains_tree); terrains_tile_list = memnew(ItemList); + terrains_tile_list->set_auto_translate(false); terrains_tile_list->set_h_size_flags(Control::SIZE_EXPAND_FILL); terrains_tile_list->set_max_columns(0); terrains_tile_list->set_same_column_width(true); diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp index 0e244412ab..ba431dfa2f 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp @@ -345,6 +345,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() { vbox_container->add_child(source_level_label); source_level_list = memnew(ItemList); + source_level_list->set_auto_translate(false); source_level_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); source_level_list->set_select_mode(ItemList::SELECT_MULTI); source_level_list->set_allow_rmb_select(true); @@ -356,6 +357,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() { vbox_container->add_child(coords_level_label); coords_level_list = memnew(ItemList); + coords_level_list->set_auto_translate(false); coords_level_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); coords_level_list->set_select_mode(ItemList::SELECT_MULTI); coords_level_list->set_allow_rmb_select(true); @@ -367,6 +369,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() { vbox_container->add_child(alternative_level_label); alternative_level_list = memnew(ItemList); + alternative_level_list->set_auto_translate(false); alternative_level_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); alternative_level_list->set_select_mode(ItemList::SELECT_MULTI); alternative_level_list->set_allow_rmb_select(true); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index a3fc6aa5f7..10dc20d24f 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -507,7 +507,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro } } -void TileSetAtlasSourceEditor::AtlasTileProxyObject::edit(Ref<TileSetAtlasSource> p_tile_set_atlas_source, RBSet<TileSelection> p_tiles) { +void TileSetAtlasSourceEditor::AtlasTileProxyObject::edit(Ref<TileSetAtlasSource> p_tile_set_atlas_source, const RBSet<TileSelection> &p_tiles) { ERR_FAIL_COND(!p_tile_set_atlas_source.is_valid()); ERR_FAIL_COND(p_tiles.is_empty()); for (const TileSelection &E : p_tiles) { @@ -954,7 +954,7 @@ void TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_pressed() { } void TileSetAtlasSourceEditor::_tile_data_editors_tree_selected() { - tile_data_editors_popup->call_deferred(SNAME("hide")); + callable_mp((Window *)tile_data_editors_popup, &Window::hide).call_deferred(); _update_current_tile_data_editor(); tile_atlas_control->queue_redraw(); tile_atlas_control_unscaled->queue_redraw(); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h index 7f6bab804d..e1e6a3113c 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.h +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h @@ -105,7 +105,7 @@ public: RBSet<TileSelection> get_edited_tiles() const { return tiles; }; // Update the proxyed object. - void edit(Ref<TileSetAtlasSource> p_tile_set_atlas_source, RBSet<TileSelection> p_tiles = RBSet<TileSelection>()); + void edit(Ref<TileSetAtlasSource> p_tile_set_atlas_source, const RBSet<TileSelection> &p_tiles = RBSet<TileSelection>()); AtlasTileProxyObject(TileSetAtlasSourceEditor *p_tiles_set_atlas_source_editor) { tiles_set_atlas_source_editor = p_tiles_set_atlas_source_editor; diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index 7242920368..bdde662ce1 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -854,6 +854,7 @@ TileSetEditor::TileSetEditor() { p->set_item_checked(TilesEditorUtils::SOURCE_SORT_ID, true); sources_list = memnew(ItemList); + sources_list->set_auto_translate(false); sources_list->set_fixed_icon_size(Size2(60, 60) * EDSCALE); sources_list->set_h_size_flags(SIZE_EXPAND_FILL); sources_list->set_v_size_flags(SIZE_EXPAND_FILL); @@ -933,6 +934,7 @@ TileSetEditor::TileSetEditor() { //// Patterns //// int thumbnail_size = 64; patterns_item_list = memnew(ItemList); + patterns_item_list->set_auto_translate(false); patterns_item_list->set_max_columns(0); patterns_item_list->set_icon_mode(ItemList::ICON_MODE_TOP); patterns_item_list->set_fixed_column_width(thumbnail_size * 3 / 2); diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp index 1f4c3651e9..7f6616fe34 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp @@ -549,6 +549,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() { split_container_right_side->add_child(right_vbox_container); scene_tiles_list = memnew(ItemList); + scene_tiles_list->set_auto_translate(false); scene_tiles_list->set_h_size_flags(SIZE_EXPAND_FILL); scene_tiles_list->set_v_size_flags(SIZE_EXPAND_FILL); SET_DRAG_FORWARDING_CDU(scene_tiles_list, TileSetScenesCollectionSourceEditor); diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index b96f3f21b8..e7e94fdefa 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -125,7 +125,7 @@ void TilesEditorUtils::_thread() { tile_map->set_position(-(scale * encompassing_rect.get_center()) + thumbnail_size2 / 2); // Add the viewport at the last moment to avoid rendering too early. - EditorNode::get_singleton()->call_deferred("add_child", viewport); + callable_mp((Node *)EditorNode::get_singleton(), &Node::add_child).call_deferred(viewport, false, Node::INTERNAL_MODE_DISABLED); RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<TilesEditorUtils *>(this), &TilesEditorUtils::_preview_frame_started), Object::CONNECT_ONE_SHOT); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 5c22e454ab..24b76526c6 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -182,7 +182,7 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p } void VisualShaderGraphPlugin::update_node_deferred(VisualShader::Type p_type, int p_node_id) { - call_deferred(SNAME("update_node"), p_type, p_node_id); + callable_mp(this, &VisualShaderGraphPlugin::update_node).call_deferred(p_type, p_node_id); } void VisualShaderGraphPlugin::update_node(VisualShader::Type p_type, int p_node_id) { @@ -1492,14 +1492,14 @@ void VisualShaderEditor::_update_custom_script(const Ref<Script> &p_script) { if (!_block_update_options_menu) { _block_update_options_menu = true; - call_deferred(SNAME("_update_options_menu_deferred")); + callable_mp(this, &VisualShaderEditor::_update_options_menu_deferred); } // To prevent rebuilding the shader multiple times when multiple scripts are saved. if (need_rebuild && !_block_rebuild_shader) { _block_rebuild_shader = true; - call_deferred(SNAME("_rebuild_shader_deferred")); + callable_mp(this, &VisualShaderEditor::_rebuild_shader_deferred); } } @@ -1581,8 +1581,7 @@ void VisualShaderEditor::_resource_removed(const Ref<Resource> &p_resource) { if (!pending_custom_scripts_to_delete) { pending_custom_scripts_to_delete = true; - - call_deferred("_resources_removed"); + callable_mp(this, &VisualShaderEditor::_resources_removed).call_deferred(); } } @@ -3322,11 +3321,11 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri } if (is_curve) { - graph_plugin->call_deferred(SNAME("update_curve"), id_to_use); + callable_mp(graph_plugin.ptr(), &VisualShaderGraphPlugin::update_curve).call_deferred(id_to_use); } if (is_curve_xyz) { - graph_plugin->call_deferred(SNAME("update_curve_xyz"), id_to_use); + callable_mp(graph_plugin.ptr(), &VisualShaderGraphPlugin::update_curve_xyz).call_deferred(id_to_use); } if (p_resource_path.is_empty()) { @@ -3466,7 +3465,7 @@ void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_t VisualShader::Type type = get_current_shader_type(); drag_buffer.push_back({ type, p_node, p_from, p_to }); if (!drag_dirty) { - call_deferred(SNAME("_nodes_dragged")); + callable_mp(this, &VisualShaderEditor::_nodes_dragged).call_deferred(); } drag_dirty = true; } @@ -4094,7 +4093,7 @@ void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos, VisualShaderNod Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).max(Vector2()); members_dialog->set_position(members_dialog->get_position() - difference); - node_filter->call_deferred(SNAME("grab_focus")); // Still not visible. + callable_mp((Control *)node_filter, &Control::grab_focus).call_deferred(); // Still not visible. node_filter->select_all(); } @@ -5187,28 +5186,17 @@ void VisualShaderEditor::_visibility_changed() { void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_update_nodes", &VisualShaderEditor::_update_nodes); ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph); - ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node); - ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed); ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item); ClassDB::bind_method("_parameter_ref_select_item", &VisualShaderEditor::_parameter_ref_select_item); ClassDB::bind_method("_varying_select_item", &VisualShaderEditor::_varying_select_item); ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size); - ClassDB::bind_method("_clear_copy_buffer", &VisualShaderEditor::_clear_copy_buffer); ClassDB::bind_method("_update_parameters", &VisualShaderEditor::_update_parameters); ClassDB::bind_method("_update_varyings", &VisualShaderEditor::_update_varyings); ClassDB::bind_method("_update_varying_tree", &VisualShaderEditor::_update_varying_tree); ClassDB::bind_method("_set_mode", &VisualShaderEditor::_set_mode); - ClassDB::bind_method("_nodes_dragged", &VisualShaderEditor::_nodes_dragged); - ClassDB::bind_method("_float_constant_selected", &VisualShaderEditor::_float_constant_selected); ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant); ClassDB::bind_method("_update_parameter", &VisualShaderEditor::_update_parameter); - ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port); - ClassDB::bind_method("_update_options_menu_deferred", &VisualShaderEditor::_update_options_menu_deferred); - ClassDB::bind_method("_rebuild_shader_deferred", &VisualShaderEditor::_rebuild_shader_deferred); - ClassDB::bind_method("_resources_removed", &VisualShaderEditor::_resources_removed); ClassDB::bind_method("_update_next_previews", &VisualShaderEditor::_update_next_previews); - - ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available); } VisualShaderEditor::VisualShaderEditor() { diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp index ec044ee06e..3804bd8d5b 100644 --- a/editor/pot_generator.cpp +++ b/editor/pot_generator.cpp @@ -69,7 +69,7 @@ void POTGenerator::generate_pot(const String &p_file) { for (int i = 0; i < files.size(); i++) { Vector<String> msgids; Vector<Vector<String>> msgids_context_plural; - String file_path = files[i]; + const String &file_path = files[i]; String file_extension = file_path.get_extension(); if (EditorTranslationParser::get_singleton()->can_parse(file_extension)) { @@ -80,7 +80,7 @@ void POTGenerator::generate_pot(const String &p_file) { } for (int j = 0; j < msgids_context_plural.size(); j++) { - Vector<String> entry = msgids_context_plural[j]; + const Vector<String> &entry = msgids_context_plural[j]; _add_new_msgid(entry[0], entry[1], entry[2], file_path); } for (int j = 0; j < msgids.size(); j++) { @@ -141,7 +141,7 @@ void POTGenerator::_write_to_pot(const String &p_file) { // Write context. if (!context.is_empty()) { - file->store_line("msgctxt " + context.c_escape().quote()); + file->store_line("msgctxt " + context.json_escape().quote()); } // Write msgid. @@ -183,11 +183,11 @@ void POTGenerator::_write_msgid(Ref<FileAccess> r_file, const String &p_id, bool } for (int i = 0; i < lines.size() - 1; i++) { - r_file->store_line((lines[i] + "\n").c_escape().quote()); + r_file->store_line((lines[i] + "\n").json_escape().quote()); } if (!last_line.is_empty()) { - r_file->store_line(last_line.c_escape().quote()); + r_file->store_line(last_line.json_escape().quote()); } } diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp index 366d0cb2fc..c0dfc18072 100644 --- a/editor/progress_dialog.cpp +++ b/editor/progress_dialog.cpp @@ -30,7 +30,6 @@ #include "progress_dialog.h" -#include "core/object/message_queue.h" #include "core/os/os.h" #include "editor/editor_interface.h" #include "editor/editor_node.h" @@ -97,15 +96,8 @@ void BackgroundProgress::_end_task(const String &p_task) { tasks.erase(p_task); } -void BackgroundProgress::_bind_methods() { - ClassDB::bind_method("_add_task", &BackgroundProgress::_add_task); - ClassDB::bind_method("_task_step", &BackgroundProgress::_task_step); - ClassDB::bind_method("_end_task", &BackgroundProgress::_end_task); - ClassDB::bind_method("_update", &BackgroundProgress::_update); -} - void BackgroundProgress::add_task(const String &p_task, const String &p_label, int p_steps) { - MessageQueue::get_singleton()->push_call(this, "_add_task", p_task, p_label, p_steps); + callable_mp(this, &BackgroundProgress::_add_task).call_deferred(p_task, p_label, p_steps); } void BackgroundProgress::task_step(const String &p_task, int p_step) { @@ -117,7 +109,7 @@ void BackgroundProgress::task_step(const String &p_task, int p_step) { } if (no_updates) { - MessageQueue::get_singleton()->push_call(this, "_update"); + callable_mp(this, &BackgroundProgress::_update).call_deferred(); } { @@ -127,7 +119,7 @@ void BackgroundProgress::task_step(const String &p_task, int p_step) { } void BackgroundProgress::end_task(const String &p_task) { - MessageQueue::get_singleton()->push_call(this, "_end_task", p_task); + callable_mp(this, &BackgroundProgress::_end_task).call_deferred(p_task); } //////////////////////////////////////////////// @@ -242,9 +234,6 @@ void ProgressDialog::_cancel_pressed() { canceled = true; } -void ProgressDialog::_bind_methods() { -} - ProgressDialog::ProgressDialog() { main = memnew(VBoxContainer); add_child(main); diff --git a/editor/progress_dialog.h b/editor/progress_dialog.h index c75c8fac10..74196a28df 100644 --- a/editor/progress_dialog.h +++ b/editor/progress_dialog.h @@ -56,8 +56,6 @@ protected: void _task_step(const String &p_task, int p_step = -1); void _end_task(const String &p_task); - static void _bind_methods(); - public: void add_task(const String &p_task, const String &p_label, int p_steps); void task_step(const String &p_task, int p_step = -1); @@ -89,9 +87,6 @@ class ProgressDialog : public PopupPanel { void _cancel_pressed(); bool canceled = false; -protected: - static void _bind_methods(); - public: static ProgressDialog *get_singleton() { return singleton; } void add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel = false); diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index bea865af13..f8161272f6 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -68,10 +68,10 @@ public: RegEx reg_json_parse = RegEx("([\t ]{0,})([^\n]+)parse_json\\(([^\n]+)"); RegEx reg_json_non_new = RegEx("([\t ]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)"); RegEx reg_json_print = RegEx("\\bJSON\\b\\.print\\("); - RegEx reg_export_simple = RegEx("export\\(([a-zA-Z0-9_]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)"); - RegEx reg_export_typed = RegEx("export\\(([a-zA-Z0-9_]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)[ ]*:[ ]*[a-zA-Z0-9_]+"); - RegEx reg_export_inferred_type = RegEx("export\\([a-zA-Z0-9_]+\\)[ ]+var[ ]+([a-zA-Z0-9_]+)[ ]*:[ ]*="); - RegEx reg_export_advanced = RegEx("export\\(([^)^\n]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)([^\n]+)"); + RegEx reg_export_simple = RegEx("export[ ]*\\(([a-zA-Z0-9_]+)\\)[ ]*var[ ]+([a-zA-Z0-9_]+)"); + RegEx reg_export_typed = RegEx("export[ ]*\\(([a-zA-Z0-9_]+)\\)[ ]*var[ ]+([a-zA-Z0-9_]+)[ ]*:[ ]*[a-zA-Z0-9_]+"); + RegEx reg_export_inferred_type = RegEx("export[ ]*\\([a-zA-Z0-9_]+\\)[ ]*var[ ]+([a-zA-Z0-9_]+)[ ]*:[ ]*="); + RegEx reg_export_advanced = RegEx("export[ ]*\\(([^)^\n]+)\\)[ ]*var[ ]+([a-zA-Z0-9_]+)([^\n]+)"); RegEx reg_setget_setget = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+?)[ \t]*setget[ \t]+([a-zA-Z0-9_]+)[ \t]*,[ \t]*([a-zA-Z0-9_]+)"); RegEx reg_setget_set = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+?)[ \t]*setget[ \t]+([a-zA-Z0-9_]+)[ \t]*[,]*[^\n]*$"); RegEx reg_setget_get = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+?)[ \t]*setget[ \t]+,[ \t]*([a-zA-Z0-9_]+)[ \t]*$"); @@ -561,7 +561,7 @@ bool ProjectConverter3To4::validate_conversion() { // Check file by file. for (int i = 0; i < collected_files.size(); i++) { - String file_name = collected_files[i]; + const String &file_name = collected_files[i]; Vector<String> lines; uint32_t ignored_lines = 0; uint64_t file_size = 0; @@ -931,6 +931,7 @@ bool ProjectConverter3To4::test_conversion(RegExContainer ®_container) { valid = valid && test_conversion_gdscript_builtin(" Transform.xform_inv(Vector3(a,b,c) + Vector3.UP) ", " (Vector3(a,b,c) + Vector3.UP) * Transform ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid && test_conversion_gdscript_builtin("export(float) var lifetime = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("export (int)var spaces=1", "export var spaces: int=1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid && test_conversion_gdscript_builtin("export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro'", "export var _font_name = 'AnonymousPro' # (String, 'AnonymousPro', 'CourierPrime')", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); // TODO, this is only a workaround valid = valid && test_conversion_gdscript_builtin("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid && test_conversion_gdscript_builtin("export(float) var lifetime: float = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); @@ -1044,107 +1045,108 @@ bool ProjectConverter3To4::test_conversion(RegExContainer ®_container) { // get_object_of_execution { - { String base = "var roman = kieliszek."; - String expected = "kieliszek."; - String got = get_object_of_execution(base); - if (got != expected) { - ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size())); + String base = "var roman = kieliszek."; + String expected = "kieliszek."; + String got = get_object_of_execution(base); + if (got != expected) { + ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size())); + } + valid = valid && (got == expected); + } + { + String base = "r."; + String expected = "r."; + String got = get_object_of_execution(base); + if (got != expected) { + ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size())); + } + valid = valid && (got == expected); + } + { + String base = "mortadela("; + String expected = ""; + String got = get_object_of_execution(base); + if (got != expected) { + ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size())); + } + valid = valid && (got == expected); + } + { + String base = "var node = $world/ukraine/lviv."; + String expected = "$world/ukraine/lviv."; + String got = get_object_of_execution(base); + if (got != expected) { + ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size())); + } + valid = valid && (got == expected); } - valid = valid && (got == expected); -} -{ - String base = "r."; - String expected = "r."; - String got = get_object_of_execution(base); - if (got != expected) { - ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size())); - } - valid = valid && (got == expected); -} -{ - String base = "mortadela("; - String expected = ""; - String got = get_object_of_execution(base); - if (got != expected) { - ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size())); - } - valid = valid && (got == expected); -} -{ - String base = "var node = $world/ukraine/lviv."; - String expected = "$world/ukraine/lviv."; - String got = get_object_of_execution(base); - if (got != expected) { - ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size())); - } - valid = valid && (got == expected); -} -} -// get_starting_space -{ - String base = "\t\t\t var roman = kieliszek."; - String expected = "\t\t\t"; - String got = get_starting_space(base); - if (got != expected) { - ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size())); - } - valid = valid && (got == expected); -} -// Parse Arguments -{ - String line = "( )"; - Vector<String> got_vector = parse_arguments(line); - String got = ""; - String expected = ""; - for (String &part : got_vector) { - got += part + "|||"; - } - if (got != expected) { - ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size())); - } - valid = valid && (got == expected); -} -{ - String line = "(a , b , c)"; - Vector<String> got_vector = parse_arguments(line); - String got = ""; - String expected = "a|||b|||c|||"; - for (String &part : got_vector) { - got += part + "|||"; - } - if (got != expected) { - ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size())); - } - valid = valid && (got == expected); -} -{ - String line = "(a , \"b,\" , c)"; - Vector<String> got_vector = parse_arguments(line); - String got = ""; - String expected = "a|||\"b,\"|||c|||"; - for (String &part : got_vector) { - got += part + "|||"; - } - if (got != expected) { - ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size())); - } - valid = valid && (got == expected); -} -{ - String line = "(a , \"(,),,,,\" , c)"; - Vector<String> got_vector = parse_arguments(line); - String got = ""; - String expected = "a|||\"(,),,,,\"|||c|||"; - for (String &part : got_vector) { - got += part + "|||"; - } - if (got != expected) { - ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size())); - } - valid = valid && (got == expected); -} -return valid; + // get_starting_space + { + String base = "\t\t\t var roman = kieliszek."; + String expected = "\t\t\t"; + String got = get_starting_space(base); + if (got != expected) { + ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size())); + } + valid = valid && (got == expected); + } + + // Parse Arguments + { + String line = "( )"; + Vector<String> got_vector = parse_arguments(line); + String got = ""; + String expected = ""; + for (String &part : got_vector) { + got += part + "|||"; + } + if (got != expected) { + ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size())); + } + valid = valid && (got == expected); + } + { + String line = "(a , b , c)"; + Vector<String> got_vector = parse_arguments(line); + String got = ""; + String expected = "a|||b|||c|||"; + for (String &part : got_vector) { + got += part + "|||"; + } + if (got != expected) { + ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size())); + } + valid = valid && (got == expected); + } + { + String line = "(a , \"b,\" , c)"; + Vector<String> got_vector = parse_arguments(line); + String got = ""; + String expected = "a|||\"b,\"|||c|||"; + for (String &part : got_vector) { + got += part + "|||"; + } + if (got != expected) { + ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size())); + } + valid = valid && (got == expected); + } + { + String line = "(a , \"(,),,,,\" , c)"; + Vector<String> got_vector = parse_arguments(line); + String got = ""; + String expected = "a|||\"(,),,,,\"|||c|||"; + for (String &part : got_vector) { + got += part + "|||"; + } + if (got != expected) { + ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size())); + } + valid = valid && (got == expected); + } + + return valid; } // Validate in all arrays if names don't do cyclic renames "Node" -> "Node2D" | "Node2D" -> "2DNode" @@ -2348,7 +2350,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai line = line.replace("OS.is_window_focused", "get_window().has_focus"); } if (line.contains("OS.move_window_to_foreground")) { - line = line.replace("OS.move_window_to_foreground", "get_window().move_to_foreground"); + line = line.replace("OS.move_window_to_foreground", "get_window().grab_focus"); } if (line.contains("OS.request_attention")) { line = line.replace("OS.request_attention", "get_window().request_attention"); @@ -2732,7 +2734,7 @@ void ProjectConverter3To4::rename_joypad_buttons_and_axes(Vector<SourceLine> &so for (int i = 0; i < reg_match.size(); ++i) { Ref<RegExMatch> match = reg_match[i]; PackedStringArray strings = match->get_strings(); - String button_index_entry = strings[0]; + const String &button_index_entry = strings[0]; int button_index_value = strings[1].to_int(); if (button_index_value == 6) { // L2 and R2 are mapped to joypad axes in Godot 4. line = line.replace("InputEventJoypadButton", "InputEventJoypadMotion"); @@ -2741,7 +2743,7 @@ void ProjectConverter3To4::rename_joypad_buttons_and_axes(Vector<SourceLine> &so line = line.replace("InputEventJoypadButton", "InputEventJoypadMotion"); line = line.replace(button_index_entry, ",\"axis\":5,\"axis_value\":1.0"); } else if (button_index_value < 22) { // There are no mappings for indexes greater than 22 in both Godot 3 & 4. - String pressure_and_pressed_properties = strings[2]; + const String &pressure_and_pressed_properties = strings[2]; line = line.replace(button_index_entry, ",\"button_index\":" + String::num_int64(reg_container.joypad_button_mappings[button_index_value]) + "," + pressure_and_pressed_properties); } } @@ -2750,7 +2752,7 @@ void ProjectConverter3To4::rename_joypad_buttons_and_axes(Vector<SourceLine> &so for (int i = 0; i < reg_match.size(); ++i) { Ref<RegExMatch> match = reg_match[i]; PackedStringArray strings = match->get_strings(); - String axis_entry = strings[0]; + const String &axis_entry = strings[0]; int axis_value = strings[1].to_int(); if (axis_value == 6) { line = line.replace(axis_entry, ",\"axis\":4"); @@ -2772,7 +2774,7 @@ Vector<String> ProjectConverter3To4::check_for_rename_joypad_buttons_and_axes(Ve for (int i = 0; i < reg_match.size(); ++i) { Ref<RegExMatch> match = reg_match[i]; PackedStringArray strings = match->get_strings(); - String button_index_entry = strings[0]; + const String &button_index_entry = strings[0]; int button_index_value = strings[1].to_int(); if (button_index_value == 6) { // L2 and R2 are mapped to joypad axes in Godot 4. found_renames.append(line_formatter(current_line, "InputEventJoypadButton", "InputEventJoypadMotion", line)); @@ -2789,7 +2791,7 @@ Vector<String> ProjectConverter3To4::check_for_rename_joypad_buttons_and_axes(Ve for (int i = 0; i < reg_match.size(); ++i) { Ref<RegExMatch> match = reg_match[i]; PackedStringArray strings = match->get_strings(); - String axis_entry = strings[0]; + const String &axis_entry = strings[0]; int axis_value = strings[1].to_int(); if (axis_value == 6) { found_renames.append(line_formatter(current_line, axis_entry, ",\"axis\":4", line)); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index f74458e89b..c986ce215a 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -103,21 +103,25 @@ void ProjectDialog::_set_message(const String &p_msg, MessageType p_type, InputT } } +static bool is_zip_file(Ref<DirAccess> p_d, const String &p_path) { + return p_path.ends_with(".zip") && p_d->file_exists(p_path); +} + String ProjectDialog::_test_path() { Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + const String base_path = project_path->get_text(); String valid_path, valid_install_path; - if (d->change_dir(project_path->get_text()) == OK) { - valid_path = project_path->get_text(); - } else if (d->change_dir(project_path->get_text().strip_edges()) == OK) { - valid_path = project_path->get_text().strip_edges(); - } else if (project_path->get_text().ends_with(".zip")) { - if (d->file_exists(project_path->get_text())) { - valid_path = project_path->get_text(); - } - } else if (project_path->get_text().strip_edges().ends_with(".zip")) { - if (d->file_exists(project_path->get_text().strip_edges())) { - valid_path = project_path->get_text().strip_edges(); - } + bool is_zip = false; + if (d->change_dir(base_path) == OK) { + valid_path = base_path; + } else if (is_zip_file(d, base_path)) { + valid_path = base_path; + is_zip = true; + } else if (d->change_dir(base_path.strip_edges()) == OK) { + valid_path = base_path.strip_edges(); + } else if (is_zip_file(d, base_path.strip_edges())) { + valid_path = base_path.strip_edges(); + is_zip = true; } if (valid_path.is_empty()) { @@ -126,7 +130,7 @@ String ProjectDialog::_test_path() { return ""; } - if (mode == MODE_IMPORT && valid_path.ends_with(".zip")) { + if (mode == MODE_IMPORT && is_zip) { if (d->change_dir(install_path->get_text()) == OK) { valid_install_path = install_path->get_text(); } else if (d->change_dir(install_path->get_text().strip_edges()) == OK) { @@ -134,15 +138,15 @@ String ProjectDialog::_test_path() { } if (valid_install_path.is_empty()) { - _set_message(TTR("The path specified doesn't exist."), MESSAGE_ERROR, INSTALL_PATH); + _set_message(TTR("The install path specified doesn't exist."), MESSAGE_ERROR, INSTALL_PATH); get_ok_button()->set_disabled(true); return ""; } } if (mode == MODE_IMPORT || mode == MODE_RENAME) { - if (!valid_path.is_empty() && !d->file_exists("project.godot")) { - if (valid_path.ends_with(".zip")) { + if (!d->file_exists("project.godot")) { + if (is_zip) { Ref<FileAccess> io_fa; zlib_filefunc_def io = zipio_create_io(&io_fa); @@ -197,7 +201,7 @@ String ProjectDialog::_test_path() { d->list_dir_end(); if (!is_folder_empty) { - _set_message(TTR("Please choose an empty folder."), MESSAGE_WARNING, INSTALL_PATH); + _set_message(TTR("Please choose an empty install folder."), MESSAGE_WARNING, INSTALL_PATH); get_ok_button()->set_disabled(true); return ""; } @@ -209,8 +213,8 @@ String ProjectDialog::_test_path() { return ""; } - } else if (valid_path.ends_with("zip")) { - _set_message(TTR("This directory already contains a Godot project."), MESSAGE_ERROR, INSTALL_PATH); + } else if (is_zip) { + _set_message(TTR("The install directory already contains a Godot project."), MESSAGE_ERROR, INSTALL_PATH); get_ok_button()->set_disabled(true); return ""; } @@ -252,7 +256,7 @@ String ProjectDialog::_test_path() { return valid_path; } -void ProjectDialog::_path_text_changed(const String &p_path) { +void ProjectDialog::_update_path(const String &p_path) { String sp = _test_path(); if (!sp.is_empty()) { // If the project name is empty or default, infer the project name from the selected folder name @@ -277,6 +281,21 @@ void ProjectDialog::_path_text_changed(const String &p_path) { } } +void ProjectDialog::_path_text_changed(const String &p_path) { + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (mode == MODE_IMPORT && is_zip_file(d, p_path)) { + install_path->set_text(p_path.get_base_dir()); + install_path_container->show(); + } else if (mode == MODE_IMPORT && is_zip_file(d, p_path.strip_edges())) { + install_path->set_text(p_path.strip_edges().get_base_dir()); + install_path_container->show(); + } else { + install_path_container->hide(); + } + + _update_path(p_path.simplify_path()); +} + void ProjectDialog::_file_selected(const String &p_path) { // If not already shown. show_dialog(); @@ -300,11 +319,11 @@ void ProjectDialog::_file_selected(const String &p_path) { String sp = p.simplify_path(); project_path->set_text(sp); - _path_text_changed(sp); + _update_path(sp); if (p.ends_with(".zip")) { - install_path->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)install_path, &Control::grab_focus).call_deferred(); } else { - get_ok_button()->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)get_ok_button(), &Control::grab_focus).call_deferred(); } } @@ -314,15 +333,15 @@ void ProjectDialog::_path_selected(const String &p_path) { String sp = p_path.simplify_path(); project_path->set_text(sp); - _path_text_changed(sp); - get_ok_button()->call_deferred(SNAME("grab_focus")); + _update_path(sp); + callable_mp((Control *)get_ok_button(), &Control::grab_focus).call_deferred(); } void ProjectDialog::_install_path_selected(const String &p_path) { String sp = p_path.simplify_path(); install_path->set_text(sp); - _path_text_changed(sp); - get_ok_button()->call_deferred(SNAME("grab_focus")); + _update_path(sp); + callable_mp((Control *)get_ok_button(), &Control::grab_focus).call_deferred(); } void ProjectDialog::_browse_path() { @@ -359,7 +378,7 @@ void ProjectDialog::_create_folder() { d->change_dir(project_name_no_edges); String dir_str = d->get_current_dir(); project_path->set_text(dir_str); - _path_text_changed(dir_str); + _update_path(dir_str); created_folder_path = d->get_current_dir(); create_dir->set_disabled(true); } else { @@ -638,7 +657,7 @@ void ProjectDialog::cancel_pressed() { _remove_created_folder(); project_path->clear(); - _path_text_changed(""); + _update_path(""); project_name->clear(); _text_changed(""); @@ -707,7 +726,7 @@ void ProjectDialog::show_dialog() { _text_changed(cur_name); } - project_name->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)project_name, &Control::grab_focus).call_deferred(); create_dir->hide(); @@ -754,8 +773,8 @@ void ProjectDialog::show_dialog() { install_path_container->hide(); renderer_container->show(); default_files_container->show(); - project_name->call_deferred(SNAME("grab_focus")); - project_name->call_deferred(SNAME("select_all")); + callable_mp((Control *)project_name, &Control::grab_focus).call_deferred(); + callable_mp(project_name, &LineEdit::select_all).call_deferred(); } else if (mode == MODE_INSTALL) { set_title(TTR("Install Project:") + " " + zip_title); @@ -968,7 +987,7 @@ ProjectDialog::ProjectDialog() { project_name->connect("text_changed", callable_mp(this, &ProjectDialog::_text_changed)); project_path->connect("text_changed", callable_mp(this, &ProjectDialog::_path_text_changed)); - install_path->connect("text_changed", callable_mp(this, &ProjectDialog::_path_text_changed)); + install_path->connect("text_changed", callable_mp(this, &ProjectDialog::_update_path)); fdialog->connect("dir_selected", callable_mp(this, &ProjectDialog::_path_selected)); fdialog->connect("file_selected", callable_mp(this, &ProjectDialog::_file_selected)); fdialog_install->connect("dir_selected", callable_mp(this, &ProjectDialog::_install_path_selected)); @@ -3074,7 +3093,7 @@ ProjectManager::ProjectManager() { language_btn->set_text(current_lang); for (int i = 0; i < editor_languages.size(); i++) { - String lang = editor_languages[i]; + const String &lang = editor_languages[i]; String lang_name = TranslationServer::get_singleton()->get_locale_name(lang); language_btn->add_item(vformat("[%s] %s", lang, lang_name), i); language_btn->set_item_metadata(i, lang); diff --git a/editor/project_manager.h b/editor/project_manager.h index 8a8b2ff99d..7b091050bd 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -104,6 +104,7 @@ private: void _set_message(const String &p_msg, MessageType p_type = MESSAGE_SUCCESS, InputType input_type = PROJECT_PATH); String _test_path(); + void _update_path(const String &p_path); void _path_text_changed(const String &p_path); void _path_selected(const String &p_path); void _file_selected(const String &p_path); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index d587737ed4..1b0d791ff1 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -70,6 +70,8 @@ void ProjectSettingsEditor::popup_project_settings(bool p_clear_filter) { if (p_clear_filter) { search_box->clear(); } + + _focus_current_search_box(); } void ProjectSettingsEditor::queue_save() { @@ -173,7 +175,7 @@ void ProjectSettingsEditor::_feature_selected(int p_index) { void ProjectSettingsEditor::_update_property_box() { const String setting = _get_setting_name(); const Vector<String> t = setting.split(".", true, 1); - const String name = t[0]; + const String &name = t[0]; const String feature = (t.size() == 2) ? t[1] : ""; bool feature_invalid = (t.size() == 2) && (t[1].is_empty()); @@ -255,8 +257,7 @@ void ProjectSettingsEditor::shortcut_input(const Ref<InputEvent> &p_event) { } if (k->is_match(InputEventKey::create_reference(KeyModifierMask::CMD_OR_CTRL | Key::F))) { - search_box->grab_focus(); - search_box->select_all(); + _focus_current_search_box(); handled = true; } @@ -328,6 +329,25 @@ void ProjectSettingsEditor::_add_feature_overrides() { } } +void ProjectSettingsEditor::_tabs_tab_changed(int p_tab) { + _focus_current_search_box(); +} + +void ProjectSettingsEditor::_focus_current_search_box() { + Control *tab = tab_container->get_current_tab_control(); + LineEdit *current_search_box = nullptr; + if (tab == general_editor) { + current_search_box = search_box; + } else if (tab == action_map_editor) { + current_search_box = action_map_editor->get_search_box(); + } + + if (current_search_box) { + current_search_box->grab_focus(); + current_search_box->select_all(); + } +} + void ProjectSettingsEditor::_editor_restart() { ProjectSettings::get_singleton()->save(); EditorNode::get_singleton()->save_all_scenes(); @@ -536,6 +556,8 @@ void ProjectSettingsEditor::_update_action_map_editor() { } void ProjectSettingsEditor::_update_theme() { + add_button->set_icon(get_editor_theme_icon(SNAME("Add"))); + del_button->set_icon(get_editor_theme_icon(SNAME("Remove"))); search_box->set_right_icon(get_editor_theme_icon(SNAME("Search"))); restart_close_button->set_icon(get_editor_theme_icon(SNAME("Close"))); restart_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); @@ -598,6 +620,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { tab_container = memnew(TabContainer); tab_container->set_use_hidden_tabs_for_min_size(true); tab_container->set_theme_type_variation("TabContainerOdd"); + tab_container->connect("tab_changed", callable_mp(this, &ProjectSettingsEditor::_tabs_tab_changed)); add_child(tab_container); general_editor = memnew(VBoxContainer); diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index 1f18c68acc..7771bdda61 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -95,6 +95,9 @@ class ProjectSettingsEditor : public AcceptDialog { void _add_setting(); void _delete_setting(); + void _tabs_tab_changed(int p_tab); + void _focus_current_search_box(); + void _editor_restart_request(); void _editor_restart(); void _editor_restart_close(); diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp index 075c856c1c..04a06ff732 100644 --- a/editor/register_editor_types.cpp +++ b/editor/register_editor_types.cpp @@ -50,6 +50,8 @@ #include "editor/filesystem_dock.h" #include "editor/gui/editor_file_dialog.h" #include "editor/gui/editor_spin_slider.h" +#include "editor/import/3d/resource_importer_obj.h" +#include "editor/import/3d/resource_importer_scene.h" #include "editor/import/editor_import_plugin.h" #include "editor/import/resource_importer_bitmask.h" #include "editor/import/resource_importer_bmfont.h" @@ -58,8 +60,6 @@ #include "editor/import/resource_importer_image.h" #include "editor/import/resource_importer_imagefont.h" #include "editor/import/resource_importer_layered_texture.h" -#include "editor/import/resource_importer_obj.h" -#include "editor/import/resource_importer_scene.h" #include "editor/import/resource_importer_shader_file.h" #include "editor/import/resource_importer_texture.h" #include "editor/import/resource_importer_texture_atlas.h" diff --git a/editor/renames_map_3_to_4.cpp b/editor/renames_map_3_to_4.cpp index 6323aecfda..ba6095db47 100644 --- a/editor/renames_map_3_to_4.cpp +++ b/editor/renames_map_3_to_4.cpp @@ -163,6 +163,7 @@ const char *RenamesMap3To4::gdscript_function_renames[][2] = { // { "_set_name", "get_tracker_name" }, // XRPositionalTracker -- CameraFeed uses this. // { "_unhandled_input", "_unhandled_key_input" }, // BaseButton, ViewportContainer -- Breaks Node, FileDialog, SubViewportContainer. + // { "add_animation", "add_animation_library" }, // AnimationPlayer -- Breaks SpriteFrames (and isn't a correct conversion). // { "create_gizmo", "_create_gizmo" }, // EditorNode3DGizmoPlugin -- May be used. // { "get_dependencies", "_get_dependencies" }, // ResourceFormatLoader -- Breaks ResourceLoader. // { "get_extents", "get_size" }, // BoxShape, RectangleShape -- Breaks Decal, VoxelGI, GPUParticlesCollisionBox, GPUParticlesCollisionSDF, GPUParticlesCollisionHeightField, GPUParticlesAttractorBox, GPUParticlesAttractorVectorField, FogVolume @@ -214,8 +215,6 @@ const char *RenamesMap3To4::gdscript_function_renames[][2] = { { "_set_current", "set_current" }, // Camera2D { "_set_editor_description", "set_editor_description" }, // Node { "_toplevel_raise_self", "_top_level_raise_self" }, // CanvasItem - { "_update_wrap_at", "_update_wrap_at_column" }, // TextEdit - { "add_animation", "add_animation_library" }, // AnimationPlayer { "add_cancel", "add_cancel_button" }, // AcceptDialog { "add_central_force", "apply_central_force" }, //RigidBody2D { "add_child_below_node", "add_sibling" }, // Node @@ -644,7 +643,6 @@ const char *RenamesMap3To4::csharp_function_renames[][2] = { { "_SetPlaying", "SetPlaying" }, // AnimatedSprite3D { "_ToplevelRaiseSelf", "_TopLevelRaiseSelf" }, // CanvasItem { "_UpdateWrapAt", "_UpdateWrapAtColumn" }, // TextEdit - { "AddAnimation", "AddAnimationLibrary" }, // AnimationPlayer { "AddCancel", "AddCancelButton" }, // AcceptDialog { "AddCentralForce", "AddConstantCentralForce" }, //RigidBody2D { "AddChildBelowNode", "AddSibling" }, // Node diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp index 60ad7e5968..be558101cf 100644 --- a/editor/scene_create_dialog.cpp +++ b/editor/scene_create_dialog.cpp @@ -65,7 +65,7 @@ void SceneCreateDialog::config(const String &p_dir) { directory = p_dir; root_name_edit->set_text(""); scene_name_edit->set_text(""); - scene_name_edit->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)scene_name_edit, &Control::grab_focus).call_deferred(); validation_panel->update(); } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 6553a592d0..6bad5d1c2e 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -29,13 +29,11 @@ /**************************************************************************/ #include "scene_tree_dock.h" -#include "node_dock.h" #include "core/config/project_settings.h" #include "core/input/input.h" #include "core/io/resource_saver.h" #include "core/object/class_db.h" -#include "core/object/message_queue.h" #include "core/os/keyboard.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/editor_feature_profile.h" @@ -50,6 +48,7 @@ #include "editor/gui/editor_file_dialog.h" #include "editor/inspector_dock.h" #include "editor/multi_node_edit.h" +#include "editor/node_dock.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" @@ -713,7 +712,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { selection.sort_custom<Node::Comparator>(); - Node *add_below_node = selection.back()->get(); + HashMap<const Node *, Node *> add_below_map; + + for (List<Node *>::Element *E = selection.back(); E; E = E->prev()) { + Node *node = E->get(); + if (!add_below_map.has(node->get_parent())) { + add_below_map.insert(node->get_parent(), node); + } + } for (Node *node : selection) { Node *parent = node->get_parent(); @@ -740,7 +746,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { dup->set_name(parent->validate_child_name(dup)); - undo_redo->add_do_method(add_below_node, "add_sibling", dup, true); + undo_redo->add_do_method(add_below_map[parent], "add_sibling", dup, true); for (Node *F : owned) { if (!duplimap.has(F)) { @@ -759,7 +765,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { undo_redo->add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name()); undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(dup->get_name()))); - add_below_node = dup; + add_below_map[parent] = dup; } undo_redo->commit_action(); @@ -1236,7 +1242,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (cant_be_set_unique_names.size()) { String popup_text = TTR("Unique names already used by another node in the scene:"); popup_text += "\n"; - for (StringName name : cant_be_set_unique_names) { + for (const StringName &name : cant_be_set_unique_names) { popup_text += "\n" + String(name); } accept->set_text(popup_text); @@ -1386,7 +1392,7 @@ void SceneTreeDock::_notification(int p_what) { node_shortcuts_toggle->set_flat(true); node_shortcuts_toggle->set_icon(get_editor_theme_icon(SNAME("Favorites"))); node_shortcuts_toggle->set_toggle_mode(true); - node_shortcuts_toggle->set_tooltip_text(TTR("Switch to Favorite Nodes")); + node_shortcuts_toggle->set_tooltip_text(TTR("Toggle the display of favorite nodes.")); node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection")); node_shortcuts_toggle->set_anchors_and_offsets_preset(Control::PRESET_CENTER_RIGHT); node_shortcuts_toggle->connect("pressed", callable_mp(this, &SceneTreeDock::_update_create_root_dialog)); @@ -1558,7 +1564,9 @@ void SceneTreeDock::_load_request(const String &p_path) { } void SceneTreeDock::_script_open_request(const Ref<Script> &p_script) { - EditorNode::get_singleton()->edit_resource(p_script); + if (ScriptEditor::get_singleton()->edit(p_script, true)) { + EditorNode::get_singleton()->editor_select(EditorNode::EDITOR_SCRIPT); + } } void SceneTreeDock::_push_item(Object *p_object) { @@ -2311,18 +2319,121 @@ void SceneTreeDock::_toggle_placeholder_from_selection() { } } -void SceneTreeDock::_toggle_editable_children(Node *p_node) { - if (p_node) { - bool editable = !EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node); - EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(p_node, editable); - if (editable) { - p_node->set_scene_instance_load_placeholder(false); +void SceneTreeDock::_reparent_nodes_to_root(Node *p_root, const Array &p_nodes, Node *p_owner) { + List<Node *> nodes; + for (int i = 0; i < p_nodes.size(); i++) { + Node *node = Object::cast_to<Node>(p_nodes[i]); + ERR_FAIL_NULL(node); + nodes.push_back(node); + } + + for (Node *node : nodes) { + node->set_owner(p_owner); + List<Node *> owned; + node->get_owned_by(p_owner, &owned); + String original_name = node->get_name(); + node->reparent(p_root); + node->set_name(original_name); + + for (Node *F : owned) { + F->set_owner(p_owner); } + } +} + +void SceneTreeDock::_reparent_nodes_to_paths_with_transform_and_name(Node *p_root, const Array &p_nodes, const Array &p_paths, const Array &p_transforms, const Array &p_names, Node *p_owner) { + ERR_FAIL_COND(p_nodes.size() != p_paths.size()); + ERR_FAIL_COND(p_nodes.size() != p_transforms.size()); + ERR_FAIL_COND(p_nodes.size() != p_names.size()); + + for (int i = 0; i < p_nodes.size(); i++) { + Node *node = Object::cast_to<Node>(p_nodes[i]); + ERR_FAIL_NULL(node); + const NodePath &np = p_paths[i]; + Node *parent_node = p_root->get_node_or_null(np); + ERR_FAIL_NULL(parent_node); + + List<Node *> owned; + node->get_owned_by(p_owner, &owned); + node->reparent(parent_node); + node->set_name(p_names[i]); + Node3D *node_3d = Object::cast_to<Node3D>(node); + if (node_3d) { + node_3d->set_transform(p_transforms[i]); + } else { + Node2D *node_2d = Object::cast_to<Node2D>(node); + if (node_2d) { + node_2d->set_transform(p_transforms[i]); + } + } + + for (Node *F : owned) { + F->set_owner(p_owner); + } + } +} + +void SceneTreeDock::_toggle_editable_children(Node *p_node) { + if (!p_node) { + return; + } + + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + + undo_redo->create_action(TTR("Toggle Editable Children")); - Node3DEditor::get_singleton()->update_all_gizmos(p_node); + bool editable = !EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node); - scene_tree->update_tree(); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_editable_instance", p_node, !editable); + undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_editable_instance", p_node, editable); + + if (editable) { + bool original_scene_instance_load_placeholder = p_node->get_scene_instance_load_placeholder(); + + undo_redo->add_undo_method(p_node, "set_scene_instance_load_placeholder", original_scene_instance_load_placeholder); + undo_redo->add_do_method(p_node, "set_scene_instance_load_placeholder", false); + } else { + List<Node *> owned; + p_node->get_owned_by(edited_scene, &owned); + + // Get the original paths, transforms, and names for undo. + Array owned_nodes_array; + Array paths_array; + Array transform_array; + Array name_array; + + for (Node *owned_node : owned) { + if (owned_node != p_node && owned_node != edited_scene && owned_node->get_owner() == edited_scene && owned_node->get_parent()->get_owner() != edited_scene) { + owned_nodes_array.push_back(owned_node); + paths_array.push_back(p_node->get_path_to(owned_node->get_parent())); + name_array.push_back(owned_node->get_name()); + Node3D *node_3d = Object::cast_to<Node3D>(owned_node); + if (node_3d) { + transform_array.push_back(node_3d->get_transform()); + } else { + Node2D *node_2d = Object::cast_to<Node2D>(owned_node); + if (node_2d) { + transform_array.push_back(node_2d->get_transform()); + } else { + transform_array.push_back(Variant()); + } + } + } + } + + if (!owned_nodes_array.is_empty()) { + undo_redo->add_undo_method(this, "_reparent_nodes_to_paths_with_transform_and_name", p_node, owned_nodes_array, paths_array, transform_array, name_array, edited_scene); + undo_redo->add_do_method(this, "_reparent_nodes_to_root", p_node, owned_nodes_array, edited_scene); + } } + + undo_redo->add_undo_method(Node3DEditor::get_singleton(), "update_all_gizmos", p_node); + undo_redo->add_do_method(Node3DEditor::get_singleton(), "update_all_gizmos", p_node); + + undo_redo->add_undo_method(scene_tree, "update_tree"); + undo_redo->add_do_method(scene_tree, "update_tree"); + + undo_redo->commit_action(); } void SceneTreeDock::_delete_confirm(bool p_cut) { @@ -2802,12 +2913,17 @@ void SceneTreeDock::_new_scene_from(String p_file) { Node *base = selection.front()->get(); HashMap<const Node *, Node *> duplimap; + HashMap<const Node *, Node *> inverse_duplimap; Node *copy = base->duplicate_from_editor(duplimap); + for (const KeyValue<const Node *, Node *> &item : duplimap) { + inverse_duplimap[item.value] = const_cast<Node *>(item.key); + } + if (copy) { // Handle Unique Nodes. for (int i = 0; i < copy->get_child_count(false); i++) { - _set_node_owner_recursive(copy->get_child(i, false), copy); + _set_node_owner_recursive(copy->get_child(i, false), copy, inverse_duplimap); } // Root node cannot ever be unique name in its own Scene! copy->set_unique_name_in_owner(false); @@ -2841,13 +2957,18 @@ void SceneTreeDock::_new_scene_from(String p_file) { } } -void SceneTreeDock::_set_node_owner_recursive(Node *p_node, Node *p_owner) { - if (!p_node->get_owner()) { - p_node->set_owner(p_owner); +void SceneTreeDock::_set_node_owner_recursive(Node *p_node, Node *p_owner, const HashMap<const Node *, Node *> &p_inverse_duplimap) { + HashMap<const Node *, Node *>::ConstIterator E = p_inverse_duplimap.find(p_node); + + if (E) { + const Node *original = E->value; + if (original->get_owner()) { + p_node->set_owner(p_owner); + } } for (int i = 0; i < p_node->get_child_count(false); i++) { - _set_node_owner_recursive(p_node->get_child(i, false), p_owner); + _set_node_owner_recursive(p_node->get_child(i, false), p_owner, p_inverse_duplimap); } } @@ -2932,7 +3053,7 @@ void SceneTreeDock::_files_dropped(Vector<String> p_files, NodePath p_to, int p_ _normalize_drop(node, to_pos, p_type); _perform_instantiate_scenes(p_files, node, to_pos); } else { - String res_path = p_files[0]; + const String &res_path = p_files[0]; StringName res_type = EditorFileSystem::get_singleton()->get_file_type(res_path); List<String> valid_properties; @@ -3048,6 +3169,9 @@ void SceneTreeDock::_nodes_dragged(Array p_nodes, NodePath p_to, int p_type) { _normalize_drop(to_node, to_pos, p_type); _do_reparent(to_node, to_pos, nodes, !Input::get_singleton()->is_key_pressed(Key::SHIFT)); + for (Node *E : nodes) { + editor_selection->add_node(E); + } } void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) { @@ -3935,6 +4059,8 @@ void SceneTreeDock::_edit_subresource(int p_idx, const PopupMenu *p_from_menu) { void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_owners"), &SceneTreeDock::_set_owners); + ClassDB::bind_method(D_METHOD("_reparent_nodes_to_root"), &SceneTreeDock::_reparent_nodes_to_root); + ClassDB::bind_method(D_METHOD("_reparent_nodes_to_paths_with_transform_and_name"), &SceneTreeDock::_reparent_nodes_to_paths_with_transform_and_name); ClassDB::bind_method(D_METHOD("_update_script_button"), &SceneTreeDock::_update_script_button); @@ -3951,7 +4077,7 @@ SceneTreeDock *SceneTreeDock::singleton = nullptr; void SceneTreeDock::_update_configuration_warning() { if (singleton) { - MessageQueue::get_singleton()->push_callable(callable_mp(singleton->scene_tree, &SceneTreeEditor::update_warning)); + callable_mp(singleton->scene_tree, &SceneTreeEditor::update_warning).call_deferred(); } } diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index fc9c271526..e765ef2a6b 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -223,6 +223,9 @@ class SceneTreeDock : public VBoxContainer { void _delete_dialog_closed(); void _toggle_editable_children_from_selection(); + + void _reparent_nodes_to_root(Node *p_root, const Array &p_nodes, Node *p_owner); + void _reparent_nodes_to_paths_with_transform_and_name(Node *p_root, const Array &p_nodes, const Array &p_paths, const Array &p_transforms, const Array &p_names, Node *p_owner); void _toggle_editable_children(Node *p_node); void _toggle_placeholder_from_selection(); @@ -234,7 +237,7 @@ class SceneTreeDock : public VBoxContainer { virtual void shortcut_input(const Ref<InputEvent> &p_event) override; void _new_scene_from(String p_file); - void _set_node_owner_recursive(Node *p_node, Node *p_owner); + void _set_node_owner_recursive(Node *p_node, Node *p_owner, const HashMap<const Node *, Node *> &p_inverse_duplimap); bool _validate_no_foreign(); bool _validate_no_instance(); diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp index ead0eeeae3..46f520df45 100644 --- a/editor/shader_globals_editor.cpp +++ b/editor/shader_globals_editor.cpp @@ -105,7 +105,6 @@ class ShaderGlobalsEditorInterface : public Object { protected: static void _bind_methods() { - ClassDB::bind_method("_set_var", &ShaderGlobalsEditorInterface::_set_var); ClassDB::bind_method("_var_changed", &ShaderGlobalsEditorInterface::_var_changed); ADD_SIGNAL(MethodInfo("var_changed")); } @@ -117,7 +116,7 @@ protected: return false; } - call_deferred("_set_var", p_name, p_value, existing); + callable_mp(this, &ShaderGlobalsEditorInterface::_set_var).call_deferred(p_name, p_value, existing); return true; } @@ -345,15 +344,29 @@ static Variant create_var(RS::GlobalShaderParameterType p_type) { } } +String ShaderGlobalsEditor::_check_new_variable_name(const String &p_variable_name) { + if (p_variable_name.is_empty()) { + return TTR("Name cannot be empty."); + } + + if (!p_variable_name.is_valid_identifier()) { + return TTR("Name must be a valid identifier."); + } + + return ""; +} + +void ShaderGlobalsEditor::_variable_name_text_changed(const String &p_variable_name) { + const String &warning = _check_new_variable_name(p_variable_name.strip_edges()); + variable_add->set_tooltip_text(warning); + variable_add->set_disabled(!warning.is_empty()); +} + void ShaderGlobalsEditor::_variable_added() { String var = variable_name->get_text().strip_edges(); - if (var.is_empty() || !var.is_valid_identifier()) { - EditorNode::get_singleton()->show_warning(TTR("Please specify a valid shader uniform identifier name.")); - return; - } if (RenderingServer::get_singleton()->global_shader_parameter_get(var).get_type() != Variant::NIL) { - EditorNode::get_singleton()->show_warning(vformat(TTR("Global shader parameter '%s' already exists'"), var)); + EditorNode::get_singleton()->show_warning(vformat(TTR("Global shader parameter '%s' already exists."), var)); return; } @@ -417,6 +430,10 @@ void ShaderGlobalsEditor::_notification(int p_what) { } } break; + case NOTIFICATION_THEME_CHANGED: { + variable_add->set_icon(get_editor_theme_icon(SNAME("Add"))); + } break; + case NOTIFICATION_PREDELETE: { inspector->edit(nullptr); } break; @@ -432,6 +449,9 @@ ShaderGlobalsEditor::ShaderGlobalsEditor() { add_menu_hb->add_child(memnew(Label(TTR("Name:")))); variable_name = memnew(LineEdit); variable_name->set_h_size_flags(SIZE_EXPAND_FILL); + variable_name->set_clear_button_enabled(true); + variable_name->connect("text_changed", callable_mp(this, &ShaderGlobalsEditor::_variable_name_text_changed)); + add_menu_hb->add_child(variable_name); add_menu_hb->add_child(memnew(Label(TTR("Type:")))); @@ -444,6 +464,7 @@ ShaderGlobalsEditor::ShaderGlobalsEditor() { } variable_add = memnew(Button(TTR("Add"))); + variable_add->set_disabled(true); add_menu_hb->add_child(variable_add); variable_add->connect("pressed", callable_mp(this, &ShaderGlobalsEditor::_variable_added)); diff --git a/editor/shader_globals_editor.h b/editor/shader_globals_editor.h index 590da342d4..fc50564aae 100644 --- a/editor/shader_globals_editor.h +++ b/editor/shader_globals_editor.h @@ -49,6 +49,9 @@ class ShaderGlobalsEditor : public VBoxContainer { OptionButton *variable_type = nullptr; Button *variable_add = nullptr; + String _check_new_variable_name(const String &p_variable_name); + + void _variable_name_text_changed(const String &p_variable_name); void _variable_added(); void _variable_deleted(const String &p_variable); void _changed(); diff --git a/editor/surface_upgrade_tool.cpp b/editor/surface_upgrade_tool.cpp index 78ebe43c96..d914303b4e 100644 --- a/editor/surface_upgrade_tool.cpp +++ b/editor/surface_upgrade_tool.cpp @@ -106,7 +106,7 @@ void SurfaceUpgradeTool::prepare_upgrade() { EditorSettings::get_singleton()->set_project_metadata("surface_upgrade_tool", "resave_paths", resave_paths); // Delay to avoid deadlocks, since this dialog can be triggered by loading a scene. - MessageQueue::get_singleton()->push_callable(callable_mp(EditorNode::get_singleton(), &EditorNode::restart_editor)); + callable_mp(EditorNode::get_singleton(), &EditorNode::restart_editor).call_deferred(); } // Ensure that the warnings and popups are skipped. diff --git a/editor/window_wrapper.cpp b/editor/window_wrapper.cpp index 2d89e4df46..aec4005ce5 100644 --- a/editor/window_wrapper.cpp +++ b/editor/window_wrapper.cpp @@ -74,7 +74,7 @@ class ShortcutBin : public Node { }; Rect2 WindowWrapper::_get_default_window_rect() const { - // Assume that the control rect is the desidered one for the window. + // Assume that the control rect is the desired one for the window. return wrapped_control->get_screen_rect(); } diff --git a/main/main.cpp b/main/main.cpp index 4dcd92bcff..b50def9cec 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1615,16 +1615,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } // Initialize WorkerThreadPool. - { + if (editor || project_manager) { + WorkerThreadPool::get_singleton()->init(-1, 0.75); + } else { int worker_threads = GLOBAL_GET("threading/worker_pool/max_threads"); - bool low_priority_use_system_threads = GLOBAL_GET("threading/worker_pool/use_system_threads_for_low_priority_tasks"); - float low_property_ratio = GLOBAL_GET("threading/worker_pool/low_priority_thread_ratio"); - - if (editor || project_manager) { - WorkerThreadPool::get_singleton()->init(); - } else { - WorkerThreadPool::get_singleton()->init(worker_threads, low_priority_use_system_threads, low_property_ratio); - } + float low_priority_ratio = GLOBAL_GET("threading/worker_pool/low_priority_thread_ratio"); + WorkerThreadPool::get_singleton()->init(worker_threads, low_priority_ratio); } #ifdef TOOLS_ENABLED diff --git a/main/performance.cpp b/main/performance.cpp index e24a3673b9..b5f1a45b9a 100644 --- a/main/performance.cpp +++ b/main/performance.cpp @@ -30,7 +30,6 @@ #include "performance.h" -#include "core/object/message_queue.h" #include "core/os/os.h" #include "core/variant/typed_array.h" #include "scene/main/node.h" diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj index 27bc2844d5..bd2560c280 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj @@ -254,7 +254,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = $min_version; "LD_CLASSIC_1000" = ""; "LD_CLASSIC_1100" = ""; "LD_CLASSIC_1200" = ""; @@ -299,7 +299,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = $min_version; "LD_CLASSIC_1000" = ""; "LD_CLASSIC_1100" = ""; "LD_CLASSIC_1200" = ""; @@ -318,7 +318,6 @@ buildSettings = { ARCHS = "$godot_archs"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - $pbx_launch_image_usage_setting CODE_SIGN_ENTITLEMENTS = "$binary/$binary.entitlements"; CODE_SIGN_IDENTITY = "$code_sign_identity_debug"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_debug"; @@ -326,7 +325,7 @@ CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"; DEVELOPMENT_TEAM = $team_id; INFOPLIST_FILE = "$binary/$binary-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = $min_version; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -354,7 +353,6 @@ buildSettings = { ARCHS = "$godot_archs"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - $pbx_launch_image_usage_setting CODE_SIGN_ENTITLEMENTS = "$binary/$binary.entitlements"; CODE_SIGN_IDENTITY = "$code_sign_identity_release"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_release"; @@ -362,7 +360,7 @@ CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"; DEVELOPMENT_TEAM = $team_id; INFOPLIST_FILE = "$binary/$binary-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = $min_version; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Contents.json b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Contents.json deleted file mode 100644 index f3ac82189f..0000000000 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Contents.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "images" : [ - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "2436h", - "filename" : "Default-Portrait-X.png", - "minimum-system-version" : "11.0", - "orientation" : "portrait", - "scale" : "3x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "2436h", - "filename" : "Default-Landscape-X.png", - "minimum-system-version" : "11.0", - "orientation" : "landscape", - "scale" : "3x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "736h", - "filename" : "Default-Portrait-736h@3x.png", - "minimum-system-version" : "8.0", - "orientation" : "portrait", - "scale" : "3x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "736h", - "filename" : "Default-Landscape-736h@3x.png", - "minimum-system-version" : "8.0", - "orientation" : "landscape", - "scale" : "3x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "667h", - "filename" : "Default-667h@2x.png", - "minimum-system-version" : "8.0", - "orientation" : "portrait", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "iphone", - "filename" : "Default-480h@2x.png", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "retina4", - "filename" : "Default-568h@2x.png", - "minimum-system-version" : "7.0", - "orientation" : "portrait", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "filename" : "Default-Portrait.png", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "1x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "filename" : "Default-Landscape.png", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "1x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "filename" : "Default-Portrait@2x.png", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "filename" : "Default-Landscape@2x.png", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-480h@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-480h@2x.png Binary files differdeleted file mode 100644 index 7c9cac3f0e..0000000000 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-480h@2x.png +++ /dev/null diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png Binary files differdeleted file mode 100644 index 0226bdf7cd..0000000000 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png +++ /dev/null diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-667h@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-667h@2x.png Binary files differdeleted file mode 100644 index 25904c186c..0000000000 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-667h@2x.png +++ /dev/null diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-736h@3x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-736h@3x.png Binary files differdeleted file mode 100644 index 649df071f9..0000000000 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-736h@3x.png +++ /dev/null diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-X.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-X.png Binary files differdeleted file mode 100644 index f3bd86a7de..0000000000 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-X.png +++ /dev/null diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape.png Binary files differdeleted file mode 100644 index d5692eaffa..0000000000 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape.png +++ /dev/null diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png Binary files differdeleted file mode 100644 index 8c4fe87b9c..0000000000 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png +++ /dev/null diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-736h@3x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-736h@3x.png Binary files differdeleted file mode 100644 index e755beb803..0000000000 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-736h@3x.png +++ /dev/null diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-X.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-X.png Binary files differdeleted file mode 100644 index f676fda263..0000000000 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-X.png +++ /dev/null diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait.png Binary files differdeleted file mode 100644 index 43da4f3ed6..0000000000 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait.png +++ /dev/null diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png Binary files differdeleted file mode 100644 index 075a6790ce..0000000000 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png +++ /dev/null diff --git a/misc/dist/macos_template.app/Contents/Info.plist b/misc/dist/macos_template.app/Contents/Info.plist index 40966d2ced..78bb559c0e 100644 --- a/misc/dist/macos_template.app/Contents/Info.plist +++ b/misc/dist/macos_template.app/Contents/Info.plist @@ -58,5 +58,6 @@ $usage_descriptions </dict> <key>NSHighResolutionCapable</key> $highres +$additional_plist_content </dict> </plist> diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected index 8a31d0fbc8..2c52144896 100644 --- a/misc/extension_api_validation/4.2-stable.expected +++ b/misc/extension_api_validation/4.2-stable.expected @@ -14,3 +14,40 @@ Validate extension JSON: Error: Field 'classes/TileData/methods/get_navigation_p Validate extension JSON: Error: Field 'classes/TileData/methods/get_occluder/arguments': size changed value in new API, from 1 to 4. Added optional argument to get_navigation_polygon and get_occluder to specify a polygon transform. + + +GH-85393 +-------- +Validate extension JSON: Error: Field 'classes/PhysicsShapeQueryParameters3D/properties/motion': type changed value in new API, from "Vector2" to "Vector3". + +The type was registered wrongly, this was a bug. + + +GH-86687 +-------- +Validate extension JSON: Error: Field 'classes/AnimationMixer/methods/_post_process_key_value/arguments/3': type changed value in new API, from "Object" to "int". + +Exposing the pointer was dangerous and it must be changed to avoid crash. Compatibility methods registered. + + +GH-84976 +-------- +Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/FinalAction/values/FINAL_ACTION_CONTINUE': value changed value in new API, from 2.0 to 0. +Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/FinalAction/values/FINAL_ACTION_MAX': value changed value in new API, from 3.0 to 2. +Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/InitialAction/values/INITIAL_ACTION_CLEAR': value changed value in new API, from 0.0 to 1. +Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/InitialAction/values/INITIAL_ACTION_CLEAR_REGION_CONTINUE': value changed value in new API, from 2.0 to 1. +Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/InitialAction/values/INITIAL_ACTION_CONTINUE': value changed value in new API, from 5.0 to 0. +Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/InitialAction/values/INITIAL_ACTION_DROP': value changed value in new API, from 4.0 to 2. +Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/InitialAction/values/INITIAL_ACTION_KEEP': value changed value in new API, from 3.0 to 0. +Validate extension JSON: Error: Field 'classes/RenderingDevice/enums/InitialAction/values/INITIAL_ACTION_MAX': value changed value in new API, from 6.0 to 3. +Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/buffer_clear/arguments': size changed value in new API, from 4 to 3. +Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/buffer_update/arguments': size changed value in new API, from 5 to 4. +Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/draw_list_begin/arguments': size changed value in new API, from 10 to 9. +Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/texture_clear/arguments': size changed value in new API, from 7 to 6. +Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/texture_copy/arguments': size changed value in new API, from 10 to 9. +Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/texture_resolve_multisample/arguments': size changed value in new API, from 3 to 2. +Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/texture_update/arguments': size changed value in new API, from 4 to 3. + +Barrier arguments have been removed from all relevant functions as they're no longer required. +Draw and compute list overlap no longer needs to be specified. +Initial and final actions have been simplified into fewer options. diff --git a/misc/hooks/README.md b/misc/hooks/README.md index 0aaeff8ae3..573f8fe350 100644 --- a/misc/hooks/README.md +++ b/misc/hooks/README.md @@ -29,7 +29,7 @@ so they should work out of the box on Linux/macOS. ##### clang-format - Download LLVM for Windows (version 13 or later) from - <https://releases.llvm.org/download.html> + <https://github.com/llvm/llvm-project/releases> - Make sure LLVM is added to the `PATH` during installation ##### black diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format index fd0213c175..e5cf0c4aa2 100755 --- a/misc/hooks/pre-commit-clang-format +++ b/misc/hooks/pre-commit-clang-format @@ -80,7 +80,7 @@ fi # To get consistent formatting, we recommend contributors to use the same # clang-format version as CI. RECOMMENDED_CLANG_FORMAT_MAJOR_MIN="13" -RECOMMENDED_CLANG_FORMAT_MAJOR_MAX="15" +RECOMMENDED_CLANG_FORMAT_MAJOR_MAX="16" if [ ! -x "$CLANG_FORMAT" ] ; then message="Error: clang-format executable not found. Please install clang-format $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX." diff --git a/modules/SCsub b/modules/SCsub index fcc01e2c1b..7c9946170f 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -7,6 +7,9 @@ Import("env") env_modules = env.Clone() +# Allow modules to detect if they are being built as a module. +env_modules.Append(CPPDEFINES=["GODOT_MODULE"]) + Export("env_modules") # Header with MODULE_*_ENABLED defines. diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp index 7c0bc4ac82..f538fc6676 100644 --- a/modules/basis_universal/register_types.cpp +++ b/modules/basis_universal/register_types.cpp @@ -221,7 +221,7 @@ static Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size imgfmt = Image::FORMAT_DXT5_RA_AS_RG; } else if (RS::get_singleton()->has_os_feature("etc2")) { format = basist::transcoder_texture_format::cTFETC2; // get this from renderer - imgfmt = Image::FORMAT_ETC2_RGBA8; + imgfmt = Image::FORMAT_ETC2_RA_AS_RG; } else { //opengl most likely, bad for normal maps, nothing to do about this. format = basist::transcoder_texture_format::cTFRGBA32; diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 6082b468f7..1de76c60b5 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -150,13 +150,13 @@ float CSGShape3D::get_snap() const { void CSGShape3D::_make_dirty(bool p_parent_removing) { if ((p_parent_removing || is_root_shape()) && !dirty) { - call_deferred(SNAME("_update_shape")); // Must be deferred; otherwise, is_root_shape() will use the previous parent + callable_mp(this, &CSGShape3D::_update_shape).call_deferred(); // Must be deferred; otherwise, is_root_shape() will use the previous parent. } if (!is_root_shape()) { parent_shape->_make_dirty(); } else if (!dirty) { - call_deferred(SNAME("_update_shape")); + callable_mp(this, &CSGShape3D::_update_shape).call_deferred(); } dirty = true; diff --git a/modules/gdscript/README.md b/modules/gdscript/README.md new file mode 100644 index 0000000000..30685e672c --- /dev/null +++ b/modules/gdscript/README.md @@ -0,0 +1,139 @@ +# Basic GDScript module architecture +This provides some basic information in how GDScript is implemented and integrates with the rest of the engine. You can learn more about GDScript in the [documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/index.html). It describes the syntax and user facing systems and concepts, and can be used as a reference for what user expectations are. + + +## General design + +GDScript is: + +1. A [gradually typed](https://en.wikipedia.org/wiki/Gradual_typing) language. Type hints are optional and help with static analysis and performance. However, typed code must easily interoperate with untyped code. +2. A tightly designed language. Features are added because they are _needed_, and not because they can be added or are interesting to develop. +3. Primarily an interpreted scripting language: it is compiled to GDScript byte code and interpreted in a GDScript virtual machine. It is meant to be easy to use and develop gameplay in. It is not meant for CPU-intensive algorithms or data processing, and is not optimized for it. For that, [C#](https://docs.godotengine.org/en/stable/tutorials/scripting/c_sharp/c_sharp_basics.html) or [GDExtension](https://docs.godotengine.org/en/stable/tutorials/scripting/gdextension/what_is_gdextension.html) may be used. + + +## Integration into Godot + +GDScript is integrated into Godot as a module. Since modules are optional, this means that Godot may be built without GDScript and work perfectly fine without it! + +The GDScript module interfaces with Godot's codebase by inheriting from the engine's scripting-related classes. New languages inherit from [`ScriptLanguage`](/core/object/script_language.h), and are registered in Godot's [`ScriptServer`](/core/object/script_language.h). Scripts, referring to a file containing code, are represented in the engine by the `Script` class. Instances of that script, which are used at runtime when actually executing the code, inherit from [`ScriptInstance`](/core/object/script_instance.h). + +To access Godot's internal classes, GDScript uses [`ClassDB`](/core/object/class_db.h). `ClassDB` is where Godot registers classes, methods and properties that it wants exposed to its scripting system. This is how GDScript understands that `Node2D` is a class it can use, and that it has a `get_parent()` method. + +[Built-in GDScript methods](https://docs.godotengine.org/en/latest/classes/class_@gdscript.html#methods) are defined and exported by [`GDScriptUtilityFunctions`](gdscript_utility_functions.h), whereas [global scope methods](https://docs.godotengine.org/en/latest/classes/class_%2540globalscope.html) are registered in [`Variant::_register_variant_utility_functions()`](/core/variant/variant_utility.cpp). + + +## Compilation + +Scripts can be at different stages of compilation. The process isn't entirely linear, but consists of this general order: tokenizing, parsing, analyzing, and finally compiling. This process is the same for scripts in the editor and scripts in an exported game. Scripts are stored as text files in both cases, and the compilation process must happen in full before the bytecode can be passed to the virtual machine and run. + +The main class of the GDScript module is the [`GDScript`](gdscript.h) class, which represents a class defined in GDScript. Each `.gd` file is called a _class file_ because it implicitly defines a class in GDScript, and thus results in an associated `GDScript` object. However, GDScript classes may define [_inner classes_](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html#inner-classes), and those are also represented by further `GDScript` objects, even though they are not in files of their own. + +The `GDScript` class contains all the information related to the corresponding GDScript class: its name and path, its members like variables, functions, symbols, signals, implicit methods like initializers, etc. This is the main class that the compilation step deals with. + +A secondary class is `GDScriptInstance`, defined in the same file, containing _runtime_ information for an instance of a `GDScript`, and is more related to the execution of a script by the virtual machine. + + +### Loading source code + +This mostly happens by calling `GDScript::load_source_code()` on a `GDScript` object. Parsing only requires a `String`, so it is entirely possible to parse a script without a `GDScript` object! + + +### Tokenizing (see [`GDScriptTokenizer`](gdscript_tokenizer.h)) + +Tokenizing is the process of converting the source code `String` into a sequence of tokens, which represent language constructs (such as `for` or `if`), identifiers, literals, etc. This happens almost exclusively during the parsing process, which asks for the next token in order to make sense of the source code. The tokenizer is only used outside of the parsing process in very rare exceptions. + + +### Parsing (see [`GDScriptParser`](gdscript_parser.h)) + +The parser takes a sequence of tokens and builds [the abstract syntax tree (AST)](https://en.wikipedia.org/wiki/Abstract_syntax_tree) of the GDScript program. The AST is used in the analyzing and compilation steps, and the source code `String` and sequence of tokens are discarded. The AST-building process finds syntax errors in a GDScript program and reports them to the user. + +The parser class also defines all the possible nodes of the AST as subtypes of `GDScriptParser::Node`, not to be confused with Godot's scene tree `Node`. For example, `GDScriptParser::IfNode` has two children nodes, one for the code in the `if` block, and one for the code in the `else` block. A `GDScriptParser::FunctionNode` contains children nodes for its name, parameters, return type, body, etc. The parser also defines typechecking data structures like `GDScriptParser::Datatype`. + +The parser was [intentionally designed](https://godotengine.org/article/gdscript-progress-report-writing-new-parser/#less-lookahead) with a look-ahead of a single token. This means that the parser only has access to the current token and the previous token (or, if you prefer, the current token and the next token). This parsing limitation ensures that GDScript will remain syntactically simple and accessible, and that the parsing process cannot become overly complex. + + +### Analysis and typechecking (see [`GDScriptAnalyzer`](gdscript_analyzer.h)) + +The analyzer takes in the AST of a program and verifies that "everything checks out". For example, when analyzing a method call with three parameters, it will check whether the function definition also contains three parameters. If the code is typed, it will check that argument and parameter types are compatible. + +There are two types of functions in the analyzer: `reduce` functions and `resolve` functions. Their parameters always include the AST node that they are attempting to reduce or resolve. +- The `reduce` functions work on GDScript expressions, which return values, and thus their main goal is to populate the `GDScriptParser::Datatype` of the underlying AST node. The datatype is then used to typecheck code that depends on this expression, and gives the compiler necessary information to generate appropriate, safe, and optimized bytecode. +For example, function calls are handled with `reduce_call()`, which must figure out what function is being called and check that the passed arguments match the function's parameters. The type of the underlying `CallNode` will be the return type of the function. +Another example is `reduce_identifier()`, which does _a lot_ of work: given the string of its `IdentifierNode`, it must figure out what that identifier refers to. It could be a local variable, class name, global or class function, function parameter, class or superclass member, or any number of other things. It has to check many different places to find this information! +A secondary goal of the `reduce` functions is to perform [constant folding](https://en.wikipedia.org/wiki/Constant_folding): to determine whether an expression is constant, and if it is, compute its _reduced value_ at this time so it does not need to be computed over and over at runtime! +- The resolve functions work on AST nodes that represent statements, and don't necessarily have values. Their goal is to do work related to program control flow, resolve their child AST nodes, deal with scoping, etc. One of the simplest examples is `resolve_if()`, which reduces the `if` condition, then resolves the `if` body and `else` body if it exists. +The `resolve_for()` function does more work than simply resolving its code block. With `for i in range(10)`, for example, it must also declare and type the new variable `i` within the scope of its code block, as well as make sure `range(10)` is iterable, among other things. +To understand classes and inheritance without introducing cyclic dependency problems that would come from immediate full class code analysis, the analyzer often asks only for class _interfaces_: it needs to know what member variables and methods exist as well as their types, but no more. +This is done through `resolve_class_interface()`, which populates `ClassNode`'s `Datatype` with that information. It first checks for superclass information with `resolve_class_inheritance()`, then populates its member information by calling `resolve_class_member()` on each member. Since this step is only about the class _interface_, methods are resolved with `resolve_function_signature()`, which gets all relevant typing information without resolving the function body! +The remaining steps of resolution, including member variable initialization code, method code, etc, can happen at a later time. + +In fully untyped code, very little static analysis is possible. For example, the analyzer cannot know whether `my_var.some_member` exists when it does not know the type of `my_var`. Therefore, it cannot emit a warning or error because `some_member` _could_ exist - or it could not. The analyzer must trust the programmer. If an error does occur, it will be at runtime. +However, GDScript is gradually typed, so all of these analyses must work when parts of the code are typed and others untyped. Static analysis in a gradually typed language is a best-effort situation: suppose there is a typed variable `var x : int`, and an untyped `var y = "some string"`. We can obviously tell this isn't going to work, but the analyzer will accept the assignment `x = y` without warnings or errors: it only knows that `y` is untyped and can therefore be anything, including the `int` that `x` expects. It must once again trust the programmer to have written code that works. In this instance, the code will error at runtime. +In both these cases, the analyzer handles the uncertainty of untyped code by calling `mark_node_unsafe()` on the respective AST node. This means it didn't have enough information to know whether the code was fully safe or necessarily wrong. Lines with unsafe AST nodes are represented by grey line numbers in the GDScript editor. Green line numbers indicate a line of code without any unsafe nodes. + +This analysis step is also where dependencies are introduced and that information stored for use later. If class `A` extends class `B` or contains a member with type `B` from some other script file, then the analyzer will attempt to load that second script. If `B` contains references to `A`, then a _cyclic_ dependency is introduced. This is OK in many cases, but impossible to resolve in others. + +Clearly, the analyzer is where a lot of the "magic" happens! It determines what constitutes proper code that can actually be compiled, and provides as many safety guarantees as possible with the typing information it is provided with. The more typed the code, the safer and more optimized it will be! + + +#### Cyclic dependencies and member resolution + +Cyclic dependencies from inheritance (`A extends B, B extends A`) are not supported in any programming language. Other cyclic dependencies are supported, such as `A extends B` and `B` uses, contains, or preloads, members of type `A`. + +To see why cyclic dependencies are complicated, suppose there is one between classes `A <-> B`. Partially through the analysis of `A`, we will need information about `B`, and therefore trigger its analysis. However, the analysis of `B` will eventually need information from `A`, which is incomplete because we never finished analyzing it. This would result in members not being found when they actually exist! + +GDScript supports cyclic dependencies due to a few features of the analyzer: + +1. Class interface resolution: when analyzing code of class `A` that depends on some other class `B`, we don't need to resolve the _code_ of `B` (its member initializers, function code, etc). We only need to know what members and methods the class has, as well as their types. These are the only things one class can use to work with, or _interface_ with, another. Because of inheritance, a class's interface depends on its superclass as well, so recursive interface resolution is needed. More details can be found in `GDScriptAnalyzer::resolve_class_interface()`. +2. Out of order member resolution: the analyzer may not even need an entire class interface to be resolved in order to figure out a specific type! For example, if class `A` contains code that references `B.is_alive`, then the analyzer doesn't need to immediately resolve `B`'s entire interface. It may simply check whether `is_alive` exists in `B`, and reduce it for its type information, on-demand. +A fundamental cyclic dependency problem occurs when the types of two different member variables are mutually dependent. This is commonly checked by a pattern that declares a temporary datatype with `GDScriptParser::DataType resolving_datatype;`, followed by `resolving_datatype.kind = GDScriptParser::DataType::RESOLVING;`. If the analyzer attempts to resolve a member on-demand that is already tagged as resolving, then a cyclic dependency problem has been found and can be reported. + + +### Compiling (see [`GDScriptCompiler`](gdscript_compiler.h)) + +Compiling is the final step in making a GDScript executable in the [virtual machine](gdscript_vm.h) (VM). The compiler takes a `GDScript` object and an AST, and uses another class, [`GDScriptByteCodeGenerator`](gdscript_byte_codegen.h), to generate bytecode corresponding to the class. In doing this, it creates the objects that the VM understands how to run, like [`GDScriptFunction`](gdscript_function.h), and completes a few extra tasks needed for compilation, such as populating runtime class member information. + +Importantly, the compilation process of a class, specifically the `GDScriptCompiler::_compile_class()` method, _cannot_ depend on information obtained by calling `GDScriptCompiler::_compile_class()` on another class, for the same cyclic dependency reasons explained in the previous section. +Any information that can only be obtained or populated during the compilation step, when `GDScript` objects become available, must be handled before `GDScriptCompiler::_compile_class()` is called. This process is centralized in `GDScriptCompiler::_prepare_compilation()` which works as the compile-time equivalent of `GDScriptAnalyzer::resolve_class_interface()`: it populates a `GDScript`'s "interface" exclusively with information from the analysis step, and without processing other external classes. This information may then be referenced by other classes without introducing problematic cycles. + +The more typing information a GDScript has, the more optimized the compiled bytecode can be. For example, if `my_var` is untyped, the bytecode for `my_var.some_member` will need to go through several layers of indirection to figure out the type of `my_var` at runtime, and from there determine how to obtain `some_member`. This varies depending on whether `my_var` is a dictionary, a script, or a native class. If the type of `my_var` was known at compile time, the bytecode can directly call the type-specific method for obtaining a member. +Similar optimizations are possible for `my_var.some_func()`. With untyped GDScript, the VM will need to resolve `my_var`'s type at runtime, then, depending on the type, use different methods to resolve the function and call it. When the function is fully resolved during static analysis, native function pointers or GDScript function objects can be compiled into the bytecode and directly called by the VM, removing several layers of indirection. + +Typed code is safer code and faster code! + + +## Loading scripts + +GDScripts can be loaded in a couple of different ways. The main method, used almost everywhere in the engine, is to load scripts through the `ResourceLoader` singleton. In this way, GDScripts are resources like any others: `ResourceLoader::load()` will simply reroute to `ResourceFormatLoaderGDScript::load()`, found in `gdscript.h/cpp`(gdscript.h). This generates a GDScript object which is compiled and ready to use. + +The other method is to manually load the source code, then pass it to a parser, then to an analyzer and then to a compiler. The previous approach does this behind the scenes, alongside some smart caching of scripts and other functionalities. It is used in the [GDScript test runner infrastructure](tests/gdscript_test_runner.h). + + +### Full and shallow scripts + +The `ResourceFormatLoaderGDScript::load()` method simply calls `GDScriptCache::get_full_script()`. The [`GDScriptCache`](gdscript_cache.h) is, as it sounds, a cache for GDScripts. Its two main methods, `get_shallow_script()` and `get_full_script()`, get and cache, respectively, scripts that have been merely parsed, and scripts which have been statically analyzed and fully compiled. Another internal class, `GDScriptParserRef`, found in the same file, provides even more granularity over the different steps of the parsing process, and is used extensively in the analyzer. + +Shallow, or "just parsed" scripts, provide information such as defined classes, class members, and so forth. This is sufficient for many purposes, like obtaining a class interface or checking whether a member exists on a specific class. Full scripts, on the other hand, have been analyzed and compiled and are ready to use. + +The distinction between full and shallow scripts is very important, as shallow scripts cannot create cyclic dependency problems, whereas full scripts can. The analyzer, for example, never asks for full scripts. Choosing when to request a shallow vs a full script is an important but subtle decision. + +In practice, full scripts are simply scripts where `GDScript::reload()` has been called. This critical function is the primary way in which scripts get compiled in Godot, and essentially does all the compilation steps covered so far in order. Whenever a script is loaded, or updated and reloaded in Godot, it will end up going through `GDScript::reload()`, except in very rare circumstances like the test runner. It is an excellent place to start reading and understanding the GDScript module! + + +## Special types of scripts + +Certain types of GDScripts behave slightly differently. For example, autoloads are loaded with `ResourceLoader::load()` during `Main::start()`, very soon after Godot is launched. Many systems aren't initialized at that time, so error reporting is often significantly reduced and may not even show up in the editor. + +Tool scripts, declared with the `@tool` annotation on a GDScript file, run in the editor itself as opposed to just when the game is launched. This leads to a significant increase in complexity, as many things that can be changed in the editor may affect a currently executing tool script. + + +## Other + +There are many other classes in the GDScript module. Here is a brief overview of some of them: + +- Declaration of GDScript warnings in [`GDScriptWarning`](gdscript_warning.h). +- [`GDScriptFunction`](gdscript_function.h), which represents an executable GDScript function. The relevant file contains both static as well as runtime information. +- The [virtual machine](gdscript_vm.cpp) is essentially defined as calling `GDScriptFunction::call()`. +- Editor-related functions can be found in parts of `GDScriptLanguage`, originally declared in [`gdscript.h`](gdscript.h) but defined in [`gdscript_editor.cpp`](gdscript_editor.cpp). Code highlighting can be found in [`GDScriptSyntaxHighlighter`](editor/gdscript_highlighter.h). +- GDScript decompilation is found in [`gdscript_disassembler.cpp`](gdscript_disassembler.h), defined as `GDScriptFunction::disassemble()`. +- Documentation generation from GDScript comments in [`GDScriptDocGen`](editor/gdscript_docgen.h)
\ No newline at end of file diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index fcb7a11a14..933bfba5ba 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -148,7 +148,7 @@ <return type="int" /> <param index="0" name="var" type="Variant" /> <description> - Returns the length of the given Variant [param var]. The length can be the character count of a [String], the element count of any array type or the size of a [Dictionary]. For every other Variant type, a run-time error is generated and execution is stopped. + Returns the length of the given Variant [param var]. The length can be the character count of a [String] or [StringName], the element count of any array type, or the size of a [Dictionary]. For every other Variant type, a run-time error is generated and execution is stopped. [codeblock] a = [1, 2, 3, 4] len(a) # Returns 4 diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index a999acd1bd..1f0830aa17 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1381,51 +1381,43 @@ String GDScript::debug_get_script_name(const Ref<Script> &p_script) { } #endif -GDScript::UpdatableFuncPtr GDScript::func_ptrs_to_update_main_thread; -thread_local GDScript::UpdatableFuncPtr *GDScript::func_ptrs_to_update_thread_local = nullptr; - -GDScript::UpdatableFuncPtrElement GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) { - UpdatableFuncPtrElement result = {}; - - { - MutexLock lock(func_ptrs_to_update_thread_local->mutex); - result.element = func_ptrs_to_update_thread_local->ptrs.push_back(p_func_ptr_ptr); - result.func_ptr = func_ptrs_to_update_thread_local; - - if (likely(func_ptrs_to_update_thread_local->initialized)) { - return result; - } - - func_ptrs_to_update_thread_local->initialized = true; +GDScript::UpdatableFuncPtr::UpdatableFuncPtr(GDScriptFunction *p_function) { + if (p_function == nullptr) { + return; } - MutexLock lock(func_ptrs_to_update_mutex); - func_ptrs_to_update.push_back(func_ptrs_to_update_thread_local); - func_ptrs_to_update_thread_local->rc++; - - return result; -} + ptr = p_function; + script = ptr->get_script(); + ERR_FAIL_NULL(script); -void GDScript::_remove_func_ptr_to_update(const UpdatableFuncPtrElement &p_func_ptr_element) { - ERR_FAIL_NULL(p_func_ptr_element.element); - ERR_FAIL_NULL(p_func_ptr_element.func_ptr); - MutexLock lock(p_func_ptr_element.func_ptr->mutex); - p_func_ptr_element.element->erase(); + MutexLock script_lock(script->func_ptrs_to_update_mutex); + list_element = script->func_ptrs_to_update.push_back(this); } -void GDScript::_fixup_thread_function_bookkeeping() { - // Transfer the ownership of these update items to the main thread, - // because the current one is dying, leaving theirs orphan, dangling. +GDScript::UpdatableFuncPtr::~UpdatableFuncPtr() { + ERR_FAIL_NULL(script); - DEV_ASSERT(!Thread::is_main_thread()); + if (list_element) { + MutexLock script_lock(script->func_ptrs_to_update_mutex); + list_element->erase(); + list_element = nullptr; + } +} - MutexLock lock(func_ptrs_to_update_main_thread.mutex); - MutexLock lock2(func_ptrs_to_update_thread_local->mutex); +void GDScript::_recurse_replace_function_ptrs(const HashMap<GDScriptFunction *, GDScriptFunction *> &p_replacements) const { + MutexLock lock(func_ptrs_to_update_mutex); + for (UpdatableFuncPtr *updatable : func_ptrs_to_update) { + HashMap<GDScriptFunction *, GDScriptFunction *>::ConstIterator replacement = p_replacements.find(updatable->ptr); + if (replacement) { + updatable->ptr = replacement->value; + } else { + // Probably a lambda from another reload, ignore. + updatable->ptr = nullptr; + } + } - while (!func_ptrs_to_update_thread_local->ptrs.is_empty()) { - List<GDScriptFunction **>::Element *E = func_ptrs_to_update_thread_local->ptrs.front(); - E->transfer_to_back(&func_ptrs_to_update_main_thread.ptrs); - func_ptrs_to_update_thread_local->transferred = true; + for (HashMap<StringName, Ref<GDScript>>::ConstIterator subscript = subclasses.begin(); subscript; ++subscript) { + subscript->value->_recurse_replace_function_ptrs(p_replacements); } } @@ -1447,30 +1439,9 @@ void GDScript::clear(ClearData *p_clear_data) { } { - MutexLock outer_lock(func_ptrs_to_update_mutex); + MutexLock lock(func_ptrs_to_update_mutex); for (UpdatableFuncPtr *updatable : func_ptrs_to_update) { - bool destroy = false; - { - MutexLock inner_lock(updatable->mutex); - if (updatable->transferred) { - func_ptrs_to_update_main_thread.mutex.lock(); - } - for (GDScriptFunction **func_ptr_ptr : updatable->ptrs) { - *func_ptr_ptr = nullptr; - } - DEV_ASSERT(updatable->rc != 0); - updatable->rc--; - if (updatable->rc == 0) { - destroy = true; - } - if (updatable->transferred) { - func_ptrs_to_update_main_thread.mutex.unlock(); - } - } - if (destroy) { - DEV_ASSERT(updatable != &func_ptrs_to_update_main_thread); - memdelete(updatable); - } + updatable->ptr = nullptr; } } @@ -1543,6 +1514,13 @@ GDScript::~GDScript() { } destructing = true; + if (is_print_verbose_enabled()) { + MutexLock lock(func_ptrs_to_update_mutex); + if (!func_ptrs_to_update.is_empty()) { + print_line(vformat("GDScript: %d orphaned lambdas becoming invalid at destruction of script '%s'.", func_ptrs_to_update.size(), fully_qualified_name)); + } + } + clear(); { @@ -2091,33 +2069,6 @@ void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) { named_globals.erase(p_name); } -void GDScriptLanguage::thread_enter() { - GDScript::func_ptrs_to_update_thread_local = memnew(GDScript::UpdatableFuncPtr); -} - -void GDScriptLanguage::thread_exit() { - // This thread may have been created before GDScript was up - // (which also means it can't have run any GDScript code at all). - if (!GDScript::func_ptrs_to_update_thread_local) { - return; - } - - GDScript::_fixup_thread_function_bookkeeping(); - - bool destroy = false; - { - MutexLock lock(GDScript::func_ptrs_to_update_thread_local->mutex); - DEV_ASSERT(GDScript::func_ptrs_to_update_thread_local->rc != 0); - GDScript::func_ptrs_to_update_thread_local->rc--; - if (GDScript::func_ptrs_to_update_thread_local->rc == 0) { - destroy = true; - } - } - if (destroy) { - memdelete(GDScript::func_ptrs_to_update_thread_local); - } -} - void GDScriptLanguage::init() { //populate global constants int gcc = CoreConstants::get_global_constant_count(); @@ -2150,8 +2101,6 @@ void GDScriptLanguage::init() { _add_global(E.name, E.ptr); } - GDScript::func_ptrs_to_update_thread_local = &GDScript::func_ptrs_to_update_main_thread; - #ifdef TESTS_ENABLED GDScriptTests::GDScriptTestRunner::handle_cmdline(); #endif @@ -2201,8 +2150,6 @@ void GDScriptLanguage::finish() { } script_list.clear(); function_list.clear(); - - DEV_ASSERT(GDScript::func_ptrs_to_update_main_thread.rc == 1); } void GDScriptLanguage::profiling_start() { diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 31811bba47..7b0e2136ed 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -117,29 +117,28 @@ class GDScript : public Script { HashMap<GDScriptFunction *, LambdaInfo> lambda_info; - // List is used here because a ptr to elements are stored, so the memory locations need to be stable - struct UpdatableFuncPtr { - List<GDScriptFunction **> ptrs; - Mutex mutex; - bool initialized : 1; - bool transferred : 1; - uint32_t rc = 1; - UpdatableFuncPtr() : - initialized(false), transferred(false) {} - }; - struct UpdatableFuncPtrElement { - List<GDScriptFunction **>::Element *element = nullptr; - UpdatableFuncPtr *func_ptr = nullptr; +public: + class UpdatableFuncPtr { + friend class GDScript; + + GDScriptFunction *ptr = nullptr; + GDScript *script = nullptr; + List<UpdatableFuncPtr *>::Element *list_element = nullptr; + + public: + GDScriptFunction *operator->() const { return ptr; } + operator GDScriptFunction *() const { return ptr; } + + UpdatableFuncPtr(GDScriptFunction *p_function); + ~UpdatableFuncPtr(); }; - static UpdatableFuncPtr func_ptrs_to_update_main_thread; - static thread_local UpdatableFuncPtr *func_ptrs_to_update_thread_local; + +private: + // List is used here because a ptr to elements are stored, so the memory locations need to be stable List<UpdatableFuncPtr *> func_ptrs_to_update; Mutex func_ptrs_to_update_mutex; - UpdatableFuncPtrElement _add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr); - static void _remove_func_ptr_to_update(const UpdatableFuncPtrElement &p_func_ptr_element); - - static void _fixup_thread_function_bookkeeping(); + void _recurse_replace_function_ptrs(const HashMap<GDScriptFunction *, GDScriptFunction *> &p_replacements) const; #ifdef TOOLS_ENABLED // For static data storage during hot-reloading. @@ -541,7 +540,7 @@ public: virtual void get_string_delimiters(List<String> *p_delimiters) const override; virtual bool is_using_templates() override; virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override; - virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override; + virtual Vector<ScriptTemplate> get_built_in_templates(const StringName &p_object) override; virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override; virtual Script *create_script() const override; #ifndef DISABLE_DEPRECATED @@ -562,11 +561,6 @@ public: virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value) override; virtual void remove_named_global_constant(const StringName &p_name) override; - /* MULTITHREAD FUNCTIONS */ - - virtual void thread_enter() override; - virtual void thread_exit() override; - /* DEBUGGER FUNCTIONS */ virtual String debug_get_error() const override; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 5478a46bbc..3fd5b3f519 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -845,7 +845,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type return result; } -void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, StringName p_name, const GDScriptParser::Node *p_source) { +void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, const StringName &p_name, const GDScriptParser::Node *p_source) { ERR_FAIL_COND(!p_class->has_member(p_name)); resolve_class_member(p_class, p_class->members_indices[p_name], p_source); } @@ -3636,7 +3636,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod switch (base.builtin_type) { case Variant::NIL: { if (base.is_hard_type()) { - push_error(vformat(R"(Invalid get index "%s" on base Nil)", name), p_identifier); + push_error(vformat(R"(Cannot get property "%s" on a null object.)", name), p_identifier); } return; } @@ -3658,6 +3658,10 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod return; } } + if (Variant::has_builtin_method(base.builtin_type, name)) { + p_identifier->set_datatype(make_callable_type(Variant::get_builtin_method_info(base.builtin_type, name))); + return; + } if (base.is_hard_type()) { #ifdef SUGGEST_GODOT4_RENAMES String rename_hint = String(); diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index ec155706df..4ed476a3df 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -62,7 +62,7 @@ class GDScriptAnalyzer { void decide_suite_type(GDScriptParser::Node *p_suite, GDScriptParser::Node *p_statement); void resolve_annotation(GDScriptParser::AnnotationNode *p_annotation); - void resolve_class_member(GDScriptParser::ClassNode *p_class, StringName p_name, const GDScriptParser::Node *p_source = nullptr); + void resolve_class_member(GDScriptParser::ClassNode *p_class, const StringName &p_name, const GDScriptParser::Node *p_source = nullptr); void resolve_class_member(GDScriptParser::ClassNode *p_class, int p_index, const GDScriptParser::Node *p_source = nullptr); void resolve_class_interface(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source = nullptr); void resolve_class_interface(GDScriptParser::ClassNode *p_class, bool p_recursive); diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 9560f670e6..f6633f8bf6 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -322,9 +322,13 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) { // Get like it was a property. GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here. - GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF); - gen->write_get_named(temp, identifier, self); + GDScriptCodeGenerator::Address base(GDScriptCodeGenerator::Address::SELF); + if (member.type == GDScriptParser::ClassNode::Member::FUNCTION && member.function->is_static) { + base = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS); + } + + gen->write_get_named(temp, identifier, base); return temp; } } @@ -1371,7 +1375,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code return GDScriptCodeGenerator::Address(); } - main_script->lambda_info.insert(function, { lambda->captures.size(), lambda->use_self }); + codegen.script->lambda_info.insert(function, { lambda->captures.size(), lambda->use_self }); gen->write_lambda(result, function, captures, lambda->use_self); for (int i = 0; i < captures.size(); i++) { @@ -3046,7 +3050,7 @@ GDScriptCompiler::FunctionLambdaInfo GDScriptCompiler::_get_function_replacement FunctionLambdaInfo info; info.function = p_func; info.parent = p_parent_func; - info.script = p_parent_func; + info.script = p_func->get_script(); info.name = p_func->get_name(); info.line = p_func->_initial_line; info.index = p_index; @@ -3057,10 +3061,14 @@ GDScriptCompiler::FunctionLambdaInfo GDScriptCompiler::_get_function_replacement info.default_arg_count = p_func->_default_arg_count; info.sublambdas = _get_function_lambda_replacement_info(p_func, p_depth, p_parent_func); - GDScript::LambdaInfo *extra_info = main_script->lambda_info.getptr(p_func); + ERR_FAIL_NULL_V(info.script, info); + GDScript::LambdaInfo *extra_info = info.script->lambda_info.getptr(p_func); if (extra_info != nullptr) { info.capture_count = extra_info->capture_count; info.use_self = extra_info->use_self; + } else { + info.capture_count = 0; + info.use_self = false; } return info; @@ -3195,22 +3203,7 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri HashMap<GDScriptFunction *, GDScriptFunction *> func_ptr_replacements; _get_function_ptr_replacements(func_ptr_replacements, old_lambda_info, &new_lambda_info); - - { - MutexLock outer_lock(main_script->func_ptrs_to_update_mutex); - for (GDScript::UpdatableFuncPtr *updatable : main_script->func_ptrs_to_update) { - MutexLock inner_lock(updatable->mutex); - for (GDScriptFunction **func_ptr_ptr : updatable->ptrs) { - GDScriptFunction **replacement = func_ptr_replacements.getptr(*func_ptr_ptr); - if (replacement != nullptr) { - *func_ptr_ptr = *replacement; - } else { - // Probably a lambda from another reload, ignore. - *func_ptr_ptr = nullptr; - } - } - } - } + main_script->_recurse_replace_function_ptrs(func_ptr_replacements); if (has_static_data && !root->annotated_static_unload) { GDScriptCache::add_static_script(p_script); diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index fd6b22f527..0adbe1ed8e 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -45,19 +45,19 @@ class GDScriptCompiler { GDScript *main_script = nullptr; struct FunctionLambdaInfo { - GDScriptFunction *function; - GDScriptFunction *parent; - Ref<GDScript> script; + GDScriptFunction *function = nullptr; + GDScriptFunction *parent = nullptr; + GDScript *script = nullptr; StringName name; - int line; - int index; - int depth; + int line = 0; + int index = 0; + int depth = 0; //uint64_t code_hash; //int code_size; - int capture_count; - int use_self; - int arg_count; - int default_arg_count; + int capture_count = 0; + bool use_self = false; + int arg_count = 0; + int default_arg_count = 0; //Vector<GDScriptDataType> argument_types; //GDScriptDataType return_type; Vector<FunctionLambdaInfo> sublambdas; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 87617cafab..9ad2ba1914 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -104,7 +104,7 @@ Ref<Script> GDScriptLanguage::make_template(const String &p_template, const Stri return scr; } -Vector<ScriptLanguage::ScriptTemplate> GDScriptLanguage::get_built_in_templates(StringName p_object) { +Vector<ScriptLanguage::ScriptTemplate> GDScriptLanguage::get_built_in_templates(const StringName &p_object) { Vector<ScriptLanguage::ScriptTemplate> templates; #ifdef TOOLS_ENABLED for (int i = 0; i < TEMPLATES_ARRAY_SIZE; i++) { @@ -537,7 +537,7 @@ struct GDScriptCompletionIdentifier { // appears. For example, if you are completing code in a class that inherits Node2D, a property found on Node2D // will have a "better" (lower) location "score" than a property that is found on CanvasItem. -static int _get_property_location(StringName p_class, StringName p_property) { +static int _get_property_location(const StringName &p_class, const StringName &p_property) { if (!ClassDB::has_property(p_class, p_property)) { return ScriptLanguage::LOCATION_OTHER; } @@ -552,7 +552,7 @@ static int _get_property_location(StringName p_class, StringName p_property) { return depth | ScriptLanguage::LOCATION_PARENT_MASK; } -static int _get_constant_location(StringName p_class, StringName p_constant) { +static int _get_constant_location(const StringName &p_class, const StringName &p_constant) { if (!ClassDB::has_integer_constant(p_class, p_constant)) { return ScriptLanguage::LOCATION_OTHER; } @@ -567,7 +567,7 @@ static int _get_constant_location(StringName p_class, StringName p_constant) { return depth | ScriptLanguage::LOCATION_PARENT_MASK; } -static int _get_signal_location(StringName p_class, StringName p_signal) { +static int _get_signal_location(const StringName &p_class, const StringName &p_signal) { if (!ClassDB::has_signal(p_class, p_signal)) { return ScriptLanguage::LOCATION_OTHER; } @@ -582,7 +582,7 @@ static int _get_signal_location(StringName p_class, StringName p_signal) { return depth | ScriptLanguage::LOCATION_PARENT_MASK; } -static int _get_method_location(StringName p_class, StringName p_method) { +static int _get_method_location(const StringName &p_class, const StringName &p_method) { if (!ClassDB::has_method(p_class, p_method)) { return ScriptLanguage::LOCATION_OTHER; } @@ -597,7 +597,7 @@ static int _get_method_location(StringName p_class, StringName p_method) { return depth | ScriptLanguage::LOCATION_PARENT_MASK; } -static int _get_enum_constant_location(StringName p_class, StringName p_enum_constant) { +static int _get_enum_constant_location(const StringName &p_class, const StringName &p_enum_constant) { if (!ClassDB::get_integer_constant_enum(p_class, p_enum_constant)) { return ScriptLanguage::LOCATION_OTHER; } @@ -620,9 +620,9 @@ static String _trim_parent_class(const String &p_class, const String &p_base_cla } Vector<String> names = p_class.split(".", false, 1); if (names.size() == 2) { - String first = names[0]; - String rest = names[1]; + const String &first = names[0]; if (ClassDB::class_exists(p_base_class) && ClassDB::class_exists(first) && ClassDB::is_parent_class(p_base_class, first)) { + const String &rest = names[1]; return rest; } } @@ -1210,6 +1210,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base return; } + int location = ScriptLanguage::LOCATION_OTHER; + if (!p_only_functions) { List<PropertyInfo> members; if (p_base.value.get_type() != Variant::NIL) { @@ -1223,7 +1225,11 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base continue; } if (!String(E.name).contains("/")) { - ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location); + if (base_type.kind == GDScriptParser::DataType::ENUM) { + // Sort enum members in their declaration order. + location += 1; + } if (GDScriptParser::theme_color_names.has(E.name)) { option.theme_color_name = GDScriptParser::theme_color_names[E.name]; } @@ -1239,7 +1245,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base // Enum types are static and cannot change, therefore we skip non-const dictionary methods. continue; } - ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location); if (E.arguments.size()) { option.insert_text += "("; } else { @@ -1494,11 +1500,8 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, } break; case GDScriptParser::Node::SELF: { if (p_context.current_class) { - if (p_context.type != GDScriptParser::COMPLETION_SUPER_METHOD) { - r_type.type = p_context.current_class->get_datatype(); - } else { - r_type.type = p_context.current_class->base_type; - } + r_type.type = p_context.current_class->get_datatype(); + r_type.type.is_meta_type = false; found = true; } } break; diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp index 547f5607d3..f6fa17c84f 100644 --- a/modules/gdscript/gdscript_lambda_callable.cpp +++ b/modules/gdscript/gdscript_lambda_callable.cpp @@ -139,20 +139,14 @@ void GDScriptLambdaCallable::call(const Variant **p_arguments, int p_argcount, V } } -GDScriptLambdaCallable::GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures) { +GDScriptLambdaCallable::GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures) : + function(p_function) { ERR_FAIL_NULL(p_script.ptr()); ERR_FAIL_NULL(p_function); script = p_script; - function = p_function; captures = p_captures; h = (uint32_t)hash_murmur3_one_64((uint64_t)this); - - updatable_func_ptr_element = p_script->_add_func_ptr_to_update(&function); -} - -GDScriptLambdaCallable::~GDScriptLambdaCallable() { - GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element); } bool GDScriptLambdaSelfCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) { @@ -264,37 +258,23 @@ void GDScriptLambdaSelfCallable::call(const Variant **p_arguments, int p_argcoun } } -GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) { +GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) : + function(p_function) { ERR_FAIL_NULL(p_self.ptr()); ERR_FAIL_NULL(p_function); reference = p_self; object = p_self.ptr(); - function = p_function; captures = p_captures; h = (uint32_t)hash_murmur3_one_64((uint64_t)this); - - GDScript *gds = p_function->get_script(); - if (gds != nullptr) { - updatable_func_ptr_element = gds->_add_func_ptr_to_update(&function); - } } -GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) { +GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) : + function(p_function) { ERR_FAIL_NULL(p_self); ERR_FAIL_NULL(p_function); object = p_self; - function = p_function; captures = p_captures; h = (uint32_t)hash_murmur3_one_64((uint64_t)this); - - GDScript *gds = p_function->get_script(); - if (gds != nullptr) { - updatable_func_ptr_element = gds->_add_func_ptr_to_update(&function); - } -} - -GDScriptLambdaSelfCallable::~GDScriptLambdaSelfCallable() { - GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element); } diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h index ee7d547544..2c5d01aa16 100644 --- a/modules/gdscript/gdscript_lambda_callable.h +++ b/modules/gdscript/gdscript_lambda_callable.h @@ -42,10 +42,9 @@ class GDScriptFunction; class GDScriptInstance; class GDScriptLambdaCallable : public CallableCustom { - GDScriptFunction *function = nullptr; + GDScript::UpdatableFuncPtr function; Ref<GDScript> script; uint32_t h; - GDScript::UpdatableFuncPtrElement updatable_func_ptr_element; Vector<Variant> captures; @@ -62,17 +61,18 @@ public: StringName get_method() const override; void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override; + GDScriptLambdaCallable(GDScriptLambdaCallable &) = delete; + GDScriptLambdaCallable(const GDScriptLambdaCallable &) = delete; GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures); - virtual ~GDScriptLambdaCallable(); + virtual ~GDScriptLambdaCallable() = default; }; // Lambda callable that references a particular object, so it can use `self` in the body. class GDScriptLambdaSelfCallable : public CallableCustom { - GDScriptFunction *function = nullptr; + GDScript::UpdatableFuncPtr function; Ref<RefCounted> reference; // For objects that are RefCounted, keep a reference. Object *object = nullptr; // For non RefCounted objects, use a direct pointer. uint32_t h; - GDScript::UpdatableFuncPtrElement updatable_func_ptr_element; Vector<Variant> captures; @@ -88,9 +88,11 @@ public: ObjectID get_object() const override; void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override; + GDScriptLambdaSelfCallable(GDScriptLambdaSelfCallable &) = delete; + GDScriptLambdaSelfCallable(const GDScriptLambdaSelfCallable &) = delete; GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures); GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures); - virtual ~GDScriptLambdaSelfCallable(); + virtual ~GDScriptLambdaSelfCallable() = default; }; #endif // GDSCRIPT_LAMBDA_CALLABLE_H diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index f3a4f2eaa6..a4a12f8bc4 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -629,7 +629,7 @@ GDScriptParser::ClassNode *GDScriptParser::find_class(const String &p_qualified_ // Starts at index 1 because index 0 was handled above. for (int i = 1; result != nullptr && i < class_names.size(); i++) { - String current_name = class_names[i]; + const String ¤t_name = class_names[i]; GDScriptParser::ClassNode *next = nullptr; if (result->has_member(current_name)) { GDScriptParser::ClassNode::Member member = result->get_member(current_name); @@ -1120,7 +1120,12 @@ void GDScriptParser::parse_property_getter(VariableNode *p_variable) { case VariableNode::PROP_INLINE: { FunctionNode *function = alloc_node<FunctionNode>(); - consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "get".)"); + if (match(GDScriptTokenizer::Token::PARENTHESIS_OPEN)) { + consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after "get(".)*"); + consume(GDScriptTokenizer::Token::COLON, R"*(Expected ":" after "get()".)*"); + } else { + consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" or "(" after "get".)"); + } IdentifierNode *identifier = alloc_node<IdentifierNode>(); complete_extents(identifier); @@ -1268,8 +1273,7 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum(bool p_is_static) { EnumNode *enum_node = alloc_node<EnumNode>(); bool named = false; - if (check(GDScriptTokenizer::Token::IDENTIFIER)) { - advance(); + if (match(GDScriptTokenizer::Token::IDENTIFIER)) { enum_node->identifier = parse_identifier(); named = true; } diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index 40c564c36b..f8cb460e40 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -194,9 +194,9 @@ struct GDScriptUtilityFunctionsDefinitions { // Calculate how many. int count = 0; if (incr > 0) { - count = ((to - from - 1) / incr) + 1; + count = Math::division_round_up(to - from, incr); } else { - count = ((from - to - 1) / -incr) + 1; + count = Math::division_round_up(from - to, -incr); } Error err = arr.resize(count); @@ -470,7 +470,8 @@ struct GDScriptUtilityFunctionsDefinitions { static inline void len(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { VALIDATE_ARG_COUNT(1); switch (p_args[0]->get_type()) { - case Variant::STRING: { + case Variant::STRING: + case Variant::STRING_NAME: { String d = *p_args[0]; *r_ret = d.length(); } break; diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 3abfc7f8e3..7b03ac74d6 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -873,8 +873,12 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GET_VARIANT_PTR(value, 2); bool valid; +#ifdef DEBUG_ENABLED + Variant::VariantSetError err_code; + dst->set(*index, *value, &valid, &err_code); +#else dst->set(*index, *value, &valid); - +#endif #ifdef DEBUG_ENABLED if (!valid) { Object *obj = dst->get_validated_object(); @@ -891,7 +895,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } else { v = "of type '" + _get_var_type(index) + "'"; } - err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'"; + err_text = "Invalid assignment of property or key " + v + " with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'."; + if (err_code == Variant::VariantSetError::SET_INDEXED_ERR) { + err_text = "Invalid assignment of index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'."; + } } OPCODE_BREAK; } @@ -922,7 +929,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } else { v = "of type '" + _get_var_type(index) + "'"; } - err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'"; + err_text = "Invalid assignment of property or key " + v + " with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'."; OPCODE_BREAK; } #endif @@ -972,7 +979,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a bool valid; #ifdef DEBUG_ENABLED // Allow better error message in cases where src and dst are the same stack position. - Variant ret = src->get(*index, &valid); + Variant::VariantGetError err_code; + Variant ret = src->get(*index, &valid, &err_code); #else *dst = src->get(*index, &valid); @@ -985,7 +993,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } else { v = "of type '" + _get_var_type(index) + "'"; } - err_text = "Invalid get index " + v + " (on base: '" + _get_var_type(src) + "')."; + err_text = "Invalid access to property or key " + v + " on a base object of type '" + _get_var_type(src) + "'."; + if (err_code == Variant::VariantGetError::GET_INDEXED_ERR) { + err_text = "Invalid access of index " + v + " on a base object of type: '" + _get_var_type(src) + "'."; + } OPCODE_BREAK; } *dst = ret; @@ -1021,7 +1032,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } else { v = "of type '" + _get_var_type(key) + "'"; } - err_text = "Invalid get index " + v + " (on base: '" + _get_var_type(src) + "')."; + err_text = "Invalid access to property or key " + v + " on a base object of type '" + _get_var_type(src) + "'."; OPCODE_BREAK; } *dst = ret; @@ -1086,7 +1097,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a if (read_only_property) { err_text = vformat(R"(Cannot set value into property "%s" (on base "%s") because it is read-only.)", String(*index), _get_var_type(dst)); } else { - err_text = "Invalid set index '" + String(*index) + "' (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'."; + err_text = "Invalid assignment of property or key '" + String(*index) + "' with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'."; } OPCODE_BREAK; } @@ -1131,7 +1142,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #endif #ifdef DEBUG_ENABLED if (!valid) { - err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "')."; + err_text = "Invalid access to property or key '" + index->operator String() + "' on a base object of type '" + _get_var_type(src) + "'."; OPCODE_BREAK; } *dst = ret; @@ -2473,7 +2484,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a Variant::construct(ret_type, retvalue, const_cast<const Variant **>(&r), 1, ce); } else { #ifdef DEBUG_ENABLED - err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)", Variant::get_type_name(r->get_type()), Variant::get_type_name(ret_type)); #endif // DEBUG_ENABLED @@ -2503,9 +2514,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a if (r->get_type() != Variant::ARRAY) { #ifdef DEBUG_ENABLED - err_text = vformat(R"(Trying to return a value of type "%s" where expected return type is "Array[%s]".)", - _get_var_type(r), _get_element_type(builtin_type, native_type, *script_type)); -#endif // DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "Array[%s]".)", + Variant::get_type_name(r->get_type()), Variant::get_type_name(builtin_type)); +#endif OPCODE_BREAK; } @@ -2536,7 +2547,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GD_ERR_BREAK(!nc); if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) { - err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)", Variant::get_type_name(r->get_type()), nc->get_name()); OPCODE_BREAK; } @@ -2554,7 +2565,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #endif // DEBUG_ENABLED if (ret_obj && !ClassDB::is_parent_class(ret_obj->get_class_name(), nc->get_name())) { #ifdef DEBUG_ENABLED - err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)", ret_obj->get_class_name(), nc->get_name()); #endif // DEBUG_ENABLED OPCODE_BREAK; @@ -2577,7 +2588,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) { #ifdef DEBUG_ENABLED - err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)", Variant::get_type_name(r->get_type()), GDScript::debug_get_script_name(Ref<Script>(base_type))); #endif // DEBUG_ENABLED OPCODE_BREAK; @@ -2599,7 +2610,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a ScriptInstance *ret_inst = ret_obj->get_script_instance(); if (!ret_inst) { #ifdef DEBUG_ENABLED - err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)", ret_obj->get_class_name(), GDScript::debug_get_script_name(Ref<GDScript>(base_type))); #endif // DEBUG_ENABLED OPCODE_BREAK; @@ -2618,7 +2629,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a if (!valid) { #ifdef DEBUG_ENABLED - err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)", GDScript::debug_get_script_name(ret_obj->get_script_instance()->get_script()), GDScript::debug_get_script_name(Ref<GDScript>(base_type))); #endif // DEBUG_ENABLED OPCODE_BREAK; diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 0b1371851b..95b3be2811 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -456,7 +456,7 @@ Variant GDScriptTextDocument::declaration(const Dictionary &p_params) { id = "class_global:" + symbol->native_class + ":" + symbol->name; break; } - call_deferred(SNAME("show_native_symbol_in_editor"), id); + callable_mp(this, &GDScriptTextDocument::show_native_symbol_in_editor).call_deferred(id); } else { notify_client_show_symbol(symbol); } diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index 361ca276bb..4d93a6fc18 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -266,7 +266,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { while (!next.is_empty()) { if (dir->current_is_dir()) { - if (next == "." || next == "..") { + if (next == "." || next == ".." || next == "completion" || next == "lsp") { next = dir->get_next(); continue; } diff --git a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_constants.out b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_constants.out index 73a54d7820..a6a3973255 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_constants.out +++ b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_constants.out @@ -3,4 +3,4 @@ GDTEST_RUNTIME_ERROR >> on function: test() >> analyzer/errors/outer_class_constants.gd >> 8 ->> Invalid get index 'OUTER_CONST' (on base: 'GDScript'). +>> Invalid access to property or key 'OUTER_CONST' on a base object of type 'GDScript'. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_constants_as_variant.out b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_constants_as_variant.out index 92e7b9316e..70fdc5b62c 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_constants_as_variant.out +++ b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_constants_as_variant.out @@ -3,4 +3,4 @@ GDTEST_RUNTIME_ERROR >> on function: test() >> analyzer/errors/outer_class_constants_as_variant.gd >> 9 ->> Invalid get index 'OUTER_CONST' (on base: 'GDScript'). +>> Invalid access to property or key 'OUTER_CONST' on a base object of type 'GDScript'. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_instance_constants.out b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_instance_constants.out index 892f8e2c3f..6632f056bd 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_instance_constants.out +++ b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_instance_constants.out @@ -3,4 +3,4 @@ GDTEST_RUNTIME_ERROR >> on function: test() >> analyzer/errors/outer_class_instance_constants.gd >> 8 ->> Invalid get index 'OUTER_CONST' (on base: 'RefCounted (Inner)'). +>> Invalid access to property or key 'OUTER_CONST' on a base object of type 'RefCounted (Inner)'. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_instance_constants_as_variant.out b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_instance_constants_as_variant.out index 8257e74f57..0459b756d1 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_instance_constants_as_variant.out +++ b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_instance_constants_as_variant.out @@ -3,4 +3,4 @@ GDTEST_RUNTIME_ERROR >> on function: test() >> analyzer/errors/outer_class_instance_constants_as_variant.gd >> 9 ->> Invalid get index 'OUTER_CONST' (on base: 'RefCounted (Inner)'). +>> Invalid access to property or key 'OUTER_CONST' on a base object of type 'RefCounted (Inner)'. diff --git a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg new file mode 100644 index 0000000000..4edee46039 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg @@ -0,0 +1,4 @@ +[output] +expected=[ + {"display": "autoplay"}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd new file mode 100644 index 0000000000..d41bbb970c --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd @@ -0,0 +1,6 @@ +extends Node + +var test: AnimationPlayer = $AnimationPlayer + +func _ready(): + test.➡ diff --git a/modules/gdscript/tests/scripts/lsp/class.notest.gd b/modules/gdscript/tests/scripts/lsp/class.gd index 53d0b14d72..53d0b14d72 100644 --- a/modules/gdscript/tests/scripts/lsp/class.notest.gd +++ b/modules/gdscript/tests/scripts/lsp/class.gd diff --git a/modules/gdscript/tests/scripts/lsp/enums.notest.gd b/modules/gdscript/tests/scripts/lsp/enums.gd index 38b9ec110a..38b9ec110a 100644 --- a/modules/gdscript/tests/scripts/lsp/enums.notest.gd +++ b/modules/gdscript/tests/scripts/lsp/enums.gd diff --git a/modules/gdscript/tests/scripts/lsp/indentation.notest.gd b/modules/gdscript/tests/scripts/lsp/indentation.gd index c25d73a719..c25d73a719 100644 --- a/modules/gdscript/tests/scripts/lsp/indentation.notest.gd +++ b/modules/gdscript/tests/scripts/lsp/indentation.gd diff --git a/modules/gdscript/tests/scripts/lsp/lambdas.notest.gd b/modules/gdscript/tests/scripts/lsp/lambdas.gd index 6f5d468eea..6f5d468eea 100644 --- a/modules/gdscript/tests/scripts/lsp/lambdas.notest.gd +++ b/modules/gdscript/tests/scripts/lsp/lambdas.gd diff --git a/modules/gdscript/tests/scripts/lsp/local_variables.notest.gd b/modules/gdscript/tests/scripts/lsp/local_variables.gd index b6cc46f7da..b6cc46f7da 100644 --- a/modules/gdscript/tests/scripts/lsp/local_variables.notest.gd +++ b/modules/gdscript/tests/scripts/lsp/local_variables.gd diff --git a/modules/gdscript/tests/scripts/lsp/properties.notest.gd b/modules/gdscript/tests/scripts/lsp/properties.gd index 8dfaee2e5b..8dfaee2e5b 100644 --- a/modules/gdscript/tests/scripts/lsp/properties.notest.gd +++ b/modules/gdscript/tests/scripts/lsp/properties.gd diff --git a/modules/gdscript/tests/scripts/lsp/scopes.notest.gd b/modules/gdscript/tests/scripts/lsp/scopes.gd index 20b8fb9bd7..20b8fb9bd7 100644 --- a/modules/gdscript/tests/scripts/lsp/scopes.notest.gd +++ b/modules/gdscript/tests/scripts/lsp/scopes.gd diff --git a/modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd b/modules/gdscript/tests/scripts/lsp/shadowing_initializer.gd index 338000fa0e..338000fa0e 100644 --- a/modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd +++ b/modules/gdscript/tests/scripts/lsp/shadowing_initializer.gd diff --git a/modules/gdscript/tests/scripts/parser/features/property_setter_getter.gd b/modules/gdscript/tests/scripts/parser/features/property_setter_getter.gd index 9e4b360fb2..82616ee3cf 100644 --- a/modules/gdscript/tests/scripts/parser/features/property_setter_getter.gd +++ b/modules/gdscript/tests/scripts/parser/features/property_setter_getter.gd @@ -6,6 +6,9 @@ var property: set(value): _backing = value - 1000 +var property_2: + get(): # Allow parentheses. + return 123 func test(): print("Not using self:") @@ -35,3 +38,5 @@ func test(): self.property = 5000 print(self.property) print(self._backing) + + print(property_2) diff --git a/modules/gdscript/tests/scripts/parser/features/property_setter_getter.out b/modules/gdscript/tests/scripts/parser/features/property_setter_getter.out index 560e0c3bd7..23f98f44ab 100644 --- a/modules/gdscript/tests/scripts/parser/features/property_setter_getter.out +++ b/modules/gdscript/tests/scripts/parser/features/property_setter_getter.out @@ -17,3 +17,4 @@ Using self: -50 5000 4000 +123 diff --git a/modules/gdscript/tests/scripts/project.godot b/modules/gdscript/tests/scripts/project.godot index 25b49c0abd..c500ef443d 100644 --- a/modules/gdscript/tests/scripts/project.godot +++ b/modules/gdscript/tests/scripts/project.godot @@ -3,7 +3,7 @@ ; It also helps for opening Godot to edit the scripts, but please don't ; let the editor changes be saved. -config_version=4 +config_version=5 [application] diff --git a/modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out b/modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out index 2a97eaea44..c524a1ae6b 100644 --- a/modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out +++ b/modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out @@ -3,4 +3,4 @@ GDTEST_RUNTIME_ERROR >> on function: test() >> runtime/errors/constant_array_is_deep.gd >> 6 ->> Invalid set index '0' (on base: 'Dictionary') with value of type 'int' +>> Invalid assignment of property or key '0' with value of type 'int' on a base object of type 'Dictionary'. diff --git a/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out b/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out index c807db6b0c..cf51b0262d 100644 --- a/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out +++ b/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out @@ -3,4 +3,4 @@ GDTEST_RUNTIME_ERROR >> on function: test() >> runtime/errors/constant_dictionary_is_deep.gd >> 6 ->> Invalid set index '0' (on base: 'Array') with value of type 'int' +>> Invalid assignment of index '0' (on base: 'Array') with value of type 'int'. diff --git a/modules/gdscript/tests/scripts/runtime/features/builtin_method_as_callable.gd b/modules/gdscript/tests/scripts/runtime/features/builtin_method_as_callable.gd new file mode 100644 index 0000000000..e4016c0119 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/builtin_method_as_callable.gd @@ -0,0 +1,6 @@ +func test(): + var array: Array = [1, 2, 3] + print(array) + var callable: Callable = array.clear + callable.call() + print(array) diff --git a/modules/gdscript/tests/scripts/runtime/features/builtin_method_as_callable.out b/modules/gdscript/tests/scripts/runtime/features/builtin_method_as_callable.out new file mode 100644 index 0000000000..c4182b38e9 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/builtin_method_as_callable.out @@ -0,0 +1,3 @@ +GDTEST_OK +[1, 2, 3] +[] diff --git a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd index f6aa58737f..97e9da3b26 100644 --- a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd +++ b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd @@ -1,12 +1,18 @@ -# GH-79521 +# GH-79521, GH-86032 class_name TestStaticMethodAsCallable static func static_func() -> String: return "Test" +static func another_static_func(): + prints("another_static_func:", static_func.call(), static_func.is_valid()) + func test(): var a: Callable = TestStaticMethodAsCallable.static_func var b: Callable = static_func prints(a.call(), a.is_valid()) prints(b.call(), b.is_valid()) + @warning_ignore("static_called_on_instance") + another_static_func() + TestStaticMethodAsCallable.another_static_func() diff --git a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out index e6d461b8f9..2b773ce8ee 100644 --- a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out +++ b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out @@ -1,3 +1,5 @@ GDTEST_OK Test true Test true +another_static_func: Test true +another_static_func: Test true diff --git a/modules/gdscript/tests/test_completion.h b/modules/gdscript/tests/test_completion.h new file mode 100644 index 0000000000..abc34bd4bf --- /dev/null +++ b/modules/gdscript/tests/test_completion.h @@ -0,0 +1,199 @@ +/**************************************************************************/ +/* test_completion.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef TEST_COMPLETION_H +#define TEST_COMPLETION_H + +#ifdef TOOLS_ENABLED + +#include "core/io/config_file.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" +#include "core/object/script_language.h" +#include "core/variant/dictionary.h" +#include "core/variant/variant.h" +#include "gdscript_test_runner.h" +#include "modules/modules_enabled.gen.h" // For mono. +#include "scene/resources/packed_scene.h" + +#include "../gdscript.h" +#include "tests/test_macros.h" + +#include "editor/editor_settings.h" +#include "scene/theme/theme_db.h" + +namespace GDScriptTests { + +static bool match_option(const Dictionary p_expected, const ScriptLanguage::CodeCompletionOption p_got) { + if (p_expected.get("display", p_got.display) != p_got.display) { + return false; + } + if (p_expected.get("insert_text", p_got.insert_text) != p_got.insert_text) { + return false; + } + if (p_expected.get("kind", p_got.kind) != Variant(p_got.kind)) { + return false; + } + if (p_expected.get("location", p_got.location) != Variant(p_got.location)) { + return false; + } + return true; +} + +static void to_dict_list(Variant p_variant, List<Dictionary> &p_list) { + ERR_FAIL_COND(!p_variant.is_array()); + + Array arr = p_variant; + for (int i = 0; i < arr.size(); i++) { + if (arr[i].get_type() == Variant::DICTIONARY) { + p_list.push_back(arr[i]); + } + } +} + +static void test_directory(const String &p_dir) { + Error err = OK; + Ref<DirAccess> dir = DirAccess::open(p_dir, &err); + + if (err != OK) { + FAIL("Invalid test directory."); + return; + } + + String path = dir->get_current_dir(); + + dir->list_dir_begin(); + String next = dir->get_next(); + + while (!next.is_empty()) { + if (dir->current_is_dir()) { + if (next == "." || next == "..") { + next = dir->get_next(); + continue; + } + test_directory(path.path_join(next)); + } else if (next.ends_with(".gd") && !next.ends_with(".notest.gd")) { + Ref<FileAccess> acc = FileAccess::open(path.path_join(next), FileAccess::READ, &err); + + if (err != OK) { + next = dir->get_next(); + continue; + } + + String code = acc->get_as_utf8_string(); + // For ease of reading ➡ (0x27A1) acts as sentinel char instead of 0xFFFF in the files. + code = code.replace_first(String::chr(0x27A1), String::chr(0xFFFF)); + // Require pointer sentinel char in scripts. + CHECK(code.find_char(0xFFFF) != -1); + + ConfigFile conf; + if (conf.load(path.path_join(next.get_basename() + ".cfg")) != OK) { + FAIL("No config file found."); + } + +#ifndef MODULE_MONO_ENABLED + if (conf.get_value("input", "cs", false)) { + next = dir->get_next(); + continue; + } +#endif + + EditorSettings::get_singleton()->set_setting("text_editor/completion/use_single_quotes", conf.get_value("input", "use_single_quotes", false)); + + List<Dictionary> include; + to_dict_list(conf.get_value("result", "include", Array()), include); + + List<Dictionary> exclude; + to_dict_list(conf.get_value("result", "exclude", Array()), exclude); + + List<ScriptLanguage::CodeCompletionOption> options; + String call_hint; + bool forced; + + Node *owner = nullptr; + if (dir->file_exists(next.get_basename() + ".tscn")) { + String project_path = "res://completion"; + Ref<PackedScene> scene = ResourceLoader::load(project_path.path_join(next.get_basename() + ".tscn"), "PackedScene"); + if (scene.is_valid()) { + owner = scene->instantiate(); + } + } + + GDScriptLanguage::get_singleton()->complete_code(code, path.path_join(next), owner, &options, forced, call_hint); + String contains_excluded; + for (ScriptLanguage::CodeCompletionOption &option : options) { + for (const Dictionary &E : exclude) { + if (match_option(E, option)) { + contains_excluded = option.display; + break; + } + } + if (!contains_excluded.is_empty()) { + break; + } + + for (const Dictionary &E : include) { + if (match_option(E, option)) { + include.erase(E); + break; + } + } + } + CHECK_MESSAGE(contains_excluded.is_empty(), "Autocompletion suggests illegal option '", contains_excluded, "' for '", path.path_join(next), "'."); + CHECK(include.is_empty()); + + String expected_call_hint = conf.get_value("result", "call_hint", call_hint); + bool expected_forced = conf.get_value("result", "forced", forced); + + CHECK(expected_call_hint == call_hint); + CHECK(expected_forced == forced); + + if (owner) { + memdelete(owner); + } + } + next = dir->get_next(); + } +} + +TEST_SUITE("[Modules][GDScript][Completion]") { + TEST_CASE("[Editor] Check suggestion list") { + // Set all editor settings that code completion relies on. + EditorSettings::get_singleton()->set_setting("text_editor/completion/use_single_quotes", false); + init_language("modules/gdscript/tests/scripts"); + + test_directory("modules/gdscript/tests/scripts/completion"); + } +} +} // namespace GDScriptTests + +#endif + +#endif // TEST_COMPLETION_H diff --git a/modules/gdscript/tests/test_lsp.h b/modules/gdscript/tests/test_lsp.h index e57df00e2d..6192272f80 100644 --- a/modules/gdscript/tests/test_lsp.h +++ b/modules/gdscript/tests/test_lsp.h @@ -76,7 +76,7 @@ namespace GDScriptTests { // LSP GDScript test scripts are located inside project of other GDScript tests: // Cannot reset `ProjectSettings` (singleton) -> Cannot load another workspace and resources in there. // -> Reuse GDScript test project. LSP specific scripts are then placed inside `lsp` folder. -// Access via `res://lsp/my_script.notest.gd`. +// Access via `res://lsp/my_script.gd`. const String root = "modules/gdscript/tests/scripts/"; /* @@ -394,7 +394,7 @@ func f(): Ref<GDScriptWorkspace> workspace = GDScriptLanguageProtocol::get_singleton()->get_workspace(); { - String path = "res://lsp/local_variables.notest.gd"; + String path = "res://lsp/local_variables.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector<InlineTestData> all_test_data = read_tests(path); @@ -413,7 +413,7 @@ func f(): } SUBCASE("Can get correct ranges for indented variables") { - String path = "res://lsp/indentation.notest.gd"; + String path = "res://lsp/indentation.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector<InlineTestData> all_test_data = read_tests(path); @@ -421,7 +421,7 @@ func f(): } SUBCASE("Can get correct ranges for scopes") { - String path = "res://lsp/scopes.notest.gd"; + String path = "res://lsp/scopes.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector<InlineTestData> all_test_data = read_tests(path); @@ -429,7 +429,7 @@ func f(): } SUBCASE("Can get correct ranges for lambda") { - String path = "res://lsp/lambdas.notest.gd"; + String path = "res://lsp/lambdas.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector<InlineTestData> all_test_data = read_tests(path); @@ -437,7 +437,7 @@ func f(): } SUBCASE("Can get correct ranges for inner class") { - String path = "res://lsp/class.notest.gd"; + String path = "res://lsp/class.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector<InlineTestData> all_test_data = read_tests(path); @@ -445,7 +445,7 @@ func f(): } SUBCASE("Can get correct ranges for inner class") { - String path = "res://lsp/enums.notest.gd"; + String path = "res://lsp/enums.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector<InlineTestData> all_test_data = read_tests(path); @@ -453,7 +453,7 @@ func f(): } SUBCASE("Can get correct ranges for shadowing & shadowed variables") { - String path = "res://lsp/shadowing_initializer.notest.gd"; + String path = "res://lsp/shadowing_initializer.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector<InlineTestData> all_test_data = read_tests(path); @@ -461,7 +461,7 @@ func f(): } SUBCASE("Can get correct ranges for properties and getter/setter") { - String path = "res://lsp/properties.notest.gd"; + String path = "res://lsp/properties.gd"; assert_no_errors_in(path); String uri = workspace->get_file_uri(path); Vector<InlineTestData> all_test_data = read_tests(path); diff --git a/modules/glslang/config.py b/modules/glslang/config.py index d22f9454ed..1169776a73 100644 --- a/modules/glslang/config.py +++ b/modules/glslang/config.py @@ -1,5 +1,7 @@ def can_build(env, platform): - return True + # glslang is only needed when Vulkan or Direct3D 12-based renderers are available, + # as OpenGL doesn't use glslang. + return env["vulkan"] or env["d3d12"] def configure(env): diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml index f5066ba4f1..1b52a82298 100644 --- a/modules/gltf/doc_classes/GLTFDocument.xml +++ b/modules/gltf/doc_classes/GLTFDocument.xml @@ -84,7 +84,7 @@ <param index="1" name="path" type="String" /> <description> Takes a [GLTFState] object through the [param state] parameter and writes a glTF file to the filesystem. - [b]Note:[/b] The extension of the glTF file determines if it is a .glb binary file or a .gltf file. + [b]Note:[/b] The extension of the glTF file determines if it is a .glb binary file or a .gltf text file. </description> </method> </methods> diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp index 83c7f463df..56e4bfbb32 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp +++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp @@ -32,12 +32,14 @@ #ifdef TOOLS_ENABLED -#include "../gltf_document.h" +#include "editor_scene_exporter_gltf_settings.h" #include "editor/editor_file_system.h" +#include "editor/editor_inspector.h" #include "editor/editor_node.h" +#include "editor/editor_scale.h" #include "editor/gui/editor_file_dialog.h" -#include "scene/gui/popup_menu.h" +#include "editor/import/3d/scene_import_settings.h" String SceneExporterGLTFPlugin::get_name() const { return "ConvertGLTF2"; @@ -48,59 +50,72 @@ bool SceneExporterGLTFPlugin::has_main_screen() const { } SceneExporterGLTFPlugin::SceneExporterGLTFPlugin() { - file_export_lib = memnew(EditorFileDialog); - EditorNode::get_singleton()->get_gui_base()->add_child(file_export_lib); - file_export_lib->connect("file_selected", callable_mp(this, &SceneExporterGLTFPlugin::_gltf2_dialog_action)); - file_export_lib->set_title(TTR("Export Library")); - file_export_lib->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); - file_export_lib->set_access(EditorFileDialog::ACCESS_FILESYSTEM); - file_export_lib->clear_filters(); - file_export_lib->add_filter("*.glb"); - file_export_lib->add_filter("*.gltf"); - file_export_lib->set_title(TTR("Export Scene to glTF 2.0 File")); - + _gltf_document.instantiate(); + // Set up the file dialog. + _file_dialog = memnew(EditorFileDialog); + _file_dialog->connect("file_selected", callable_mp(this, &SceneExporterGLTFPlugin::_export_scene_as_gltf)); + _file_dialog->set_title(TTR("Export Library")); + _file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); + _file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + _file_dialog->clear_filters(); + _file_dialog->add_filter("*.glb"); + _file_dialog->add_filter("*.gltf"); + _file_dialog->set_title(TTR("Export Scene to glTF 2.0 File")); + EditorNode::get_singleton()->get_gui_base()->add_child(_file_dialog); + // Set up the export settings menu. + _export_settings.instantiate(); + _export_settings->generate_property_list(_gltf_document); + _settings_inspector = memnew(EditorInspector); + _settings_inspector->set_custom_minimum_size(Size2(350, 300) * EDSCALE); + _file_dialog->add_side_menu(_settings_inspector, TTR("Export Settings:")); + // Add a button to the Scene -> Export menu to pop up the settings dialog. PopupMenu *menu = get_export_as_menu(); int idx = menu->get_item_count(); menu->add_item(TTR("glTF 2.0 Scene...")); - menu->set_item_metadata(idx, callable_mp(this, &SceneExporterGLTFPlugin::convert_scene_to_gltf2)); + menu->set_item_metadata(idx, callable_mp(this, &SceneExporterGLTFPlugin::_popup_gltf_export_dialog)); +} + +void SceneExporterGLTFPlugin::_popup_gltf_export_dialog() { + Node *root = EditorNode::get_singleton()->get_tree()->get_edited_scene_root(); + if (!root) { + EditorNode::get_singleton()->show_accept(TTR("This operation can't be done without a scene."), TTR("OK")); + return; + } + // Set the file dialog's file name to the scene name. + String filename = String(root->get_scene_file_path().get_file().get_basename()); + if (filename.is_empty()) { + filename = root->get_name(); + } + _file_dialog->set_current_file(filename + String(".gltf")); + // Generate and refresh the export settings. + _export_settings->generate_property_list(_gltf_document); + _settings_inspector->edit(nullptr); + _settings_inspector->edit(_export_settings.ptr()); + // Show the file dialog. + _file_dialog->popup_centered_ratio(); } -void SceneExporterGLTFPlugin::_gltf2_dialog_action(String p_file) { +void SceneExporterGLTFPlugin::_export_scene_as_gltf(const String &p_file_path) { Node *root = EditorNode::get_singleton()->get_tree()->get_edited_scene_root(); if (!root) { EditorNode::get_singleton()->show_accept(TTR("This operation can't be done without a scene."), TTR("OK")); return; } List<String> deps; - Ref<GLTFDocument> doc; - doc.instantiate(); Ref<GLTFState> state; state.instantiate(); + state->set_copyright(_export_settings->get_copyright()); int32_t flags = 0; flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; - Error err = doc->append_from_scene(root, state, flags); + Error err = _gltf_document->append_from_scene(root, state, flags); if (err != OK) { ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err))); } - err = doc->write_to_filesystem(state, p_file); + err = _gltf_document->write_to_filesystem(state, p_file_path); if (err != OK) { ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err))); } EditorFileSystem::get_singleton()->scan_changes(); } -void SceneExporterGLTFPlugin::convert_scene_to_gltf2() { - Node *root = EditorNode::get_singleton()->get_tree()->get_edited_scene_root(); - if (!root) { - EditorNode::get_singleton()->show_accept(TTR("This operation can't be done without a scene."), TTR("OK")); - return; - } - String filename = String(root->get_scene_file_path().get_file().get_basename()); - if (filename.is_empty()) { - filename = root->get_name(); - } - file_export_lib->set_current_file(filename + String(".gltf")); - file_export_lib->popup_centered_ratio(); -} - #endif // TOOLS_ENABLED diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h index f92b3c5180..683ff6d4f6 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h +++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h @@ -33,18 +33,23 @@ #ifdef TOOLS_ENABLED -#include "editor_scene_importer_gltf.h" +#include "../gltf_document.h" +#include "editor_scene_exporter_gltf_settings.h" #include "editor/editor_plugin.h" class EditorFileDialog; +class EditorInspector; class SceneExporterGLTFPlugin : public EditorPlugin { GDCLASS(SceneExporterGLTFPlugin, EditorPlugin); - EditorFileDialog *file_export_lib = nullptr; - void _gltf2_dialog_action(String p_file); - void convert_scene_to_gltf2(); + Ref<GLTFDocument> _gltf_document; + Ref<EditorSceneExporterGLTFSettings> _export_settings; + EditorInspector *_settings_inspector = nullptr; + EditorFileDialog *_file_dialog = nullptr; + void _popup_gltf_export_dialog(); + void _export_scene_as_gltf(const String &p_file_path); public: virtual String get_name() const override; diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp new file mode 100644 index 0000000000..b0283b0c55 --- /dev/null +++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp @@ -0,0 +1,176 @@ +/**************************************************************************/ +/* editor_scene_exporter_gltf_settings.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "editor_scene_exporter_gltf_settings.h" + +const uint32_t PROP_EDITOR_SCRIPT_VAR = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_SCRIPT_VARIABLE; + +bool EditorSceneExporterGLTFSettings::_set(const StringName &p_name, const Variant &p_value) { + String name_str = String(p_name); + if (name_str.contains("/")) { + return _set_extension_setting(name_str, p_value); + } + if (p_name == StringName("image_format")) { + _document->set_image_format(p_value); + emit_signal("property_list_changed"); + return true; + } + if (p_name == StringName("lossy_quality")) { + _document->set_lossy_quality(p_value); + return true; + } + if (p_name == StringName("root_node_mode")) { + _document->set_root_node_mode((GLTFDocument::RootNodeMode)(int64_t)p_value); + return true; + } + return false; +} + +bool EditorSceneExporterGLTFSettings::_get(const StringName &p_name, Variant &r_ret) const { + String name_str = String(p_name); + if (name_str.contains("/")) { + return _get_extension_setting(name_str, r_ret); + } + if (p_name == StringName("image_format")) { + r_ret = _document->get_image_format(); + return true; + } + if (p_name == StringName("lossy_quality")) { + r_ret = _document->get_lossy_quality(); + return true; + } + if (p_name == StringName("root_node_mode")) { + r_ret = _document->get_root_node_mode(); + return true; + } + return false; +} + +void EditorSceneExporterGLTFSettings::_get_property_list(List<PropertyInfo> *p_list) const { + for (PropertyInfo prop : _property_list) { + if (prop.name == "lossy_quality") { + String image_format = get("image_format"); + bool is_image_format_lossy = image_format == "JPEG" || image_format.findn("Lossy") != -1; + prop.usage = is_image_format_lossy ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_STORAGE; + } + p_list->push_back(prop); + } +} + +bool EditorSceneExporterGLTFSettings::_set_extension_setting(const String &p_name_str, const Variant &p_value) { + PackedStringArray split = String(p_name_str).split("/", true, 1); + if (!_config_name_to_extension_map.has(split[0])) { + return false; + } + Ref<GLTFDocumentExtension> extension = _config_name_to_extension_map[split[0]]; + bool valid; + extension->set(split[1], p_value, &valid); + return valid; +} + +bool EditorSceneExporterGLTFSettings::_get_extension_setting(const String &p_name_str, Variant &r_ret) const { + PackedStringArray split = String(p_name_str).split("/", true, 1); + if (!_config_name_to_extension_map.has(split[0])) { + return false; + } + Ref<GLTFDocumentExtension> extension = _config_name_to_extension_map[split[0]]; + bool valid; + r_ret = extension->get(split[1], &valid); + return valid; +} + +String get_friendly_config_prefix(Ref<GLTFDocumentExtension> p_extension) { + String config_prefix = p_extension->get_name(); + if (!config_prefix.is_empty()) { + return config_prefix; + } + const String class_name = p_extension->get_class_name(); + config_prefix = class_name.trim_prefix("GLTFDocumentExtension").capitalize(); + if (!config_prefix.is_empty()) { + return config_prefix; + } + PackedStringArray supported_extensions = p_extension->get_supported_extensions(); + if (supported_extensions.size() > 0) { + return supported_extensions[0]; + } + return "Unknown GLTFDocumentExtension"; +} + +// Run this before popping up the export settings, because the extensions may have changed. +void EditorSceneExporterGLTFSettings::generate_property_list(Ref<GLTFDocument> p_document) { + _property_list.clear(); + _document = p_document; + String image_format_hint_string = "None,PNG,JPEG"; + // Add properties from all document extensions. + for (Ref<GLTFDocumentExtension> &extension : GLTFDocument::get_all_gltf_document_extensions()) { + const String config_prefix = get_friendly_config_prefix(extension); + _config_name_to_extension_map[config_prefix] = extension; + // If the extension allows saving in different image formats, add to the enum. + PackedStringArray saveable_image_formats = extension->get_saveable_image_formats(); + for (int i = 0; i < saveable_image_formats.size(); i++) { + image_format_hint_string += "," + saveable_image_formats[i]; + } + // Look through the extension's properties and find the relevant ones. + List<PropertyInfo> ext_prop_list; + extension->get_property_list(&ext_prop_list); + for (const PropertyInfo &prop : ext_prop_list) { + // We only want properties that will show up in the exporter + // settings list. Exclude Resource's properties, as they are + // not relevant to the exporter. Include any user-defined script + // variables exposed to the editor (PROP_EDITOR_SCRIPT_VAR). + if ((prop.usage & PROP_EDITOR_SCRIPT_VAR) == PROP_EDITOR_SCRIPT_VAR) { + PropertyInfo ext_prop = prop; + ext_prop.name = config_prefix + "/" + prop.name; + _property_list.push_back(ext_prop); + } + } + } + // Add top-level properties (in addition to what _bind_methods registers). + PropertyInfo image_format_prop = PropertyInfo(Variant::STRING, "image_format", PROPERTY_HINT_ENUM, image_format_hint_string); + _property_list.push_back(image_format_prop); + PropertyInfo lossy_quality_prop = PropertyInfo(Variant::FLOAT, "lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"); + _property_list.push_back(lossy_quality_prop); + PropertyInfo root_node_mode_prop = PropertyInfo(Variant::INT, "root_node_mode", PROPERTY_HINT_ENUM, "Single Root,Keep Root,Multi Root"); + _property_list.push_back(root_node_mode_prop); +} + +String EditorSceneExporterGLTFSettings::get_copyright() const { + return _copyright; +} + +void EditorSceneExporterGLTFSettings::set_copyright(const String &p_copyright) { + _copyright = p_copyright; +} + +void EditorSceneExporterGLTFSettings::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_copyright"), &EditorSceneExporterGLTFSettings::get_copyright); + ClassDB::bind_method(D_METHOD("set_copyright", "copyright"), &EditorSceneExporterGLTFSettings::set_copyright); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "copyright", PROPERTY_HINT_PLACEHOLDER_TEXT, "Example: 2014 Godette"), "set_copyright", "get_copyright"); +} diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.h b/modules/gltf/editor/editor_scene_exporter_gltf_settings.h new file mode 100644 index 0000000000..6032932367 --- /dev/null +++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.h @@ -0,0 +1,64 @@ +/**************************************************************************/ +/* editor_scene_exporter_gltf_settings.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef EDITOR_SCENE_EXPORTER_GLTF_SETTINGS_H +#define EDITOR_SCENE_EXPORTER_GLTF_SETTINGS_H + +#ifdef TOOLS_ENABLED + +#include "../gltf_document.h" + +class EditorSceneExporterGLTFSettings : public RefCounted { + GDCLASS(EditorSceneExporterGLTFSettings, RefCounted); + List<PropertyInfo> _property_list; + Ref<GLTFDocument> _document; + HashMap<String, Ref<GLTFDocumentExtension>> _config_name_to_extension_map; + + String _copyright; + +protected: + static void _bind_methods(); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + bool _set_extension_setting(const String &p_name_str, const Variant &p_value); + bool _get_extension_setting(const String &p_name_str, Variant &r_ret) const; + +public: + void generate_property_list(Ref<GLTFDocument> p_document); + + String get_copyright() const; + void set_copyright(const String &p_copyright); +}; + +#endif // TOOLS_ENABLED + +#endif // EDITOR_SCENE_EXPORTER_GLTF_SETTINGS_H diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index 9587604e56..24dab16b90 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -134,7 +134,19 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ // Get global paths for source and sink. // Escape paths to be valid Python strings to embed in the script. - const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape(); + String source_global = ProjectSettings::get_singleton()->globalize_path(p_path); + +#ifdef WINDOWS_ENABLED + // On Windows, when using a network share path, the above will return a path starting with "//" + // which once handed to Blender will be treated like a relative path. So we need to replace the + // first two characters with "\\" to make it absolute again. + if (source_global.is_network_share_path()) { + source_global = "\\\\" + source_global.substr(2); + } +#endif + + source_global = source_global.c_escape(); + const String blend_basename = p_path.get_file().get_basename(); const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join( vformat("%s-%s.gltf", blend_basename, p_path.md5_text())); diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h index ec467db457..c1f4280170 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.h +++ b/modules/gltf/editor/editor_scene_importer_blend.h @@ -34,7 +34,7 @@ #ifdef TOOLS_ENABLED #include "editor/editor_file_system.h" -#include "editor/import/resource_importer_scene.h" +#include "editor/import/3d/resource_importer_scene.h" class Animation; class Node; diff --git a/modules/gltf/editor/editor_scene_importer_fbx.h b/modules/gltf/editor/editor_scene_importer_fbx.h index cc60830eac..86ee6568c9 100644 --- a/modules/gltf/editor/editor_scene_importer_fbx.h +++ b/modules/gltf/editor/editor_scene_importer_fbx.h @@ -35,7 +35,7 @@ #include "editor/editor_file_system.h" #include "editor/fbx_importer_manager.h" -#include "editor/import/resource_importer_scene.h" +#include "editor/import/3d/resource_importer_scene.h" class Animation; class Node; diff --git a/modules/gltf/editor/editor_scene_importer_gltf.h b/modules/gltf/editor/editor_scene_importer_gltf.h index 7726c845bf..ec563bf525 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.h +++ b/modules/gltf/editor/editor_scene_importer_gltf.h @@ -33,7 +33,7 @@ #ifdef TOOLS_ENABLED -#include "editor/import/resource_importer_scene.h" +#include "editor/import/3d/resource_importer_scene.h" class Animation; class Node; diff --git a/modules/gltf/extensions/gltf_document_extension.h b/modules/gltf/extensions/gltf_document_extension.h index 512b7aba91..761dff725c 100644 --- a/modules/gltf/extensions/gltf_document_extension.h +++ b/modules/gltf/extensions/gltf_document_extension.h @@ -33,6 +33,8 @@ #include "../gltf_state.h" +#include "scene/3d/node_3d.h" + class GLTFDocumentExtension : public Resource { GDCLASS(GLTFDocumentExtension, Resource); diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 4060f7f626..8a60df85cf 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -3218,7 +3218,7 @@ void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector< bool must_import = true; Vector<uint8_t> img_data = p_image->get_data(); Dictionary generator_parameters; - String file_path = p_state->get_base_path() + "/" + p_state->filename.get_basename() + "_" + p_image->get_name(); + String file_path = p_state->get_base_path().path_join(p_state->filename.get_basename() + "_" + p_image->get_name()); file_path += p_file_extension.is_empty() ? ".png" : p_file_extension; if (FileAccess::exists(file_path + ".import")) { Ref<ConfigFile> config; @@ -3230,6 +3230,8 @@ void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector< if (!generator_parameters.has("md5")) { must_import = false; // Didn't come from a gltf document; don't overwrite. } + } + if (must_import) { String existing_md5 = generator_parameters["md5"]; unsigned char md5_hash[16]; CryptoCore::md5(img_data.ptr(), img_data.size(), md5_hash); @@ -3658,141 +3660,143 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { mr["metallicFactor"] = base_material->get_metallic(); mr["roughnessFactor"] = base_material->get_roughness(); - bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); - bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); - bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); - if (has_ao || has_roughness || has_metalness) { - Dictionary mrt; - Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); - BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); - Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); - BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); - Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); - BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); - Ref<ImageTexture> orm_texture; - orm_texture.instantiate(); - Ref<Image> orm_image; - orm_image.instantiate(); - int32_t height = 0; - int32_t width = 0; - Ref<Image> ao_image; - if (has_ao) { - height = ao_texture->get_height(); - width = ao_texture->get_width(); - ao_image = ao_texture->get_image(); - Ref<ImageTexture> img_tex = ao_image; - if (img_tex.is_valid()) { - ao_image = img_tex->get_image(); - } - if (ao_image->is_compressed()) { - ao_image->decompress(); - } - } - Ref<Image> roughness_image; - if (has_roughness) { - height = roughness_texture->get_height(); - width = roughness_texture->get_width(); - roughness_image = roughness_texture->get_image(); - Ref<ImageTexture> img_tex = roughness_image; - if (img_tex.is_valid()) { - roughness_image = img_tex->get_image(); - } - if (roughness_image->is_compressed()) { - roughness_image->decompress(); - } - } - Ref<Image> metallness_image; - if (has_metalness) { - height = metallic_texture->get_height(); - width = metallic_texture->get_width(); - metallness_image = metallic_texture->get_image(); - Ref<ImageTexture> img_tex = metallness_image; - if (img_tex.is_valid()) { - metallness_image = img_tex->get_image(); - } - if (metallness_image->is_compressed()) { - metallness_image->decompress(); + if (_image_format != "None") { + bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); + bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); + bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); + if (has_ao || has_roughness || has_metalness) { + Dictionary mrt; + Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); + BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); + Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); + BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); + Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); + BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); + Ref<ImageTexture> orm_texture; + orm_texture.instantiate(); + Ref<Image> orm_image; + orm_image.instantiate(); + int32_t height = 0; + int32_t width = 0; + Ref<Image> ao_image; + if (has_ao) { + height = ao_texture->get_height(); + width = ao_texture->get_width(); + ao_image = ao_texture->get_image(); + Ref<ImageTexture> img_tex = ao_image; + if (img_tex.is_valid()) { + ao_image = img_tex->get_image(); + } + if (ao_image->is_compressed()) { + ao_image->decompress(); + } } - } - Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); - if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { - height = albedo_texture->get_height(); - width = albedo_texture->get_width(); - } - orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); - if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { - ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { - roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { - metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - for (int32_t h = 0; h < height; h++) { - for (int32_t w = 0; w < width; w++) { - Color c = Color(1.0f, 1.0f, 1.0f); - if (has_ao) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { - c.r = ao_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { - c.r = ao_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { - c.r = ao_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { - c.r = ao_image->get_pixel(w, h).a; - } + Ref<Image> roughness_image; + if (has_roughness) { + height = roughness_texture->get_height(); + width = roughness_texture->get_width(); + roughness_image = roughness_texture->get_image(); + Ref<ImageTexture> img_tex = roughness_image; + if (img_tex.is_valid()) { + roughness_image = img_tex->get_image(); } - if (has_roughness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).a; - } + if (roughness_image->is_compressed()) { + roughness_image->decompress(); + } + } + Ref<Image> metallness_image; + if (has_metalness) { + height = metallic_texture->get_height(); + width = metallic_texture->get_width(); + metallness_image = metallic_texture->get_image(); + Ref<ImageTexture> img_tex = metallness_image; + if (img_tex.is_valid()) { + metallness_image = img_tex->get_image(); + } + if (metallness_image->is_compressed()) { + metallness_image->decompress(); } - if (has_metalness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).a; + } + Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { + height = albedo_texture->get_height(); + width = albedo_texture->get_width(); + } + orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); + if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { + ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { + roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { + metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + for (int32_t h = 0; h < height; h++) { + for (int32_t w = 0; w < width; w++) { + Color c = Color(1.0f, 1.0f, 1.0f); + if (has_ao) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { + c.r = ao_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { + c.r = ao_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { + c.r = ao_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { + c.r = ao_image->get_pixel(w, h).a; + } + } + if (has_roughness) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).a; + } } + if (has_metalness) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).a; + } + } + orm_image->set_pixel(w, h, c); } - orm_image->set_pixel(w, h, c); } - } - orm_image->generate_mipmaps(); - orm_texture->set_image(orm_image); - GLTFTextureIndex orm_texture_index = -1; - if (has_ao || has_roughness || has_metalness) { - orm_texture->set_name(material->get_name() + "_orm"); - orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); - } - if (has_ao) { - Dictionary occt; - occt["index"] = orm_texture_index; - d["occlusionTexture"] = occt; - } - if (has_roughness || has_metalness) { - mrt["index"] = orm_texture_index; - Dictionary extensions = _serialize_texture_transform_uv1(material); - if (!extensions.is_empty()) { - mrt["extensions"] = extensions; - p_state->use_khr_texture_transform = true; + orm_image->generate_mipmaps(); + orm_texture->set_image(orm_image); + GLTFTextureIndex orm_texture_index = -1; + if (has_ao || has_roughness || has_metalness) { + orm_texture->set_name(material->get_name() + "_orm"); + orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + } + if (has_ao) { + Dictionary occt; + occt["index"] = orm_texture_index; + d["occlusionTexture"] = occt; + } + if (has_roughness || has_metalness) { + mrt["index"] = orm_texture_index; + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + mrt["extensions"] = extensions; + p_state->use_khr_texture_transform = true; + } + mr["metallicRoughnessTexture"] = mrt; } - mr["metallicRoughnessTexture"] = mrt; } } d["pbrMetallicRoughness"] = mr; - if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { + if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING) && _image_format != "None") { Dictionary nt; Ref<ImageTexture> tex; tex.instantiate(); @@ -3845,7 +3849,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { d["emissiveFactor"] = arr; } - if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { + if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION) && _image_format != "None") { Dictionary et; Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); GLTFTextureIndex gltf_texture_index = -1; @@ -5045,7 +5049,7 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> p_state) { AnimationPlayer *animation_player = p_state->animation_players[player_i]; List<StringName> animations; animation_player->get_animation_list(&animations); - for (StringName animation_name : animations) { + for (const StringName &animation_name : animations) { _convert_animation(p_state, animation_player, animation_name); } } @@ -6151,9 +6155,9 @@ T GLTFDocument::_interpolate_track(const Vector<real_t> &p_times, const Vector<T const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); - const T from = p_values[idx * 3 + 1]; + const T &from = p_values[idx * 3 + 1]; const T c1 = from + p_values[idx * 3 + 2]; - const T to = p_values[idx * 3 + 4]; + const T &to = p_values[idx * 3 + 4]; const T c2 = to + p_values[idx * 3 + 3]; return interp.bezier(from, c1, c2, to, c); @@ -6284,6 +6288,9 @@ void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_ animation->add_track(Animation::TYPE_POSITION_3D); animation->track_set_path(position_idx, transform_node_path); animation->track_set_imported(position_idx, true); //helps merging later + if (track.position_track.interpolation == GLTFAnimation::INTERP_STEP) { + animation->track_set_interpolation_type(position_idx, Animation::InterpolationType::INTERPOLATION_NEAREST); + } base_idx++; } } @@ -6306,6 +6313,9 @@ void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_ animation->add_track(Animation::TYPE_ROTATION_3D); animation->track_set_path(rotation_idx, transform_node_path); animation->track_set_imported(rotation_idx, true); //helps merging later + if (track.rotation_track.interpolation == GLTFAnimation::INTERP_STEP) { + animation->track_set_interpolation_type(rotation_idx, Animation::InterpolationType::INTERPOLATION_NEAREST); + } base_idx++; } } @@ -6328,6 +6338,9 @@ void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_ animation->add_track(Animation::TYPE_SCALE_3D); animation->track_set_path(scale_idx, transform_node_path); animation->track_set_imported(scale_idx, true); //helps merging later + if (track.scale_track.interpolation == GLTFAnimation::INTERP_STEP) { + animation->track_set_interpolation_type(scale_idx, Animation::InterpolationType::INTERPOLATION_NEAREST); + } base_idx++; } } @@ -7052,9 +7065,9 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p } else if (String(final_track_path).contains(":")) { //Process skeleton const Vector<String> node_suffix = String(final_track_path).split(":"); - const String node = node_suffix[0]; + const String &node = node_suffix[0]; const NodePath node_path = node; - const String suffix = node_suffix[1]; + const String &suffix = node_suffix[1]; Node *godot_node = animation_base_node->get_node_or_null(node_path); if (!godot_node) { continue; @@ -7336,6 +7349,10 @@ void GLTFDocument::unregister_all_gltf_document_extensions() { all_document_extensions.clear(); } +Vector<Ref<GLTFDocumentExtension>> GLTFDocument::get_all_gltf_document_extensions() { + return all_document_extensions; +} + PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> p_state, Error *r_err) { Error err = _encode_buffer_glb(p_state, ""); if (r_err) { diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 7e378fe94d..f321bb7111 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -86,6 +86,7 @@ public: static void register_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension, bool p_first_priority = false); static void unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension); static void unregister_all_gltf_document_extensions(); + static Vector<Ref<GLTFDocumentExtension>> get_all_gltf_document_extensions(); void set_naming_version(int p_version); int get_naming_version() const; diff --git a/modules/gltf/structures/gltf_skeleton.h b/modules/gltf/structures/gltf_skeleton.h index 72a4a06e5c..b2f2dcb2a2 100644 --- a/modules/gltf/structures/gltf_skeleton.h +++ b/modules/gltf/structures/gltf_skeleton.h @@ -82,7 +82,7 @@ public: //RBMap<int32_t, GLTFNodeIndex> get_godot_bone_node() { // return this->godot_bone_node; //} - //void set_godot_bone_node(RBMap<int32_t, GLTFNodeIndex> p_godot_bone_node) { + //void set_godot_bone_node(const RBMap<int32_t, GLTFNodeIndex> &p_godot_bone_node) { // this->godot_bone_node = p_godot_bone_node; //} Dictionary get_godot_bone_node(); diff --git a/modules/gltf/structures/gltf_skin.h b/modules/gltf/structures/gltf_skin.h index 164cabfe12..cd5f2d9ca2 100644 --- a/modules/gltf/structures/gltf_skin.h +++ b/modules/gltf/structures/gltf_skin.h @@ -34,6 +34,7 @@ #include "../gltf_defines.h" #include "core/io/resource.h" +#include "scene/resources/skin.h" template <typename T> class TypedArray; diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index f7c01ff840..225138dfb3 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -1316,6 +1316,7 @@ GridMapEditor::GridMapEditor() { EDITOR_DEF("editors/grid_map/preview_size", 64); mesh_library_palette = memnew(ItemList); + mesh_library_palette->set_auto_translate(false); add_child(mesh_library_palette); mesh_library_palette->set_v_size_flags(SIZE_EXPAND_FILL); mesh_library_palette->connect("gui_input", callable_mp(this, &GridMapEditor::_mesh_library_palette_input)); diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 6f493f48e3..e3475b3959 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -32,7 +32,6 @@ #include "core/core_string_names.h" #include "core/io/marshalls.h" -#include "core/object/message_queue.h" #include "scene/3d/light_3d.h" #include "scene/resources/mesh_library.h" #include "scene/resources/physics_material.h" @@ -975,7 +974,7 @@ void GridMap::_queue_octants_dirty() { return; } - MessageQueue::get_singleton()->push_call(this, "_update_octants_callback"); + callable_mp(this, &GridMap::_update_octants_callback).call_deferred(); awaiting_update = true; } @@ -1082,7 +1081,6 @@ void GridMap::_bind_methods() { ClassDB::bind_method(D_METHOD("local_to_map", "local_position"), &GridMap::local_to_map); ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &GridMap::map_to_local); - ClassDB::bind_method(D_METHOD("_update_octants_callback"), &GridMap::_update_octants_callback); #ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &GridMap::resource_changed); #endif diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp index e7fa909706..ada0cd01fa 100644 --- a/modules/jpg/image_loader_jpegd.cpp +++ b/modules/jpg/image_loader_jpegd.cpp @@ -162,6 +162,7 @@ static Error _jpgd_save_to_output_stream(jpge::output_stream *p_output_stream, c ERR_FAIL_COND_V_MSG(error != OK, error, "Couldn't decompress image."); } if (image->get_format() != Image::FORMAT_RGB8) { + image = p_img->duplicate(); image->convert(Image::FORMAT_RGB8); } @@ -173,12 +174,16 @@ static Error _jpgd_save_to_output_stream(jpge::output_stream *p_output_stream, c const uint8_t *src_data = image->get_data().ptr(); for (int i = 0; i < image->get_height(); i++) { - enc.process_scanline(&src_data[i * image->get_width() * 3]); + if (!enc.process_scanline(&src_data[i * image->get_width() * 3])) { + return FAILED; + } } - enc.process_scanline(nullptr); - - return OK; + if (enc.process_scanline(nullptr)) { + return OK; + } else { + return FAILED; + } } static Vector<uint8_t> _jpgd_buffer_save_func(const Ref<Image> &p_img, float p_quality) { diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index a4ecb767a7..4746ffb79b 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -357,7 +357,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i for (int m_i = 0; m_i < mesh_instances.size(); m_i++) { if (p_step_function) { - float p = float(m_i + 1) / mesh_instances.size() * 0.1; + float p = float(m_i + 1) / MAX(1, mesh_instances.size()) * 0.1; p_step_function(0.3 + p, vformat(RTR("Plotting mesh into acceleration structure %d/%d"), m_i + 1, mesh_instances.size()), p_bake_userdata, false); } @@ -703,7 +703,7 @@ void LightmapperRD::_raster_geometry(RenderingDevice *rd, Size2i atlas_size, int raster_push_constant.uv_offset[0] = -0.5f / float(atlas_size.x); raster_push_constant.uv_offset[1] = -0.5f / float(atlas_size.y); - RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i], RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i], RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); //draw opaque rd->draw_list_bind_render_pipeline(draw_list, raster_pipeline); rd->draw_list_bind_uniform_set(draw_list, raster_base_uniform, 0); @@ -756,7 +756,7 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade rd->compute_list_bind_uniform_set(compute_list, dilate_uniform_set, 1); push_constant.region_ofs[0] = 0; push_constant.region_ofs[1] = 0; - Vector3i group_size((atlas_size.x - 1) / 8 + 1, (atlas_size.y - 1) / 8 + 1, 1); //restore group size + Vector3i group_size(Math::division_round_up(atlas_size.x, 8), Math::division_round_up(atlas_size.y, 8), 1); //restore group size for (int i = 0; i < atlas_slices; i++) { push_constant.atlas_slice = i; @@ -939,8 +939,8 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh // We use a region with 1/4 the amount of pixels if we're denoising SH lightmaps, as // all four of them are denoised in the shader in one dispatch. const int max_region_size = p_bake_sh ? 512 : 1024; - int x_regions = (p_atlas_size.width - 1) / max_region_size + 1; - int y_regions = (p_atlas_size.height - 1) / max_region_size + 1; + int x_regions = Math::division_round_up(p_atlas_size.width, max_region_size); + int y_regions = Math::division_round_up(p_atlas_size.height, max_region_size); for (int s = 0; s < p_atlas_slices; s++) { p_push_constant.atlas_slice = s; @@ -958,7 +958,7 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh p_rd->compute_list_bind_uniform_set(compute_list, p_compute_base_uniform_set, 0); p_rd->compute_list_bind_uniform_set(compute_list, denoise_uniform_set, 1); p_rd->compute_list_set_push_constant(compute_list, &p_push_constant, sizeof(PushConstant)); - p_rd->compute_list_dispatch(compute_list, (w - 1) / 8 + 1, (h - 1) / 8 + 1, 1); + p_rd->compute_list_dispatch(compute_list, Math::division_round_up(w, 8), Math::division_round_up(h, 8), 1); p_rd->compute_list_end(); p_rd->submit(); @@ -1399,7 +1399,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d rd->free(compute_shader_secondary); \ rd->free(compute_shader_light_probes); - Vector3i group_size((atlas_size.x - 1) / 8 + 1, (atlas_size.y - 1) / 8 + 1, 1); + Vector3i group_size(Math::division_round_up(atlas_size.x, 8), Math::division_round_up(atlas_size.y, 8), 1); rd->submit(); rd->sync(); @@ -1592,10 +1592,10 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d int max_region_size = nearest_power_of_2_templated(int(GLOBAL_GET("rendering/lightmapping/bake_performance/region_size"))); int max_rays = GLOBAL_GET("rendering/lightmapping/bake_performance/max_rays_per_pass"); - int x_regions = (atlas_size.width - 1) / max_region_size + 1; - int y_regions = (atlas_size.height - 1) / max_region_size + 1; + int x_regions = Math::division_round_up(atlas_size.width, max_region_size); + int y_regions = Math::division_round_up(atlas_size.height, max_region_size); - int ray_iterations = (push_constant.ray_count - 1) / max_rays + 1; + int ray_iterations = Math::division_round_up((int32_t)push_constant.ray_count, max_rays); rd->submit(); rd->sync(); @@ -1614,7 +1614,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d push_constant.region_ofs[0] = x; push_constant.region_ofs[1] = y; - group_size = Vector3i((w - 1) / 8 + 1, (h - 1) / 8 + 1, 1); + group_size = Vector3i(Math::division_round_up(w, 8), Math::division_round_up(h, 8), 1); for (int k = 0; k < ray_iterations; k++) { RD::ComputeListID compute_list = rd->compute_list_begin(); @@ -1700,7 +1700,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d push_constant.probe_count = probe_positions.size(); int max_rays = GLOBAL_GET("rendering/lightmapping/bake_performance/max_rays_per_probe_pass"); - int ray_iterations = (push_constant.ray_count - 1) / max_rays + 1; + int ray_iterations = Math::division_round_up((int32_t)push_constant.ray_count, max_rays); for (int i = 0; i < ray_iterations; i++) { RD::ComputeListID compute_list = rd->compute_list_begin(); @@ -1711,7 +1711,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d push_constant.ray_from = i * max_rays; push_constant.ray_to = MIN((i + 1) * max_rays, int32_t(push_constant.ray_count)); rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant)); - rd->compute_list_dispatch(compute_list, (probe_positions.size() - 1) / 64 + 1, 1, 1); + rd->compute_list_dispatch(compute_list, Math::division_round_up(probe_positions.size(), 64), 1, 1); rd->compute_list_end(); //done rd->submit(); @@ -1863,7 +1863,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d seams_push_constant.slice = uint32_t(i * subslices + k); seams_push_constant.debug = debug; - RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); rd->draw_list_bind_uniform_set(draw_list, raster_base_uniform, 0); rd->draw_list_bind_uniform_set(draw_list, blendseams_raster_uniform, 1); diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl index a2a480043a..21e039396d 100644 --- a/modules/lightmapper_rd/lm_compute.glsl +++ b/modules/lightmapper_rd/lm_compute.glsl @@ -264,7 +264,16 @@ uint trace_ray(vec3 p_from, vec3 p_to, bool p_any_hit, out float r_distance, out break; } - bvec3 mask = lessThanEqual(side.xyz, min(side.yzx, side.zxy)); + // There should be only one axis updated at a time for DDA to work properly. + bvec3 mask = bvec3(true, false, false); + float m = side.x; + if (side.y < m) { + m = side.y; + mask = bvec3(false, true, false); + } + if (side.z < m) { + mask = bvec3(false, false, true); + } side += vec3(mask) * delta; icell += ivec3(vec3(mask)) * step; iters++; diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp index 8103799974..4fe8f20723 100644 --- a/modules/lightmapper_rd/register_types.cpp +++ b/modules/lightmapper_rd/register_types.cpp @@ -46,18 +46,18 @@ void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level) { return; } - GLOBAL_DEF("rendering/lightmapping/bake_quality/low_quality_ray_count", 32); - GLOBAL_DEF("rendering/lightmapping/bake_quality/medium_quality_ray_count", 128); - GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_ray_count", 512); - GLOBAL_DEF("rendering/lightmapping/bake_quality/ultra_quality_ray_count", 2048); - GLOBAL_DEF("rendering/lightmapping/bake_performance/max_rays_per_pass", 32); - GLOBAL_DEF("rendering/lightmapping/bake_performance/region_size", 512); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/low_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 32); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/medium_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 128); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/high_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 512); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/ultra_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 2048); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/max_rays_per_pass", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 32); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/region_size", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 512); - GLOBAL_DEF("rendering/lightmapping/bake_quality/low_quality_probe_ray_count", 64); - GLOBAL_DEF("rendering/lightmapping/bake_quality/medium_quality_probe_ray_count", 256); - GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_probe_ray_count", 512); - GLOBAL_DEF("rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count", 2048); - GLOBAL_DEF("rendering/lightmapping/bake_performance/max_rays_per_probe_pass", 64); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/low_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 64); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/medium_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 256); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/high_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 512); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 2048); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/max_rays_per_probe_pass", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/denoising/denoiser", PROPERTY_HINT_ENUM, "JNLM,OIDN"), 0); #ifndef _3D_DISABLED diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 8e1587997b..ac6977504a 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -371,7 +371,7 @@ Ref<Script> CSharpLanguage::make_template(const String &p_template, const String return scr; } -Vector<ScriptLanguage::ScriptTemplate> CSharpLanguage::get_built_in_templates(StringName p_object) { +Vector<ScriptLanguage::ScriptTemplate> CSharpLanguage::get_built_in_templates(const StringName &p_object) { Vector<ScriptLanguage::ScriptTemplate> templates; #ifdef TOOLS_ENABLED for (int i = 0; i < TEMPLATES_ARRAY_SIZE; i++) { @@ -2246,6 +2246,17 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda } else { p_instance_to_update->update(propnames, values); } + } else if (placeholders.size()) { + uint64_t script_modified_time = FileAccess::get_modified_time(get_path()); + uint64_t last_valid_build_time = GDMono::get_singleton()->get_project_assembly_modified_time(); + if (script_modified_time > last_valid_build_time) { + for (PlaceHolderScriptInstance *instance : placeholders) { + Object *owner = instance->get_owner(); + if (owner->get_script_instance() == instance) { + owner->notify_property_list_changed(); + } + } + } } } #endif @@ -2354,6 +2365,8 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) { MethodInfo mi; mi.name = name; + mi.return_val = PropertyInfo::from_dict(method_info_dict["return_val"]); + Array params = method_info_dict["params"]; for (int j = 0; j < params.size(); j++) { diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 401f5c62e5..41e8d63be1 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -423,7 +423,7 @@ public: void get_string_delimiters(List<String> *p_delimiters) const override; bool is_using_templates() override; virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override; - virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override; + virtual Vector<ScriptTemplate> get_built_in_templates(const StringName &p_object) override; /* TODO */ bool validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override { return true; diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs index 147ef852b3..1113629fef 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs @@ -146,7 +146,7 @@ namespace Godot.SourceGenerators DiagnosticSeverity.Error, isEnabledByDefault: true, description, - helpLinkUri: string.Format(_helpLinkFormat, "GD1003")), + helpLinkUri: string.Format(_helpLinkFormat, "GD0103")), location, location?.SourceTree?.FilePath)); } diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj index 9e36497b06..d0972f1eae 100644 --- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj @@ -1,8 +1,8 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <ProjectGuid>{6CE9A984-37B1-4F8A-8FE9-609F05F071B3}</ProjectGuid> - <TargetFramework>netstandard2.0</TargetFramework> - <LangVersion>7.2</LangVersion> + <TargetFramework>net6.0</TargetFramework> + <LangVersion>10</LangVersion> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" ExcludeAssets="runtime" /> diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj index d2132115f3..eb6ac8bafc 100644 --- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj @@ -2,13 +2,10 @@ <PropertyGroup> <ProjectGuid>{B06C2951-C8E3-4F28-80B2-717CF327EB19}</ProjectGuid> <OutputType>Exe</OutputType> - <TargetFramework>net472</TargetFramework> - <LangVersion>7.2</LangVersion> + <TargetFramework>net6.0</TargetFramework> + <LangVersion>10</LangVersion> </PropertyGroup> <ItemGroup> - <Reference Include="System" /> - </ItemGroup> - <ItemGroup> <ProjectReference Include="..\GodotTools.IdeMessaging\GodotTools.IdeMessaging.csproj" /> </ItemGroup> <ItemGroup> diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj index c05096bdcc..22778f21cb 100644 --- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj @@ -1,12 +1,15 @@ <Project Sdk="Microsoft.NET.Sdk"> - <PropertyGroup> - <ProjectGuid>{EAFFF236-FA96-4A4D-BD23-0E51EF988277}</ProjectGuid> - <OutputType>Exe</OutputType> - <TargetFramework>net472</TargetFramework> - <LangVersion>7.2</LangVersion> - </PropertyGroup> - <ItemGroup> - <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" /> - <PackageReference Include="EnvDTE" Version="8.0.2" /> - </ItemGroup> + <PropertyGroup> + <ProjectGuid>{EAFFF236-FA96-4A4D-BD23-0E51EF988277}</ProjectGuid> + <OutputType>Exe</OutputType> + <TargetFramework>net6.0-windows</TargetFramework> + <LangVersion>10</LangVersion> + </PropertyGroup> + <PropertyGroup Condition="Exists('$(SolutionDir)/../../../../bin/GodotSharp/Api/Debug/GodotSharp.dll') And ('$(GodotPlatform)' == 'windows' Or ('$(GodotPlatform)' == '' And '$(OS)' == 'Windows_NT'))"> + <OutputPath>$(SolutionDir)/../../../../bin/GodotSharp/Tools</OutputPath> + <AppendTargetFrameworkToOutputPath>False</AppendTargetFrameworkToOutputPath> + </PropertyGroup> + <ItemGroup> + <PackageReference Include="EnvDTE" Version="17.8.37221" /> + </ItemGroup> </Project> diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs index cc0deb6cc0..8e8eaa79b8 100644 --- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs +++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs @@ -129,7 +129,7 @@ namespace GodotTools.OpenVisualStudio { var mainWindow = dte.MainWindow; mainWindow.Activate(); - SetForegroundWindow(new IntPtr(mainWindow.HWnd)); + SetForegroundWindow(mainWindow.HWnd); MessageFilter.Revoke(); } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 650afb4cdf..5408b9b13e 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -9,6 +9,7 @@ using System.Linq; using GodotTools.Build; using GodotTools.Ides; using GodotTools.Ides.Rider; +using GodotTools.Inspector; using GodotTools.Internals; using GodotTools.ProjectEditor; using JetBrains.Annotations; @@ -45,6 +46,7 @@ namespace GodotTools // TODO Use WeakReference once we have proper serialization. private WeakRef _exportPluginWeak; + private WeakRef _inspectorPluginWeak; public GodotIdeManager GodotIdeManager { get; private set; } @@ -52,6 +54,8 @@ namespace GodotTools public bool SkipBuildBeforePlaying { get; set; } = false; + public DateTime LastValidBuildDateTime { get; private set; } + [UsedImplicitly] private bool CreateProjectSolutionIfNeeded() { @@ -437,6 +441,21 @@ namespace GodotTools } } + private void UpdateLastValidBuildDateTime() + { + var dllName = $"{GodotSharpDirs.ProjectAssemblyName}.dll"; + var path = Path.Combine(GodotSharpDirs.ProjectBaseOutputPath, "Debug", dllName); + LastValidBuildDateTime = File.GetLastWriteTime(path); + } + + private void BuildFinished(BuildResult buildResult) + { + if (buildResult == BuildResult.Success) + { + UpdateLastValidBuildDateTime(); + } + } + private void BuildStateChanged() { if (_bottomPanelBtn != null) @@ -447,6 +466,8 @@ namespace GodotTools { base._EnablePlugin(); + UpdateLastValidBuildDateTime(); + ProjectSettings.SettingsChanged += GodotSharpDirs.DetermineProjectLocation; if (Instance != null) @@ -615,6 +636,12 @@ namespace GodotTools AddExportPlugin(exportPlugin); _exportPluginWeak = WeakRef(exportPlugin); + // Inspector plugin + var inspectorPlugin = new InspectorPlugin(); + AddInspectorPlugin(inspectorPlugin); + _inspectorPluginWeak = WeakRef(inspectorPlugin); + BuildManager.BuildFinished += BuildFinished; + BuildManager.Initialize(); RiderPathManager.Initialize(); @@ -627,6 +654,10 @@ namespace GodotTools base._DisablePlugin(); _editorSettings.SettingsChanged -= OnSettingsChanged; + + // Custom signals aren't automatically disconnected currently. + MSBuildPanel.BuildStateChanged -= BuildStateChanged; + BuildManager.BuildFinished -= BuildFinished; } public override void _ExitTree() @@ -661,6 +692,13 @@ namespace GodotTools _exportPluginWeak.Dispose(); } + if (IsInstanceValid(_inspectorPluginWeak)) + { + (_inspectorPluginWeak.GetRef().AsGodotObject() as InspectorPlugin)?.Dispose(); + + _inspectorPluginWeak.Dispose(); + } + GodotIdeManager?.Dispose(); } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj index 56ae37b4dd..b5567ea3c7 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj +++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj @@ -28,7 +28,7 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="JetBrains.Annotations" Version="2019.1.3.0" ExcludeAssets="runtime" PrivateAssets="all" /> - <PackageReference Include="JetBrains.Rider.PathLocator" Version="1.0.4" /> + <PackageReference Include="JetBrains.Rider.PathLocator" Version="1.0.8" /> <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <Reference Include="GodotSharp"> @@ -49,7 +49,5 @@ <ProjectReference Include="..\GodotTools.IdeMessaging\GodotTools.IdeMessaging.csproj" /> <ProjectReference Include="..\GodotTools.ProjectEditor\GodotTools.ProjectEditor.csproj" /> <ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj" /> - <!-- Include it if this is an SCons build targeting Windows, or if it's not an SCons build but we're on Windows --> - <ProjectReference Include="..\GodotTools.OpenVisualStudio\GodotTools.OpenVisualStudio.csproj" Condition=" '$(GodotPlatform)' == 'windows' Or ( '$(GodotPlatform)' == '' And '$(OS)' == 'Windows_NT' ) " /> </ItemGroup> </Project> diff --git a/modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorOutOfSyncWarning.cs b/modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorOutOfSyncWarning.cs new file mode 100644 index 0000000000..c5c451f143 --- /dev/null +++ b/modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorOutOfSyncWarning.cs @@ -0,0 +1,37 @@ +using Godot; +using GodotTools.Internals; + +namespace GodotTools.Inspector +{ + public partial class InspectorOutOfSyncWarning : HBoxContainer + { + public override void _Ready() + { + SetAnchorsPreset(LayoutPreset.TopWide); + + var iconTexture = GetThemeIcon("StatusWarning", "EditorIcons"); + + var icon = new TextureRect() + { + Texture = iconTexture, + ExpandMode = TextureRect.ExpandModeEnum.FitWidthProportional, + CustomMinimumSize = iconTexture.GetSize(), + }; + + icon.SizeFlagsVertical = SizeFlags.ShrinkCenter; + + var label = new Label() + { + Text = "This inspector might be out of date. Please build the C# project.".TTR(), + AutowrapMode = TextServer.AutowrapMode.WordSmart, + CustomMinimumSize = new Vector2(100f, 0f), + }; + + label.AddThemeColorOverride("font_color", GetThemeColor("warning_color", "Editor")); + label.SizeFlagsHorizontal = SizeFlags.Fill | SizeFlags.Expand; + + AddChild(icon); + AddChild(label); + } + } +} diff --git a/modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorPlugin.cs new file mode 100644 index 0000000000..8282ca6ea6 --- /dev/null +++ b/modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorPlugin.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using Godot; +using GodotTools.Utils; + +namespace GodotTools.Inspector +{ + public partial class InspectorPlugin : EditorInspectorPlugin + { + public override bool _CanHandle(GodotObject godotObject) + { + foreach (var script in EnumerateScripts(godotObject)) + { + if (script is CSharpScript) + { + return true; + } + } + return false; + } + + public override void _ParseBegin(GodotObject godotObject) + { + foreach (var script in EnumerateScripts(godotObject)) + { + if (script is not CSharpScript) continue; + + if (File.GetLastWriteTime(script.ResourcePath) > GodotSharpEditor.Instance.LastValidBuildDateTime) + { + AddCustomControl(new InspectorOutOfSyncWarning()); + break; + } + } + } + + private static IEnumerable<Script> EnumerateScripts(GodotObject godotObject) + { + var script = godotObject.GetScript().As<Script>(); + while (script != null) + { + yield return script; + script = script.GetBaseScript(); + } + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs index a087b20308..968afa664b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs @@ -662,6 +662,19 @@ namespace Godot.Bridge methodInfo.Add("name", method.Name); + var returnVal = new Collections.Dictionary() + { + { "name", method.ReturnVal.Name }, + { "type", (int)method.ReturnVal.Type }, + { "usage", (int)method.ReturnVal.Usage } + }; + if (method.ReturnVal.ClassName != null) + { + returnVal["class_name"] = method.ReturnVal.ClassName; + } + + methodInfo.Add("return_val", returnVal); + var methodParams = new Collections.Array(); if (method.Arguments != null) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs index 104e30981f..8960323754 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs @@ -124,6 +124,29 @@ namespace Godot } /// <summary> + /// Returns the squared distance between this vector and <paramref name="to"/>. + /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if + /// you need to compare vectors or need the squared distance for some formula. + /// </summary> + /// <param name="to">The other vector to use.</param> + /// <returns>The squared distance between the two vectors.</returns> + public readonly int DistanceSquaredTo(Vector2I to) + { + return (to - this).LengthSquared(); + } + + /// <summary> + /// Returns the distance between this vector and <paramref name="to"/>. + /// </summary> + /// <seealso cref="DistanceSquaredTo(Vector2I)"/> + /// <param name="to">The other vector to use.</param> + /// <returns>The distance between the two vectors.</returns> + public readonly real_t DistanceTo(Vector2I to) + { + return (to - this).Length(); + } + + /// <summary> /// Returns the length (magnitude) of this vector. /// </summary> /// <seealso cref="LengthSquared"/> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs index 4af9fd878b..2d7bbc926d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs @@ -132,6 +132,29 @@ namespace Godot } /// <summary> + /// Returns the squared distance between this vector and <paramref name="to"/>. + /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if + /// you need to compare vectors or need the squared distance for some formula. + /// </summary> + /// <param name="to">The other vector to use.</param> + /// <returns>The squared distance between the two vectors.</returns> + public readonly int DistanceSquaredTo(Vector3I to) + { + return (to - this).LengthSquared(); + } + + /// <summary> + /// Returns the distance between this vector and <paramref name="to"/>. + /// </summary> + /// <seealso cref="DistanceSquaredTo(Vector3I)"/> + /// <param name="to">The other vector to use.</param> + /// <returns>The distance between the two vectors.</returns> + public readonly real_t DistanceTo(Vector3I to) + { + return (to - this).Length(); + } + + /// <summary> /// Returns the length (magnitude) of this vector. /// </summary> /// <seealso cref="LengthSquared"/> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs index 7d4d3dd353..9a85f359d7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs @@ -149,6 +149,29 @@ namespace Godot } /// <summary> + /// Returns the squared distance between this vector and <paramref name="to"/>. + /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if + /// you need to compare vectors or need the squared distance for some formula. + /// </summary> + /// <param name="to">The other vector to use.</param> + /// <returns>The squared distance between the two vectors.</returns> + public readonly int DistanceSquaredTo(Vector4I to) + { + return (to - this).LengthSquared(); + } + + /// <summary> + /// Returns the distance between this vector and <paramref name="to"/>. + /// </summary> + /// <seealso cref="DistanceSquaredTo(Vector4I)"/> + /// <param name="to">The other vector to use.</param> + /// <returns>The distance between the two vectors.</returns> + public readonly real_t DistanceTo(Vector4I to) + { + return (to - this).Length(); + } + + /// <summary> /// Returns the length (magnitude) of this vector. /// </summary> /// <seealso cref="LengthSquared"/> diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp index c95e4ff9c9..31307e648d 100644 --- a/modules/multiplayer/scene_replication_interface.cpp +++ b/modules/multiplayer/scene_replication_interface.cpp @@ -707,7 +707,7 @@ MultiplayerSynchronizer *SceneReplicationInterface::_find_synchronizer(int p_pee return sync; } -void SceneReplicationInterface::_send_delta(int p_peer, const HashSet<ObjectID> p_synchronizers, uint64_t p_usec, const HashMap<ObjectID, uint64_t> p_last_watch_usecs) { +void SceneReplicationInterface::_send_delta(int p_peer, const HashSet<ObjectID> &p_synchronizers, uint64_t p_usec, const HashMap<ObjectID, uint64_t> &p_last_watch_usecs) { MAKE_ROOM(/* header */ 1 + /* element */ 4 + 8 + 4 + delta_mtu); uint8_t *ptr = packet_cache.ptrw(); ptr[0] = SceneMultiplayer::NETWORK_COMMAND_SYNC | (1 << SceneMultiplayer::CMD_FLAG_0_SHIFT); @@ -799,7 +799,7 @@ Error SceneReplicationInterface::on_delta_receive(int p_from, const uint8_t *p_b return OK; } -void SceneReplicationInterface::_send_sync(int p_peer, const HashSet<ObjectID> p_synchronizers, uint16_t p_sync_net_time, uint64_t p_usec) { +void SceneReplicationInterface::_send_sync(int p_peer, const HashSet<ObjectID> &p_synchronizers, uint16_t p_sync_net_time, uint64_t p_usec) { MAKE_ROOM(/* header */ 3 + /* element */ 4 + 4 + sync_mtu); uint8_t *ptr = packet_cache.ptrw(); ptr[0] = SceneMultiplayer::NETWORK_COMMAND_SYNC; diff --git a/modules/multiplayer/scene_replication_interface.h b/modules/multiplayer/scene_replication_interface.h index 3b3ec6a9ef..31211bb108 100644 --- a/modules/multiplayer/scene_replication_interface.h +++ b/modules/multiplayer/scene_replication_interface.h @@ -101,8 +101,8 @@ private: bool _verify_synchronizer(int p_peer, MultiplayerSynchronizer *p_sync, uint32_t &r_net_id); MultiplayerSynchronizer *_find_synchronizer(int p_peer, uint32_t p_net_ida); - void _send_sync(int p_peer, const HashSet<ObjectID> p_synchronizers, uint16_t p_sync_net_time, uint64_t p_usec); - void _send_delta(int p_peer, const HashSet<ObjectID> p_synchronizers, uint64_t p_usec, const HashMap<ObjectID, uint64_t> p_last_watch_usecs); + void _send_sync(int p_peer, const HashSet<ObjectID> &p_synchronizers, uint16_t p_sync_net_time, uint64_t p_usec); + void _send_delta(int p_peer, const HashSet<ObjectID> &p_synchronizers, uint64_t p_usec, const HashMap<ObjectID, uint64_t> &p_last_watch_usecs); Error _make_spawn_packet(Node *p_node, MultiplayerSpawner *p_spawner, int &r_len); Error _make_despawn_packet(Node *p_node, int &r_len); Error _send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable); diff --git a/modules/navigation/nav_agent.cpp b/modules/navigation/nav_agent.cpp index cb219ac6c0..5a87ff6c4b 100644 --- a/modules/navigation/nav_agent.cpp +++ b/modules/navigation/nav_agent.cpp @@ -326,7 +326,7 @@ const Dictionary NavAgent::get_avoidance_data() const { _avoidance_data["new_velocity"] = Vector3(rvo_agent_3d.newVelocity_.x(), rvo_agent_3d.newVelocity_.y(), rvo_agent_3d.newVelocity_.z()); _avoidance_data["velocity"] = Vector3(rvo_agent_3d.velocity_.x(), rvo_agent_3d.velocity_.y(), rvo_agent_3d.velocity_.z()); _avoidance_data["position"] = Vector3(rvo_agent_3d.position_.x(), rvo_agent_3d.position_.y(), rvo_agent_3d.position_.z()); - _avoidance_data["prefered_velocity"] = Vector3(rvo_agent_3d.prefVelocity_.x(), rvo_agent_3d.prefVelocity_.y(), rvo_agent_3d.prefVelocity_.z()); + _avoidance_data["preferred_velocity"] = Vector3(rvo_agent_3d.prefVelocity_.x(), rvo_agent_3d.prefVelocity_.y(), rvo_agent_3d.prefVelocity_.z()); _avoidance_data["radius"] = float(rvo_agent_3d.radius_); _avoidance_data["time_horizon_agents"] = float(rvo_agent_3d.timeHorizon_); _avoidance_data["time_horizon_obstacles"] = 0.0; @@ -341,7 +341,7 @@ const Dictionary NavAgent::get_avoidance_data() const { _avoidance_data["new_velocity"] = Vector3(rvo_agent_2d.newVelocity_.x(), 0.0, rvo_agent_2d.newVelocity_.y()); _avoidance_data["velocity"] = Vector3(rvo_agent_2d.velocity_.x(), 0.0, rvo_agent_2d.velocity_.y()); _avoidance_data["position"] = Vector3(rvo_agent_2d.position_.x(), 0.0, rvo_agent_2d.position_.y()); - _avoidance_data["prefered_velocity"] = Vector3(rvo_agent_2d.prefVelocity_.x(), 0.0, rvo_agent_2d.prefVelocity_.y()); + _avoidance_data["preferred_velocity"] = Vector3(rvo_agent_2d.prefVelocity_.x(), 0.0, rvo_agent_2d.prefVelocity_.y()); _avoidance_data["radius"] = float(rvo_agent_2d.radius_); _avoidance_data["time_horizon_agents"] = float(rvo_agent_2d.timeHorizon_); _avoidance_data["time_horizon_obstacles"] = float(rvo_agent_2d.timeHorizonObst_); diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp index 1b0c5cb9e3..0443fec4a0 100644 --- a/modules/noise/noise_texture_2d.cpp +++ b/modules/noise/noise_texture_2d.cpp @@ -49,10 +49,6 @@ NoiseTexture2D::~NoiseTexture2D() { } void NoiseTexture2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture2D::_update_texture); - ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture2D::_generate_texture); - ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture2D::_thread_done); - ClassDB::bind_method(D_METHOD("set_width", "width"), &NoiseTexture2D::set_width); ClassDB::bind_method(D_METHOD("set_height", "height"), &NoiseTexture2D::set_height); @@ -138,7 +134,7 @@ void NoiseTexture2D::_thread_done(const Ref<Image> &p_image) { void NoiseTexture2D::_thread_function(void *p_ud) { NoiseTexture2D *tex = static_cast<NoiseTexture2D *>(p_ud); - tex->call_deferred(SNAME("_thread_done"), tex->_generate_texture()); + callable_mp(tex, &NoiseTexture2D::_thread_done).call_deferred(tex->_generate_texture()); } void NoiseTexture2D::_queue_update() { @@ -147,7 +143,7 @@ void NoiseTexture2D::_queue_update() { } update_queued = true; - call_deferred(SNAME("_update_texture")); + callable_mp(this, &NoiseTexture2D::_update_texture).call_deferred(); } Ref<Image> NoiseTexture2D::_generate_texture() { diff --git a/modules/noise/noise_texture_3d.cpp b/modules/noise/noise_texture_3d.cpp index 33e257a5c2..f2e01b0612 100644 --- a/modules/noise/noise_texture_3d.cpp +++ b/modules/noise/noise_texture_3d.cpp @@ -49,10 +49,6 @@ NoiseTexture3D::~NoiseTexture3D() { } void NoiseTexture3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture3D::_update_texture); - ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture3D::_generate_texture); - ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture3D::_thread_done); - ClassDB::bind_method(D_METHOD("set_width", "width"), &NoiseTexture3D::set_width); ClassDB::bind_method(D_METHOD("set_height", "height"), &NoiseTexture3D::set_height); ClassDB::bind_method(D_METHOD("set_depth", "depth"), &NoiseTexture3D::set_depth); @@ -126,7 +122,7 @@ void NoiseTexture3D::_thread_done(const TypedArray<Image> &p_data) { void NoiseTexture3D::_thread_function(void *p_ud) { NoiseTexture3D *tex = static_cast<NoiseTexture3D *>(p_ud); - tex->call_deferred(SNAME("_thread_done"), tex->_generate_texture()); + callable_mp(tex, &NoiseTexture3D::_thread_done).call_deferred(tex->_generate_texture()); } void NoiseTexture3D::_queue_update() { @@ -135,7 +131,7 @@ void NoiseTexture3D::_queue_update() { } update_queued = true; - call_deferred(SNAME("_update_texture")); + callable_mp(this, &NoiseTexture3D::_update_texture).call_deferred(); } TypedArray<Image> NoiseTexture3D::_generate_texture() { diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index c64b6de78c..4cf810f905 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -120,6 +120,7 @@ env_openxr.add_source_files(module_obj, "extensions/openxr_wmr_controller_extens env_openxr.add_source_files(module_obj, "extensions/openxr_ml2_controller_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_extension_wrapper_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_api_extension.cpp") +env_openxr.add_source_files(module_obj, "extensions/openxr_meta_controller_extension.cpp") env.modules_sources += module_obj diff --git a/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp b/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp index df607b0def..75cfb095bb 100644 --- a/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp +++ b/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp @@ -360,6 +360,9 @@ void OpenXRInteractionProfileMetadata::_register_core_metadata() { register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + register_io_path("/interaction_profiles/oculus/touch_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); register_io_path("/interaction_profiles/oculus/touch_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); diff --git a/modules/openxr/doc_classes/OpenXRHand.xml b/modules/openxr/doc_classes/OpenXRHand.xml index cc7766507f..eb7decd30d 100644 --- a/modules/openxr/doc_classes/OpenXRHand.xml +++ b/modules/openxr/doc_classes/OpenXRHand.xml @@ -1,10 +1,12 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="OpenXRHand" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> - Node supporting finger tracking in OpenXR. + Node supporting hand and finger tracking in OpenXR. </brief_description> <description> - This node enables OpenXR's hand tracking functionality. The node should be a child node of an [XROrigin3D] node, tracking will update its position to where the player's actual hand is positioned. This node also updates the skeleton of a properly skinned hand model. The hand mesh should be a child node of this node. + This node enables OpenXR's hand tracking functionality. The node should be a child node of an [XROrigin3D] node, tracking will update its position to the player's tracked hand Palm joint location (the center of the middle finger's metacarpal bone). This node also updates the skeleton of a properly skinned hand or avatar model. + If the skeleton is a hand (one of the hand bones is the root node of the skeleton), then the skeleton will be placed relative to the hand palm location and the hand mesh and skeleton should be children of the OpenXRHand node. + If the hand bones are part of a full skeleton, then the root of the hand will keep its location with the assumption that IK is used to position the hand and arm. </description> <tutorials> </tutorials> @@ -18,6 +20,9 @@ <member name="motion_range" type="int" setter="set_motion_range" getter="get_motion_range" enum="OpenXRHand.MotionRange" default="0"> Set the motion range (if supported) limiting the hand motion. </member> + <member name="skeleton_rig" type="int" setter="set_skeleton_rig" getter="get_skeleton_rig" enum="OpenXRHand.SkeletonRig" default="0"> + Set the type of skeleton rig the [member hand_skeleton] is compliant with. + </member> </members> <constants> <constant name="HAND_LEFT" value="0" enum="Hands"> @@ -38,5 +43,14 @@ <constant name="MOTION_RANGE_MAX" value="2" enum="MotionRange"> Maximum supported motion ranges. </constant> + <constant name="SKELETON_RIG_OPENXR" value="0" enum="SkeletonRig"> + An OpenXR compliant skeleton. + </constant> + <constant name="SKELETON_RIG_HUMANOID" value="1" enum="SkeletonRig"> + A [SkeletonProfileHumanoid] compliant skeleton. + </constant> + <constant name="SKELETON_RIG_MAX" value="2" enum="SkeletonRig"> + Maximum supported hands. + </constant> </constants> </class> diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml index 666d20d7e7..caaaeb90ff 100644 --- a/modules/openxr/doc_classes/OpenXRInterface.xml +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -71,6 +71,13 @@ If handtracking is enabled, returns the rotation of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. </description> </method> + <method name="get_hand_tracking_source" qualifiers="const"> + <return type="int" enum="OpenXRInterface.HandTrackedSource" /> + <param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" /> + <description> + If handtracking is enabled and hand tracking source is supported, gets the source of the hand tracking data for [param hand]. + </description> + </method> <method name="get_motion_range" qualifiers="const"> <return type="int" enum="OpenXRInterface.HandMotionRange" /> <param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" /> @@ -177,10 +184,25 @@ Maximum value for the hand enum. </constant> <constant name="HAND_MOTION_RANGE_UNOBSTRUCTED" value="0" enum="HandMotionRange"> + Full hand range, if user closes their hands, we make a full fist. </constant> <constant name="HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER" value="1" enum="HandMotionRange"> + Conform to controller, if user closes their hands, the tracked data conforms to the shape of the controller. </constant> <constant name="HAND_MOTION_RANGE_MAX" value="2" enum="HandMotionRange"> + Maximum value for the motion range enum. + </constant> + <constant name="HAND_TRACKED_SOURCE_UNKNOWN" value="0" enum="HandTrackedSource"> + The source of hand tracking data is unknown (the extension is likely unsupported). + </constant> + <constant name="HAND_TRACKED_SOURCE_UNOBSTRUCTED" value="1" enum="HandTrackedSource"> + The source of hand tracking is unobstructed, this means that an accurate method of hand tracking is used, e.g. optical hand tracking, data gloves, etc. + </constant> + <constant name="HAND_TRACKED_SOURCE_CONTROLLER" value="2" enum="HandTrackedSource"> + The source of hand tracking is a controller, bone positions are inferred from controller inputs. + </constant> + <constant name="HAND_TRACKED_SOURCE_MAX" value="3" enum="HandTrackedSource"> + Maximum value for the hand tracked source enum. </constant> <constant name="HAND_JOINT_PALM" value="0" enum="HandJoints"> Palm joint. diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp index 64e07eff21..dacf284046 100644 --- a/modules/openxr/editor/openxr_action_map_editor.cpp +++ b/modules/openxr/editor/openxr_action_map_editor.cpp @@ -43,7 +43,6 @@ void OpenXRActionMapEditor::_bind_methods() { ClassDB::bind_method("_add_interaction_profile_editor", &OpenXRActionMapEditor::_add_interaction_profile_editor); ClassDB::bind_method(D_METHOD("_add_action_set", "name"), &OpenXRActionMapEditor::_add_action_set); - ClassDB::bind_method(D_METHOD("_set_focus_on_action_set", "action_set"), &OpenXRActionMapEditor::_set_focus_on_action_set); ClassDB::bind_method(D_METHOD("_remove_action_set", "name"), &OpenXRActionMapEditor::_remove_action_set); ClassDB::bind_method(D_METHOD("_do_add_action_set_editor", "action_set_editor"), &OpenXRActionMapEditor::_do_add_action_set_editor); @@ -175,7 +174,7 @@ void OpenXRActionMapEditor::_on_add_action_set() { // Make sure our action set is the current tab tabs->set_current_tab(0); - call_deferred("_set_focus_on_action_set", new_action_set_editor); + callable_mp(this, &OpenXRActionMapEditor::_set_focus_on_action_set).call_deferred(new_action_set_editor); } void OpenXRActionMapEditor::_set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor) { diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp index 08fcdaf771..51642d8503 100644 --- a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp +++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp @@ -77,7 +77,7 @@ void OpenXRSelectInteractionProfileDialog::open(PackedStringArray p_do_not_inclu // in with the new PackedStringArray interaction_profiles = OpenXRInteractionProfileMetadata::get_singleton()->get_interaction_profile_paths(); for (int i = 0; i < interaction_profiles.size(); i++) { - String path = interaction_profiles[i]; + const String &path = interaction_profiles[i]; if (!p_do_not_include.has(path)) { Button *ip_button = memnew(Button); ip_button->set_flat(true); diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp index 0d667b56c6..04fc4bf890 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp @@ -60,6 +60,7 @@ HashMap<String, bool *> OpenXRHandTrackingExtension::get_requested_extensions() request_extensions[XR_EXT_HAND_TRACKING_EXTENSION_NAME] = &hand_tracking_ext; request_extensions[XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME] = &hand_motion_range_ext; + request_extensions[XR_EXT_HAND_TRACKING_DATA_SOURCE_EXTENSION_NAME] = &hand_tracking_source_ext; return request_extensions; } @@ -137,20 +138,32 @@ void OpenXRHandTrackingExtension::on_process() { for (int i = 0; i < OPENXR_MAX_TRACKED_HANDS; i++) { if (hand_trackers[i].hand_tracker == XR_NULL_HANDLE) { - XrHandTrackerCreateInfoEXT createInfo = { + void *next_pointer = nullptr; + + // Originally not all XR runtimes supported hand tracking data sourced both from controllers and normal hand tracking. + // With this extension we can indicate we accept input from both sources so hand tracking data is consistently provided + // on runtimes that support this. + XrHandTrackingDataSourceEXT data_sources[2] = { XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT, XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT }; + XrHandTrackingDataSourceInfoEXT data_source_info = { XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT, next_pointer, 2, data_sources }; + if (hand_tracking_source_ext) { + // If supported include this info + next_pointer = &data_source_info; + } + + XrHandTrackerCreateInfoEXT create_info = { XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, // type - nullptr, // next + next_pointer, // next i == 0 ? XR_HAND_LEFT_EXT : XR_HAND_RIGHT_EXT, // hand XR_HAND_JOINT_SET_DEFAULT_EXT, // handJointSet }; - result = xrCreateHandTrackerEXT(OpenXRAPI::get_singleton()->get_session(), &createInfo, &hand_trackers[i].hand_tracker); + result = xrCreateHandTrackerEXT(OpenXRAPI::get_singleton()->get_session(), &create_info, &hand_trackers[i].hand_tracker); if (XR_FAILED(result)) { // not successful? then we do nothing. print_line("OpenXR: Failed to obtain hand tracking information [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); hand_trackers[i].is_initialized = false; } else { - void *next_pointer = nullptr; + next_pointer = nullptr; hand_trackers[i].velocities.type = XR_TYPE_HAND_JOINT_VELOCITIES_EXT; hand_trackers[i].velocities.next = next_pointer; @@ -158,6 +171,14 @@ void OpenXRHandTrackingExtension::on_process() { hand_trackers[i].velocities.jointVelocities = hand_trackers[i].joint_velocities; next_pointer = &hand_trackers[i].velocities; + if (hand_tracking_source_ext) { + hand_trackers[i].data_source.type = XR_TYPE_HAND_TRACKING_DATA_SOURCE_STATE_EXT; + hand_trackers[i].data_source.next = next_pointer; + hand_trackers[i].data_source.isActive = false; + hand_trackers[i].data_source.dataSource = XrHandTrackingDataSourceEXT(0); + next_pointer = &hand_trackers[i].data_source; + } + hand_trackers[i].locations.type = XR_TYPE_HAND_JOINT_LOCATIONS_EXT; hand_trackers[i].locations.next = next_pointer; hand_trackers[i].locations.isActive = false; @@ -171,14 +192,9 @@ void OpenXRHandTrackingExtension::on_process() { if (hand_trackers[i].is_initialized) { void *next_pointer = nullptr; - XrHandJointsMotionRangeInfoEXT motionRangeInfo; - + XrHandJointsMotionRangeInfoEXT motion_range_info = { XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT, next_pointer, hand_trackers[i].motion_range }; if (hand_motion_range_ext) { - motionRangeInfo.type = XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT; - motionRangeInfo.next = next_pointer; - motionRangeInfo.handJointsMotionRange = hand_trackers[i].motion_range; - - next_pointer = &motionRangeInfo; + next_pointer = &motion_range_info; } XrHandJointsLocateInfoEXT locateInfo = { @@ -240,6 +256,25 @@ XrHandJointsMotionRangeEXT OpenXRHandTrackingExtension::get_motion_range(HandTra return hand_trackers[p_hand].motion_range; } +OpenXRHandTrackingExtension::HandTrackedSource OpenXRHandTrackingExtension::get_hand_tracking_source(HandTrackedHands p_hand) const { + ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, OPENXR_SOURCE_UNKNOWN); + + if (hand_tracking_source_ext && hand_trackers[p_hand].data_source.isActive) { + switch (hand_trackers[p_hand].data_source.dataSource) { + case XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT: + return OPENXR_SOURCE_UNOBSTRUCTED; + + case XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT: + return OPENXR_SOURCE_CONTROLLER; + + default: + return OPENXR_SOURCE_UNKNOWN; + } + } + + return OPENXR_SOURCE_UNKNOWN; +} + void OpenXRHandTrackingExtension::set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range) { ERR_FAIL_UNSIGNED_INDEX(p_hand, OPENXR_MAX_TRACKED_HANDS); hand_trackers[p_hand].motion_range = p_motion_range; diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.h b/modules/openxr/extensions/openxr_hand_tracking_extension.h index f9b26fd604..967538b377 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.h +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.h @@ -43,9 +43,17 @@ public: OPENXR_MAX_TRACKED_HANDS }; + enum HandTrackedSource { + OPENXR_SOURCE_UNKNOWN, + OPENXR_SOURCE_UNOBSTRUCTED, + OPENXR_SOURCE_CONTROLLER, + OPENXR_SOURCE_MAX + }; + struct HandTracker { bool is_initialized = false; XrHandJointsMotionRangeEXT motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT; + HandTrackedSource source = OPENXR_SOURCE_UNKNOWN; XrHandTrackerEXT hand_tracker = XR_NULL_HANDLE; XrHandJointLocationEXT joint_locations[XR_HAND_JOINT_COUNT_EXT]; @@ -53,6 +61,7 @@ public: XrHandJointVelocitiesEXT velocities; XrHandJointLocationsEXT locations; + XrHandTrackingDataSourceStateEXT data_source; }; static OpenXRHandTrackingExtension *get_singleton(); @@ -77,6 +86,8 @@ public: XrHandJointsMotionRangeEXT get_motion_range(HandTrackedHands p_hand) const; void set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range); + HandTrackedSource get_hand_tracking_source(HandTrackedHands p_hand) const; + XrSpaceLocationFlags get_hand_joint_location_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; Quaternion get_hand_joint_rotation(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; Vector3 get_hand_joint_position(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; @@ -96,6 +107,7 @@ private: // related extensions bool hand_tracking_ext = false; bool hand_motion_range_ext = false; + bool hand_tracking_source_ext = false; // functions void cleanup_hand_tracking(); diff --git a/modules/openxr/extensions/openxr_meta_controller_extension.cpp b/modules/openxr/extensions/openxr_meta_controller_extension.cpp new file mode 100644 index 0000000000..72dc74bf64 --- /dev/null +++ b/modules/openxr/extensions/openxr_meta_controller_extension.cpp @@ -0,0 +1,184 @@ +/**************************************************************************/ +/* openxr_meta_controller_extension.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "openxr_meta_controller_extension.h" + +#include "../action_map/openxr_interaction_profile_metadata.h" + +HashMap<String, bool *> OpenXRMetaControllerExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + request_extensions[XR_FB_TOUCH_CONTROLLER_PROXIMITY_EXTENSION_NAME] = &available[META_TOUCH_PROXIMITY]; + request_extensions[XR_FB_TOUCH_CONTROLLER_PRO_EXTENSION_NAME] = &available[META_TOUCH_PRO]; + request_extensions[XR_META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME] = &available[META_TOUCH_PLUS]; + + return request_extensions; +} + +bool OpenXRMetaControllerExtension::is_available(MetaControllers p_type) { + return available[p_type]; +} + +void OpenXRMetaControllerExtension::on_register_metadata() { + OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton(); + ERR_FAIL_NULL(metadata); + + // Note, we register controllers regardless if they are supported on the current hardware. + + // Normal touch controller is part of the core spec, but we do have some extensions. + metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger proximity", "/user/hand/left", "/user/hand/left/input/trigger/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger proximity", "/user/hand/right", "/user/hand/right/input/trigger/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Thumb proximity", "/user/hand/left", "/user/hand/left/input/thumb_fb/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Thumb proximity", "/user/hand/right", "/user/hand/right/input/thumb_fb/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL); + + // Touch controller pro (Quest Pro) + metadata->register_interaction_profile("Touch controller pro", "/interaction_profiles/facebook/touch_controller_pro", "XR_FB_touch_controller_pro"); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger proximity", "/user/hand/left", "/user/hand/left/input/trigger/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger curl", "/user/hand/left", "/user/hand/left/input/trigger/curl_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger slide", "/user/hand/left", "/user/hand/left/input/trigger/slide_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger force", "/user/hand/left", "/user/hand/left/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger proximity", "/user/hand/right", "/user/hand/right/input/trigger/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger curl", "/user/hand/right", "/user/hand/right/input/trigger/curl_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger slide", "/user/hand/right", "/user/hand/right/input/trigger/slide_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger force", "/user/hand/right", "/user/hand/right/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumb proximity", "/user/hand/left", "/user/hand/left/input/thumb_fb/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumb proximity", "/user/hand/right", "/user/hand/right/input/thumb_fb/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick X", "/user/hand/left", "/user/hand/left/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick Y", "/user/hand/left", "/user/hand/left/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick X", "/user/hand/right", "/user/hand/right/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick Y", "/user/hand/right", "/user/hand/right/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest force", "/user/hand/left", "/user/hand/left/input/thumbrest/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest force", "/user/hand/right", "/user/hand/right/input/thumbrest/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Stylus force", "/user/hand/left", "/user/hand/left/input/stylus_fb/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Stylus force", "/user/hand/right", "/user/hand/right/input/stylus_fb/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic trigger output", "/user/hand/left", "/user/hand/left/output/haptic_trigger_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic thumb output", "/user/hand/left", "/user/hand/left/output/haptic_thumb_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic trigger output", "/user/hand/right", "/user/hand/right/output/haptic_trigger_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic thumb output", "/user/hand/right", "/user/hand/right/output/haptic_thumb_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + + // Touch controller plus (Quest 3) + metadata->register_interaction_profile("Touch controller plus", "/interaction_profiles/meta/touch_controller_plus", "XR_META_touch_controller_plus"); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger proximity", "/user/hand/left", "/user/hand/left/input/trigger/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger curl", "/user/hand/left", "/user/hand/left/input/trigger/curl_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger slide", "/user/hand/left", "/user/hand/left/input/trigger/slide_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger force", "/user/hand/left", "/user/hand/left/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger proximity", "/user/hand/right", "/user/hand/right/input/trigger/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger curl", "/user/hand/right", "/user/hand/right/input/trigger/curl_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger slide", "/user/hand/right", "/user/hand/right/input/trigger/slide_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger force", "/user/hand/right", "/user/hand/right/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumb proximity", "/user/hand/left", "/user/hand/left/input/thumb_meta/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumb proximity", "/user/hand/right", "/user/hand/right/input/thumb_meta/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick X", "/user/hand/left", "/user/hand/left/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick Y", "/user/hand/left", "/user/hand/left/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick X", "/user/hand/right", "/user/hand/right/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick Y", "/user/hand/right", "/user/hand/right/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); +} diff --git a/modules/openxr/extensions/openxr_meta_controller_extension.h b/modules/openxr/extensions/openxr_meta_controller_extension.h new file mode 100644 index 0000000000..7a60d2a0b9 --- /dev/null +++ b/modules/openxr/extensions/openxr_meta_controller_extension.h @@ -0,0 +1,55 @@ +/**************************************************************************/ +/* openxr_meta_controller_extension.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef OPENXR_META_CONTROLLER_EXTENSION_H +#define OPENXR_META_CONTROLLER_EXTENSION_H + +#include "openxr_extension_wrapper.h" + +class OpenXRMetaControllerExtension : public OpenXRExtensionWrapper { +public: + enum MetaControllers { + META_TOUCH_PROXIMITY, // Proximity extensions for normal touch controllers + META_TOUCH_PRO, // Touch controller for the Quest Pro + META_TOUCH_PLUS, // Touch controller for the Quest Plus + META_MAX_CONTROLLERS + }; + + virtual HashMap<String, bool *> get_requested_extensions() override; + + bool is_available(MetaControllers p_type); + + virtual void on_register_metadata() override; + +private: + bool available[META_MAX_CONTROLLERS] = { false, false, false }; +}; + +#endif // OPENXR_META_CONTROLLER_EXTENSION_H diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 66f8192c9e..ceeb1b0278 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -77,6 +77,8 @@ void OpenXRInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("set_motion_range", "hand", "motion_range"), &OpenXRInterface::set_motion_range); ClassDB::bind_method(D_METHOD("get_motion_range", "hand"), &OpenXRInterface::get_motion_range); + ClassDB::bind_method(D_METHOD("get_hand_tracking_source", "hand"), &OpenXRInterface::get_hand_tracking_source); + ClassDB::bind_method(D_METHOD("get_hand_joint_flags", "hand", "joint"), &OpenXRInterface::get_hand_joint_flags); ClassDB::bind_method(D_METHOD("get_hand_joint_rotation", "hand", "joint"), &OpenXRInterface::get_hand_joint_rotation); @@ -97,6 +99,11 @@ void OpenXRInterface::_bind_methods() { BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER); BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_MAX); + BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_UNKNOWN); + BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_UNOBSTRUCTED); + BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_CONTROLLER); + BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_MAX); + BIND_ENUM_CONSTANT(HAND_JOINT_PALM); BIND_ENUM_CONSTANT(HAND_JOINT_WRIST); BIND_ENUM_CONSTANT(HAND_JOINT_THUMB_METACARPAL); @@ -1269,6 +1276,27 @@ OpenXRInterface::HandMotionRange OpenXRInterface::get_motion_range(const Hand p_ return HAND_MOTION_RANGE_MAX; } +OpenXRInterface::HandTrackedSource OpenXRInterface::get_hand_tracking_source(const Hand p_hand) const { + ERR_FAIL_INDEX_V(p_hand, HAND_MAX, HAND_TRACKED_SOURCE_UNKNOWN); + + OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); + if (hand_tracking_ext && hand_tracking_ext->get_active()) { + OpenXRHandTrackingExtension::HandTrackedSource source = hand_tracking_ext->get_hand_tracking_source(OpenXRHandTrackingExtension::HandTrackedHands(p_hand)); + switch (source) { + case OpenXRHandTrackingExtension::OPENXR_SOURCE_UNOBSTRUCTED: + return HAND_TRACKED_SOURCE_UNOBSTRUCTED; + case OpenXRHandTrackingExtension::OPENXR_SOURCE_CONTROLLER: + return HAND_TRACKED_SOURCE_CONTROLLER; + case OpenXRHandTrackingExtension::OPENXR_SOURCE_UNKNOWN: + return HAND_TRACKED_SOURCE_UNKNOWN; + default: + ERR_FAIL_V_MSG(HAND_TRACKED_SOURCE_UNKNOWN, "Unknown hand tracking source returned by OpenXR"); + } + } + + return HAND_TRACKED_SOURCE_UNKNOWN; +} + BitField<OpenXRInterface::HandJointFlags> OpenXRInterface::get_hand_joint_flags(Hand p_hand, HandJoints p_joint) const { BitField<OpenXRInterface::HandJointFlags> bits; diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h index 489d0845ba..ca95fdf04d 100644 --- a/modules/openxr/openxr_interface.h +++ b/modules/openxr/openxr_interface.h @@ -194,6 +194,15 @@ public: void set_motion_range(const Hand p_hand, const HandMotionRange p_motion_range); HandMotionRange get_motion_range(const Hand p_hand) const; + enum HandTrackedSource { + HAND_TRACKED_SOURCE_UNKNOWN, + HAND_TRACKED_SOURCE_UNOBSTRUCTED, + HAND_TRACKED_SOURCE_CONTROLLER, + HAND_TRACKED_SOURCE_MAX + }; + + HandTrackedSource get_hand_tracking_source(const Hand p_hand) const; + enum HandJoints { HAND_JOINT_PALM = 0, HAND_JOINT_WRIST = 1, @@ -248,6 +257,7 @@ public: VARIANT_ENUM_CAST(OpenXRInterface::Hand) VARIANT_ENUM_CAST(OpenXRInterface::HandMotionRange) +VARIANT_ENUM_CAST(OpenXRInterface::HandTrackedSource) VARIANT_ENUM_CAST(OpenXRInterface::HandJoints) VARIANT_BITFIELD_CAST(OpenXRInterface::HandJointFlags) diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp index 544932bdeb..5cc793dca3 100644 --- a/modules/openxr/register_types.cpp +++ b/modules/openxr/register_types.cpp @@ -49,6 +49,7 @@ #include "extensions/openxr_htc_controller_extension.h" #include "extensions/openxr_htc_vive_tracker_extension.h" #include "extensions/openxr_huawei_controller_extension.h" +#include "extensions/openxr_meta_controller_extension.h" #include "extensions/openxr_ml2_controller_extension.h" #include "extensions/openxr_palm_pose_extension.h" #include "extensions/openxr_pico_controller_extension.h" @@ -115,6 +116,7 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { OpenXRAPI::register_extension_wrapper(memnew(OpenXRDisplayRefreshRateExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRWMRControllerExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRML2ControllerExtension)); + OpenXRAPI::register_extension_wrapper(memnew(OpenXRMetaControllerExtension)); // register gated extensions if (GLOBAL_GET("xr/openxr/extensions/eye_gaze_interaction") && (!OS::get_singleton()->has_feature("mobile") || OS::get_singleton()->has_feature(XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME))) { diff --git a/modules/openxr/scene/openxr_hand.cpp b/modules/openxr/scene/openxr_hand.cpp index c48fac8055..8ce33b55c3 100644 --- a/modules/openxr/scene/openxr_hand.cpp +++ b/modules/openxr/scene/openxr_hand.cpp @@ -46,9 +46,13 @@ void OpenXRHand::_bind_methods() { ClassDB::bind_method(D_METHOD("set_motion_range", "motion_range"), &OpenXRHand::set_motion_range); ClassDB::bind_method(D_METHOD("get_motion_range"), &OpenXRHand::get_motion_range); + ClassDB::bind_method(D_METHOD("set_skeleton_rig", "skeleton_rig"), &OpenXRHand::set_skeleton_rig); + ClassDB::bind_method(D_METHOD("get_skeleton_rig"), &OpenXRHand::get_skeleton_rig); + ADD_PROPERTY(PropertyInfo(Variant::INT, "hand", PROPERTY_HINT_ENUM, "Left,Right"), "set_hand", "get_hand"); ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_range", PROPERTY_HINT_ENUM, "Unobstructed,Conform to controller"), "set_motion_range", "get_motion_range"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "hand_skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"), "set_hand_skeleton", "get_hand_skeleton"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton_rig", PROPERTY_HINT_ENUM, "OpenXR,Humanoid"), "set_skeleton_rig", "get_skeleton_rig"); BIND_ENUM_CONSTANT(HAND_LEFT); BIND_ENUM_CONSTANT(HAND_RIGHT); @@ -57,6 +61,10 @@ void OpenXRHand::_bind_methods() { BIND_ENUM_CONSTANT(MOTION_RANGE_UNOBSTRUCTED); BIND_ENUM_CONSTANT(MOTION_RANGE_CONFORM_TO_CONTROLLER); BIND_ENUM_CONSTANT(MOTION_RANGE_MAX); + + BIND_ENUM_CONSTANT(SKELETON_RIG_OPENXR); + BIND_ENUM_CONSTANT(SKELETON_RIG_HUMANOID); + BIND_ENUM_CONSTANT(SKELETON_RIG_MAX); } OpenXRHand::OpenXRHand() { @@ -64,7 +72,7 @@ OpenXRHand::OpenXRHand() { hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); } -void OpenXRHand::set_hand(const Hands p_hand) { +void OpenXRHand::set_hand(Hands p_hand) { ERR_FAIL_INDEX(p_hand, HAND_MAX); hand = p_hand; @@ -80,7 +88,7 @@ void OpenXRHand::set_hand_skeleton(const NodePath &p_hand_skeleton) { // TODO if inside tree call _get_bones() } -void OpenXRHand::set_motion_range(const MotionRange p_motion_range) { +void OpenXRHand::set_motion_range(MotionRange p_motion_range) { ERR_FAIL_INDEX(p_motion_range, MOTION_RANGE_MAX); motion_range = p_motion_range; @@ -116,6 +124,16 @@ void OpenXRHand::_set_motion_range() { hand_tracking_ext->set_motion_range(OpenXRHandTrackingExtension::HandTrackedHands(hand), xr_motion_range); } +void OpenXRHand::set_skeleton_rig(SkeletonRig p_skeleton_rig) { + ERR_FAIL_INDEX(p_skeleton_rig, SKELETON_RIG_MAX); + + skeleton_rig = p_skeleton_rig; +} + +OpenXRHand::SkeletonRig OpenXRHand::get_skeleton_rig() const { + return skeleton_rig; +} + Skeleton3D *OpenXRHand::get_skeleton() { if (!has_node(hand_skeleton)) { return nullptr; @@ -130,39 +148,81 @@ Skeleton3D *OpenXRHand::get_skeleton() { return skeleton; } -void OpenXRHand::_get_bones() { - const char *bone_names[XR_HAND_JOINT_COUNT_EXT] = { - "Palm", - "Wrist", - "Thumb_Metacarpal", - "Thumb_Proximal", - "Thumb_Distal", - "Thumb_Tip", - "Index_Metacarpal", - "Index_Proximal", - "Index_Intermediate", - "Index_Distal", - "Index_Tip", - "Middle_Metacarpal", - "Middle_Proximal", - "Middle_Intermediate", - "Middle_Distal", - "Middle_Tip", - "Ring_Metacarpal", - "Ring_Proximal", - "Ring_Intermediate", - "Ring_Distal", - "Ring_Tip", - "Little_Metacarpal", - "Little_Proximal", - "Little_Intermediate", - "Little_Distal", - "Little_Tip", +void OpenXRHand::_get_joint_data() { + // Table of bone names for different rig types. + static const String bone_names[SKELETON_RIG_MAX][XR_HAND_JOINT_COUNT_EXT] = { + // SKELETON_RIG_OPENXR bone names. + { + "Palm", + "Wrist", + "Thumb_Metacarpal", + "Thumb_Proximal", + "Thumb_Distal", + "Thumb_Tip", + "Index_Metacarpal", + "Index_Proximal", + "Index_Intermediate", + "Index_Distal", + "Index_Tip", + "Middle_Metacarpal", + "Middle_Proximal", + "Middle_Intermediate", + "Middle_Distal", + "Middle_Tip", + "Ring_Metacarpal", + "Ring_Proximal", + "Ring_Intermediate", + "Ring_Distal", + "Ring_Tip", + "Little_Metacarpal", + "Little_Proximal", + "Little_Intermediate", + "Little_Distal", + "Little_Tip" }, + + // SKELETON_RIG_HUMANOID bone names. + { + "Palm", + "Hand", + "ThumbMetacarpal", + "ThumbProximal", + "ThumbDistal", + "ThumbTip", + "IndexMetacarpal", + "IndexProximal", + "IndexIntermediate", + "IndexDistal", + "IndexTip", + "MiddleMetacarpal", + "MiddleProximal", + "MiddleIntermediate", + "MiddleDistal", + "MiddleTip", + "RingMetacarpal", + "RingProximal", + "RingIntermediate", + "RingDistal", + "RingTip", + "LittleMetacarpal", + "LittleProximal", + "LittleIntermediate", + "LittleDistal", + "LittleTip" } + }; + + // Table of bone name formats for different rig types and left/right hands. + static const String bone_name_formats[SKELETON_RIG_MAX][2] = { + // SKELETON_RIG_OPENXR bone name format. + { "<bone>_L", "<bone>_R" }, + + // SKELETON_RIG_HUMANOID bone name format. + { "Left<bone>", "Right<bone>" } }; // reset JIC for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { - bones[i] = -1; + joints[i].bone = -1; + joints[i].parent_joint = -1; } Skeleton3D *skeleton = get_skeleton(); @@ -170,20 +230,46 @@ void OpenXRHand::_get_bones() { return; } - // We cast to spatials which should allow us to use any subclass of that. + // Find the skeleton-bones associated with each OpenXR joint. + int bones[XR_HAND_JOINT_COUNT_EXT]; for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { - String bone_name = bone_names[i]; - if (hand == 0) { - bone_name += String("_L"); - } else { - bone_name += String("_R"); - } + // Construct the expected bone name. + String bone_name = bone_name_formats[skeleton_rig][hand].replace("<bone>", bone_names[skeleton_rig][i]); + // Find the skeleton bone. bones[i] = skeleton->find_bone(bone_name); if (bones[i] == -1) { print_line("Couldn't obtain bone for", bone_name); } } + + // Assemble the OpenXR joint relationship to the available skeleton bones. + for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { + // Get the skeleton bone (skip if not found). + const int bone = bones[i]; + if (bone == -1) { + continue; + } + + // Find the parent skeleton-bone. + const int parent_bone = skeleton->get_bone_parent(bone); + if (parent_bone == -1) { + // If no parent skeleton-bone exists then drive this relative to palm joint. + joints[i].bone = bone; + joints[i].parent_joint = XR_HAND_JOINT_PALM_EXT; + continue; + } + + // Find the OpenXR joint associated with the parent skeleton-bone. + for (int j = 0; j < XR_HAND_JOINT_COUNT_EXT; ++j) { + if (bones[j] == parent_bone) { + // If a parent joint is found then drive this bone relative to it. + joints[i].bone = bone; + joints[i].parent_joint = j; + break; + } + } + } } void OpenXRHand::_update_skeleton() { @@ -198,12 +284,25 @@ void OpenXRHand::_update_skeleton() { return; } + // Table of bone adjustments for different rig types + static const Quaternion bone_adjustments[SKELETON_RIG_MAX] = { + // SKELETON_RIG_OPENXR bone adjustment. This is an identity quaternion + // because the incoming quaternions are already in OpenXR format. + Quaternion(), + + // SKELETON_RIG_HUMANOID bone adjustment. This rotation performs: + // OpenXR Z+ -> Godot Humanoid Y- (Back along the bone) + // OpenXR Y+ -> Godot Humanoid Z- (Out the back of the hand) + Quaternion(0.0, -Math_SQRT12, Math_SQRT12, 0.0), + }; + // we cache our transforms so we can quickly calculate local transforms XRPose::TrackingConfidence confidences[XR_HAND_JOINT_COUNT_EXT]; Quaternion quaternions[XR_HAND_JOINT_COUNT_EXT]; Quaternion inv_quaternions[XR_HAND_JOINT_COUNT_EXT]; Vector3 positions[XR_HAND_JOINT_COUNT_EXT]; + const Quaternion &rig_adjustment = bone_adjustments[skeleton_rig]; const OpenXRHandTrackingExtension::HandTracker *hand_tracker = hand_tracking_ext->get_hand_tracker(OpenXRHandTrackingExtension::HandTrackedHands(hand)); const float ws = XRServer::get_singleton()->get_world_scale(); @@ -218,7 +317,7 @@ void OpenXRHand::_update_skeleton() { if (location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) { if (pose.orientation.x != 0 || pose.orientation.y != 0 || pose.orientation.z != 0 || pose.orientation.w != 0) { - quaternions[i] = Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w); + quaternions[i] = Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w) * rig_adjustment; inv_quaternions[i] = quaternions[i].inverse(); if (location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) { @@ -234,40 +333,25 @@ void OpenXRHand::_update_skeleton() { } if (confidences[XR_HAND_JOINT_PALM_EXT] != XRPose::XR_TRACKING_CONFIDENCE_NONE) { - // now update our skeleton - for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { - if (bones[i] != -1) { - int bone = bones[i]; - int parent = skeleton->get_bone_parent(bone); - - // Get our target quaternion - Quaternion q = quaternions[i]; + // Iterate over all the OpenXR joints. + for (int joint = 0; joint < XR_HAND_JOINT_COUNT_EXT; joint++) { + // Get the skeleton bone (skip if none). + const int bone = joints[joint].bone; + if (bone == -1) { + continue; + } - // Get our target position - Vector3 p = positions[i]; + // Calculate the relative relationship to the parent bone joint. + const int parent_joint = joints[joint].parent_joint; + const Quaternion q = inv_quaternions[parent_joint] * quaternions[joint]; + const Vector3 p = inv_quaternions[parent_joint].xform(positions[joint] - positions[parent_joint]); - // get local translation, parent should already be processed - if (parent == -1) { - // use our palm location here, that is what we are tracking - q = inv_quaternions[XR_HAND_JOINT_PALM_EXT] * q; - p = inv_quaternions[XR_HAND_JOINT_PALM_EXT].xform(p - positions[XR_HAND_JOINT_PALM_EXT]); - } else { - int found = false; - for (int b = 0; b < XR_HAND_JOINT_COUNT_EXT && !found; b++) { - if (bones[b] == parent) { - q = inv_quaternions[b] * q; - p = inv_quaternions[b].xform(p - positions[b]); - found = true; - } - } - } - - // and set our pose - skeleton->set_bone_pose_position(bones[i], p); - skeleton->set_bone_pose_rotation(bones[i], q); - } + // and set our pose + skeleton->set_bone_pose_position(joints[joint].bone, p); + skeleton->set_bone_pose_rotation(joints[joint].bone, q); } + // Transform the OpenXRHand to the skeleton pose. Transform3D t; t.basis = Basis(quaternions[XR_HAND_JOINT_PALM_EXT]); t.origin = positions[XR_HAND_JOINT_PALM_EXT]; @@ -288,7 +372,7 @@ void OpenXRHand::_update_skeleton() { void OpenXRHand::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - _get_bones(); + _get_joint_data(); set_process_internal(true); } break; @@ -297,7 +381,8 @@ void OpenXRHand::_notification(int p_what) { // reset for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { - bones[i] = -1; + joints[i].bone = -1; + joints[i].parent_joint = -1; } } break; case NOTIFICATION_INTERNAL_PROCESS: { diff --git a/modules/openxr/scene/openxr_hand.h b/modules/openxr/scene/openxr_hand.h index edfb474ac7..14eb893bcc 100644 --- a/modules/openxr/scene/openxr_hand.h +++ b/modules/openxr/scene/openxr_hand.h @@ -55,20 +55,32 @@ public: MOTION_RANGE_MAX }; + enum SkeletonRig { + SKELETON_RIG_OPENXR, + SKELETON_RIG_HUMANOID, + SKELETON_RIG_MAX + }; + private: + struct JointData { + int bone = -1; + int parent_joint = -1; + }; + OpenXRAPI *openxr_api = nullptr; OpenXRHandTrackingExtension *hand_tracking_ext = nullptr; Hands hand = HAND_LEFT; MotionRange motion_range = MOTION_RANGE_UNOBSTRUCTED; NodePath hand_skeleton; + SkeletonRig skeleton_rig = SKELETON_RIG_OPENXR; - int64_t bones[XR_HAND_JOINT_COUNT_EXT]; + JointData joints[XR_HAND_JOINT_COUNT_EXT]; void _set_motion_range(); Skeleton3D *get_skeleton(); - void _get_bones(); + void _get_joint_data(); void _update_skeleton(); protected: @@ -77,19 +89,23 @@ protected: public: OpenXRHand(); - void set_hand(const Hands p_hand); + void set_hand(Hands p_hand); Hands get_hand() const; - void set_motion_range(const MotionRange p_motion_range); + void set_motion_range(MotionRange p_motion_range); MotionRange get_motion_range() const; void set_hand_skeleton(const NodePath &p_hand_skeleton); NodePath get_hand_skeleton() const; + void set_skeleton_rig(SkeletonRig p_skeleton_rig); + SkeletonRig get_skeleton_rig() const; + void _notification(int p_what); }; VARIANT_ENUM_CAST(OpenXRHand::Hands) VARIANT_ENUM_CAST(OpenXRHand::MotionRange) +VARIANT_ENUM_CAST(OpenXRHand::SkeletonRig) #endif // OPENXR_HAND_H diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp index 704c107f20..d49578d2a9 100644 --- a/modules/regex/regex.cpp +++ b/modules/regex/regex.cpp @@ -270,16 +270,18 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end) TypedArray<RegExMatch> RegEx::search_all(const String &p_subject, int p_offset, int p_end) const { ERR_FAIL_COND_V_MSG(p_offset < 0, Array(), "RegEx search offset must be >= 0"); - int last_end = -1; + int last_end = 0; TypedArray<RegExMatch> result; Ref<RegExMatch> match = search(p_subject, p_offset, p_end); + while (match.is_valid()) { - if (last_end == match->get_end(0)) { - break; + last_end = match->get_end(0); + if (match->get_start(0) == last_end) { + last_end++; } + result.push_back(match); - last_end = match->get_end(0); - match = search(p_subject, match->get_end(0), p_end); + match = search(p_subject, last_end, p_end); } return result; } diff --git a/modules/regex/tests/test_regex.h b/modules/regex/tests/test_regex.h index 3e4d769377..0b401da831 100644 --- a/modules/regex/tests/test_regex.h +++ b/modules/regex/tests/test_regex.h @@ -164,7 +164,7 @@ TEST_CASE("[RegEx] Uninitialized use") { ERR_PRINT_ON } -TEST_CASE("[RegEx] Empty Pattern") { +TEST_CASE("[RegEx] Empty pattern") { const String s = "Godot"; RegEx re; @@ -222,6 +222,143 @@ TEST_CASE("[RegEx] Match start and end positions") { CHECK(match->get_start("vowel") == 2); CHECK(match->get_end("vowel") == 3); } + +TEST_CASE("[RegEx] Asterisk search all") { + const String s = "Godot Engine"; + + RegEx re("o*"); + REQUIRE(re.is_valid()); + Ref<RegExMatch> match; + const Array all_results = re.search_all(s); + CHECK(all_results.size() == 13); + + match = all_results[0]; + CHECK(match->get_string(0) == ""); + match = all_results[1]; + CHECK(match->get_string(0) == "o"); + match = all_results[2]; + CHECK(match->get_string(0) == ""); + match = all_results[3]; + CHECK(match->get_string(0) == "o"); + + for (int i = 4; i < 13; i++) { + match = all_results[i]; + CHECK(match->get_string(0) == ""); + } +} + +TEST_CASE("[RegEx] Simple lookahead") { + const String s = "Godot Engine"; + + RegEx re("o(?=t)"); + REQUIRE(re.is_valid()); + Ref<RegExMatch> match = re.search(s); + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 3); + CHECK(match->get_end(0) == 4); +} + +TEST_CASE("[RegEx] Lookahead groups empty matches") { + const String s = "12"; + + RegEx re("(?=(\\d+))"); + REQUIRE(re.is_valid()); + Ref<RegExMatch> match = re.search(s); + CHECK(match->get_string(0) == ""); + CHECK(match->get_string(1) == "12"); + + const Array all_results = re.search_all(s); + CHECK(all_results.size() == 2); + + match = all_results[0]; + REQUIRE(match != nullptr); + CHECK(match->get_string(0) == String("")); + CHECK(match->get_string(1) == String("12")); + + match = all_results[1]; + REQUIRE(match != nullptr); + CHECK(match->get_string(0) == String("")); + CHECK(match->get_string(1) == String("2")); +} + +TEST_CASE("[RegEx] Simple lookbehind") { + const String s = "Godot Engine"; + + RegEx re("(?<=d)o"); + REQUIRE(re.is_valid()); + Ref<RegExMatch> match = re.search(s); + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 3); + CHECK(match->get_end(0) == 4); +} + +TEST_CASE("[RegEx] Simple lookbehind search all") { + const String s = "ababbaabab"; + + RegEx re("(?<=a)b"); + REQUIRE(re.is_valid()); + const Array all_results = re.search_all(s); + CHECK(all_results.size() == 4); + + Ref<RegExMatch> match = all_results[0]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 1); + CHECK(match->get_end(0) == 2); + + match = all_results[1]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 3); + CHECK(match->get_end(0) == 4); + + match = all_results[2]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 7); + CHECK(match->get_end(0) == 8); + + match = all_results[3]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 9); + CHECK(match->get_end(0) == 10); +} + +TEST_CASE("[RegEx] Lookbehind groups empty matches") { + const String s = "abaaabab"; + + RegEx re("(?<=(b))"); + REQUIRE(re.is_valid()); + Ref<RegExMatch> match; + + const Array all_results = re.search_all(s); + CHECK(all_results.size() == 3); + + match = all_results[0]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 2); + CHECK(match->get_end(0) == 2); + CHECK(match->get_start(1) == 1); + CHECK(match->get_end(1) == 2); + CHECK(match->get_string(0) == String("")); + CHECK(match->get_string(1) == String("b")); + + match = all_results[1]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 6); + CHECK(match->get_end(0) == 6); + CHECK(match->get_start(1) == 5); + CHECK(match->get_end(1) == 6); + CHECK(match->get_string(0) == String("")); + CHECK(match->get_string(1) == String("b")); + + match = all_results[2]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 8); + CHECK(match->get_end(0) == 8); + CHECK(match->get_start(1) == 7); + CHECK(match->get_end(1) == 8); + CHECK(match->get_string(0) == String("")); + CHECK(match->get_string(1) == String("b")); +} + } // namespace TestRegEx #endif // TEST_REGEX_H diff --git a/modules/svg/SCsub b/modules/svg/SCsub index d0c6250b11..ff0c3c9141 100644 --- a/modules/svg/SCsub +++ b/modules/svg/SCsub @@ -43,6 +43,8 @@ thirdparty_sources = [ "src/renderer/tvgShape.cpp", "src/renderer/tvgSwCanvas.cpp", "src/renderer/tvgTaskScheduler.cpp", + "src/renderer/tvgText.cpp", + # "src/renderer/tvgWgCanvas.cpp", # renderer sw_engine "src/renderer/sw_engine/tvgSwFill.cpp", "src/renderer/sw_engine/tvgSwImage.cpp", diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub index 3c468e61d7..09d9b2dd67 100644 --- a/modules/text_server_adv/SCsub +++ b/modules/text_server_adv/SCsub @@ -401,6 +401,8 @@ if env["builtin_icu4c"]: "common/uloc.cpp", "common/uloc_keytype.cpp", "common/uloc_tag.cpp", + "common/ulocale.cpp", + "common/ulocbuilder.cpp", "common/umapfile.cpp", "common/umath.cpp", "common/umutablecptrie.cpp", @@ -466,7 +468,7 @@ if env["builtin_icu4c"]: ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - icu_data_name = "icudt73l.dat" + icu_data_name = "icudt74l.dat" if env.editor_build: env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name) diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct index 4093842650..cd4331b60e 100644 --- a/modules/text_server_adv/gdextension_build/SConstruct +++ b/modules/text_server_adv/gdextension_build/SConstruct @@ -74,6 +74,8 @@ if env["thorvg_enabled"] and env["freetype_enabled"]: "src/renderer/tvgShape.cpp", "src/renderer/tvgSwCanvas.cpp", "src/renderer/tvgTaskScheduler.cpp", + "src/renderer/tvgText.cpp", + # "src/renderer/tvgWgCanvas.cpp", # renderer sw_engine "src/renderer/sw_engine/tvgSwFill.cpp", "src/renderer/sw_engine/tvgSwImage.cpp", @@ -623,6 +625,8 @@ thirdparty_icu_sources = [ "common/uloc.cpp", "common/uloc_keytype.cpp", "common/uloc_tag.cpp", + "common/ulocale.cpp", + "common/ulocbuilder.cpp", "common/umapfile.cpp", "common/umath.cpp", "common/umutablecptrie.cpp", @@ -688,7 +692,7 @@ thirdparty_icu_sources = [ ] thirdparty_icu_sources = [thirdparty_icu_dir + file for file in thirdparty_icu_sources] -icu_data_name = "icudt73l.dat" +icu_data_name = "icudt74l.dat" if env["static_icu_data"]: env_icu.Depends("../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/" + icu_data_name) diff --git a/modules/text_server_adv/register_types.h b/modules/text_server_adv/register_types.h index c11765048d..477e030e03 100644 --- a/modules/text_server_adv/register_types.h +++ b/modules/text_server_adv/register_types.h @@ -34,7 +34,7 @@ #ifdef GDEXTENSION #include <godot_cpp/core/class_db.hpp> using namespace godot; -#else +#elif defined(GODOT_MODULE) #include "modules/register_module_types.h" #endif diff --git a/modules/text_server_adv/script_iterator.h b/modules/text_server_adv/script_iterator.h index 164fdec784..f7876d6cbc 100644 --- a/modules/text_server_adv/script_iterator.h +++ b/modules/text_server_adv/script_iterator.h @@ -40,7 +40,7 @@ using namespace godot; -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/string/ustring.h" diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index bcc7bff909..19f302423c 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -44,7 +44,7 @@ using namespace godot; #define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var) -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/config/project_settings.h" @@ -370,7 +370,7 @@ bool TextServerAdvanced::_has_feature(Feature p_feature) const { String TextServerAdvanced::_get_name() const { #ifdef GDEXTENSION return "ICU / HarfBuzz / Graphite (GDExtension)"; -#else +#elif defined(GODOT_MODULE) return "ICU / HarfBuzz / Graphite (Built-in)"; #endif } @@ -4852,7 +4852,7 @@ RID TextServerAdvanced::_find_sys_font_for_text(const RID &p_fdef, const String #ifdef GDEXTENSION for (int fb = 0; fb < fallback_font_name.size(); fb++) { const String &E = fallback_font_name[fb]; -#else +#elif defined(GODOT_MODULE) for (const String &E : fallback_font_name) { #endif SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this); @@ -6757,7 +6757,7 @@ String TextServerAdvanced::_strip_diacritics(const String &p_string) const { if (u_getCombiningClass(normalized_string[i]) == 0) { #ifdef GDEXTENSION result = result + String::chr(normalized_string[i]); -#else +#elif defined(GODOT_MODULE) result = result + normalized_string[i]; #endif } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index e5d0ab3105..0b5fe47b8b 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -78,7 +78,7 @@ using namespace godot; -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/extension/ext_wrappers.gen.inc" diff --git a/modules/text_server_adv/thorvg_bounds_iterator.cpp b/modules/text_server_adv/thorvg_bounds_iterator.cpp index 807f356b83..d273eef97f 100644 --- a/modules/text_server_adv/thorvg_bounds_iterator.cpp +++ b/modules/text_server_adv/thorvg_bounds_iterator.cpp @@ -35,7 +35,7 @@ using namespace godot; -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/typedefs.h" diff --git a/modules/text_server_adv/thorvg_bounds_iterator.h b/modules/text_server_adv/thorvg_bounds_iterator.h index a44cbb99a7..afa2c13764 100644 --- a/modules/text_server_adv/thorvg_bounds_iterator.h +++ b/modules/text_server_adv/thorvg_bounds_iterator.h @@ -39,7 +39,7 @@ using namespace godot; -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/typedefs.h" diff --git a/modules/text_server_adv/thorvg_svg_in_ot.cpp b/modules/text_server_adv/thorvg_svg_in_ot.cpp index 828f8d7d56..136ccf3aaf 100644 --- a/modules/text_server_adv/thorvg_svg_in_ot.cpp +++ b/modules/text_server_adv/thorvg_svg_in_ot.cpp @@ -38,7 +38,7 @@ using namespace godot; -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/error/error_macros.h" diff --git a/modules/text_server_adv/thorvg_svg_in_ot.h b/modules/text_server_adv/thorvg_svg_in_ot.h index 034fffb5e6..ce048674fd 100644 --- a/modules/text_server_adv/thorvg_svg_in_ot.h +++ b/modules/text_server_adv/thorvg_svg_in_ot.h @@ -40,7 +40,7 @@ using namespace godot; -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/os/mutex.h" diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct index 0d2fbd97fd..0efced0bfc 100644 --- a/modules/text_server_fb/gdextension_build/SConstruct +++ b/modules/text_server_fb/gdextension_build/SConstruct @@ -69,6 +69,8 @@ if env["thorvg_enabled"] and env["freetype_enabled"]: "src/renderer/tvgShape.cpp", "src/renderer/tvgSwCanvas.cpp", "src/renderer/tvgTaskScheduler.cpp", + "src/renderer/tvgText.cpp", + # "src/renderer/tvgWgCanvas.cpp", # renderer sw_engine "src/renderer/sw_engine/tvgSwFill.cpp", "src/renderer/sw_engine/tvgSwImage.cpp", diff --git a/modules/text_server_fb/register_types.h b/modules/text_server_fb/register_types.h index 97bc06a8f7..0933ea83c5 100644 --- a/modules/text_server_fb/register_types.h +++ b/modules/text_server_fb/register_types.h @@ -34,7 +34,7 @@ #ifdef GDEXTENSION #include <godot_cpp/core/class_db.hpp> using namespace godot; -#else +#elif defined(GODOT_MODULE) #include "modules/register_module_types.h" #endif diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 8fc7694aa4..0b486b7d7b 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -44,7 +44,7 @@ using namespace godot; #define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var) -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/config/project_settings.h" @@ -95,7 +95,7 @@ bool TextServerFallback::_has_feature(Feature p_feature) const { String TextServerFallback::_get_name() const { #ifdef GDEXTENSION return "Fallback (GDExtension)"; -#else +#elif defined(GODOT_MODULE) return "Fallback (Built-in)"; #endif } @@ -3654,7 +3654,7 @@ RID TextServerFallback::_find_sys_font_for_text(const RID &p_fdef, const String #ifdef GDEXTENSION for (int fb = 0; fb < fallback_font_name.size(); fb++) { const String &E = fallback_font_name[fb]; -#else +#elif defined(GODOT_MODULE) for (const String &E : fallback_font_name) { #endif SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this); diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index 68e0cbff6c..2bb3724858 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -76,7 +76,7 @@ using namespace godot; -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/extension/ext_wrappers.gen.inc" diff --git a/modules/text_server_fb/thorvg_bounds_iterator.cpp b/modules/text_server_fb/thorvg_bounds_iterator.cpp index 807f356b83..d273eef97f 100644 --- a/modules/text_server_fb/thorvg_bounds_iterator.cpp +++ b/modules/text_server_fb/thorvg_bounds_iterator.cpp @@ -35,7 +35,7 @@ using namespace godot; -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/typedefs.h" diff --git a/modules/text_server_fb/thorvg_bounds_iterator.h b/modules/text_server_fb/thorvg_bounds_iterator.h index a44cbb99a7..afa2c13764 100644 --- a/modules/text_server_fb/thorvg_bounds_iterator.h +++ b/modules/text_server_fb/thorvg_bounds_iterator.h @@ -39,7 +39,7 @@ using namespace godot; -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/typedefs.h" diff --git a/modules/text_server_fb/thorvg_svg_in_ot.cpp b/modules/text_server_fb/thorvg_svg_in_ot.cpp index 7c8fedabc8..1ad33a88d4 100644 --- a/modules/text_server_fb/thorvg_svg_in_ot.cpp +++ b/modules/text_server_fb/thorvg_svg_in_ot.cpp @@ -38,7 +38,7 @@ using namespace godot; -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/error/error_macros.h" diff --git a/modules/text_server_fb/thorvg_svg_in_ot.h b/modules/text_server_fb/thorvg_svg_in_ot.h index 034fffb5e6..ce048674fd 100644 --- a/modules/text_server_fb/thorvg_svg_in_ot.h +++ b/modules/text_server_fb/thorvg_svg_in_ot.h @@ -40,7 +40,7 @@ using namespace godot; -#else +#elif defined(GODOT_MODULE) // Headers for building as built-in module. #include "core/os/mutex.h" diff --git a/modules/zip/zip_packer.cpp b/modules/zip/zip_packer.cpp index e67c65d4d1..e96d9da7a9 100644 --- a/modules/zip/zip_packer.cpp +++ b/modules/zip/zip_packer.cpp @@ -88,7 +88,7 @@ Error ZIPPacker::start_file(const String &p_path) { Z_DEFAULT_STRATEGY, nullptr, 0, - 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions. + 0, // "version made by", indicates the compatibility of the file attribute information (the `external_fa` field above). 1 << 11); // Bit 11 is the language encoding flag. When set, filename and comment fields must be encoded using UTF-8. return err == ZIP_OK ? OK : FAILED; } diff --git a/platform/android/detect.py b/platform/android/detect.py index a417ef454b..b396e5eb2d 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -200,7 +200,7 @@ def configure(env: "Environment"): env.Append(LIBS=["OpenSLES", "EGL", "android", "log", "z", "dl"]) if env["vulkan"]: - env.Append(CPPDEFINES=["VULKAN_ENABLED"]) + env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"]) if not env["use_volk"]: env.Append(LIBS=["vulkan"]) diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index ee1ec2790d..e276048d40 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -48,6 +48,7 @@ void register_android_exporter() { EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks")); EDITOR_DEF("export/android/debug_keystore_user", "androiddebugkey"); EDITOR_DEF("export/android/debug_keystore_pass", "android"); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore_pass", PROPERTY_HINT_PASSWORD)); EDITOR_DEF("export/android/force_system_user", false); EDITOR_DEF("export/android/shutdown_adb_on_exit", true); diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 10d54e8d97..762e5a8323 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -1111,7 +1111,7 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p } for (int i = 0; i < feature_names.size(); i++) { - String feature_name = feature_names[i]; + const String &feature_name = feature_names[i]; bool feature_required = feature_required_list[i]; int feature_version = feature_versions[i]; bool has_version_attribute = feature_version != -1; @@ -1823,10 +1823,10 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_user", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_password", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_password", PROPERTY_HINT_PASSWORD, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password", PROPERTY_HINT_PASSWORD, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Leave empty to use project version"), "")); @@ -2229,6 +2229,54 @@ String EditorExportPlatformAndroid::get_apksigner_path(int p_target_sdk, bool p_ return apksigner_path; } +static bool has_valid_keystore_credentials(String &r_error_str, const String &p_keystore, const String &p_username, const String &p_password, const String &p_type) { + String output; + List<String> args; + args.push_back("-list"); + args.push_back("-keystore"); + args.push_back(p_keystore); + args.push_back("-storepass"); + args.push_back(p_password); + args.push_back("-alias"); + args.push_back(p_username); + Error error = OS::get_singleton()->execute("keytool", args, &output, nullptr, true); + String keytool_error = "keytool error:"; + bool valid = output.substr(0, keytool_error.length()) != keytool_error; + + if (error != OK) { + r_error_str = TTR("Error: There was a problem validating the keystore username and password"); + return false; + } + if (!valid) { + r_error_str = TTR(p_type + " Username and/or Password is invalid for the given " + p_type + " Keystore"); + return false; + } + r_error_str = ""; + return true; +} + +bool EditorExportPlatformAndroid::has_valid_username_and_password(const Ref<EditorExportPreset> &p_preset, String &r_error) { + String dk = p_preset->get_or_env("keystore/debug", ENV_ANDROID_KEYSTORE_DEBUG_PATH); + String dk_user = p_preset->get_or_env("keystore/debug_user", ENV_ANDROID_KEYSTORE_DEBUG_USER); + String dk_password = p_preset->get_or_env("keystore/debug_password", ENV_ANDROID_KEYSTORE_DEBUG_PASS); + String rk = p_preset->get_or_env("keystore/release", ENV_ANDROID_KEYSTORE_RELEASE_PATH); + String rk_user = p_preset->get_or_env("keystore/release_user", ENV_ANDROID_KEYSTORE_RELEASE_USER); + String rk_password = p_preset->get_or_env("keystore/release_password", ENV_ANDROID_KEYSTORE_RELEASE_PASS); + + bool valid = true; + if (!dk.is_empty() && !dk_user.is_empty() && !dk_password.is_empty()) { + String err = ""; + valid = has_valid_keystore_credentials(err, dk, dk_user, dk_password, "Debug"); + r_error += err; + } + if (!rk.is_empty() && !rk_user.is_empty() && !rk_password.is_empty()) { + String err = ""; + valid = has_valid_keystore_credentials(err, rk, rk_user, rk_password, "Release"); + r_error += err; + } + return valid; +} + bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const { String err; bool valid = false; @@ -2842,6 +2890,11 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Unsupported export format!")); return ERR_UNCONFIGURED; } + String err_string; + if (!has_valid_username_and_password(p_preset, err_string)) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR(err_string)); + return ERR_UNCONFIGURED; + } if (use_gradle_build) { print_verbose("Starting gradle build..."); diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h index a2d0417c5d..5b585581b0 100644 --- a/platform/android/export/export_plugin.h +++ b/platform/android/export/export_plugin.h @@ -228,6 +228,7 @@ public: virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override; virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override; + static bool has_valid_username_and_password(const Ref<EditorExportPreset> &p_preset, String &r_error); virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override; diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp index 1249f2219f..f56eda4694 100644 --- a/platform/android/file_access_android.cpp +++ b/platform/android/file_access_android.cpp @@ -121,6 +121,75 @@ uint8_t FileAccessAndroid::get_8() const { return byte; } +uint16_t FileAccessAndroid::get_16() const { + if (pos >= len) { + eof = true; + return 0; + } + + uint16_t bytes = 0; + int r = AAsset_read(asset, &bytes, 2); + + if (r >= 0) { + pos += r; + if (pos >= len) { + eof = true; + } + } + + if (big_endian) { + bytes = BSWAP16(bytes); + } + + return bytes; +} + +uint32_t FileAccessAndroid::get_32() const { + if (pos >= len) { + eof = true; + return 0; + } + + uint32_t bytes = 0; + int r = AAsset_read(asset, &bytes, 4); + + if (r >= 0) { + pos += r; + if (pos >= len) { + eof = true; + } + } + + if (big_endian) { + bytes = BSWAP32(bytes); + } + + return bytes; +} + +uint64_t FileAccessAndroid::get_64() const { + if (pos >= len) { + eof = true; + return 0; + } + + uint64_t bytes = 0; + int r = AAsset_read(asset, &bytes, 8); + + if (r >= 0) { + pos += r; + if (pos >= len) { + eof = true; + } + } + + if (big_endian) { + bytes = BSWAP64(bytes); + } + + return bytes; +} + uint64_t FileAccessAndroid::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); @@ -151,6 +220,18 @@ void FileAccessAndroid::store_8(uint8_t p_dest) { ERR_FAIL(); } +void FileAccessAndroid::store_16(uint16_t p_dest) { + ERR_FAIL(); +} + +void FileAccessAndroid::store_32(uint32_t p_dest) { + ERR_FAIL(); +} + +void FileAccessAndroid::store_64(uint64_t p_dest) { + ERR_FAIL(); +} + bool FileAccessAndroid::file_exists(const String &p_path) { String path = fix_path(p_path).simplify_path(); if (path.begins_with("/")) { diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index 3aa4ca98fc..ec613b6687 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -66,12 +66,18 @@ public: virtual bool eof_reached() const override; // reading passed EOF virtual uint8_t get_8() const override; // get a byte + virtual uint16_t get_16() const override; + virtual uint32_t get_32() const override; + virtual uint64_t get_64() const override; virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; virtual Error get_error() const override; // get last error virtual void flush() override; virtual void store_8(uint8_t p_dest) override; // store a byte + virtual void store_16(uint16_t p_dest) override; + virtual void store_32(uint32_t p_dest) override; + virtual void store_64(uint64_t p_dest) override; virtual bool file_exists(const String &p_path) override; // return true if a file exists diff --git a/platform/android/file_access_filesystem_jandroid.cpp b/platform/android/file_access_filesystem_jandroid.cpp index beea73fd61..46d9728632 100644 --- a/platform/android/file_access_filesystem_jandroid.cpp +++ b/platform/android/file_access_filesystem_jandroid.cpp @@ -181,6 +181,36 @@ uint8_t FileAccessFilesystemJAndroid::get_8() const { return byte; } +uint16_t FileAccessFilesystemJAndroid::get_16() const { + ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); + uint16_t bytes = 0; + get_buffer(reinterpret_cast<uint8_t *>(&bytes), 2); + if (big_endian) { + bytes = BSWAP16(bytes); + } + return bytes; +} + +uint32_t FileAccessFilesystemJAndroid::get_32() const { + ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); + uint32_t bytes = 0; + get_buffer(reinterpret_cast<uint8_t *>(&bytes), 4); + if (big_endian) { + bytes = BSWAP32(bytes); + } + return bytes; +} + +uint64_t FileAccessFilesystemJAndroid::get_64() const { + ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); + uint64_t bytes = 0; + get_buffer(reinterpret_cast<uint8_t *>(&bytes), 8); + if (big_endian) { + bytes = BSWAP64(bytes); + } + return bytes; +} + String FileAccessFilesystemJAndroid::get_line() const { ERR_FAIL_COND_V_MSG(!is_open(), String(), "File must be opened before use."); @@ -250,6 +280,27 @@ void FileAccessFilesystemJAndroid::store_8(uint8_t p_dest) { store_buffer(&p_dest, 1); } +void FileAccessFilesystemJAndroid::store_16(uint16_t p_dest) { + if (big_endian) { + p_dest = BSWAP16(p_dest); + } + store_buffer(reinterpret_cast<uint8_t *>(&p_dest), 2); +} + +void FileAccessFilesystemJAndroid::store_32(uint32_t p_dest) { + if (big_endian) { + p_dest = BSWAP32(p_dest); + } + store_buffer(reinterpret_cast<uint8_t *>(&p_dest), 4); +} + +void FileAccessFilesystemJAndroid::store_64(uint64_t p_dest) { + if (big_endian) { + p_dest = BSWAP64(p_dest); + } + store_buffer(reinterpret_cast<uint8_t *>(&p_dest), 8); +} + void FileAccessFilesystemJAndroid::store_buffer(const uint8_t *p_src, uint64_t p_length) { if (_file_write) { ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use."); diff --git a/platform/android/file_access_filesystem_jandroid.h b/platform/android/file_access_filesystem_jandroid.h index 0c3f8d7259..f33aa64ebe 100644 --- a/platform/android/file_access_filesystem_jandroid.h +++ b/platform/android/file_access_filesystem_jandroid.h @@ -77,6 +77,9 @@ public: virtual bool eof_reached() const override; ///< reading passed EOF virtual uint8_t get_8() const override; ///< get a byte + virtual uint16_t get_16() const override; + virtual uint32_t get_32() const override; + virtual uint64_t get_64() const override; virtual String get_line() const override; ///< get a line virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; @@ -84,6 +87,9 @@ public: virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte + virtual void store_16(uint16_t p_dest) override; + virtual void store_32(uint32_t p_dest) override; + virtual void store_64(uint64_t p_dest) override; virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; virtual bool file_exists(const String &p_path) override; ///< return true if a file exists diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt index 0d7017ae71..caf64bc933 100644 --- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt @@ -91,6 +91,10 @@ open class GodotEditor : GodotActivity() { private val commandLineParams = ArrayList<String>() override fun onCreate(savedInstanceState: Bundle?) { + // We exclude certain permissions from the set we request at startup, as they'll be + // requested on demand based on use-cases. + PermissionsUtil.requestManifestPermissions(this, setOf(Manifest.permission.RECORD_AUDIO)) + val params = intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS) Log.d(TAG, "Received parameters ${params.contentToString()}") updateCommandLineParams(params) diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt index 217e7a2b60..da86e67c7d 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt @@ -484,6 +484,14 @@ class Godot(private val context: Context) : SensorEventListener { return containerLayout } + fun onStart(host: GodotHost) { + if (host != primaryHost) { + return + } + + renderView!!.onActivityStarted() + } + fun onResume(host: GodotHost) { if (host != primaryHost) { return @@ -528,6 +536,14 @@ class Godot(private val context: Context) : SensorEventListener { } } + fun onStop(host: GodotHost) { + if (host != primaryHost) { + return + } + + renderView!!.onActivityStopped() + } + fun onDestroy(primaryHost: GodotHost) { if (this.primaryHost != primaryHost) { return diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt b/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt index a60f6e997e..e01c5481d5 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt @@ -30,7 +30,6 @@ package org.godotengine.godot -import android.Manifest import android.app.Activity import android.content.Intent import android.content.pm.PackageManager @@ -65,10 +64,6 @@ abstract class GodotActivity : FragmentActivity(), GodotHost { private set override fun onCreate(savedInstanceState: Bundle?) { - // We exclude certain permissions from the set we request at startup, as they'll be - // requested on demand based on use-cases. - PermissionsUtil.requestManifestPermissions(this, setOf(Manifest.permission.RECORD_AUDIO)) - super.onCreate(savedInstanceState) setContentView(R.layout.godot_app_layout) @@ -156,7 +151,8 @@ abstract class GodotActivity : FragmentActivity(), GodotHost { super.onRequestPermissionsResult(requestCode, permissions, grantResults) godotFragment?.onRequestPermissionsResult(requestCode, permissions, grantResults) - if (requestCode == PermissionsUtil.REQUEST_ALL_PERMISSION_REQ_CODE) { + // Logging the result of permission requests + if (requestCode == PermissionsUtil.REQUEST_ALL_PERMISSION_REQ_CODE || requestCode == PermissionsUtil.REQUEST_SINGLE_PERMISSION_REQ_CODE) { Log.d(TAG, "Received permissions request result..") for (i in permissions.indices) { val permissionGranted = grantResults[i] == PackageManager.PERMISSION_GRANTED diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java b/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java index f1c029e7a1..643c9a658e 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java @@ -271,6 +271,32 @@ public class GodotFragment extends Fragment implements IDownloaderClient, GodotH } @Override + public void onStop() { + super.onStop(); + if (!godot.isInitialized()) { + if (null != mDownloaderClientStub) { + mDownloaderClientStub.disconnect(getActivity()); + } + return; + } + + godot.onStop(this); + } + + @Override + public void onStart() { + super.onStart(); + if (!godot.isInitialized()) { + if (null != mDownloaderClientStub) { + mDownloaderClientStub.connect(getActivity()); + } + return; + } + + godot.onStart(this); + } + + @Override public void onResume() { super.onResume(); if (!godot.isInitialized()) { diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java index 52350c12a6..81043ce782 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java @@ -114,12 +114,30 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView @Override public void onActivityPaused() { - onPause(); + queueEvent(() -> { + GodotLib.focusout(); + // Pause the renderer + godotRenderer.onActivityPaused(); + }); + } + + @Override + public void onActivityStopped() { + pauseGLThread(); } @Override public void onActivityResumed() { - onResume(); + queueEvent(() -> { + // Resume the renderer + godotRenderer.onActivityResumed(); + GodotLib.focusin(); + }); + } + + @Override + public void onActivityStarted() { + resumeGLThread(); } @Override @@ -283,26 +301,4 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView /* Set the renderer responsible for frame rendering */ setRenderer(godotRenderer); } - - @Override - public void onResume() { - super.onResume(); - - queueEvent(() -> { - // Resume the renderer - godotRenderer.onActivityResumed(); - GodotLib.focusin(); - }); - } - - @Override - public void onPause() { - super.onPause(); - - queueEvent(() -> { - GodotLib.focusout(); - // Pause the renderer - godotRenderer.onActivityPaused(); - }); - } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java index edcd9c4d1f..4b51bd778d 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java @@ -178,12 +178,10 @@ public class GodotIO { } public int[] getDisplaySafeArea() { - DisplayMetrics metrics = activity.getResources().getDisplayMetrics(); - Display display = activity.getWindowManager().getDefaultDisplay(); - Point size = new Point(); - display.getRealSize(size); + Rect rect = new Rect(); + activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect); - int[] result = { 0, 0, size.x, size.y }; + int[] result = { rect.left, rect.top, rect.right, rect.bottom }; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets(); DisplayCutout cutout = insets.getDisplayCutout(); diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java index ebf3a6b2fb..5b2f9f57c7 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java @@ -47,8 +47,13 @@ public interface GodotRenderView { void queueOnRenderThread(Runnable event); void onActivityPaused(); + + void onActivityStopped(); + void onActivityResumed(); + void onActivityStarted(); + void onBackPressed(); GodotInputHandler getInputHandler(); diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java index 48708152be..a1ee9bd6b4 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java @@ -92,12 +92,30 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV @Override public void onActivityPaused() { - onPause(); + queueOnVkThread(() -> { + GodotLib.focusout(); + // Pause the renderer + mRenderer.onVkPause(); + }); + } + + @Override + public void onActivityStopped() { + pauseRenderThread(); + } + + @Override + public void onActivityStarted() { + resumeRenderThread(); } @Override public void onActivityResumed() { - onResume(); + queueOnVkThread(() -> { + // Resume the renderer + mRenderer.onVkResume(); + GodotLib.focusin(); + }); } @Override @@ -211,26 +229,4 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV } return super.onResolvePointerIcon(me, pointerIndex); } - - @Override - public void onResume() { - super.onResume(); - - queueOnVkThread(() -> { - // Resume the renderer - mRenderer.onVkResume(); - GodotLib.focusin(); - }); - } - - @Override - public void onPause() { - super.onPause(); - - queueOnVkThread(() -> { - GodotLib.focusout(); - // Pause the renderer - mRenderer.onVkPause(); - }); - } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java b/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java index 56397bb2c2..ef97aaeab9 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java @@ -122,8 +122,8 @@ import javax.microedition.khronos.opengles.GL10; * <p> * <h3>Activity Life-cycle</h3> * A GLSurfaceView must be notified when to pause and resume rendering. GLSurfaceView clients - * are required to call {@link #onPause()} when the activity stops and - * {@link #onResume()} when the activity starts. These calls allow GLSurfaceView to + * are required to call {@link #pauseGLThread()} when the activity stops and + * {@link #resumeGLThread()} when the activity starts. These calls allow GLSurfaceView to * pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate * the OpenGL display. * <p> @@ -339,8 +339,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback * setRenderer is called: * <ul> * <li>{@link #getRenderMode()} - * <li>{@link #onPause()} - * <li>{@link #onResume()} + * <li>{@link #pauseGLThread()} + * <li>{@link #resumeGLThread()} * <li>{@link #queueEvent(Runnable)} * <li>{@link #requestRender()} * <li>{@link #setRenderMode(int)} @@ -568,6 +568,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } + // -- GODOT start -- /** * Pause the rendering thread, optionally tearing down the EGL context * depending upon the value of {@link #setPreserveEGLContextOnPause(boolean)}. @@ -578,22 +579,23 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback * * Must not be called before a renderer has been set. */ - public void onPause() { + protected final void pauseGLThread() { mGLThread.onPause(); } /** * Resumes the rendering thread, re-creating the OpenGL context if necessary. It - * is the counterpart to {@link #onPause()}. + * is the counterpart to {@link #pauseGLThread()}. * * This method should typically be called in * {@link android.app.Activity#onStart Activity.onStart}. * * Must not be called before a renderer has been set. */ - public void onResume() { + protected final void resumeGLThread() { mGLThread.onResume(); } + // -- GODOT end -- /** * Queue a runnable to be run on the GL rendering thread. This can be used diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java index 9a82204467..737b4ac20b 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java +++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java @@ -56,9 +56,9 @@ import java.util.Set; public final class PermissionsUtil { private static final String TAG = PermissionsUtil.class.getSimpleName(); - static final int REQUEST_RECORD_AUDIO_PERMISSION = 1; - static final int REQUEST_CAMERA_PERMISSION = 2; - static final int REQUEST_VIBRATE_PERMISSION = 3; + public static final int REQUEST_RECORD_AUDIO_PERMISSION = 1; + public static final int REQUEST_CAMERA_PERMISSION = 2; + public static final int REQUEST_VIBRATE_PERMISSION = 3; public static final int REQUEST_ALL_PERMISSION_REQ_CODE = 1001; public static final int REQUEST_SINGLE_PERMISSION_REQ_CODE = 1002; public static final int REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE = 2002; @@ -70,7 +70,7 @@ public final class PermissionsUtil { * Request a dangerous permission. name must be specified in <a href="https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/res/AndroidManifest.xml">this</a> * @param permissionName the name of the requested permission. * @param activity the caller activity for this method. - * @return true/false. "true" if permission was granted otherwise returns "false". + * @return true/false. "true" if permission is already granted, "false" if a permission request was dispatched. */ public static boolean requestPermission(String permissionName, Activity activity) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { @@ -124,7 +124,7 @@ public final class PermissionsUtil { /** * Request dangerous permissions which are defined in the Android manifest file from the user. * @param activity the caller activity for this method. - * @return true/false. "true" if all permissions were granted otherwise returns "false". + * @return true/false. "true" if all permissions were already granted, returns "false" if permissions requests were dispatched. */ public static boolean requestManifestPermissions(Activity activity) { return requestManifestPermissions(activity, null); @@ -134,7 +134,7 @@ public final class PermissionsUtil { * Request dangerous permissions which are defined in the Android manifest file from the user. * @param activity the caller activity for this method. * @param excludes Set of permissions to exclude from the request - * @return true/false. "true" if all permissions were granted otherwise returns "false". + * @return true/false. "true" if all permissions were already granted, returns "false" if permissions requests were dispatched. */ public static boolean requestManifestPermissions(Activity activity, @Nullable Set<String> excludes) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { @@ -235,7 +235,7 @@ public final class PermissionsUtil { /** * Check if the given permission is in the AndroidManifest.xml file. * @param context the caller context for this method. - * @param permission the permession to look for in the manifest file. + * @param permission the permission to look for in the manifest file. * @return "true" if the permission is in the manifest file of the activity, "false" otherwise. */ public static boolean hasManifestPermission(Context context, String permission) { diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt index 3828004198..791b425444 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt @@ -99,7 +99,7 @@ open internal class VkSurfaceView(context: Context) : SurfaceView(context), Surf * * Must not be called before a [VkRenderer] has been set. */ - open fun onResume() { + protected fun resumeRenderThread() { vkThread.onResume() } @@ -108,7 +108,7 @@ open internal class VkSurfaceView(context: Context) : SurfaceView(context), Surf * * Must not be called before a [VkRenderer] has been set. */ - open fun onPause() { + protected fun pauseRenderThread() { vkThread.onPause() } diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index 50075ed3f5..08e792cc04 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -484,7 +484,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv * env->DeleteLocalRef(jobj); } - MessageQueue::get_singleton()->push_callp(obj, str_method, argptrs, count); + Callable(obj, str_method).call_deferredp(argptrs, count); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jclass clazz, jstring p_permission, jboolean p_result) { diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp index 4e401e633e..3c950bb1b1 100644 --- a/platform/android/java_godot_wrapper.cpp +++ b/platform/android/java_godot_wrapper.cpp @@ -334,7 +334,7 @@ void GodotJavaWrapper::vibrate(int p_duration_ms) { } } -int GodotJavaWrapper::create_new_godot_instance(List<String> args) { +int GodotJavaWrapper::create_new_godot_instance(const List<String> &args) { if (_create_new_godot_instance) { JNIEnv *env = get_jni_env(); ERR_FAIL_NULL_V(env, 0); diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h index 52043c6027..93998021a9 100644 --- a/platform/android/java_godot_wrapper.h +++ b/platform/android/java_godot_wrapper.h @@ -104,7 +104,7 @@ public: void init_input_devices(); void vibrate(int p_duration_ms); String get_input_fallback_mapping(); - int create_new_godot_instance(List<String> args); + int create_new_godot_instance(const List<String> &args); void begin_benchmark_measure(const String &p_context, const String &p_label); void end_benchmark_measure(const String &p_context, const String &p_label); void dump_benchmark(const String &benchmark_file); diff --git a/platform/ios/SCsub b/platform/ios/SCsub index 18ba6617af..30d4216464 100644 --- a/platform/ios/SCsub +++ b/platform/ios/SCsub @@ -20,6 +20,7 @@ ios_lib = [ "device_metrics.m", "keyboard_input_view.mm", "key_mapping_ios.mm", + "ios_terminal_logger.mm", ] env_ios = env.Clone() diff --git a/platform/ios/detect.py b/platform/ios/detect.py index 26d81c8ed6..23f688501b 100644 --- a/platform/ios/detect.py +++ b/platform/ios/detect.py @@ -152,7 +152,7 @@ def configure(env: "Environment"): env.Append(CPPDEFINES=["IOS_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED"]) if env["vulkan"]: - env.Append(CPPDEFINES=["VULKAN_ENABLED"]) + env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"]) if env["opengl3"]: env.Append(CPPDEFINES=["GLES3_ENABLED", "GLES_SILENCE_DEPRECATION"]) diff --git a/platform/ios/doc_classes/EditorExportPlatformIOS.xml b/platform/ios/doc_classes/EditorExportPlatformIOS.xml index ecae6d721e..35ef6d6a78 100644 --- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml +++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml @@ -10,6 +10,13 @@ <link title="iOS plugins documentation index">$DOCS_URL/tutorials/platform/ios/index.html</link> </tutorials> <members> + <member name="application/additional_plist_content" type="String" setter="" getter=""> + Additional data added to the root [code]<dict>[/code] section of the [url=https://developer.apple.com/documentation/bundleresources/information_property_list]Info.plist[/url] file. The value should be an XML section with pairs of key-value elements, e.g.: + [codeblock] + <key>key_name</key> + <string>value</string> + [/codeblock] + </member> <member name="application/app_store_team_id" type="String" setter="" getter=""> Apple Team ID, unique 10-character string. To locate your Team ID check "Membership details" section in your Apple developer account dashboard, or "Organizational Unit" of your code signing certificate. See [url=https://developer.apple.com/help/account/manage-your-team/locate-your-team-id]Locate your Team ID[/url]. </member> @@ -34,8 +41,8 @@ <member name="application/icon_interpolation" type="int" setter="" getter=""> Interpolation method used to resize application icon. </member> - <member name="application/launch_screens_interpolation" type="int" setter="" getter=""> - Interpolation method used to resize launch screen images. + <member name="application/min_ios_version" type="String" setter="" getter=""> + Minimum version of iOS required for this application to run in the [code]major.minor.patch[/code] or [code]major.minor[/code] format, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]). </member> <member name="application/provisioning_profile_uuid_debug" type="String" setter="" getter=""> UUID of the provisioning profile. If left empty, Xcode will download or create a provisioning profile automatically. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url]. @@ -63,6 +70,14 @@ <member name="capabilities/access_wifi" type="bool" setter="" getter=""> If [code]true[/code], networking features related to Wi-Fi access are enabled. See [url=https://developer.apple.com/support/required-device-capabilities/]Required Device Capabilities[/url]. </member> + <member name="capabilities/performance_a12" type="bool" setter="" getter=""> + Requires the graphics performance and features of the A12 Bionic and later chips (devices supporting all Vulkan renderer features). + Enabling this option limits supported devices to: iPhone XS, iPhone XR, iPad Mini (5th gen.), iPad Air (3rd gen.), iPad (8th gen) and newer. + </member> + <member name="capabilities/performance_gaming_tier" type="bool" setter="" getter=""> + Requires the graphics performance and features of the A17 Pro and later chips. + Enabling this option limits supported devices to: iPhone 15 Pro and newer. + </member> <member name="capabilities/push_notifications" type="bool" setter="" getter=""> If [code]true[/code], push notifications are enabled. See [url=https://developer.apple.com/support/required-device-capabilities/]Required Device Capabilities[/url]. </member> @@ -108,39 +123,6 @@ <member name="icons/spotlight_80x80" type="String" setter="" getter=""> Spotlight icon file on iPad and iPhone (2x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url]. </member> - <member name="landscape_launch_screens/ipad_1024x768" type="String" setter="" getter=""> - Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image]. - </member> - <member name="landscape_launch_screens/ipad_2048x1536" type="String" setter="" getter=""> - Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image]. - </member> - <member name="landscape_launch_screens/iphone_2208x1242" type="String" setter="" getter=""> - Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image]. - </member> - <member name="landscape_launch_screens/iphone_2436x1125" type="String" setter="" getter=""> - Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image]. - </member> - <member name="portrait_launch_screens/ipad_768x1024" type="String" setter="" getter=""> - Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image]. - </member> - <member name="portrait_launch_screens/ipad_1536x2048" type="String" setter="" getter=""> - Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image]. - </member> - <member name="portrait_launch_screens/iphone_640x960" type="String" setter="" getter=""> - Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image]. - </member> - <member name="portrait_launch_screens/iphone_640x1136" type="String" setter="" getter=""> - Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image]. - </member> - <member name="portrait_launch_screens/iphone_750x1334" type="String" setter="" getter=""> - Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image]. - </member> - <member name="portrait_launch_screens/iphone_1125x2436" type="String" setter="" getter=""> - Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image]. - </member> - <member name="portrait_launch_screens/iphone_1242x2208" type="String" setter="" getter=""> - Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image]. - </member> <member name="privacy/camera_usage_description" type="String" setter="" getter=""> A message displayed when requesting access to the device's camera (in English). </member> @@ -174,9 +156,6 @@ <member name="storyboard/use_custom_bg_color" type="bool" setter="" getter=""> If [code]true[/code], [member storyboard/custom_bg_color] is used as a launch screen background color, otherwise [code]application/boot_splash/bg_color[/code] project setting is used. </member> - <member name="storyboard/use_launch_screen_storyboard" type="bool" setter="" getter=""> - If [code]true[/code], storyboard launch screen is used instead of launch screen images. - </member> <member name="user_data/accessible_from_files_app" type="bool" setter="" getter=""> If [code]true[/code], the app "Documents" folder can be accessed via "Files" app. See [url=https://developer.apple.com/documentation/bundleresources/information_property_list/lssupportsopeningdocumentsinplace]LSSupportsOpeningDocumentsInPlace[/url]. </member> diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index b478759e45..6943f0c637 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -34,6 +34,7 @@ #include "run_icon_svg.gen.h" #include "core/io/json.h" +#include "core/io/plist.h" #include "core/string/translation.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" @@ -105,29 +106,6 @@ static const IconInfo icon_infos[] = { { PNAME("icons/notification_60x60"), "iphone", "Icon-60.png", "60", "3x", "20x20", false } }; -struct LoadingScreenInfo { - const char *preset_key; - const char *export_name; - int width = 0; - int height = 0; - bool rotate = false; -}; - -static const LoadingScreenInfo loading_screen_infos[] = { - { PNAME("landscape_launch_screens/iphone_2436x1125"), "Default-Landscape-X.png", 2436, 1125, false }, - { PNAME("landscape_launch_screens/iphone_2208x1242"), "Default-Landscape-736h@3x.png", 2208, 1242, false }, - { PNAME("landscape_launch_screens/ipad_1024x768"), "Default-Landscape.png", 1024, 768, false }, - { PNAME("landscape_launch_screens/ipad_2048x1536"), "Default-Landscape@2x.png", 2048, 1536, false }, - - { PNAME("portrait_launch_screens/iphone_640x960"), "Default-480h@2x.png", 640, 960, false }, - { PNAME("portrait_launch_screens/iphone_640x1136"), "Default-568h@2x.png", 640, 1136, false }, - { PNAME("portrait_launch_screens/iphone_750x1334"), "Default-667h@2x.png", 750, 1334, false }, - { PNAME("portrait_launch_screens/iphone_1125x2436"), "Default-Portrait-X.png", 1125, 2436, false }, - { PNAME("portrait_launch_screens/ipad_768x1024"), "Default-Portrait.png", 768, 1024, false }, - { PNAME("portrait_launch_screens/ipad_1536x2048"), "Default-Portrait@2x.png", 1536, 2048, false }, - { PNAME("portrait_launch_screens/iphone_1242x2208"), "Default-Portrait-736h@3x.png", 1242, 2208, false } -}; - String EditorExportPlatformIOS::get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const { if (p_preset) { if (p_name == "application/app_store_team_id") { @@ -147,12 +125,6 @@ String EditorExportPlatformIOS::get_export_option_warning(const EditorExportPres } bool EditorExportPlatformIOS::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const { - if (p_preset) { - bool sb = p_preset->get("storyboard/use_launch_screen_storyboard"); - if (!sb && p_option != "storyboard/use_launch_screen_storyboard" && p_option.begins_with("storyboard/")) { - return false; - } - } return true; } @@ -181,8 +153,11 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "Leave empty to use project version"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version", PROPERTY_HINT_PLACEHOLDER_TEXT, "Leave empty to use project version"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/min_ios_version"), "12.0")); + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/additional_plist_content", PROPERTY_HINT_MULTILINE_TEXT), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4)); - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/launch_screens_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/export_project_only"), false)); @@ -217,6 +192,8 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/access_wifi"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/push_notifications"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/performance_gaming_tier"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/performance_a12"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data/accessible_from_files_app"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data/accessible_from_itunes_sharing"), false)); @@ -235,16 +212,11 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, icon_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); } } - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false, true)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale to Fit,Scale to Fill,Scale"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_custom_bg_color"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color())); - - for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); - } } void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug) { @@ -262,8 +234,8 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ }; String dbg_sign_id = p_preset->get("application/code_sign_identity_debug").operator String().is_empty() ? "iPhone Developer" : p_preset->get("application/code_sign_identity_debug"); String rel_sign_id = p_preset->get("application/code_sign_identity_release").operator String().is_empty() ? "iPhone Distribution" : p_preset->get("application/code_sign_identity_release"); - bool dbg_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG).operator String().is_empty() || (dbg_sign_id != "iPhone Developer"); - bool rel_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE).operator String().is_empty() || (rel_sign_id != "iPhone Distribution"); + bool dbg_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG).operator String().is_empty() || (dbg_sign_id != "iPhone Developer" && dbg_sign_id != "iPhone Distribution"); + bool rel_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE).operator String().is_empty() || (rel_sign_id != "iPhone Developer" && rel_sign_id != "iPhone Distribution"); String str; String strnew; str.parse_utf8((const char *)pfile.ptr(), pfile.size()); @@ -287,6 +259,8 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ strnew += lines[i].replace("$short_version", p_preset->get_version("application/short_version")) + "\n"; } else if (lines[i].find("$version") != -1) { strnew += lines[i].replace("$version", p_preset->get_version("application/version")) + "\n"; + } else if (lines[i].find("$min_version") != -1) { + strnew += lines[i].replace("$min_version", p_preset->get("application/min_ios_version")) + "\n"; } else if (lines[i].find("$signature") != -1) { strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n"; } else if (lines[i].find("$team_id") != -1) { @@ -359,7 +333,12 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ if ((bool)p_preset->get("capabilities/access_wifi") && !capabilities_list.has("wifi")) { capabilities_list.push_back("wifi"); } - + if ((bool)p_preset->get("capabilities/performance_gaming_tier") && !capabilities_list.has("iphone-performance-gaming-tier")) { + capabilities_list.push_back("iphone-performance-gaming-tier"); + } + if ((bool)p_preset->get("capabilities/performance_a12") && !capabilities_list.has("iphone-ipad-minimum-performance-a12")) { + capabilities_list.push_back("iphone-ipad-minimum-performance-a12"); + } for (int idx = 0; idx < capabilities_list.size(); idx++) { capabilities += "<string>" + capabilities_list[idx] + "</string>\n"; } @@ -413,29 +392,20 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ String description = p_preset->get("privacy/photolibrary_usage_description"); strnew += lines[i].replace("$photolibrary_usage_description", description) + "\n"; } else if (lines[i].find("$plist_launch_screen_name") != -1) { - bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); - String value = is_on ? "<key>UILaunchStoryboardName</key>\n<string>Launch Screen</string>" : ""; + String value = "<key>UILaunchStoryboardName</key>\n<string>Launch Screen</string>"; strnew += lines[i].replace("$plist_launch_screen_name", value) + "\n"; } else if (lines[i].find("$pbx_launch_screen_file_reference") != -1) { - bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); - String value = is_on ? "90DD2D9D24B36E8000717FE1 = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = \"Launch Screen.storyboard\"; sourceTree = \"<group>\"; };" : ""; + String value = "90DD2D9D24B36E8000717FE1 = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = \"Launch Screen.storyboard\"; sourceTree = \"<group>\"; };"; strnew += lines[i].replace("$pbx_launch_screen_file_reference", value) + "\n"; } else if (lines[i].find("$pbx_launch_screen_copy_files") != -1) { - bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); - String value = is_on ? "90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */," : ""; + String value = "90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */,"; strnew += lines[i].replace("$pbx_launch_screen_copy_files", value) + "\n"; } else if (lines[i].find("$pbx_launch_screen_build_phase") != -1) { - bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); - String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */," : ""; + String value = "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */,"; strnew += lines[i].replace("$pbx_launch_screen_build_phase", value) + "\n"; } else if (lines[i].find("$pbx_launch_screen_build_reference") != -1) { - bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); - String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */; };" : ""; + String value = "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */; };"; strnew += lines[i].replace("$pbx_launch_screen_build_reference", value) + "\n"; - } else if (lines[i].find("$pbx_launch_image_usage_setting") != -1) { - bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); - String value = is_on ? "" : "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;"; - strnew += lines[i].replace("$pbx_launch_image_usage_setting", value) + "\n"; } else if (lines[i].find("$launch_screen_image_mode") != -1) { int image_scale_mode = p_preset->get("storyboard/image_scale_mode"); String value; @@ -783,94 +753,6 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor return OK; } -Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) { - Ref<DirAccess> da = DirAccess::open(p_dest_dir); - ERR_FAIL_COND_V_MSG(da.is_null(), ERR_CANT_OPEN, "Cannot open directory '" + p_dest_dir + "'."); - - for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { - LoadingScreenInfo info = loading_screen_infos[i]; - String loading_screen_file = p_preset->get(info.preset_key); - - Color boot_bg_color = GLOBAL_GET("application/boot_splash/bg_color"); - String boot_logo_path = GLOBAL_GET("application/boot_splash/image"); - bool boot_logo_scale = GLOBAL_GET("application/boot_splash/fullsize"); - - if (loading_screen_file.size() > 0) { - // Load custom loading screens, and resize if required. - Ref<Image> img = memnew(Image); - Error err = ImageLoader::load_image(loading_screen_file, img); - if (err != OK) { - ERR_PRINT("Invalid loading screen (" + String(info.preset_key) + "): '" + loading_screen_file + "'."); - return ERR_UNCONFIGURED; - } - if (img->get_width() != info.width || img->get_height() != info.height) { - WARN_PRINT("Loading screen (" + String(info.preset_key) + "): '" + loading_screen_file + "' has incorrect size (" + String::num_int64(img->get_width()) + "x" + String::num_int64(img->get_height()) + ") and was automatically resized to " + String::num_int64(info.width) + "x" + String::num_int64(info.height) + "."); - float aspect_ratio = (float)img->get_width() / (float)img->get_height(); - if (boot_logo_scale) { - if (info.height * aspect_ratio <= info.width) { - img->resize(info.height * aspect_ratio, info.height, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int())); - } else { - img->resize(info.width, info.width / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int())); - } - } - Ref<Image> new_img = Image::create_empty(info.width, info.height, false, Image::FORMAT_RGBA8); - new_img->fill(boot_bg_color); - _blend_and_rotate(new_img, img, false); - err = new_img->save_png(p_dest_dir + info.export_name); - } else { - err = da->copy(loading_screen_file, p_dest_dir + info.export_name); - } - if (err) { - String err_str = String("Failed to export loading screen (") + info.preset_key + ") from path '" + loading_screen_file + "'."; - ERR_PRINT(err_str.utf8().get_data()); - return err; - } - } else { - // Generate loading screen from the splash screen - Ref<Image> img = Image::create_empty(info.width, info.height, false, Image::FORMAT_RGBA8); - img->fill(boot_bg_color); - - Ref<Image> img_bs; - - if (boot_logo_path.length() > 0) { - img_bs = Ref<Image>(memnew(Image)); - ImageLoader::load_image(boot_logo_path, img_bs); - } - if (!img_bs.is_valid()) { - img_bs = Ref<Image>(memnew(Image(boot_splash_png))); - } - if (img_bs.is_valid()) { - float aspect_ratio = (float)img_bs->get_width() / (float)img_bs->get_height(); - if (info.rotate) { - if (boot_logo_scale) { - if (info.width * aspect_ratio <= info.height) { - img_bs->resize(info.width * aspect_ratio, info.width, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int())); - } else { - img_bs->resize(info.height, info.height / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int())); - } - } - } else { - if (boot_logo_scale) { - if (info.height * aspect_ratio <= info.width) { - img_bs->resize(info.height * aspect_ratio, info.height, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int())); - } else { - img_bs->resize(info.width, info.width / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int())); - } - } - } - _blend_and_rotate(img, img_bs, info.rotate); - } - Error err = img->save_png(p_dest_dir + info.export_name); - if (err) { - String err_str = String("Failed to export loading screen (") + info.preset_key + ") from splash screen."; - WARN_PRINT(err_str.utf8().get_data()); - } - } - } - - return OK; -} - Error EditorExportPlatformIOS::_walk_dir_recursive(Ref<DirAccess> &p_da, FileHandler p_handler, void *p_userdata) { Vector<String> dirs; String current_dir = p_da->get_current_dir(); @@ -986,7 +868,183 @@ struct ExportLibsData { String dest_dir; }; -void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets) { +void EditorExportPlatformIOS::_check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const { + Ref<PList> plist; + plist.instantiate(); + plist->load_file(p_path.path_join("Info.plist")); + Ref<PListNode> root_node = plist->get_root(); + if (root_node.is_null()) { + return; + } + Dictionary root = root_node->get_value(); + if (!root.has("AvailableLibraries")) { + return; + } + Ref<PListNode> libs_node = root["AvailableLibraries"]; + if (libs_node.is_null()) { + return; + } + Array libs = libs_node->get_value(); + r_total_libs = libs.size(); + for (int j = 0; j < libs.size(); j++) { + Ref<PListNode> lib_node = libs[j]; + if (lib_node.is_null()) { + return; + } + Dictionary lib = lib_node->get_value(); + if (lib.has("BinaryPath")) { + Ref<PListNode> path_node = lib["BinaryPath"]; + if (path_node.is_valid()) { + String path = path_node->get_value(); + if (path.ends_with(".a")) { + r_static_libs++; + } + if (path.ends_with(".dylib")) { + r_dylibs++; + } + if (path.ends_with(".framework")) { + r_frameworks++; + } + } + } + } +} + +Error EditorExportPlatformIOS::_convert_to_framework(const String &p_source, const String &p_destination, const String &p_id) const { + print_line("Converting to .framework", p_source, " -> ", p_destination); + + Ref<DirAccess> da = DirAccess::create_for_path(p_source); + if (da.is_null()) { + return ERR_CANT_OPEN; + } + + Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (filesystem_da.is_null()) { + return ERR_CANT_OPEN; + } + + if (!filesystem_da->dir_exists(p_destination)) { + Error make_dir_err = filesystem_da->make_dir_recursive(p_destination); + if (make_dir_err) { + return make_dir_err; + } + } + + String asset = p_source.ends_with("/") ? p_source.left(p_source.length() - 1) : p_source; + if (asset.ends_with(".xcframework")) { + Ref<PList> plist; + plist.instantiate(); + plist->load_file(p_source.path_join("Info.plist")); + Ref<PListNode> root_node = plist->get_root(); + if (root_node.is_null()) { + return ERR_CANT_OPEN; + } + Dictionary root = root_node->get_value(); + if (!root.has("AvailableLibraries")) { + return ERR_CANT_OPEN; + } + Ref<PListNode> libs_node = root["AvailableLibraries"]; + if (libs_node.is_null()) { + return ERR_CANT_OPEN; + } + Array libs = libs_node->get_value(); + for (int j = 0; j < libs.size(); j++) { + Ref<PListNode> lib_node = libs[j]; + if (lib_node.is_null()) { + return ERR_CANT_OPEN; + } + Dictionary lib = lib_node->get_value(); + if (lib.has("BinaryPath") && lib.has("LibraryPath") && lib.has("LibraryIdentifier")) { + Ref<PListNode> bpath_node = lib["BinaryPath"]; + Ref<PListNode> lpath_node = lib["LibraryPath"]; + Ref<PListNode> lid_node = lib["LibraryIdentifier"]; + if (bpath_node.is_valid() && lpath_node.is_valid() && lid_node.is_valid()) { + String binary_path = bpath_node->get_value(); + String library_identifier = lid_node->get_value(); + + String file_name = binary_path.get_basename().get_file(); + String framework_name = file_name + ".framework"; + + bpath_node->data_string = framework_name.utf8(); + lpath_node->data_string = framework_name.utf8(); + if (!filesystem_da->dir_exists(p_destination.path_join(library_identifier))) { + filesystem_da->make_dir_recursive(p_destination.path_join(library_identifier)); + } + _convert_to_framework(p_source.path_join(library_identifier).path_join(binary_path), p_destination.path_join(library_identifier).path_join(framework_name), p_id); + if (lib.has("DebugSymbolsPath")) { + Ref<PListNode> dpath_node = lib["DebugSymbolsPath"]; + if (dpath_node.is_valid()) { + String dpath = dpath_node->get_value(); + if (da->dir_exists(p_source.path_join(library_identifier).path_join(dpath))) { + da->copy_dir(p_source.path_join(library_identifier).path_join(dpath), p_destination.path_join(library_identifier).path_join("dSYMs")); + } + } + } + } + } + } + String info_plist = plist->save_text(); + + Ref<FileAccess> f = FileAccess::open(p_destination.path_join("Info.plist"), FileAccess::WRITE); + if (f.is_valid()) { + f->store_string(info_plist); + } + } else { + String file_name = p_destination.get_basename().get_file(); + String framework_name = file_name + ".framework"; + + da->copy(p_source, p_destination.path_join(file_name)); + + // Performing `install_name_tool -id @rpath/{name}.framework/{name} ./{name}` on dylib + { + List<String> install_name_args; + install_name_args.push_back("-id"); + install_name_args.push_back(String("@rpath").path_join(framework_name).path_join(file_name)); + install_name_args.push_back(p_destination.path_join(file_name)); + + OS::get_singleton()->execute("install_name_tool", install_name_args); + } + + // Creating Info.plist + { + String info_plist_format = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + "<plist version=\"1.0\">\n" + " <dict>\n" + " <key>CFBundleShortVersionString</key>\n" + " <string>1.0</string>\n" + " <key>CFBundleIdentifier</key>\n" + " <string>$id.framework.$name</string>\n" + " <key>CFBundleName</key>\n" + " <string>$name</string>\n" + " <key>CFBundleExecutable</key>\n" + " <string>$name</string>\n" + " <key>DTPlatformName</key>\n" + " <string>iphoneos</string>\n" + " <key>CFBundleInfoDictionaryVersion</key>\n" + " <string>6.0</string>\n" + " <key>CFBundleVersion</key>\n" + " <string>1</string>\n" + " <key>CFBundlePackageType</key>\n" + " <string>FMWK</string>\n" + " <key>MinimumOSVersion</key>\n" + " <string>12.0</string>\n" + " </dict>\n" + "</plist>"; + + String info_plist = info_plist_format.replace("$id", p_id).replace("$name", file_name); + + Ref<FileAccess> f = FileAccess::open(p_destination.path_join("Info.plist"), FileAccess::WRITE); + if (f.is_valid()) { + f->store_string(info_plist); + } + } + } + + return OK; +} + +void EditorExportPlatformIOS::_add_assets_to_project(const String &p_out_dir, const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets) { // that is just a random number, we just need Godot IDs not to clash with // existing IDs in the project. PbxId current_id = { 0x58938401, 0, 0 }; @@ -1011,7 +1069,12 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese String type; if (asset.exported_path.ends_with(".framework")) { - if (asset.should_embed) { + int total_libs = 0; + int static_libs = 0; + int dylibs = 0; + int frameworks = 0; + _check_xcframework_content(p_out_dir.path_join(asset.exported_path), total_libs, static_libs, dylibs, frameworks); + if (asset.should_embed && (static_libs != total_libs)) { additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n"; framework_id = (++current_id).str(); pbx_embeded_frameworks += framework_id + ",\n"; @@ -1074,12 +1137,12 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese } } -Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) { +Error EditorExportPlatformIOS::_copy_asset(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) { String binary_name = p_out_dir.get_file().get_basename(); Ref<DirAccess> da = DirAccess::create_for_path(p_asset); if (da.is_null()) { - ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't create directory: " + p_asset + "."); + ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't open directory: " + p_asset + "."); } bool file_exists = da->file_exists(p_asset); bool dir_exists = da->dir_exists(p_asset); @@ -1093,7 +1156,8 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String String destination; String asset_path; - bool create_framework = false; + Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V_MSG(filesystem_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'."); if (p_is_framework && asset.ends_with(".dylib")) { // For iOS we need to turn .dylib into .framework @@ -1113,10 +1177,23 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String asset_path = asset_path.path_join(framework_name); destination_dir = p_out_dir.path_join(asset_path); destination = destination_dir.path_join(file_name); - create_framework = true; - } else if (p_is_framework && (asset.ends_with(".framework") || asset.ends_with(".xcframework"))) { - asset_path = String("dylibs").path_join(base_dir); + // Convert to framework and copy. + Error err = _convert_to_framework(p_asset, destination, p_preset->get("application/bundle_identifier")); + if (err) { + return err; + } + } else if (p_is_framework && asset.ends_with(".xcframework")) { + // For iOS we need to turn .dylib inside .xcframework + // into .framework to be able to send application to AppStore + + int total_libs = 0; + int static_libs = 0; + int dylibs = 0; + int frameworks = 0; + _check_xcframework_content(p_asset, total_libs, static_libs, dylibs, frameworks); + + asset_path = String("dylibs").path_join(base_dir); String file_name; if (!p_custom_file_name) { @@ -1128,8 +1205,29 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String asset_path = asset_path.path_join(file_name); destination_dir = p_out_dir.path_join(asset_path); destination = destination_dir; - } else { - asset_path = base_dir; + + if (dylibs > 0) { + // Convert to framework and copy. + Error err = _convert_to_framework(p_asset, destination, p_preset->get("application/bundle_identifier")); + if (err) { + return err; + } + } else { + // Copy as is. + if (!filesystem_da->dir_exists(destination_dir)) { + Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir); + if (make_dir_err) { + return make_dir_err; + } + } + Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination); + if (err) { + return err; + } + } + } else if (p_is_framework && asset.ends_with(".framework")) { + // Framework. + asset_path = String("dylibs").path_join(base_dir); String file_name; @@ -1139,99 +1237,67 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String file_name = *p_custom_file_name; } - destination_dir = p_out_dir.path_join(asset_path); asset_path = asset_path.path_join(file_name); - destination = p_out_dir.path_join(asset_path); - } - - Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V_MSG(filesystem_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'."); + destination_dir = p_out_dir.path_join(asset_path); + destination = destination_dir; - if (!filesystem_da->dir_exists(destination_dir)) { - Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir); - if (make_dir_err) { - return make_dir_err; + // Copy as is. + if (!filesystem_da->dir_exists(destination_dir)) { + Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir); + if (make_dir_err) { + return make_dir_err; + } } - } - - Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination); - if (err) { - return err; - } - if (asset_path.ends_with("/")) { - asset_path = asset_path.left(asset_path.length() - 1); - } - IOSExportAsset exported_asset = { binary_name.path_join(asset_path), p_is_framework, p_should_embed }; - r_exported_assets.push_back(exported_asset); + Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination); + if (err) { + return err; + } + } else { + // Unknown resource. + asset_path = base_dir; - if (create_framework) { String file_name; if (!p_custom_file_name) { - file_name = p_asset.get_basename().get_file(); + file_name = p_asset.get_file(); } else { file_name = *p_custom_file_name; } - String framework_name = file_name + ".framework"; - - // Performing `install_name_tool -id @rpath/{name}.framework/{name} ./{name}` on dylib - { - List<String> install_name_args; - install_name_args.push_back("-id"); - install_name_args.push_back(String("@rpath").path_join(framework_name).path_join(file_name)); - install_name_args.push_back(destination); - - OS::get_singleton()->execute("install_name_tool", install_name_args); - } - - // Creating Info.plist - { - String info_plist_format = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" - "<plist version=\"1.0\">\n" - "<dict>\n" - "<key>CFBundleShortVersionString</key>\n" - "<string>1.0</string>\n" - "<key>CFBundleIdentifier</key>\n" - "<string>com.gdextension.framework.$name</string>\n" - "<key>CFBundleName</key>\n" - "<string>$name</string>\n" - "<key>CFBundleExecutable</key>\n" - "<string>$name</string>\n" - "<key>DTPlatformName</key>\n" - "<string>iphoneos</string>\n" - "<key>CFBundleInfoDictionaryVersion</key>\n" - "<string>6.0</string>\n" - "<key>CFBundleVersion</key>\n" - "<string>1</string>\n" - "<key>CFBundlePackageType</key>\n" - "<string>FMWK</string>\n" - "<key>MinimumOSVersion</key>\n" - "<string>10.0</string>\n" - "</dict>\n" - "</plist>"; - - String info_plist = info_plist_format.replace("$name", file_name); + destination_dir = p_out_dir.path_join(asset_path); + asset_path = asset_path.path_join(file_name); + destination = p_out_dir.path_join(asset_path); - Ref<FileAccess> f = FileAccess::open(destination_dir.path_join("Info.plist"), FileAccess::WRITE); - if (f.is_valid()) { - f->store_string(info_plist); + // Copy as is. + if (!filesystem_da->dir_exists(destination_dir)) { + Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir); + if (make_dir_err) { + return make_dir_err; } } + Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination); + if (err) { + return err; + } } + if (asset_path.ends_with("/")) { + asset_path = asset_path.left(asset_path.length() - 1); + } + IOSExportAsset exported_asset = { binary_name.path_join(asset_path), p_is_framework, p_should_embed }; + r_exported_assets.push_back(exported_asset); + return OK; } -Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) { +Error EditorExportPlatformIOS::_export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) { for (int f_idx = 0; f_idx < p_assets.size(); ++f_idx) { - String asset = p_assets[f_idx]; + const String &asset = p_assets[f_idx]; if (asset.begins_with("res://")) { - Error err = _copy_asset(p_out_dir, asset, nullptr, p_is_framework, p_should_embed, r_exported_assets); + Error err = _copy_asset(p_preset, p_out_dir, asset, nullptr, p_is_framework, p_should_embed, r_exported_assets); ERR_FAIL_COND_V(err != OK, err); } else if (ProjectSettings::get_singleton()->localize_path(asset).begins_with("res://")) { - Error err = _copy_asset(p_out_dir, ProjectSettings::get_singleton()->localize_path(asset), nullptr, p_is_framework, p_should_embed, r_exported_assets); + Error err = _copy_asset(p_preset, p_out_dir, ProjectSettings::get_singleton()->localize_path(asset), nullptr, p_is_framework, p_should_embed, r_exported_assets); ERR_FAIL_COND_V(err != OK, err); } else { // either SDK-builtin or already a part of the export template @@ -1243,26 +1309,26 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir return OK; } -Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets) { +Error EditorExportPlatformIOS::_export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets) { Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins(); for (int i = 0; i < export_plugins.size(); i++) { Vector<String> linked_frameworks = export_plugins[i]->get_ios_frameworks(); - Error err = _export_additional_assets(p_out_dir, linked_frameworks, true, false, r_exported_assets); + Error err = _export_additional_assets(p_preset, p_out_dir, linked_frameworks, true, false, r_exported_assets); ERR_FAIL_COND_V(err, err); Vector<String> embedded_frameworks = export_plugins[i]->get_ios_embedded_frameworks(); - err = _export_additional_assets(p_out_dir, embedded_frameworks, true, true, r_exported_assets); + err = _export_additional_assets(p_preset, p_out_dir, embedded_frameworks, true, true, r_exported_assets); ERR_FAIL_COND_V(err, err); Vector<String> project_static_libs = export_plugins[i]->get_ios_project_static_libs(); for (int j = 0; j < project_static_libs.size(); j++) { project_static_libs.write[j] = project_static_libs[j].get_file(); // Only the file name as it's copied to the project } - err = _export_additional_assets(p_out_dir, project_static_libs, true, false, r_exported_assets); + err = _export_additional_assets(p_preset, p_out_dir, project_static_libs, true, false, r_exported_assets); ERR_FAIL_COND_V(err, err); Vector<String> ios_bundle_files = export_plugins[i]->get_ios_bundle_files(); - err = _export_additional_assets(p_out_dir, ios_bundle_files, false, false, r_exported_assets); + err = _export_additional_assets(p_preset, p_out_dir, ios_bundle_files, false, false, r_exported_assets); ERR_FAIL_COND_V(err, err); } @@ -1270,7 +1336,7 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir for (int i = 0; i < p_libraries.size(); ++i) { library_paths.push_back(p_libraries[i].path); } - Error err = _export_additional_assets(p_out_dir, library_paths, true, true, r_exported_assets); + Error err = _export_additional_assets(p_preset, p_out_dir, library_paths, true, true, r_exported_assets); ERR_FAIL_COND_V(err, err); return OK; @@ -1315,7 +1381,7 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset> String plugin_binary_result_file = plugin.binary.get_file(); // We shouldn't embed .xcframework that contains static libraries. // Static libraries are not embedded anyway. - err = _copy_asset(dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets); + err = _copy_asset(p_preset, dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets); ERR_FAIL_COND_V(err != OK, err); // Adding dependencies. @@ -1440,15 +1506,15 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset> // Export files { // Export linked plugin dependency - err = _export_additional_assets(dest_dir, plugin_linked_dependencies, true, false, r_exported_assets); + err = _export_additional_assets(p_preset, dest_dir, plugin_linked_dependencies, true, false, r_exported_assets); ERR_FAIL_COND_V(err != OK, err); // Export embedded plugin dependency - err = _export_additional_assets(dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets); + err = _export_additional_assets(p_preset, dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets); ERR_FAIL_COND_V(err != OK, err); // Export plugin files - err = _export_additional_assets(dest_dir, plugin_files, false, false, r_exported_assets); + err = _export_additional_assets(p_preset, dest_dir, plugin_files, false, false, r_exported_assets); ERR_FAIL_COND_V(err != OK, err); } @@ -1619,6 +1685,8 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres false }; + config_data.plist_content += p_preset->get("application/additional_plist_content").operator String() + "\n"; + Vector<IOSExportAsset> assets; Ref<DirAccess> tmp_app_path = DirAccess::create_for_path(dest_dir); @@ -1824,9 +1892,6 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres } { - bool use_storyboard = p_preset->get("storyboard/use_launch_screen_storyboard"); - - String launch_image_path = binary_dir + "/Images.xcassets/LaunchImage.launchimage/"; String splash_image_path = binary_dir + "/Images.xcassets/SplashImage.imageset/"; Ref<DirAccess> launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); @@ -1835,30 +1900,11 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres return ERR_CANT_CREATE; } - if (use_storyboard) { - print_line("Using Launch Storyboard"); + print_line("Exporting launch screen storyboard"); - if (launch_screen_da->change_dir(launch_image_path) == OK) { - launch_screen_da->erase_contents_recursive(); - launch_screen_da->remove(launch_image_path); - } - - err = _export_loading_screen_file(p_preset, splash_image_path); + err = _export_loading_screen_file(p_preset, splash_image_path); + if (err != OK) { add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Failed to create a file at path \"%s\" with code %d."), splash_image_path, err)); - } else { - print_line("Using Launch Images"); - - const String launch_screen_path = binary_dir + "/Launch Screen.storyboard"; - - launch_screen_da->remove(launch_screen_path); - - if (launch_screen_da->change_dir(splash_image_path) == OK) { - launch_screen_da->erase_contents_recursive(); - launch_screen_da->remove(splash_image_path); - } - - err = _export_loading_screen_images(p_preset, launch_image_path); - add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Failed to create a file at path \"%s\" with code %d."), launch_image_path, err)); } } @@ -1867,8 +1913,8 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres } print_line("Exporting additional assets"); - _export_additional_assets(binary_dir, libraries, assets); - _add_assets_to_project(p_preset, project_file_data, assets); + _export_additional_assets(p_preset, binary_dir, libraries, assets); + _add_assets_to_project(dest_dir, p_preset, project_file_data, assets); String project_file_name = binary_dir + ".xcodeproj/project.pbxproj"; { Ref<FileAccess> f = FileAccess::open(project_file_name, FileAccess::WRITE); @@ -2010,6 +2056,26 @@ bool EditorExportPlatformIOS::has_valid_export_configuration(const Ref<EditorExp valid = dvalid || rvalid; r_missing_templates = !valid; + const String &additional_plist_content = p_preset->get("application/additional_plist_content"); + if (!additional_plist_content.is_empty()) { + const String &plist = vformat("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" + "<plist version=\"1.0\">" + "<dict>\n" + "%s\n" + "</dict>\n" + "</plist>\n", + additional_plist_content); + + String plist_err; + Ref<PList> plist_parser; + plist_parser.instantiate(); + if (!plist_parser->load_string(plist, plist_err)) { + err += TTR("Invalid additional PList content: ") + plist_err + "\n"; + valid = false; + } + } + if (!err.is_empty()) { r_error = err; } diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h index fd2243bcda..edbe566dab 100644 --- a/platform/ios/export/export_plugin.h +++ b/platform/ios/export/export_plugin.h @@ -127,17 +127,19 @@ class EditorExportPlatformIOS : public EditorExportPlatform { String _get_linker_flags(); String _get_cpp_code(); void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug); - Error _export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir); Error _export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir); Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir); Vector<ExportArchitecture> _get_supported_architectures() const; Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset) const; - void _add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets); - Error _export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets); - Error _copy_asset(const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets); - Error _export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets); + void _check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const; + Error _convert_to_framework(const String &p_source, const String &p_destination, const String &p_id) const; + + void _add_assets_to_project(const String &p_out_dir, const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets); + Error _export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets); + Error _copy_asset(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets); + Error _export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets); Error _export_ios_plugins(const Ref<EditorExportPreset> &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector<IOSExportAsset> &r_exported_assets, bool p_debug); Error _export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags, bool p_simulator, bool p_oneclick); diff --git a/platform/ios/ios_terminal_logger.h b/platform/ios/ios_terminal_logger.h new file mode 100644 index 0000000000..7f0bc37a07 --- /dev/null +++ b/platform/ios/ios_terminal_logger.h @@ -0,0 +1,45 @@ +/**************************************************************************/ +/* ios_terminal_logger.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef IOS_TERMINAL_LOGGER_H +#define IOS_TERMINAL_LOGGER_H + +#ifdef IOS_ENABLED + +#include "core/io/logger.h" + +class IOSTerminalLogger : public StdLogger { +public: + virtual void log_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, ErrorType p_type = ERR_ERROR) override; +}; + +#endif // IOS_ENABLED + +#endif // IOS_TERMINAL_LOGGER_H diff --git a/platform/ios/ios_terminal_logger.mm b/platform/ios/ios_terminal_logger.mm new file mode 100644 index 0000000000..b4c9821cdc --- /dev/null +++ b/platform/ios/ios_terminal_logger.mm @@ -0,0 +1,74 @@ +/**************************************************************************/ +/* ios_terminal_logger.mm */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "ios_terminal_logger.h" + +#ifdef IOS_ENABLED + +#include <os/log.h> + +void IOSTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type) { + if (!should_log(true)) { + return; + } + + const char *err_details; + if (p_rationale && p_rationale[0]) { + err_details = p_rationale; + } else { + err_details = p_code; + } + + switch (p_type) { + case ERR_WARNING: + os_log_info(OS_LOG_DEFAULT, + "WARNING: %{public}s\nat: %{public}s (%{public}s:%i)", + err_details, p_function, p_file, p_line); + break; + case ERR_SCRIPT: + os_log_error(OS_LOG_DEFAULT, + "SCRIPT ERROR: %{public}s\nat: %{public}s (%{public}s:%i)", + err_details, p_function, p_file, p_line); + break; + case ERR_SHADER: + os_log_error(OS_LOG_DEFAULT, + "SHADER ERROR: %{public}s\nat: %{public}s (%{public}s:%i)", + err_details, p_function, p_file, p_line); + break; + case ERR_ERROR: + default: + os_log_error(OS_LOG_DEFAULT, + "ERROR: %{public}s\nat: %{public}s (%{public}s:%i)", + err_details, p_function, p_file, p_line); + break; + } +} + +#endif // IOS_ENABLED diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm index a646705305..6ac21fa9c8 100644 --- a/platform/ios/os_ios.mm +++ b/platform/ios/os_ios.mm @@ -35,6 +35,7 @@ #import "app_delegate.h" #import "display_server_ios.h" #import "godot_view.h" +#import "ios_terminal_logger.h" #import "view_controller.h" #include "core/config/project_settings.h" @@ -105,12 +106,7 @@ OS_IOS::OS_IOS() { main_loop = nullptr; Vector<Logger *> loggers; - loggers.push_back(memnew(SyslogLogger)); -#ifdef DEBUG_ENABLED - // it seems iOS app's stdout/stderr is only obtainable if you launch it from - // Xcode - loggers.push_back(memnew(StdLogger)); -#endif + loggers.push_back(memnew(IOSTerminalLogger)); _set_logger(memnew(CompositeLogger(loggers))); AudioDriverManager::add_driver(&audio_driver); @@ -257,6 +253,8 @@ Error OS_IOS::open_dynamic_library(const String p_path, void *&p_library_handle, path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file().get_basename() + ".framework")); } + ERR_FAIL_COND_V(!FileAccess::exists(path), ERR_FILE_NOT_FOUND); + p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror())); diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 59cc6e7962..eaaaad82b9 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -434,7 +434,7 @@ def configure(env: "Environment"): env.Append(CPPDEFINES=["X11_ENABLED"]) if env["vulkan"]: - env.Append(CPPDEFINES=["VULKAN_ENABLED"]) + env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"]) if not env["use_volk"]: env.ParseConfig("pkg-config vulkan --cflags --libs") if not env["builtin_glslang"]: diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp index 6a5b5b8064..3641f20c70 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.cpp +++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp @@ -162,7 +162,7 @@ void FreeDesktopPortalDesktop::append_dbus_dict_filters(DBusMessageIter *p_iter, append_dbus_string(&struct_iter, p_filter_names[i]); dbus_message_iter_open_container(&struct_iter, DBUS_TYPE_ARRAY, "(us)", &array_iter); - String flt = p_filter_exts[i]; + const String &flt = p_filter_exts[i]; int filter_slice_count = flt.get_slice_count(","); for (int j = 0; j < filter_slice_count; j++) { dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, nullptr, &array_struct_iter); diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index d22d398a67..aed8574902 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -316,7 +316,7 @@ Vector<String> OS_LinuxBSD::get_video_adapter_driver_info() const { continue; } String device_class = columns[1].trim_suffix(":"); - String vendor_device_id_mapping = columns[2]; + const String &vendor_device_id_mapping = columns[2]; #ifdef MODULE_REGEX_ENABLED if (regex_id_format.search(vendor_device_id_mapping).is_null()) { diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 1434342bbc..d8a81266d0 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -2891,10 +2891,15 @@ void DisplayServerX11::window_move_to_foreground(WindowID p_window) { XFlush(x11_display); } +DisplayServerX11::WindowID DisplayServerX11::get_focused_window() const { + return last_focused_window; +} + bool DisplayServerX11::window_is_focused(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), false); + const WindowData &wd = windows[p_window]; return wd.focused; @@ -3875,7 +3880,7 @@ void DisplayServerX11::_xim_preedit_draw_callback(::XIM xim, ::XPointer client_d ds->im_selection = Point2i(); } - OS_Unix::get_singleton()->get_main_loop()->call_deferred(SNAME("notification"), MainLoop::NOTIFICATION_OS_IME_UPDATE); + callable_mp((Object *)OS_Unix::get_singleton()->get_main_loop(), &Object::notification).call_deferred(MainLoop::NOTIFICATION_OS_IME_UPDATE, false); } } diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index ac2c7843f6..378d8bb407 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -491,6 +491,8 @@ public: virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override; virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual WindowID get_focused_window() const override; + virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; virtual bool can_any_window_draw() const override; diff --git a/platform/linuxbsd/x11/key_mapping_x11.cpp b/platform/linuxbsd/x11/key_mapping_x11.cpp index 0f709872cb..c0e6b91d57 100644 --- a/platform/linuxbsd/x11/key_mapping_x11.cpp +++ b/platform/linuxbsd/x11/key_mapping_x11.cpp @@ -88,7 +88,6 @@ void KeyMappingX11::initialize() { xkeysym_map[XK_KP_Equal] = Key::EQUAL; xkeysym_map[XK_KP_Separator] = Key::COMMA; xkeysym_map[XK_KP_Decimal] = Key::KP_PERIOD; - xkeysym_map[XK_KP_Delete] = Key::KP_PERIOD; xkeysym_map[XK_KP_Multiply] = Key::KP_MULTIPLY; xkeysym_map[XK_KP_Divide] = Key::KP_DIVIDE; xkeysym_map[XK_KP_Subtract] = Key::KP_SUBTRACT; @@ -105,6 +104,7 @@ void KeyMappingX11::initialize() { xkeysym_map[XK_KP_9] = Key::KP_9; // Same keys but with numlock off. xkeysym_map[XK_KP_Insert] = Key::INSERT; + xkeysym_map[XK_KP_Delete] = Key::KEY_DELETE; xkeysym_map[XK_KP_End] = Key::END; xkeysym_map[XK_KP_Down] = Key::DOWN; xkeysym_map[XK_KP_Page_Down] = Key::PAGEDOWN; diff --git a/platform/macos/detect.py b/platform/macos/detect.py index b41d2141fb..12db2690de 100644 --- a/platform/macos/detect.py +++ b/platform/macos/detect.py @@ -260,7 +260,7 @@ def configure(env: "Environment"): env.Append(LINKFLAGS=["-rpath", "@executable_path/../Frameworks", "-rpath", "@executable_path"]) if env["vulkan"]: - env.Append(CPPDEFINES=["VULKAN_ENABLED"]) + env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"]) env.Append(LINKFLAGS=["-framework", "Metal", "-framework", "IOSurface"]) if not env["use_volk"]: env.Append(LINKFLAGS=["-lMoltenVK"]) diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index f8fd0f93ef..cc343a6d64 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -428,6 +428,8 @@ public: virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override; virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual WindowID get_focused_window() const override; + virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; virtual bool can_any_window_draw() const override; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index bd92b7d472..378688f78a 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -3723,6 +3723,10 @@ bool DisplayServerMacOS::window_is_focused(WindowID p_window) const { return wd.focused; } +DisplayServerMacOS::WindowID DisplayServerMacOS::get_focused_window() const { + return last_focused_window; +} + bool DisplayServerMacOS::window_can_draw(WindowID p_window) const { return windows[p_window].is_visible; } diff --git a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml index 85fefe65c0..506b0dffb8 100644 --- a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml +++ b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml @@ -10,6 +10,13 @@ <link title="Running Godot apps on macOS">$DOCS_URL/tutorials//export/running_on_macos.html</link> </tutorials> <members> + <member name="application/additional_plist_content" type="String" setter="" getter=""> + Additional data added to the root [code]<dict>[/code] section of the [url=https://developer.apple.com/documentation/bundleresources/information_property_list]Info.plist[/url] file. The value should be an XML section with pairs of key-value elements, e.g.: + [codeblock] + <key>key_name</key> + <string>value</string> + [/codeblock] + </member> <member name="application/app_category" type="String" setter="" getter=""> Application category for the App Store. </member> diff --git a/platform/macos/export/codesign.cpp b/platform/macos/export/codesign.cpp index 2b8898e6a1..082c0abea7 100644 --- a/platform/macos/export/codesign.cpp +++ b/platform/macos/export/codesign.cpp @@ -32,8 +32,8 @@ #include "lipo.h" #include "macho.h" -#include "plist.h" +#include "core/io/plist.h" #include "core/os/os.h" #include "editor/editor_paths.h" #include "editor/editor_settings.h" diff --git a/platform/macos/export/codesign.h b/platform/macos/export/codesign.h index 3e61751a96..49d53b376e 100644 --- a/platform/macos/export/codesign.h +++ b/platform/macos/export/codesign.h @@ -41,11 +41,10 @@ // - Requirements code generator is not implemented (only hard-coded requirements for the ad-hoc signing is supported). // - RFC5652/CMS blob generation is not implemented, supports ad-hoc signing only. -#include "plist.h" - #include "core/crypto/crypto_core.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" +#include "core/io/plist.h" #include "core/object/ref_counted.h" #include "modules/modules_enabled.gen.h" // For regex. diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index 6f9db1427b..c347082010 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -37,6 +37,7 @@ #include "run_icon_svg.gen.h" #include "core/io/image_loader.h" +#include "core/io/plist.h" #include "core/string/translation.h" #include "drivers/png/png_driver_common.h" #include "editor/editor_node.h" @@ -388,6 +389,8 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_angle", PROPERTY_HINT_ENUM, "Auto,Yes,No"), 0, true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/additional_plist_content", PROPERTY_HINT_MULTILINE_TEXT), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/platform_build"), "14C18")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/sdk_version"), "13.1")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/sdk_build"), "22C55")); @@ -672,6 +675,8 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref<EditorExportPreset> &p_pres strnew += lines[i].replace("$min_version", p_preset->get("application/min_macos_version")) + "\n"; } else if (lines[i].find("$highres") != -1) { strnew += lines[i].replace("$highres", p_preset->get("display/high_res") ? "\t<true/>" : "\t<false/>") + "\n"; + } else if (lines[i].find("$additional_plist_content") != -1) { + strnew += lines[i].replace("$additional_plist_content", p_preset->get("application/additional_plist_content")) + "\n"; } else if (lines[i].find("$platfbuild") != -1) { strnew += lines[i].replace("$platfbuild", p_preset->get("xcode/platform_build")) + "\n"; } else if (lines[i].find("$sdkver") != -1) { @@ -2051,13 +2056,17 @@ bool EditorExportPlatformMacOS::has_valid_export_configuration(const Ref<EditorE String architecture = p_preset->get("binary_format/architecture"); if (architecture == "universal" || architecture == "x86_64") { if (!ResourceImporterTextureSettings::should_import_s3tc_bptc()) { + err += TTR("Cannot export for universal or x86_64 if S3TC BPTC texture format is disabled. Enable it in the Project Settings (Rendering > Textures > VRAM Compression > Import S3TC BPTC).") + "\n"; valid = false; } - } else if (architecture == "arm64") { + } + if (architecture == "universal" || architecture == "arm64") { if (!ResourceImporterTextureSettings::should_import_etc2_astc()) { + err += TTR("Cannot export for universal or arm64 if ETC2 ASTC texture format is disabled. Enable it in the Project Settings (Rendering > Textures > VRAM Compression > Import ETC2 ASTC).") + "\n"; valid = false; } - } else { + } + if (architecture != "universal" && architecture != "x86_64" && architecture != "arm64") { ERR_PRINT("Invalid architecture"); } @@ -2091,6 +2100,26 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor }; } + const String &additional_plist_content = p_preset->get("application/additional_plist_content"); + if (!additional_plist_content.is_empty()) { + const String &plist = vformat("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" + "<plist version=\"1.0\">" + "<dict>\n" + "%s\n" + "</dict>\n" + "</plist>\n", + additional_plist_content); + + String plist_err; + Ref<PList> plist_parser; + plist_parser.instantiate(); + if (!plist_parser->load_string(plist, plist_err)) { + err += TTR("Invalid additional PList content: ") + plist_err + "\n"; + valid = false; + } + } + List<ExportOption> options; get_export_options(&options); for (const EditorExportPlatform::ExportOption &E : options) { diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm index 29dff683d5..b8496d72fb 100644 --- a/platform/macos/os_macos.mm +++ b/platform/macos/os_macos.mm @@ -230,6 +230,8 @@ Error OS_MacOS::open_dynamic_library(const String p_path, void *&p_library_handl path = get_framework_executable(get_executable_path().get_base_dir().path_join("../Frameworks").path_join(p_path.get_file())); } + ERR_FAIL_COND_V(!FileAccess::exists(path), ERR_FILE_NOT_FOUND); + p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror())); diff --git a/platform/web/detect.py b/platform/web/detect.py index 579eaaff03..53fae67f6a 100644 --- a/platform/web/detect.py +++ b/platform/web/detect.py @@ -30,6 +30,9 @@ def get_opts(): return [ ("initial_memory", "Initial WASM memory (in MiB)", 32), + # Matches default values from before Emscripten 3.1.27. New defaults are too low for Godot. + ("stack_size", "WASM stack size (in KiB)", 5120), + ("default_pthread_stack_size", "WASM pthread default stack size (in KiB)", 2048), BoolVariable("use_assertions", "Use Emscripten runtime assertions", False), BoolVariable("use_ubsan", "Use Emscripten undefined behavior sanitizer (UBSAN)", False), BoolVariable("use_asan", "Use Emscripten address sanitizer (ASAN)", False), @@ -193,11 +196,6 @@ def configure(env: "Environment"): env.Prepend(CPPPATH=["#platform/web"]) env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED"]) - if cc_semver >= (3, 1, 25): - env.Append(LINKFLAGS=["-s", "STACK_SIZE=5MB"]) - else: - env.Append(LINKFLAGS=["-s", "TOTAL_STACK=5MB"]) - if env["opengl3"]: env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"]) # This setting just makes WebGL 2 APIs available, it does NOT disable WebGL 1. @@ -208,11 +206,14 @@ def configure(env: "Environment"): if env["javascript_eval"]: env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"]) + stack_size_opt = "STACK_SIZE" if cc_semver >= (3, 1, 25) else "TOTAL_STACK" + env.Append(LINKFLAGS=["-s", "%s=%sKB" % (stack_size_opt, env["stack_size"])]) + # Thread support (via SharedArrayBuffer). env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"]) env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"]) env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"]) - env.Append(LINKFLAGS=["-s", "DEFAULT_PTHREAD_STACK_SIZE=2MB"]) + env.Append(LINKFLAGS=["-s", "DEFAULT_PTHREAD_STACK_SIZE=%sKB" % env["default_pthread_stack_size"]]) env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"]) env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"]) diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp index a70812cf5b..ee170280e2 100644 --- a/platform/web/export/export_plugin.cpp +++ b/platform/web/export/export_plugin.cpp @@ -112,7 +112,7 @@ Error EditorExportPlatformWeb::_write_or_error(const uint8_t *p_content, int p_s return OK; } -void EditorExportPlatformWeb::_replace_strings(HashMap<String, String> p_replaces, Vector<uint8_t> &r_template) { +void EditorExportPlatformWeb::_replace_strings(const HashMap<String, String> &p_replaces, Vector<uint8_t> &r_template) { String str_template = String::utf8(reinterpret_cast<const char *>(r_template.ptr()), r_template.size()); String out; Vector<String> lines = str_template.split("\n"); diff --git a/platform/web/export/export_plugin.h b/platform/web/export/export_plugin.h index 887000ac45..9bb82d472e 100644 --- a/platform/web/export/export_plugin.h +++ b/platform/web/export/export_plugin.h @@ -90,7 +90,7 @@ class EditorExportPlatformWeb : public EditorExportPlatform { } Error _extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa); - void _replace_strings(HashMap<String, String> p_replaces, Vector<uint8_t> &r_template); + void _replace_strings(const HashMap<String, String> &p_replaces, Vector<uint8_t> &r_template); void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes); Error _add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr); Error _build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects); diff --git a/platform/windows/SCsub b/platform/windows/SCsub index 0549e408a7..1cfbc33ef8 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -3,6 +3,7 @@ Import("env") import os +from pathlib import Path from platform_methods import run_in_subprocess import platform_windows_builders @@ -25,6 +26,19 @@ common_win_wrap = [ "console_wrapper_windows.cpp", ] + +def arrange_program_clean(prog): + """ + Given an SCons program, arrange for output files SCons doesn't know about + to be cleaned when SCons is called with --clean + """ + extensions_to_clean = [".ilk", ".exp", ".pdb", ".lib"] + for program in prog: + executable_stem = Path(program.name).stem + extra_files_to_clean = [f"#bin/{executable_stem}{extension}" for extension in extensions_to_clean] + Clean(prog, extra_files_to_clean) + + res_file = "godot_res.rc" res_target = "godot_res" + env["OBJSUFFIX"] res_obj = env.RES(res_target, res_file) @@ -32,6 +46,7 @@ res_obj = env.RES(res_target, res_file) sources = common_win + res_obj prog = env.add_program("#bin/godot", sources, PROGSUFFIX=env["PROGSUFFIX"]) +arrange_program_clean(prog) # Build console wrapper app. if env["windows_subsystem"] == "gui": @@ -48,6 +63,7 @@ if env["windows_subsystem"] == "gui": env_wrap.Append(LIBS=["version"]) prog_wrap = env_wrap.add_program("#bin/godot", common_win_wrap + res_wrap_obj, PROGSUFFIX=env["PROGSUFFIX_WRAP"]) + arrange_program_clean(prog_wrap) env_wrap.Depends(prog_wrap, prog) # Microsoft Visual Studio Project Generation diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 801b32140a..bc04057793 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -436,7 +436,7 @@ def configure_msvc(env, vcvars_msvc_config): LIBS += ["psapi", "dbghelp"] if env["vulkan"]: - env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"]) + env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"]) if not env["use_volk"]: LIBS += ["vulkan"] @@ -445,7 +445,7 @@ def configure_msvc(env, vcvars_msvc_config): print("The Direct3D 12 rendering driver requires dxc_path to be set.") sys.exit(255) - env.AppendUnique(CPPDEFINES=["D3D12_ENABLED"]) + env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"]) LIBS += ["d3d12", "dxgi", "dxguid"] LIBS += ["version"] # Mesa dependency. @@ -657,12 +657,12 @@ def configure_mingw(env): env.Append(LIBS=["psapi", "dbghelp"]) if env["vulkan"]: - env.Append(CPPDEFINES=["VULKAN_ENABLED"]) + env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"]) if not env["use_volk"]: env.Append(LIBS=["vulkan"]) if env["d3d12"]: - env.AppendUnique(CPPDEFINES=["D3D12_ENABLED"]) + env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"]) env.Append(LIBS=["d3d12", "dxgi", "dxguid"]) arch_subdir = "arm64" if env["arch"] == "arm64" else "x64" diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 2bec804c7c..b56954ae81 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -687,6 +687,8 @@ typedef struct { } EnumRectData; typedef struct { + Vector<DISPLAYCONFIG_PATH_INFO> paths; + Vector<DISPLAYCONFIG_MODE_INFO> modes; int count; int screen; float rate; @@ -738,12 +740,30 @@ static BOOL CALLBACK _MonitorEnumProcRefreshRate(HMONITOR hMonitor, HDC hdcMonit minfo.cbSize = sizeof(minfo); GetMonitorInfoW(hMonitor, &minfo); - DEVMODEW dm; - memset(&dm, 0, sizeof(dm)); - dm.dmSize = sizeof(dm); - EnumDisplaySettingsW(minfo.szDevice, ENUM_CURRENT_SETTINGS, &dm); + bool found = false; + for (const DISPLAYCONFIG_PATH_INFO &path : data->paths) { + DISPLAYCONFIG_SOURCE_DEVICE_NAME source_name; + memset(&source_name, 0, sizeof(source_name)); + source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + source_name.header.size = sizeof(source_name); + source_name.header.adapterId = path.sourceInfo.adapterId; + source_name.header.id = path.sourceInfo.id; + if (DisplayConfigGetDeviceInfo(&source_name.header) == ERROR_SUCCESS) { + if (wcscmp(minfo.szDevice, source_name.viewGdiDeviceName) == 0 && path.targetInfo.refreshRate.Numerator != 0 && path.targetInfo.refreshRate.Denominator != 0) { + data->rate = (double)path.targetInfo.refreshRate.Numerator / (double)path.targetInfo.refreshRate.Denominator; + found = true; + break; + } + } + } + if (!found) { + DEVMODEW dm; + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + EnumDisplaySettingsW(minfo.szDevice, ENUM_CURRENT_SETTINGS, &dm); - data->rate = dm.dmDisplayFrequency; + data->rate = dm.dmDisplayFrequency; + } } data->count++; @@ -932,7 +952,19 @@ float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const { _THREAD_SAFE_METHOD_ p_screen = _get_screen_index(p_screen); - EnumRefreshRateData data = { 0, p_screen, SCREEN_REFRESH_RATE_FALLBACK }; + EnumRefreshRateData data = { Vector<DISPLAYCONFIG_PATH_INFO>(), Vector<DISPLAYCONFIG_MODE_INFO>(), 0, p_screen, SCREEN_REFRESH_RATE_FALLBACK }; + + uint32_t path_count = 0; + uint32_t mode_count = 0; + if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &path_count, &mode_count) == ERROR_SUCCESS) { + data.paths.resize(path_count); + data.modes.resize(mode_count); + if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &path_count, data.paths.ptrw(), &mode_count, data.modes.ptrw(), nullptr) != ERROR_SUCCESS) { + data.paths.clear(); + data.modes.clear(); + } + } + EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcRefreshRate, (LPARAM)&data); return data.rate; } @@ -1916,6 +1948,10 @@ bool DisplayServerWindows::window_is_focused(WindowID p_window) const { return wd.window_focused; } +DisplayServerWindows::WindowID DisplayServerWindows::get_focused_window() const { + return last_focused_window; +} + bool DisplayServerWindows::window_can_draw(WindowID p_window) const { _THREAD_SAFE_METHOD_ diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 29c2460c10..2668e14540 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -611,6 +611,8 @@ public: virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override; virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual WindowID get_focused_window() const override; + virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; virtual bool can_any_window_draw() const override; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 1d3b80e21e..6ad616da85 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -360,6 +360,8 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han path = get_executable_path().get_base_dir().path_join(p_path.get_file()); } + ERR_FAIL_COND_V(!FileAccess::exists(path), ERR_FILE_NOT_FOUND); + typedef DLL_DIRECTORY_COOKIE(WINAPI * PAddDllDirectory)(PCWSTR); typedef BOOL(WINAPI * PRemoveDllDirectory)(DLL_DIRECTORY_COOKIE); @@ -1183,7 +1185,7 @@ Vector<String> OS_Windows::get_system_font_path_for_text(const String &p_font_na if (FAILED(hr)) { continue; } - String fpath = String::utf16((const char16_t *)&file_path[0]); + String fpath = String::utf16((const char16_t *)&file_path[0]).replace("\\", "/"); WIN32_FIND_DATAW d; HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d); @@ -1262,7 +1264,7 @@ String OS_Windows::get_system_font_path(const String &p_font_name, int p_weight, if (FAILED(hr)) { continue; } - String fpath = String::utf16((const char16_t *)&file_path[0]); + String fpath = String::utf16((const char16_t *)&file_path[0]).replace("\\", "/"); WIN32_FIND_DATAW d; HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d); diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h index 29ab1d45c3..770a59de9e 100644 --- a/platform/windows/vulkan_context_win.h +++ b/platform/windows/vulkan_context_win.h @@ -39,7 +39,7 @@ #include <windows.h> class VulkanContextWindows : public VulkanContext { - virtual const char *_get_platform_surface_extension() const; + virtual const char *_get_platform_surface_extension() const override final; public: struct WindowPlatformData { diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index 08b315fa6c..b3a20edea8 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -577,14 +577,16 @@ PackedStringArray AnimatedSprite2D::get_configuration_warnings() const { } void AnimatedSprite2D::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { - if (p_idx == 0 && p_function == "play" && frames.is_valid()) { - List<StringName> al; - frames->get_animation_list(&al); - for (const StringName &name : al) { - r_options->push_back(String(name).quote()); + if (p_idx == 0 && frames.is_valid()) { + if (p_function == "play" || p_function == "play_backwards" || p_function == "set_animation" || p_function == "set_autoplay") { + List<StringName> al; + frames->get_animation_list(&al); + for (const StringName &name : al) { + r_options->push_back(String(name).quote()); + } } } - Node::get_argument_options(p_function, p_idx, r_options); + Node2D::get_argument_options(p_function, p_idx, r_options); } #ifndef DISABLE_DEPRECATED diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 0f5fa6543e..08baa7e387 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -229,7 +229,7 @@ void Camera2D::_notification(int p_what) { } break; case NOTIFICATION_TRANSFORM_CHANGED: { - if (!is_processing_internal() && !is_physics_processing_internal()) { + if (!position_smoothing_enabled || _is_editing_in_editor()) { _update_scroll(); } } break; diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index 2fbe4eb409..4e5852984b 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -523,30 +523,22 @@ void CollisionObject2D::_input_event_call(Viewport *p_viewport, const Ref<InputE } void CollisionObject2D::_mouse_enter() { - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_enter); - } + GDVIRTUAL_CALL(_mouse_enter); emit_signal(SceneStringNames::get_singleton()->mouse_entered); } void CollisionObject2D::_mouse_exit() { - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_exit); - } + GDVIRTUAL_CALL(_mouse_exit); emit_signal(SceneStringNames::get_singleton()->mouse_exited); } void CollisionObject2D::_mouse_shape_enter(int p_shape) { - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_shape_enter, p_shape); - } + GDVIRTUAL_CALL(_mouse_shape_enter, p_shape); emit_signal(SceneStringNames::get_singleton()->mouse_shape_entered, p_shape); } void CollisionObject2D::_mouse_shape_exit(int p_shape) { - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_shape_exit, p_shape); - } + GDVIRTUAL_CALL(_mouse_shape_exit, p_shape); emit_signal(SceneStringNames::get_singleton()->mouse_shape_exited, p_shape); } diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index ee33ff88d4..71da9cc520 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -712,12 +712,15 @@ void GPUParticles2D::_notification(int p_what) { } break; case NOTIFICATION_INTERNAL_PROCESS: { - RS::get_singleton()->particles_set_emitter_velocity(particles, - Vector3((get_global_position() - previous_position).x, - (get_global_position() - previous_position).y, - 0.0) / - get_process_delta_time()); + const Vector3 velocity = Vector3((get_global_position() - previous_position).x, (get_global_position() - previous_position).y, 0.0) / + get_process_delta_time(); + + if (velocity != previous_velocity) { + RS::get_singleton()->particles_set_emitter_velocity(particles, velocity); + previous_velocity = velocity; + } previous_position = get_global_position(); + if (one_shot) { time += get_process_delta_time(); if (time > emission_time) { diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index 40831cd30e..58996b0327 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -64,6 +64,7 @@ private: bool fractional_delta = false; bool interpolate = true; float interp_to_end_factor = 0; + Vector3 previous_velocity; Vector2 previous_position; #ifdef TOOLS_ENABLED bool show_visibility_rect = false; diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 15b638ed92..c03786caef 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -425,6 +425,17 @@ real_t PointLight2D::get_texture_scale() const { return _scale; } +#ifndef DISABLE_DEPRECATED +bool PointLight2D::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "mode" && p_value.is_num()) { // Compatibility with Godot 3.x. + set_blend_mode((BlendMode)(int)p_value); + return true; + } + + return false; +} +#endif // DISABLE_DEPRECATED + void PointLight2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture", "texture"), &PointLight2D::set_texture); ClassDB::bind_method(D_METHOD("get_texture"), &PointLight2D::get_texture); diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index 6a454a421e..3c1171deae 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -146,6 +146,9 @@ private: Vector2 texture_offset; protected: +#ifndef DISABLE_DEPRECATED + bool _set(const StringName &p_name, const Variant &p_value); +#endif // DISABLE_DEPRECATED static void _bind_methods(); public: diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 8e4b6bfa19..00c0912690 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -245,7 +245,7 @@ void NavigationRegion2D::bake_navigation_polygon(bool p_on_thread) { void NavigationRegion2D::_bake_finished(Ref<NavigationPolygon> p_navigation_polygon) { if (!Thread::is_main_thread()) { - call_deferred(SNAME("_bake_finished"), p_navigation_polygon); + callable_mp(this, &NavigationRegion2D::_bake_finished).call_deferred(p_navigation_polygon); return; } diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index ee0ccc42ff..a0e7e4cf25 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -146,8 +146,8 @@ void Path2D::_notification(int p_what) { for (int i = 0; i < sample_count; i++) { const Vector2 p = r[i].get_origin(); - const Vector2 side = r[i].columns[0]; - const Vector2 forward = r[i].columns[1]; + const Vector2 side = r[i].columns[1]; + const Vector2 forward = r[i].columns[0]; // Fish Bone. w[0] = p + (side - forward) * 5; @@ -232,8 +232,8 @@ void PathFollow2D::_update_transform() { if (rotates) { Transform2D xform = c->sample_baked_with_rotation(progress, cubic); - xform.translate_local(v_offset, h_offset); - set_rotation(xform[1].angle()); + xform.translate_local(h_offset, v_offset); + set_rotation(xform[0].angle()); set_position(xform[2]); } else { Vector2 pos = c->sample_baked(progress, cubic); diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index ee186de5f1..4266060466 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -375,14 +375,14 @@ void Polygon2D::_notification(int p_what) { // Compute transform between mesh and skeleton for runtime AABB compute. const Transform2D mesh_transform = get_global_transform(); const Transform2D skeleton_transform = skeleton_node->get_global_transform(); - const Transform2D mesh_to_sk2d = mesh_transform * skeleton_transform.affine_inverse(); + const Transform2D mesh_to_sk2d = skeleton_transform.affine_inverse() * mesh_transform; // Convert 2d transform to 3d. sd.mesh_to_skeleton_xform.basis.rows[0][0] = mesh_to_sk2d.columns[0][0]; - sd.mesh_to_skeleton_xform.basis.rows[0][1] = mesh_to_sk2d.columns[0][1]; + sd.mesh_to_skeleton_xform.basis.rows[1][0] = mesh_to_sk2d.columns[0][1]; sd.mesh_to_skeleton_xform.origin.x = mesh_to_sk2d.get_origin().x; - sd.mesh_to_skeleton_xform.basis.rows[1][0] = mesh_to_sk2d.columns[1][0]; + sd.mesh_to_skeleton_xform.basis.rows[0][1] = mesh_to_sk2d.columns[1][0]; sd.mesh_to_skeleton_xform.basis.rows[1][1] = mesh_to_sk2d.columns[1][1]; sd.mesh_to_skeleton_xform.origin.y = mesh_to_sk2d.get_origin().y; } diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 527bbaf956..69e0414855 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -433,29 +433,23 @@ PackedStringArray Bone2D::get_configuration_warnings() const { } void Bone2D::calculate_length_and_rotation() { - // if there is at least a single child Bone2D node, we can calculate + // If there is at least a single child Bone2D node, we can calculate // the length and direction. We will always just use the first Bone2D for this. - bool calculated = false; int child_count = get_child_count(); - if (child_count > 0) { - for (int i = 0; i < child_count; i++) { - Bone2D *child = Object::cast_to<Bone2D>(get_child(i)); - if (child) { - Vector2 child_local_pos = to_local(child->get_global_position()); - length = child_local_pos.length(); - bone_angle = child_local_pos.normalized().angle(); - calculated = true; - break; - } + Transform2D global_inv = get_global_transform().affine_inverse(); + + for (int i = 0; i < child_count; i++) { + Bone2D *child = Object::cast_to<Bone2D>(get_child(i)); + if (child) { + Vector2 child_local_pos = global_inv.xform(child->get_global_position()); + length = child_local_pos.length(); + bone_angle = child_local_pos.angle(); + return; // Finished! } } - if (calculated) { - return; // Finished! - } else { - WARN_PRINT("No Bone2D children of node " + get_name() + ". Cannot calculate bone length or angle reliably.\nUsing transform rotation for bone angle"); - bone_angle = get_transform().get_rotation(); - return; - } + + WARN_PRINT("No Bone2D children of node " + get_name() + ". Cannot calculate bone length or angle reliably.\nUsing transform rotation for bone angle."); + bone_angle = get_transform().get_rotation(); } void Bone2D::set_autocalculate_length_and_angle(bool p_autocalculate) { @@ -555,7 +549,7 @@ void Skeleton2D::_make_bone_setup_dirty() { } bone_setup_dirty = true; if (is_inside_tree()) { - call_deferred(SNAME("_update_bone_setup")); + callable_mp(this, &Skeleton2D::_update_bone_setup).call_deferred(); } } @@ -593,7 +587,7 @@ void Skeleton2D::_make_transform_dirty() { } transform_dirty = true; if (is_inside_tree()) { - call_deferred(SNAME("_update_transform")); + callable_mp(this, &Skeleton2D::_update_transform).call_deferred(); } } @@ -764,9 +758,6 @@ void Skeleton2D::execute_modifications(real_t p_delta, int p_execution_mode) { } void Skeleton2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update_bone_setup"), &Skeleton2D::_update_bone_setup); - ClassDB::bind_method(D_METHOD("_update_transform"), &Skeleton2D::_update_transform); - ClassDB::bind_method(D_METHOD("get_bone_count"), &Skeleton2D::get_bone_count); ClassDB::bind_method(D_METHOD("get_bone", "idx"), &Skeleton2D::get_bone); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index f2be91cbf3..decbbab476 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -32,2858 +32,8 @@ #include "tile_map.compat.inc" #include "core/core_string_names.h" -#include "core/io/marshalls.h" -#include "scene/resources/world_2d.h" -#include "servers/navigation_server_2d.h" - -#ifdef DEBUG_ENABLED -#include "servers/navigation_server_3d.h" -#endif // DEBUG_ENABLED - -#ifdef DEBUG_ENABLED -/////////////////////////////// Debug ////////////////////////////////////////// -constexpr int TILE_MAP_DEBUG_QUADRANT_SIZE = 16; - -Vector2i TileMapLayer::_coords_to_debug_quadrant_coords(const Vector2i &p_coords) const { - return Vector2i( - p_coords.x > 0 ? p_coords.x / TILE_MAP_DEBUG_QUADRANT_SIZE : (p_coords.x - (TILE_MAP_DEBUG_QUADRANT_SIZE - 1)) / TILE_MAP_DEBUG_QUADRANT_SIZE, - p_coords.y > 0 ? p_coords.y / TILE_MAP_DEBUG_QUADRANT_SIZE : (p_coords.y - (TILE_MAP_DEBUG_QUADRANT_SIZE - 1)) / TILE_MAP_DEBUG_QUADRANT_SIZE); -} - -void TileMapLayer::_debug_update() { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - RenderingServer *rs = RenderingServer::get_singleton(); - - // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree(); - - if (forced_cleanup) { - for (KeyValue<Vector2i, Ref<DebugQuadrant>> &kv : debug_quadrant_map) { - // Free the quadrant. - Ref<DebugQuadrant> &debug_quadrant = kv.value; - if (debug_quadrant->canvas_item.is_valid()) { - rs->free(debug_quadrant->canvas_item); - } - } - debug_quadrant_map.clear(); - _debug_was_cleaned_up = true; - return; - } - - // Check if anything is dirty, in such a case, redraw debug. - bool anything_changed = false; - for (int i = 0; i < DIRTY_FLAGS_MAX; i++) { - if (dirty.flags[i]) { - anything_changed = true; - break; - } - } - - // List all debug quadrants to update, creating new ones if needed. - SelfList<DebugQuadrant>::List dirty_debug_quadrant_list; - - if (_debug_was_cleaned_up || anything_changed) { - // Update all cells. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - CellData &cell_data = kv.value; - _debug_quadrants_update_cell(cell_data, dirty_debug_quadrant_list); - } - } else { - // Update dirty cells. - for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - _debug_quadrants_update_cell(cell_data, dirty_debug_quadrant_list); - } - } - - // Update those quadrants. - for (SelfList<DebugQuadrant> *quadrant_list_element = dirty_debug_quadrant_list.first(); quadrant_list_element;) { - SelfList<DebugQuadrant> *next_quadrant_list_element = quadrant_list_element->next(); // "Hack" to clear the list while iterating. - - DebugQuadrant &debug_quadrant = *quadrant_list_element->self(); - - // Check if the quadrant has a tile. - bool has_a_tile = false; - RID &ci = debug_quadrant.canvas_item; - for (SelfList<CellData> *cell_data_list_element = debug_quadrant.cells.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - if (cell_data.cell.source_id != TileSet::INVALID_SOURCE) { - has_a_tile = true; - break; - } - } - - if (has_a_tile) { - // Update the quadrant. - if (ci.is_valid()) { - rs->canvas_item_clear(ci); - } else { - ci = rs->canvas_item_create(); - rs->canvas_item_set_z_index(ci, RS::CANVAS_ITEM_Z_MAX - 1); - rs->canvas_item_set_parent(ci, tile_map_node->get_canvas_item()); - } - - const Vector2 quadrant_pos = tile_map_node->map_to_local(debug_quadrant.quadrant_coords * TILE_MAP_DEBUG_QUADRANT_SIZE); - Transform2D xform(0, quadrant_pos); - rs->canvas_item_set_transform(ci, xform); - - for (SelfList<CellData> *cell_data_list_element = debug_quadrant.cells.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - if (cell_data.cell.source_id != TileSet::INVALID_SOURCE) { - _rendering_draw_cell_debug(ci, quadrant_pos, cell_data); - _physics_draw_cell_debug(ci, quadrant_pos, cell_data); - _navigation_draw_cell_debug(ci, quadrant_pos, cell_data); - _scenes_draw_cell_debug(ci, quadrant_pos, cell_data); - } - } - } else { - // Free the quadrant. - if (ci.is_valid()) { - rs->free(ci); - } - quadrant_list_element->remove_from_list(); - debug_quadrant_map.erase(debug_quadrant.quadrant_coords); - } - - quadrant_list_element = next_quadrant_list_element; - } - - dirty_debug_quadrant_list.clear(); - - _debug_was_cleaned_up = false; -} - -void TileMapLayer::_debug_quadrants_update_cell(CellData &r_cell_data, SelfList<DebugQuadrant>::List &r_dirty_debug_quadrant_list) { - Vector2i quadrant_coords = _coords_to_debug_quadrant_coords(r_cell_data.coords); - - if (!debug_quadrant_map.has(quadrant_coords)) { - // Create a new quadrant and add it to the quadrant map. - Ref<DebugQuadrant> new_quadrant; - new_quadrant.instantiate(); - new_quadrant->quadrant_coords = quadrant_coords; - debug_quadrant_map[quadrant_coords] = new_quadrant; - } - - // Add the cell to its quadrant, if it is not already in there. - Ref<DebugQuadrant> &debug_quadrant = debug_quadrant_map[quadrant_coords]; - if (!r_cell_data.debug_quadrant_list_element.in_list()) { - debug_quadrant->cells.add(&r_cell_data.debug_quadrant_list_element); - } - - // Mark the quadrant as dirty. - if (!debug_quadrant->dirty_quadrant_list_element.in_list()) { - r_dirty_debug_quadrant_list.add(&debug_quadrant->dirty_quadrant_list_element); - } -} -#endif // DEBUG_ENABLED - -/////////////////////////////// Rendering ////////////////////////////////////// -void TileMapLayer::_rendering_update() { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - RenderingServer *rs = RenderingServer::get_singleton(); - - // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree(); - - // ----------- Layer level processing ----------- - if (forced_cleanup) { - // Cleanup. - if (canvas_item.is_valid()) { - rs->free(canvas_item); - canvas_item = RID(); - } - } else { - // Create/Update the layer's CanvasItem. - if (!canvas_item.is_valid()) { - RID ci = rs->canvas_item_create(); - rs->canvas_item_set_parent(ci, tile_map_node->get_canvas_item()); - canvas_item = ci; - } - RID &ci = canvas_item; - rs->canvas_item_set_draw_index(ci, layer_index_in_tile_map_node - (int64_t)0x80000000); - rs->canvas_item_set_sort_children_by_y(ci, y_sort_enabled); - rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid()); - rs->canvas_item_set_z_index(ci, z_index); - rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree())); - rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree())); - rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask()); - - // Modulate the layer. - Color layer_modulate = modulate; - int selected_layer = tile_map_node->get_selected_layer(); - if (selected_layer >= 0 && layer_index_in_tile_map_node != selected_layer) { - int z_selected = tile_map_node->get_layer_z_index(selected_layer); - if (z_index < z_selected || (z_index == z_selected && layer_index_in_tile_map_node < selected_layer)) { - layer_modulate = layer_modulate.darkened(0.5); - } else if (z_index > z_selected || (z_index == z_selected && layer_index_in_tile_map_node > selected_layer)) { - layer_modulate = layer_modulate.darkened(0.5); - layer_modulate.a *= 0.3; - } - } - rs->canvas_item_set_modulate(ci, layer_modulate); - } - - // ----------- Quadrants processing ----------- - - // List all rendering quadrants to update, creating new ones if needed. - SelfList<RenderingQuadrant>::List dirty_rendering_quadrant_list; - - // Check if anything changed that might change the quadrant shape. - // If so, recreate everything. - bool quandrant_shape_changed = dirty.flags[DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE] || - (tile_map_node->is_y_sort_enabled() && y_sort_enabled && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] || dirty.flags[DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_TILE_MAP_LOCAL_XFORM] || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET])); - - // Free all quadrants. - if (forced_cleanup || quandrant_shape_changed) { - for (const KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) { - for (int i = 0; i < kv.value->canvas_items.size(); i++) { - const RID &ci = kv.value->canvas_items[i]; - if (ci.is_valid()) { - rs->free(ci); - } - } - kv.value->cells.clear(); - } - rendering_quadrant_map.clear(); - _rendering_was_cleaned_up = true; - } - - if (!forced_cleanup) { - // List all quadrants to update, recreating them if needed. - if (dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || _rendering_was_cleaned_up) { - // Update all cells. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - CellData &cell_data = kv.value; - _rendering_quadrants_update_cell(cell_data, dirty_rendering_quadrant_list); - } - } else { - // Update dirty cells. - for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - _rendering_quadrants_update_cell(cell_data, dirty_rendering_quadrant_list); - } - } - - // Update all dirty quadrants. - for (SelfList<RenderingQuadrant> *quadrant_list_element = dirty_rendering_quadrant_list.first(); quadrant_list_element;) { - SelfList<RenderingQuadrant> *next_quadrant_list_element = quadrant_list_element->next(); // "Hack" to clear the list while iterating. - - const Ref<RenderingQuadrant> &rendering_quadrant = quadrant_list_element->self(); - - // Check if the quadrant has a tile. - bool has_a_tile = false; - for (SelfList<CellData> *cell_data_list_element = rendering_quadrant->cells.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - if (cell_data.cell.source_id != TileSet::INVALID_SOURCE) { - has_a_tile = true; - break; - } - } - - if (has_a_tile) { - // Process the quadrant. - - // First, clear the quadrant's canvas items. - for (RID &ci : rendering_quadrant->canvas_items) { - rs->free(ci); - } - rendering_quadrant->canvas_items.clear(); - - // Sort the quadrant cells. - if (tile_map_node->is_y_sort_enabled() && is_y_sort_enabled()) { - // For compatibility reasons, we use another comparator for Y-sorted layers. - rendering_quadrant->cells.sort_custom<CellDataYSortedComparator>(); - } else { - rendering_quadrant->cells.sort(); - } - - // Those allow to group cell per material or z-index. - Ref<Material> prev_material; - int prev_z_index = 0; - RID prev_ci; - - for (SelfList<CellData> *cell_data_quadrant_list_element = rendering_quadrant->cells.first(); cell_data_quadrant_list_element; cell_data_quadrant_list_element = cell_data_quadrant_list_element->next()) { - CellData &cell_data = *cell_data_quadrant_list_element->self(); - - TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(*tile_set->get_source(cell_data.cell.source_id)); - - // Get the tile data. - const TileData *tile_data; - if (cell_data.runtime_tile_data_cache) { - tile_data = cell_data.runtime_tile_data_cache; - } else { - tile_data = atlas_source->get_tile_data(cell_data.cell.get_atlas_coords(), cell_data.cell.alternative_tile); - } - - Ref<Material> mat = tile_data->get_material(); - int tile_z_index = tile_data->get_z_index(); - - // Quandrant pos. - - // --- CanvasItems --- - RID ci; - - // Check if the material or the z_index changed. - if (prev_ci == RID() || prev_material != mat || prev_z_index != tile_z_index) { - // If so, create a new CanvasItem. - ci = rs->canvas_item_create(); - if (mat.is_valid()) { - rs->canvas_item_set_material(ci, mat->get_rid()); - } - rs->canvas_item_set_parent(ci, canvas_item); - rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid()); - - Transform2D xform(0, rendering_quadrant->canvas_items_position); - rs->canvas_item_set_transform(ci, xform); - - rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask()); - rs->canvas_item_set_z_as_relative_to_parent(ci, true); - rs->canvas_item_set_z_index(ci, tile_z_index); - - rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree())); - rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree())); - - rendering_quadrant->canvas_items.push_back(ci); - - prev_ci = ci; - prev_material = mat; - prev_z_index = tile_z_index; - - } else { - // Keep the same canvas_item to draw on. - ci = prev_ci; - } - - const Vector2 local_tile_pos = tile_map_node->map_to_local(cell_data.coords); - - // Random animation offset. - real_t random_animation_offset = 0.0; - if (atlas_source->get_tile_animation_mode(cell_data.cell.get_atlas_coords()) != TileSetAtlasSource::TILE_ANIMATION_MODE_DEFAULT) { - Array to_hash; - to_hash.push_back(local_tile_pos); - to_hash.push_back(get_instance_id()); // Use instance id as a random hash - random_animation_offset = RandomPCG(to_hash.hash()).randf(); - } - - // Drawing the tile in the canvas item. - tile_map_node->draw_tile(ci, local_tile_pos - rendering_quadrant->canvas_items_position, tile_set, cell_data.cell.source_id, cell_data.cell.get_atlas_coords(), cell_data.cell.alternative_tile, -1, tile_map_node->get_self_modulate(), tile_data, random_animation_offset); - } - } else { - // Free the quadrant. - for (int i = 0; i < rendering_quadrant->canvas_items.size(); i++) { - const RID &ci = rendering_quadrant->canvas_items[i]; - if (ci.is_valid()) { - rs->free(ci); - } - } - rendering_quadrant->cells.clear(); - rendering_quadrant_map.erase(rendering_quadrant->quadrant_coords); - } - - quadrant_list_element = next_quadrant_list_element; - } - - dirty_rendering_quadrant_list.clear(); - - // Reset the drawing indices. - { - int index = -(int64_t)0x80000000; // Always must be drawn below children. - - // Sort the quadrants coords per local coordinates. - RBMap<Vector2, Ref<RenderingQuadrant>, RenderingQuadrant::CoordsWorldComparator> local_to_map; - for (KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) { - Ref<RenderingQuadrant> &rendering_quadrant = kv.value; - local_to_map[tile_map_node->map_to_local(rendering_quadrant->quadrant_coords)] = rendering_quadrant; - } - - // Sort the quadrants. - for (const KeyValue<Vector2, Ref<RenderingQuadrant>> &E : local_to_map) { - for (const RID &ci : E.value->canvas_items) { - RS::get_singleton()->canvas_item_set_draw_index(ci, index++); - } - } - } - - // Updates on TileMap changes. - if (dirty.flags[DIRTY_FLAGS_TILE_MAP_LIGHT_MASK] || - dirty.flags[DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL] || - dirty.flags[DIRTY_FLAGS_TILE_MAP_MATERIAL] || - dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER] || - dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT]) { - for (KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) { - Ref<RenderingQuadrant> &rendering_quadrant = kv.value; - for (const RID &ci : rendering_quadrant->canvas_items) { - rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask()); - rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid()); - rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree())); - rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree())); - } - } - } - } - - // ----------- Occluders processing ----------- - if (forced_cleanup) { - // Clean everything. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - _rendering_occluders_clear_cell(kv.value); - } - } else { - if (_rendering_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { - // Update all cells. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - _rendering_occluders_update_cell(kv.value); - } - } else { - // Update dirty cells. - for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - _rendering_occluders_update_cell(cell_data); - } - } - - // Updates on TileMap changes. - if (dirty.flags[DIRTY_FLAGS_TILE_MAP_IN_CANVAS] || dirty.flags[DIRTY_FLAGS_TILE_MAP_VISIBILITY]) { - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - CellData &cell_data = kv.value; - for (const RID &occluder : cell_data.occluders) { - if (occluder.is_null()) { - continue; - } - Transform2D xform(0, tile_map_node->map_to_local(kv.key)); - rs->canvas_light_occluder_attach_to_canvas(occluder, tile_map_node->get_canvas()); - rs->canvas_light_occluder_set_transform(occluder, tile_map_node->get_global_transform() * xform); - } - } - } - } - - // ----------- - // Mark the rendering state as up to date. - _rendering_was_cleaned_up = forced_cleanup; -} - -void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfList<RenderingQuadrant>::List &r_dirty_rendering_quadrant_list) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - - // Check if the cell is valid and retrieve its y_sort_origin. - bool is_valid = false; - int tile_y_sort_origin = 0; - TileSetSource *source; - if (tile_set->has_source(r_cell_data.cell.source_id)) { - source = *tile_set->get_source(r_cell_data.cell.source_id); - TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); - if (atlas_source && atlas_source->has_tile(r_cell_data.cell.get_atlas_coords()) && atlas_source->has_alternative_tile(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile)) { - is_valid = true; - const TileData *tile_data; - if (r_cell_data.runtime_tile_data_cache) { - tile_data = r_cell_data.runtime_tile_data_cache; - } else { - tile_data = atlas_source->get_tile_data(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile); - } - tile_y_sort_origin = tile_data->get_y_sort_origin(); - } - } - - if (is_valid) { - // Get the quadrant coords. - Vector2 canvas_items_position; - Vector2i quadrant_coords; - if (tile_map_node->is_y_sort_enabled() && is_y_sort_enabled()) { - canvas_items_position = Vector2(0, tile_map_node->map_to_local(r_cell_data.coords).y + tile_y_sort_origin + y_sort_origin); - quadrant_coords = canvas_items_position * 100; - } else { - int quad_size = tile_map_node->get_rendering_quadrant_size(); - const Vector2i &coords = r_cell_data.coords; - - // Rounding down, instead of simply rounding towards zero (truncating). - quadrant_coords = Vector2i( - coords.x > 0 ? coords.x / quad_size : (coords.x - (quad_size - 1)) / quad_size, - coords.y > 0 ? coords.y / quad_size : (coords.y - (quad_size - 1)) / quad_size); - canvas_items_position = quad_size * quadrant_coords; - } - - Ref<RenderingQuadrant> rendering_quadrant; - if (rendering_quadrant_map.has(quadrant_coords)) { - // Reuse existing rendering quadrant. - rendering_quadrant = rendering_quadrant_map[quadrant_coords]; - } else { - // Create a new rendering quadrant. - rendering_quadrant.instantiate(); - rendering_quadrant->quadrant_coords = quadrant_coords; - rendering_quadrant->canvas_items_position = canvas_items_position; - rendering_quadrant_map[quadrant_coords] = rendering_quadrant; - } - - // Mark the old quadrant as dirty (if it exists). - if (r_cell_data.rendering_quadrant.is_valid()) { - if (!r_cell_data.rendering_quadrant->dirty_quadrant_list_element.in_list()) { - r_dirty_rendering_quadrant_list.add(&r_cell_data.rendering_quadrant->dirty_quadrant_list_element); - } - } - - // Remove the cell from that quadrant. - if (r_cell_data.rendering_quadrant_list_element.in_list()) { - r_cell_data.rendering_quadrant_list_element.remove_from_list(); - } - - // Add the cell to its new quadrant. - r_cell_data.rendering_quadrant = rendering_quadrant; - r_cell_data.rendering_quadrant->cells.add(&r_cell_data.rendering_quadrant_list_element); - - // Add the new quadrant to the dirty quadrant list. - if (!rendering_quadrant->dirty_quadrant_list_element.in_list()) { - r_dirty_rendering_quadrant_list.add(&rendering_quadrant->dirty_quadrant_list_element); - } - } else { - Ref<RenderingQuadrant> rendering_quadrant = r_cell_data.rendering_quadrant; - - // Remove the cell from its quadrant. - r_cell_data.rendering_quadrant = Ref<RenderingQuadrant>(); - if (r_cell_data.rendering_quadrant_list_element.in_list()) { - rendering_quadrant->cells.remove(&r_cell_data.rendering_quadrant_list_element); - } - - if (rendering_quadrant.is_valid()) { - // Add the quadrant to the dirty quadrant list. - if (!rendering_quadrant->dirty_quadrant_list_element.in_list()) { - r_dirty_rendering_quadrant_list.add(&rendering_quadrant->dirty_quadrant_list_element); - } - } - } -} - -void TileMapLayer::_rendering_occluders_clear_cell(CellData &r_cell_data) { - RenderingServer *rs = RenderingServer::get_singleton(); - - // Free the occluders. - for (const RID &rid : r_cell_data.occluders) { - rs->free(rid); - } - r_cell_data.occluders.clear(); -} - -void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) { - bool node_visible = tile_map_node->is_visible_in_tree(); - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - RenderingServer *rs = RenderingServer::get_singleton(); - - // Free unused occluders then resize the occluders array. - for (uint32_t i = tile_set->get_occlusion_layers_count(); i < r_cell_data.occluders.size(); i++) { - RID occluder_id = r_cell_data.occluders[i]; - if (occluder_id.is_valid()) { - rs->free(occluder_id); - } - } - r_cell_data.occluders.resize(tile_set->get_occlusion_layers_count()); - - TileSetSource *source; - if (tile_set->has_source(r_cell_data.cell.source_id)) { - source = *tile_set->get_source(r_cell_data.cell.source_id); - - if (source->has_tile(r_cell_data.cell.get_atlas_coords()) && source->has_alternative_tile(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile)) { - TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); - if (atlas_source) { - // Get the tile data. - const TileData *tile_data; - if (r_cell_data.runtime_tile_data_cache) { - tile_data = r_cell_data.runtime_tile_data_cache; - } else { - tile_data = atlas_source->get_tile_data(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile); - } - - // Transform flags. - bool flip_h = (r_cell_data.cell.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H); - bool flip_v = (r_cell_data.cell.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V); - bool transpose = (r_cell_data.cell.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); - - // Create, update or clear occluders. - for (uint32_t occlusion_layer_index = 0; occlusion_layer_index < r_cell_data.occluders.size(); occlusion_layer_index++) { - Ref<OccluderPolygon2D> occluder_polygon = tile_data->get_occluder(occlusion_layer_index); - - RID &occluder = r_cell_data.occluders[occlusion_layer_index]; - - if (occluder_polygon.is_valid()) { - // Create or update occluder. - Transform2D xform; - xform.set_origin(tile_map_node->map_to_local(r_cell_data.coords)); - if (!occluder.is_valid()) { - occluder = rs->canvas_light_occluder_create(); - } - rs->canvas_light_occluder_set_enabled(occluder, node_visible); - rs->canvas_light_occluder_set_transform(occluder, tile_map_node->get_global_transform() * xform); - rs->canvas_light_occluder_set_polygon(occluder, tile_data->get_occluder(occlusion_layer_index, flip_h, flip_v, transpose)->get_rid()); - rs->canvas_light_occluder_attach_to_canvas(occluder, tile_map_node->get_canvas()); - rs->canvas_light_occluder_set_light_mask(occluder, tile_set->get_occlusion_layer_light_mask(occlusion_layer_index)); - } else { - // Clear occluder. - if (occluder.is_valid()) { - rs->free(occluder); - occluder = RID(); - } - } - } - - return; - } - } - } - - // If we did not return earlier, clear the cell. - _rendering_occluders_clear_cell(r_cell_data); -} - -#ifdef DEBUG_ENABLED -void TileMapLayer::_rendering_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - ERR_FAIL_COND(!tile_set.is_valid()); - - if (!Engine::get_singleton()->is_editor_hint()) { - return; - } - - // Draw a placeholder for tiles needing one. - RenderingServer *rs = RenderingServer::get_singleton(); - const TileMapCell &c = r_cell_data.cell; - - TileSetSource *source; - if (tile_set->has_source(c.source_id)) { - source = *tile_set->get_source(c.source_id); - - if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { - TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); - if (atlas_source) { - Vector2i grid_size = atlas_source->get_atlas_grid_size(); - if (!atlas_source->get_runtime_texture().is_valid() || c.get_atlas_coords().x >= grid_size.x || c.get_atlas_coords().y >= grid_size.y) { - // Generate a random color from the hashed values of the tiles. - Array to_hash; - to_hash.push_back(c.source_id); - to_hash.push_back(c.get_atlas_coords()); - to_hash.push_back(c.alternative_tile); - uint32_t hash = RandomPCG(to_hash.hash()).rand(); - - Color color; - color = color.from_hsv( - (float)((hash >> 24) & 0xFF) / 256.0, - Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0), - Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0), - 0.8); - - // Draw a placeholder tile. - Transform2D cell_to_quadrant; - cell_to_quadrant.set_origin(tile_map_node->map_to_local(r_cell_data.coords) - p_quadrant_pos); - rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant); - rs->canvas_item_add_circle(p_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color); - } - } - } - } -} -#endif // DEBUG_ENABLED - -/////////////////////////////// Physics ////////////////////////////////////// - -void TileMapLayer::_physics_update() { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - - // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid(); - if (forced_cleanup) { - // Clean everything. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - _physics_clear_cell(kv.value); - } - } else { - if (_physics_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || dirty.flags[DIRTY_FLAGS_TILE_MAP_COLLISION_ANIMATABLE]) { - // Update all cells. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - _physics_update_cell(kv.value); - } - } else { - // Update dirty cells. - for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - _physics_update_cell(cell_data); - } - } - } - - // ----------- - // Mark the physics state as up to date. - _physics_was_cleaned_up = forced_cleanup; -} - -void TileMapLayer::_physics_notify_tilemap_change(TileMapLayer::DirtyFlags p_what) { - Transform2D gl_transform = tile_map_node->get_global_transform(); - PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); - - bool in_editor = false; -#ifdef TOOLS_ENABLED - in_editor = Engine::get_singleton()->is_editor_hint(); -#endif - - if (p_what == DIRTY_FLAGS_TILE_MAP_XFORM) { - if (tile_map_node->is_inside_tree() && (!tile_map_node->is_collision_animatable() || in_editor)) { - // Move the collisison shapes along with the TileMap. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - const CellData &cell_data = kv.value; - - for (RID body : cell_data.bodies) { - if (body.is_valid()) { - Transform2D xform(0, tile_map_node->map_to_local(bodies_coords[body])); - xform = gl_transform * xform; - ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); - } - } - } - } - } else if (p_what == DIRTY_FLAGS_TILE_MAP_LOCAL_XFORM) { - // With collisions animatable, move the collisison shapes along with the TileMap only on local xform change (they are synchornized on physics tick instead). - if (tile_map_node->is_inside_tree() && tile_map_node->is_collision_animatable() && !in_editor) { - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - const CellData &cell_data = kv.value; - - for (RID body : cell_data.bodies) { - if (body.is_valid()) { - Transform2D xform(0, tile_map_node->map_to_local(bodies_coords[body])); - xform = gl_transform * xform; - ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); - } - } - } - } - } else if (p_what == DIRTY_FLAGS_TILE_MAP_IN_TREE) { - // Changes in the tree may cause the space to change (e.g. when reparenting to a SubViewport). - if (tile_map_node->is_inside_tree()) { - RID space = tile_map_node->get_world_2d()->get_space(); - - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - const CellData &cell_data = kv.value; - - for (RID body : cell_data.bodies) { - if (body.is_valid()) { - ps->body_set_space(body, space); - } - } - } - } - } -} - -void TileMapLayer::_physics_clear_cell(CellData &r_cell_data) { - PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); - - // Clear bodies. - for (RID body : r_cell_data.bodies) { - if (body.is_valid()) { - bodies_coords.erase(body); - ps->free(body); - } - } - r_cell_data.bodies.clear(); -} - -void TileMapLayer::_physics_update_cell(CellData &r_cell_data) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - Transform2D gl_transform = tile_map_node->get_global_transform(); - RID space = tile_map_node->get_world_2d()->get_space(); - PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); - - // Recreate bodies and shapes. - TileMapCell &c = r_cell_data.cell; - - TileSetSource *source; - if (tile_set->has_source(c.source_id)) { - source = *tile_set->get_source(c.source_id); - - if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { - TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); - if (atlas_source) { - const TileData *tile_data; - if (r_cell_data.runtime_tile_data_cache) { - tile_data = r_cell_data.runtime_tile_data_cache; - } else { - tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); - } - - // Transform flags. - bool flip_h = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H); - bool flip_v = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V); - bool transpose = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); - - // Free unused bodies then resize the bodies array. - for (uint32_t i = tile_set->get_physics_layers_count(); i < r_cell_data.bodies.size(); i++) { - RID body = r_cell_data.bodies[i]; - if (body.is_valid()) { - bodies_coords.erase(body); - ps->free(body); - } - } - r_cell_data.bodies.resize(tile_set->get_physics_layers_count()); - - for (uint32_t tile_set_physics_layer = 0; tile_set_physics_layer < (uint32_t)tile_set->get_physics_layers_count(); tile_set_physics_layer++) { - Ref<PhysicsMaterial> physics_material = tile_set->get_physics_layer_physics_material(tile_set_physics_layer); - uint32_t physics_layer = tile_set->get_physics_layer_collision_layer(tile_set_physics_layer); - uint32_t physics_mask = tile_set->get_physics_layer_collision_mask(tile_set_physics_layer); - - RID body = r_cell_data.bodies[tile_set_physics_layer]; - if (tile_data->get_collision_polygons_count(tile_set_physics_layer) == 0) { - // No body needed, free it if it exists. - if (body.is_valid()) { - bodies_coords.erase(body); - ps->free(body); - } - body = RID(); - } else { - // Create or update the body. - if (!body.is_valid()) { - body = ps->body_create(); - } - bodies_coords[body] = r_cell_data.coords; - ps->body_set_mode(body, tile_map_node->is_collision_animatable() ? PhysicsServer2D::BODY_MODE_KINEMATIC : PhysicsServer2D::BODY_MODE_STATIC); - ps->body_set_space(body, space); - - Transform2D xform; - xform.set_origin(tile_map_node->map_to_local(r_cell_data.coords)); - xform = gl_transform * xform; - ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); - - ps->body_attach_object_instance_id(body, tile_map_node->get_instance_id()); - ps->body_set_collision_layer(body, physics_layer); - ps->body_set_collision_mask(body, physics_mask); - ps->body_set_pickable(body, false); - ps->body_set_state(body, PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, tile_data->get_constant_linear_velocity(tile_set_physics_layer)); - ps->body_set_state(body, PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, tile_data->get_constant_angular_velocity(tile_set_physics_layer)); - - if (!physics_material.is_valid()) { - ps->body_set_param(body, PhysicsServer2D::BODY_PARAM_BOUNCE, 0); - ps->body_set_param(body, PhysicsServer2D::BODY_PARAM_FRICTION, 1); - } else { - ps->body_set_param(body, PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material->computed_bounce()); - ps->body_set_param(body, PhysicsServer2D::BODY_PARAM_FRICTION, physics_material->computed_friction()); - } - - // Clear body's shape if needed. - ps->body_clear_shapes(body); - - // Add the shapes to the body. - int body_shape_index = 0; - for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(tile_set_physics_layer); polygon_index++) { - // Iterate over the polygons. - bool one_way_collision = tile_data->is_collision_polygon_one_way(tile_set_physics_layer, polygon_index); - float one_way_collision_margin = tile_data->get_collision_polygon_one_way_margin(tile_set_physics_layer, polygon_index); - int shapes_count = tile_data->get_collision_polygon_shapes_count(tile_set_physics_layer, polygon_index); - for (int shape_index = 0; shape_index < shapes_count; shape_index++) { - // Add decomposed convex shapes. - Ref<ConvexPolygonShape2D> shape = tile_data->get_collision_polygon_shape(tile_set_physics_layer, polygon_index, shape_index, flip_h, flip_v, transpose); - ps->body_add_shape(body, shape->get_rid()); - ps->body_set_shape_as_one_way_collision(body, body_shape_index, one_way_collision, one_way_collision_margin); - - body_shape_index++; - } - } - } - - // Set the body again. - r_cell_data.bodies[tile_set_physics_layer] = body; - } - - return; - } - } - } - - // If we did not return earlier, clear the cell. - _physics_clear_cell(r_cell_data); -} - -#ifdef DEBUG_ENABLED -void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data) { - // Draw the debug collision shapes. - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - ERR_FAIL_COND(!tile_set.is_valid()); - - if (!tile_map_node->get_tree()) { - return; - } - - bool show_collision = false; - switch (tile_map_node->get_collision_visibility_mode()) { - case TileMap::VISIBILITY_MODE_DEFAULT: - show_collision = !Engine::get_singleton()->is_editor_hint() && tile_map_node->get_tree()->is_debugging_collisions_hint(); - break; - case TileMap::VISIBILITY_MODE_FORCE_HIDE: - show_collision = false; - break; - case TileMap::VISIBILITY_MODE_FORCE_SHOW: - show_collision = true; - break; - } - if (!show_collision) { - return; - } - - RenderingServer *rs = RenderingServer::get_singleton(); - PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); - - Color debug_collision_color = tile_map_node->get_tree()->get_debug_collisions_color(); - Vector<Color> color; - color.push_back(debug_collision_color); - - Transform2D quadrant_to_local(0, p_quadrant_pos); - Transform2D global_to_quadrant = (tile_map_node->get_global_transform() * quadrant_to_local).affine_inverse(); - - for (RID body : r_cell_data.bodies) { - if (body.is_valid()) { - Transform2D body_to_quadrant = global_to_quadrant * Transform2D(ps->body_get_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM)); - rs->canvas_item_add_set_transform(p_canvas_item, body_to_quadrant); - for (int shape_index = 0; shape_index < ps->body_get_shape_count(body); shape_index++) { - const RID &shape = ps->body_get_shape(body, shape_index); - const PhysicsServer2D::ShapeType &type = ps->shape_get_type(shape); - if (type == PhysicsServer2D::SHAPE_CONVEX_POLYGON) { - rs->canvas_item_add_polygon(p_canvas_item, ps->shape_get_data(shape), color); - } else { - WARN_PRINT("Wrong shape type for a tile, should be SHAPE_CONVEX_POLYGON."); - } - } - rs->canvas_item_add_set_transform(p_canvas_item, Transform2D()); - } - } -}; -#endif // DEBUG_ENABLED - -/////////////////////////////// Navigation ////////////////////////////////////// - -void TileMapLayer::_navigation_update() { - ERR_FAIL_NULL(NavigationServer2D::get_singleton()); - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - NavigationServer2D *ns = NavigationServer2D::get_singleton(); - - // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !navigation_enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid(); - - // ----------- Layer level processing ----------- - if (forced_cleanup) { - if (navigation_map.is_valid() && !uses_world_navigation_map) { - ns->free(navigation_map); - navigation_map = RID(); - } - } else { - // Update navigation maps. - if (!navigation_map.is_valid()) { - if (layer_index_in_tile_map_node == 0) { - // Use the default World2D navigation map for the first layer when empty. - navigation_map = tile_map_node->get_world_2d()->get_navigation_map(); - uses_world_navigation_map = true; - } else { - RID new_layer_map = ns->map_create(); - // Set the default NavigationPolygon cell_size on the new map as a mismatch causes an error. - ns->map_set_cell_size(new_layer_map, 1.0); - ns->map_set_active(new_layer_map, true); - navigation_map = new_layer_map; - uses_world_navigation_map = false; - } - } - } - - // ----------- Navigation regions processing ----------- - if (forced_cleanup) { - // Clean everything. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - _navigation_clear_cell(kv.value); - } - } else { - if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { - // Update all cells. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - _navigation_update_cell(kv.value); - } - } else { - // Update dirty cells. - for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - _navigation_update_cell(cell_data); - } - } - - if (dirty.flags[DIRTY_FLAGS_TILE_MAP_XFORM]) { - Transform2D tilemap_xform = tile_map_node->get_global_transform(); - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - const CellData &cell_data = kv.value; - // Update navigation regions transform. - for (const RID ®ion : cell_data.navigation_regions) { - if (!region.is_valid()) { - continue; - } - Transform2D tile_transform; - tile_transform.set_origin(tile_map_node->map_to_local(kv.key)); - NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform); - } - } - } - } - - // ----------- - // Mark the navigation state as up to date. - _navigation_was_cleaned_up = forced_cleanup; -} - -void TileMapLayer::_navigation_clear_cell(CellData &r_cell_data) { - NavigationServer2D *ns = NavigationServer2D::get_singleton(); - // Clear navigation shapes. - for (uint32_t i = 0; i < r_cell_data.navigation_regions.size(); i++) { - const RID ®ion = r_cell_data.navigation_regions[i]; - if (region.is_valid()) { - ns->region_set_map(region, RID()); - ns->free(region); - } - } - r_cell_data.navigation_regions.clear(); -} - -void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - NavigationServer2D *ns = NavigationServer2D::get_singleton(); - Transform2D tilemap_xform = tile_map_node->get_global_transform(); - - // Get the navigation polygons and create regions. - TileMapCell &c = r_cell_data.cell; - - TileSetSource *source; - if (tile_set->has_source(c.source_id)) { - source = *tile_set->get_source(c.source_id); - - if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { - TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); - if (atlas_source) { - const TileData *tile_data; - if (r_cell_data.runtime_tile_data_cache) { - tile_data = r_cell_data.runtime_tile_data_cache; - } else { - tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); - } - - // Transform flags. - bool flip_h = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H); - bool flip_v = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V); - bool transpose = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); - - // Free unused regions then resize the regions array. - for (uint32_t i = tile_set->get_navigation_layers_count(); i < r_cell_data.navigation_regions.size(); i++) { - RID ®ion = r_cell_data.navigation_regions[i]; - if (region.is_valid()) { - ns->region_set_map(region, RID()); - ns->free(region); - region = RID(); - } - } - r_cell_data.navigation_regions.resize(tile_set->get_navigation_layers_count()); - - // Create, update or clear regions. - for (uint32_t navigation_layer_index = 0; navigation_layer_index < r_cell_data.navigation_regions.size(); navigation_layer_index++) { - Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer_index, flip_h, flip_v, transpose); - - RID ®ion = r_cell_data.navigation_regions[navigation_layer_index]; - - if (navigation_polygon.is_valid() && (navigation_polygon->get_polygon_count() > 0 || navigation_polygon->get_outline_count() > 0)) { - // Create or update regions. - Transform2D tile_transform; - tile_transform.set_origin(tile_map_node->map_to_local(r_cell_data.coords)); - if (!region.is_valid()) { - region = ns->region_create(); - } - ns->region_set_owner_id(region, tile_map_node->get_instance_id()); - ns->region_set_map(region, navigation_map); - ns->region_set_transform(region, tilemap_xform * tile_transform); - ns->region_set_navigation_layers(region, tile_set->get_navigation_layer_layers(navigation_layer_index)); - ns->region_set_navigation_polygon(region, navigation_polygon); - } else { - // Clear region. - if (region.is_valid()) { - ns->region_set_map(region, RID()); - ns->free(region); - region = RID(); - } - } - } - - return; - } - } - } - - // If we did not return earlier, clear the cell. - _navigation_clear_cell(r_cell_data); -} - -#ifdef DEBUG_ENABLED -void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data) { - // Draw the debug collision shapes. - bool show_navigation = false; - switch (tile_map_node->get_navigation_visibility_mode()) { - case TileMap::VISIBILITY_MODE_DEFAULT: - show_navigation = !Engine::get_singleton()->is_editor_hint() && tile_map_node->get_tree()->is_debugging_navigation_hint(); - break; - case TileMap::VISIBILITY_MODE_FORCE_HIDE: - show_navigation = false; - break; - case TileMap::VISIBILITY_MODE_FORCE_SHOW: - show_navigation = true; - break; - } - if (!show_navigation) { - return; - } - - // Check if the navigation is used. - if (r_cell_data.navigation_regions.is_empty()) { - return; - } - - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - - RenderingServer *rs = RenderingServer::get_singleton(); - const NavigationServer2D *ns2d = NavigationServer2D::get_singleton(); - - bool enabled_geometry_face_random_color = ns2d->get_debug_navigation_enable_geometry_face_random_color(); - bool enabled_edge_lines = ns2d->get_debug_navigation_enable_edge_lines(); - - Color debug_face_color = ns2d->get_debug_navigation_geometry_face_color(); - Color debug_edge_color = ns2d->get_debug_navigation_geometry_edge_color(); - - RandomPCG rand; - - const TileMapCell &c = r_cell_data.cell; - - TileSetSource *source; - if (tile_set->has_source(c.source_id)) { - source = *tile_set->get_source(c.source_id); - - if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { - TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); - if (atlas_source) { - const TileData *tile_data; - if (r_cell_data.runtime_tile_data_cache) { - tile_data = r_cell_data.runtime_tile_data_cache; - } else { - tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); - } - - Transform2D cell_to_quadrant; - cell_to_quadrant.set_origin(tile_map_node->map_to_local(r_cell_data.coords) - p_quadrant_pos); - rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant); - - for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) { - bool flip_h = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H); - bool flip_v = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V); - bool transpose = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); - Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(layer_index, flip_h, flip_v, transpose); - if (navigation_polygon.is_valid()) { - Vector<Vector2> navigation_polygon_vertices = navigation_polygon->get_vertices(); - if (navigation_polygon_vertices.size() < 3) { - continue; - } - - for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) { - // An array of vertices for this polygon. - Vector<int> polygon = navigation_polygon->get_polygon(i); - Vector<Vector2> debug_polygon_vertices; - debug_polygon_vertices.resize(polygon.size()); - for (int j = 0; j < polygon.size(); j++) { - ERR_FAIL_INDEX(polygon[j], navigation_polygon_vertices.size()); - debug_polygon_vertices.write[j] = navigation_polygon_vertices[polygon[j]]; - } - - // Generate the polygon color, slightly randomly modified from the settings one. - Color random_variation_color = debug_face_color; - if (enabled_geometry_face_random_color) { - random_variation_color.set_hsv( - debug_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1, - debug_face_color.get_s(), - debug_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2); - } - random_variation_color.a = debug_face_color.a; - - Vector<Color> debug_face_colors; - debug_face_colors.push_back(random_variation_color); - rs->canvas_item_add_polygon(p_canvas_item, debug_polygon_vertices, debug_face_colors); - - if (enabled_edge_lines) { - Vector<Color> debug_edge_colors; - debug_edge_colors.push_back(debug_edge_color); - debug_polygon_vertices.push_back(debug_polygon_vertices[0]); // Add first again for closing polyline. - rs->canvas_item_add_polyline(p_canvas_item, debug_polygon_vertices, debug_edge_colors); - } - } - } - } - } - } - } -} -#endif // DEBUG_ENABLED - -/////////////////////////////// Scenes ////////////////////////////////////// - -void TileMapLayer::_scenes_update() { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - - // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid(); - - if (forced_cleanup) { - // Clean everything. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - _scenes_clear_cell(kv.value); - } - } else { - if (_scenes_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { - // Update all cells. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - _scenes_update_cell(kv.value); - } - } else { - // Update dirty cells. - for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - _scenes_update_cell(cell_data); - } - } - } - - // ----------- - // Mark the scenes state as up to date. - _scenes_was_cleaned_up = forced_cleanup; -} - -void TileMapLayer::_scenes_clear_cell(CellData &r_cell_data) { - // Cleanup existing scene. - Node *node = tile_map_node->get_node_or_null(r_cell_data.scene); - if (node) { - node->queue_free(); - } - r_cell_data.scene = ""; -} - -void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - - // Clear the scene in any case. - _scenes_clear_cell(r_cell_data); - - // Create the scene. - const TileMapCell &c = r_cell_data.cell; - - TileSetSource *source; - if (tile_set->has_source(c.source_id)) { - source = *tile_set->get_source(c.source_id); - - if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { - TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source); - if (scenes_collection_source) { - Ref<PackedScene> packed_scene = scenes_collection_source->get_scene_tile_scene(c.alternative_tile); - if (packed_scene.is_valid()) { - Node *scene = packed_scene->instantiate(); - Control *scene_as_control = Object::cast_to<Control>(scene); - Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene); - if (scene_as_control) { - scene_as_control->set_position(tile_map_node->map_to_local(r_cell_data.coords) + scene_as_control->get_position()); - } else if (scene_as_node2d) { - Transform2D xform; - xform.set_origin(tile_map_node->map_to_local(r_cell_data.coords)); - scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform()); - } - tile_map_node->add_child(scene); - r_cell_data.scene = scene->get_name(); - } - } - } - } -} - -#ifdef DEBUG_ENABLED -void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - ERR_FAIL_COND(!tile_set.is_valid()); - - if (!Engine::get_singleton()->is_editor_hint()) { - return; - } - - // Draw a placeholder for scenes needing one. - RenderingServer *rs = RenderingServer::get_singleton(); - - const TileMapCell &c = r_cell_data.cell; - - TileSetSource *source; - if (tile_set->has_source(c.source_id)) { - source = *tile_set->get_source(c.source_id); - - if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { - return; - } - - TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source); - if (scenes_collection_source) { - if (!scenes_collection_source->get_scene_tile_scene(c.alternative_tile).is_valid() || scenes_collection_source->get_scene_tile_display_placeholder(c.alternative_tile)) { - // Generate a random color from the hashed values of the tiles. - Array to_hash; - to_hash.push_back(c.source_id); - to_hash.push_back(c.alternative_tile); - uint32_t hash = RandomPCG(to_hash.hash()).rand(); - - Color color; - color = color.from_hsv( - (float)((hash >> 24) & 0xFF) / 256.0, - Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0), - Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0), - 0.8); - - // Draw a placeholder tile. - Transform2D cell_to_quadrant; - cell_to_quadrant.set_origin(tile_map_node->map_to_local(r_cell_data.coords) - p_quadrant_pos); - rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant); - rs->canvas_item_add_circle(p_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color); - } - } - } -} -#endif // DEBUG_ENABLED - -///////////////////////////////////////////////////////////////////// - -void TileMapLayer::_build_runtime_update_tile_data() { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - - // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree(); - if (!forced_cleanup) { - if (tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update)) { - if (_runtime_update_tile_data_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { - for (KeyValue<Vector2i, CellData> &E : tile_map) { - _build_runtime_update_tile_data_for_cell(E.value); - } - } else if (dirty.flags[DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE]) { - for (KeyValue<Vector2i, CellData> &E : tile_map) { - _build_runtime_update_tile_data_for_cell(E.value, true); - } - } else { - for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - _build_runtime_update_tile_data_for_cell(cell_data); - } - } - } - } - - // ----------- - // Mark the navigation state as up to date. - _runtime_update_tile_data_was_cleaned_up = forced_cleanup; -} - -void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_auto_add_to_dirty_list) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - - TileMapCell &c = r_cell_data.cell; - TileSetSource *source; - if (tile_set->has_source(c.source_id)) { - source = *tile_set->get_source(c.source_id); - - if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { - TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); - if (atlas_source) { - bool ret = false; - if (tile_map_node->GDVIRTUAL_CALL(_use_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, ret) && ret) { - TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); - - // Create the runtime TileData. - TileData *tile_data_runtime_use = tile_data->duplicate(); - tile_data_runtime_use->set_allow_transform(true); - r_cell_data.runtime_tile_data_cache = tile_data_runtime_use; - - tile_map_node->GDVIRTUAL_CALL(_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, tile_data_runtime_use); - - if (p_auto_add_to_dirty_list) { - dirty.cell_list.add(&r_cell_data.dirty_list_element); - } - } - } - } - } -} - -void TileMapLayer::_clear_runtime_update_tile_data() { - for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - - // Clear the runtime tile data. - if (cell_data.runtime_tile_data_cache) { - memdelete(cell_data.runtime_tile_data_cache); - cell_data.runtime_tile_data_cache = nullptr; - } - } -} - -TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - if (!tile_set.is_valid()) { - return TileSet::TerrainsPattern(); - } - // Returns all tiles compatible with the given constraints. - RBMap<TileSet::TerrainsPattern, int> terrain_pattern_score; - RBSet<TileSet::TerrainsPattern> pattern_set = tile_set->get_terrains_pattern_set(p_terrain_set); - ERR_FAIL_COND_V(pattern_set.is_empty(), TileSet::TerrainsPattern()); - for (TileSet::TerrainsPattern &terrain_pattern : pattern_set) { - int score = 0; - - // Check the center bit constraint. - TerrainConstraint terrain_constraint = TerrainConstraint(tile_map_node, p_position, terrain_pattern.get_terrain()); - const RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_constraint); - if (in_set_constraint_element) { - if (in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) { - score += in_set_constraint_element->get().get_priority(); - } - } else if (p_current_pattern.get_terrain() != terrain_pattern.get_terrain()) { - continue; // Ignore a pattern that cannot keep bits without constraints unmodified. - } - - // Check the surrounding bits - bool invalid_pattern = false; - for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { - TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); - if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { - // Check if the bit is compatible with the constraints. - TerrainConstraint terrain_bit_constraint = TerrainConstraint(tile_map_node, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit)); - in_set_constraint_element = p_constraints.find(terrain_bit_constraint); - if (in_set_constraint_element) { - if (in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) { - score += in_set_constraint_element->get().get_priority(); - } - } else if (p_current_pattern.get_terrain_peering_bit(bit) != terrain_pattern.get_terrain_peering_bit(bit)) { - invalid_pattern = true; // Ignore a pattern that cannot keep bits without constraints unmodified. - break; - } - } - } - if (invalid_pattern) { - continue; - } - - terrain_pattern_score[terrain_pattern] = score; - } - - // Compute the minimum score. - TileSet::TerrainsPattern min_score_pattern = p_current_pattern; - int min_score = INT32_MAX; - for (KeyValue<TileSet::TerrainsPattern, int> E : terrain_pattern_score) { - if (E.value < min_score) { - min_score_pattern = E.key; - min_score = E.value; - } - } - - return min_score_pattern; -} - -RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - if (!tile_set.is_valid()) { - return RBSet<TerrainConstraint>(); - } - - // Compute the constraints needed from the surrounding tiles. - RBSet<TerrainConstraint> output; - output.insert(TerrainConstraint(tile_map_node, p_position, p_terrains_pattern.get_terrain())); - - for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { - TileSet::CellNeighbor side = TileSet::CellNeighbor(i); - if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, side)) { - TerrainConstraint c = TerrainConstraint(tile_map_node, p_position, side, p_terrains_pattern.get_terrain_peering_bit(side)); - output.insert(c); - } - } - - return output; -} - -RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - if (!tile_set.is_valid()) { - return RBSet<TerrainConstraint>(); - } - - ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), RBSet<TerrainConstraint>()); - - // Build a set of dummy constraints to get the constrained points. - RBSet<TerrainConstraint> dummy_constraints; - for (const Vector2i &E : p_painted) { - for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over neighbor bits. - TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); - if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { - dummy_constraints.insert(TerrainConstraint(tile_map_node, E, bit, -1)); - } - } - } - - // For each constrained point, we get all overlapping tiles, and select the most adequate terrain for it. - RBSet<TerrainConstraint> constraints; - for (const TerrainConstraint &E_constraint : dummy_constraints) { - HashMap<int, int> terrain_count; - - // Count the number of occurrences per terrain. - HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = E_constraint.get_overlapping_coords_and_peering_bits(); - for (const KeyValue<Vector2i, TileSet::CellNeighbor> &E_overlapping : overlapping_terrain_bits) { - TileData *neighbor_tile_data = nullptr; - TileMapCell neighbor_cell = get_cell(E_overlapping.key); - if (neighbor_cell.source_id != TileSet::INVALID_SOURCE) { - Ref<TileSetSource> source = tile_set->get_source(neighbor_cell.source_id); - Ref<TileSetAtlasSource> atlas_source = source; - if (atlas_source.is_valid()) { - TileData *tile_data = atlas_source->get_tile_data(neighbor_cell.get_atlas_coords(), neighbor_cell.alternative_tile); - if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { - neighbor_tile_data = tile_data; - } - } - } - - int terrain = neighbor_tile_data ? neighbor_tile_data->get_terrain_peering_bit(TileSet::CellNeighbor(E_overlapping.value)) : -1; - if (!p_ignore_empty_terrains || terrain >= 0) { - if (!terrain_count.has(terrain)) { - terrain_count[terrain] = 0; - } - terrain_count[terrain] += 1; - } - } - - // Get the terrain with the max number of occurrences. - int max = 0; - int max_terrain = -1; - for (const KeyValue<int, int> &E_terrain_count : terrain_count) { - if (E_terrain_count.value > max) { - max = E_terrain_count.value; - max_terrain = E_terrain_count.key; - } - } - - // Set the adequate terrain. - if (max > 0) { - TerrainConstraint c = E_constraint; - c.set_terrain(max_terrain); - constraints.insert(c); - } - } - - // Add the centers as constraints. - for (Vector2i E_coords : p_painted) { - TileData *tile_data = nullptr; - TileMapCell cell = get_cell(E_coords); - if (cell.source_id != TileSet::INVALID_SOURCE) { - Ref<TileSetSource> source = tile_set->get_source(cell.source_id); - Ref<TileSetAtlasSource> atlas_source = source; - if (atlas_source.is_valid()) { - tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); - } - } - - int terrain = (tile_data && tile_data->get_terrain_set() == p_terrain_set) ? tile_data->get_terrain() : -1; - if (!p_ignore_empty_terrains || terrain >= 0) { - constraints.insert(TerrainConstraint(tile_map_node, E_coords, terrain)); - } - } - - return constraints; -} - -void TileMapLayer::set_tile_map(TileMap *p_tile_map) { - tile_map_node = p_tile_map; -} - -void TileMapLayer::set_layer_index_in_tile_map_node(int p_index) { - if (p_index == layer_index_in_tile_map_node) { - return; - } - layer_index_in_tile_map_node = p_index; - dirty.flags[DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE] = true; - tile_map_node->queue_internal_update(); -} - -Rect2 TileMapLayer::get_rect(bool &r_changed) const { - // Compute the displayed area of the tilemap. - r_changed = false; -#ifdef DEBUG_ENABLED - - if (rect_cache_dirty) { - Rect2 r_total; - bool first = true; - for (const KeyValue<Vector2i, CellData> &E : tile_map) { - Rect2 r; - r.position = tile_map_node->map_to_local(E.key); - r.size = Size2(); - if (first) { - r_total = r; - first = false; - } else { - r_total = r_total.merge(r); - } - } - - r_changed = rect_cache != r_total; - - rect_cache = r_total; - rect_cache_dirty = false; - } -#endif - return rect_cache; -} - -HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - if (!tile_set.is_valid()) { - return HashMap<Vector2i, TileSet::TerrainsPattern>(); - } - - // Copy the constraints set. - RBSet<TerrainConstraint> constraints = p_constraints; - - // Output map. - HashMap<Vector2i, TileSet::TerrainsPattern> output; - - // Add all positions to a set. - for (int i = 0; i < p_to_replace.size(); i++) { - const Vector2i &coords = p_to_replace[i]; - - // Select the best pattern for the given constraints. - TileSet::TerrainsPattern current_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set); - TileMapCell cell = get_cell(coords); - if (cell.source_id != TileSet::INVALID_SOURCE) { - TileSetSource *source = *tile_set->get_source(cell.source_id); - TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); - if (atlas_source) { - // Get tile data. - TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); - if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { - current_pattern = tile_data->get_terrains_pattern(); - } - } - } - TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints, current_pattern); - - // Update the constraint set with the new ones. - RBSet<TerrainConstraint> new_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, pattern); - for (const TerrainConstraint &E_constraint : new_constraints) { - if (constraints.has(E_constraint)) { - constraints.erase(E_constraint); - } - TerrainConstraint c = E_constraint; - c.set_priority(5); - constraints.insert(c); - } - - output[coords] = pattern; - } - return output; -} - -HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { - HashMap<Vector2i, TileSet::TerrainsPattern> output; - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - ERR_FAIL_COND_V(!tile_set.is_valid(), output); - ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); - - // Build list and set of tiles that can be modified (painted and their surroundings). - Vector<Vector2i> can_modify_list; - RBSet<Vector2i> can_modify_set; - RBSet<Vector2i> painted_set; - for (int i = p_coords_array.size() - 1; i >= 0; i--) { - const Vector2i &coords = p_coords_array[i]; - can_modify_list.push_back(coords); - can_modify_set.insert(coords); - painted_set.insert(coords); - } - for (Vector2i coords : p_coords_array) { - // Find the adequate neighbor. - for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { - TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); - if (tile_map_node->is_existing_neighbor(bit)) { - Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit); - if (!can_modify_set.has(neighbor)) { - can_modify_list.push_back(neighbor); - can_modify_set.insert(neighbor); - } - } - } - } - - // Build a set, out of the possibly modified tiles, of the one with a center bit that is set (or will be) to the painted terrain. - RBSet<Vector2i> cells_with_terrain_center_bit; - for (Vector2i coords : can_modify_set) { - bool connect = false; - if (painted_set.has(coords)) { - connect = true; - } else { - // Get the center bit of the cell. - TileData *tile_data = nullptr; - TileMapCell cell = get_cell(coords); - if (cell.source_id != TileSet::INVALID_SOURCE) { - Ref<TileSetSource> source = tile_set->get_source(cell.source_id); - Ref<TileSetAtlasSource> atlas_source = source; - if (atlas_source.is_valid()) { - tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); - } - } - - if (tile_data && tile_data->get_terrain_set() == p_terrain_set && tile_data->get_terrain() == p_terrain) { - connect = true; - } - } - if (connect) { - cells_with_terrain_center_bit.insert(coords); - } - } - - RBSet<TerrainConstraint> constraints; - - // Add new constraints from the path drawn. - for (Vector2i coords : p_coords_array) { - // Constraints on the center bit. - TerrainConstraint c = TerrainConstraint(tile_map_node, coords, p_terrain); - c.set_priority(10); - constraints.insert(c); - - // Constraints on the connecting bits. - for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { - TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); - if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { - c = TerrainConstraint(tile_map_node, coords, bit, p_terrain); - c.set_priority(10); - if ((int(bit) % 2) == 0) { - // Side peering bits: add the constraint if the center is of the same terrain. - Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit); - if (cells_with_terrain_center_bit.has(neighbor)) { - constraints.insert(c); - } - } else { - // Corner peering bits: add the constraint if all tiles on the constraint has the same center bit. - HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = c.get_overlapping_coords_and_peering_bits(); - bool valid = true; - for (KeyValue<Vector2i, TileSet::CellNeighbor> kv : overlapping_terrain_bits) { - if (!cells_with_terrain_center_bit.has(kv.key)) { - valid = false; - break; - } - } - if (valid) { - constraints.insert(c); - } - } - } - } - } - - // Fills in the constraint list from existing tiles. - for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(painted_set, p_terrain_set, p_ignore_empty_terrains)) { - constraints.insert(c); - } - - // Fill the terrains. - output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints); - return output; -} - -HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { - HashMap<Vector2i, TileSet::TerrainsPattern> output; - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - ERR_FAIL_COND_V(!tile_set.is_valid(), output); - ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); - - // Make sure the path is correct and build the peering bit list while doing it. - Vector<TileSet::CellNeighbor> neighbor_list; - for (int i = 0; i < p_coords_array.size() - 1; i++) { - // Find the adequate neighbor. - TileSet::CellNeighbor found_bit = TileSet::CELL_NEIGHBOR_MAX; - for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { - TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); - if (tile_map_node->is_existing_neighbor(bit)) { - if (tile_map_node->get_neighbor_cell(p_coords_array[i], bit) == p_coords_array[i + 1]) { - found_bit = bit; - break; - } - } - } - ERR_FAIL_COND_V_MSG(found_bit == TileSet::CELL_NEIGHBOR_MAX, output, vformat("Invalid terrain path, %s is not a neighboring tile of %s", p_coords_array[i + 1], p_coords_array[i])); - neighbor_list.push_back(found_bit); - } - - // Build list and set of tiles that can be modified (painted and their surroundings). - Vector<Vector2i> can_modify_list; - RBSet<Vector2i> can_modify_set; - RBSet<Vector2i> painted_set; - for (int i = p_coords_array.size() - 1; i >= 0; i--) { - const Vector2i &coords = p_coords_array[i]; - can_modify_list.push_back(coords); - can_modify_set.insert(coords); - painted_set.insert(coords); - } - for (Vector2i coords : p_coords_array) { - // Find the adequate neighbor. - for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { - TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); - if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { - Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit); - if (!can_modify_set.has(neighbor)) { - can_modify_list.push_back(neighbor); - can_modify_set.insert(neighbor); - } - } - } - } - - RBSet<TerrainConstraint> constraints; - - // Add new constraints from the path drawn. - for (Vector2i coords : p_coords_array) { - // Constraints on the center bit. - TerrainConstraint c = TerrainConstraint(tile_map_node, coords, p_terrain); - c.set_priority(10); - constraints.insert(c); - } - for (int i = 0; i < p_coords_array.size() - 1; i++) { - // Constraints on the peering bits. - TerrainConstraint c = TerrainConstraint(tile_map_node, p_coords_array[i], neighbor_list[i], p_terrain); - c.set_priority(10); - constraints.insert(c); - } - - // Fills in the constraint list from existing tiles. - for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(painted_set, p_terrain_set, p_ignore_empty_terrains)) { - constraints.insert(c); - } - - // Fill the terrains. - output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints); - return output; -} - -HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains) { - HashMap<Vector2i, TileSet::TerrainsPattern> output; - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - ERR_FAIL_COND_V(!tile_set.is_valid(), output); - ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); - - // Build list and set of tiles that can be modified (painted and their surroundings). - Vector<Vector2i> can_modify_list; - RBSet<Vector2i> can_modify_set; - RBSet<Vector2i> painted_set; - for (int i = p_coords_array.size() - 1; i >= 0; i--) { - const Vector2i &coords = p_coords_array[i]; - can_modify_list.push_back(coords); - can_modify_set.insert(coords); - painted_set.insert(coords); - } - for (Vector2i coords : p_coords_array) { - // Find the adequate neighbor. - for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { - TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); - if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { - Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit); - if (!can_modify_set.has(neighbor)) { - can_modify_list.push_back(neighbor); - can_modify_set.insert(neighbor); - } - } - } - } - - // Add constraint by the new ones. - RBSet<TerrainConstraint> constraints; - - // Add new constraints from the path drawn. - for (Vector2i coords : p_coords_array) { - // Constraints on the center bit. - RBSet<TerrainConstraint> added_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, p_terrains_pattern); - for (TerrainConstraint c : added_constraints) { - c.set_priority(10); - constraints.insert(c); - } - } - - // Fills in the constraint list from modified tiles border. - for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(painted_set, p_terrain_set, p_ignore_empty_terrains)) { - constraints.insert(c); - } - - // Fill the terrains. - output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints); - return output; -} - -TileMapCell TileMapLayer::get_cell(const Vector2i &p_coords, bool p_use_proxies) const { - if (!tile_map.has(p_coords)) { - return TileMapCell(); - } else { - TileMapCell c = tile_map.find(p_coords)->value.cell; - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - if (p_use_proxies && tile_set.is_valid()) { - Array proxyed = tile_set->map_tile_proxy(c.source_id, c.get_atlas_coords(), c.alternative_tile); - c.source_id = proxyed[0]; - c.set_atlas_coords(proxyed[1]); - c.alternative_tile = proxyed[2]; - } - return c; - } -} - -void TileMapLayer::set_tile_data(TileMapLayer::DataFormat p_format, const Vector<int> &p_data) { - ERR_FAIL_COND(p_format > TileMapLayer::FORMAT_3); - - // Set data for a given tile from raw data. - - int c = p_data.size(); - const int *r = p_data.ptr(); - - int offset = (p_format >= TileMapLayer::FORMAT_2) ? 3 : 2; - ERR_FAIL_COND_MSG(c % offset != 0, vformat("Corrupted tile data. Got size: %s. Expected modulo: %s", offset)); - - clear(); - -#ifdef DISABLE_DEPRECATED - ERR_FAIL_COND_MSG(p_format != TileMapLayer::FORMAT_3, vformat("Cannot handle deprecated TileMap data format version %d. This Godot version was compiled with no support for deprecated data.", p_format)); -#endif - - for (int i = 0; i < c; i += offset) { - const uint8_t *ptr = (const uint8_t *)&r[i]; - uint8_t local[12]; - for (int j = 0; j < ((p_format >= TileMapLayer::FORMAT_2) ? 12 : 8); j++) { - local[j] = ptr[j]; - } - -#ifdef BIG_ENDIAN_ENABLED - - SWAP(local[0], local[3]); - SWAP(local[1], local[2]); - SWAP(local[4], local[7]); - SWAP(local[5], local[6]); - //TODO: ask someone to check this... - if (FORMAT >= FORMAT_2) { - SWAP(local[8], local[11]); - SWAP(local[9], local[10]); - } -#endif - // Extracts position in TileMap. - int16_t x = decode_uint16(&local[0]); - int16_t y = decode_uint16(&local[2]); - - if (p_format == TileMapLayer::FORMAT_3) { - uint16_t source_id = decode_uint16(&local[4]); - uint16_t atlas_coords_x = decode_uint16(&local[6]); - uint16_t atlas_coords_y = decode_uint16(&local[8]); - uint16_t alternative_tile = decode_uint16(&local[10]); - set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile); - } else { -#ifndef DISABLE_DEPRECATED - // Previous decated format. - - uint32_t v = decode_uint32(&local[4]); - // Extract the transform flags that used to be in the tilemap. - bool flip_h = v & (1UL << 29); - bool flip_v = v & (1UL << 30); - bool transpose = v & (1UL << 31); - v &= (1UL << 29) - 1; - - // Extract autotile/atlas coords. - int16_t coord_x = 0; - int16_t coord_y = 0; - if (p_format == TileMapLayer::FORMAT_2) { - coord_x = decode_uint16(&local[8]); - coord_y = decode_uint16(&local[10]); - } - - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - if (tile_set.is_valid()) { - Array a = tile_set->compatibility_tilemap_map(v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose); - if (a.size() == 3) { - set_cell(Vector2i(x, y), a[0], a[1], a[2]); - } else { - ERR_PRINT(vformat("No valid tile in Tileset for: tile:%s coords:%s flip_h:%s flip_v:%s transpose:%s", v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose)); - } - } else { - int compatibility_alternative_tile = ((int)flip_h) + ((int)flip_v << 1) + ((int)transpose << 2); - set_cell(Vector2i(x, y), v, Vector2i(coord_x, coord_y), compatibility_alternative_tile); - } -#endif - } - } -} - -Vector<int> TileMapLayer::get_tile_data() const { - // Export tile data to raw format. - Vector<int> tile_data; - tile_data.resize(tile_map.size() * 3); - int *w = tile_data.ptrw(); - - // Save in highest format. - - int idx = 0; - for (const KeyValue<Vector2i, CellData> &E : tile_map) { - uint8_t *ptr = (uint8_t *)&w[idx]; - encode_uint16((int16_t)(E.key.x), &ptr[0]); - encode_uint16((int16_t)(E.key.y), &ptr[2]); - encode_uint16(E.value.cell.source_id, &ptr[4]); - encode_uint16(E.value.cell.coord_x, &ptr[6]); - encode_uint16(E.value.cell.coord_y, &ptr[8]); - encode_uint16(E.value.cell.alternative_tile, &ptr[10]); - idx += 3; - } - - return tile_data; -} - -void TileMapLayer::notify_tile_map_change(DirtyFlags p_what) { - dirty.flags[p_what] = true; - tile_map_node->queue_internal_update(); - _physics_notify_tilemap_change(p_what); -} - -void TileMapLayer::internal_update() { - // Find TileData that need a runtime modification. - // This may add cells to the dirty list is a runtime modification has been notified. - _build_runtime_update_tile_data(); - - // Update all subsystems. - _rendering_update(); - _physics_update(); - _navigation_update(); - _scenes_update(); -#ifdef DEBUG_ENABLED - _debug_update(); -#endif // DEBUG_ENABLED - - _clear_runtime_update_tile_data(); - - // Clear the "what is dirty" flags. - for (int i = 0; i < DIRTY_FLAGS_MAX; i++) { - dirty.flags[i] = false; - } - - // List the cells to delete definitely. - Vector<Vector2i> to_delete; - for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - // Select the the cell from tile_map if it is invalid. - if (cell_data.cell.source_id == TileSet::INVALID_SOURCE) { - to_delete.push_back(cell_data.coords); - } - } - - // Remove cells that are empty after the cleanup. - for (const Vector2i &coords : to_delete) { - tile_map.erase(coords); - } - - // Clear the dirty cells list. - dirty.cell_list.clear(); -} - -void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) { - // Set the current cell tile (using integer position). - Vector2i pk(p_coords); - HashMap<Vector2i, CellData>::Iterator E = tile_map.find(pk); - - int source_id = p_source_id; - Vector2i atlas_coords = p_atlas_coords; - int alternative_tile = p_alternative_tile; - - if ((source_id == TileSet::INVALID_SOURCE || atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE) && - (source_id != TileSet::INVALID_SOURCE || atlas_coords != TileSetSource::INVALID_ATLAS_COORDS || alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE)) { - source_id = TileSet::INVALID_SOURCE; - atlas_coords = TileSetSource::INVALID_ATLAS_COORDS; - alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE; - } - - if (!E) { - if (source_id == TileSet::INVALID_SOURCE) { - return; // Nothing to do, the tile is already empty. - } - - // Insert a new cell in the tile map. - CellData new_cell_data; - new_cell_data.coords = pk; - E = tile_map.insert(pk, new_cell_data); - } else { - if (E->value.cell.source_id == source_id && E->value.cell.get_atlas_coords() == atlas_coords && E->value.cell.alternative_tile == alternative_tile) { - return; // Nothing changed. - } - } - - TileMapCell &c = E->value.cell; - c.source_id = source_id; - c.set_atlas_coords(atlas_coords); - c.alternative_tile = alternative_tile; - - // Make the given cell dirty. - if (!E->value.dirty_list_element.in_list()) { - dirty.cell_list.add(&(E->value.dirty_list_element)); - } - tile_map_node->queue_internal_update(); - - used_rect_cache_dirty = true; -} - -void TileMapLayer::erase_cell(const Vector2i &p_coords) { - set_cell(p_coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); -} - -int TileMapLayer::get_cell_source_id(const Vector2i &p_coords, bool p_use_proxies) const { - // Get a cell source id from position. - HashMap<Vector2i, CellData>::ConstIterator E = tile_map.find(p_coords); - - if (!E) { - return TileSet::INVALID_SOURCE; - } - - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - if (p_use_proxies && tile_set.is_valid()) { - Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); - return proxyed[0]; - } - - return E->value.cell.source_id; -} - -Vector2i TileMapLayer::get_cell_atlas_coords(const Vector2i &p_coords, bool p_use_proxies) const { - // Get a cell source id from position. - HashMap<Vector2i, CellData>::ConstIterator E = tile_map.find(p_coords); - - if (!E) { - return TileSetSource::INVALID_ATLAS_COORDS; - } - - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - if (p_use_proxies && tile_set.is_valid()) { - Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); - return proxyed[1]; - } - - return E->value.cell.get_atlas_coords(); -} - -int TileMapLayer::get_cell_alternative_tile(const Vector2i &p_coords, bool p_use_proxies) const { - // Get a cell source id from position. - HashMap<Vector2i, CellData>::ConstIterator E = tile_map.find(p_coords); - - if (!E) { - return TileSetSource::INVALID_TILE_ALTERNATIVE; - } - - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - if (p_use_proxies && tile_set.is_valid()) { - Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); - return proxyed[2]; - } - - return E->value.cell.alternative_tile; -} - -TileData *TileMapLayer::get_cell_tile_data(const Vector2i &p_coords, bool p_use_proxies) const { - int source_id = get_cell_source_id(p_coords, p_use_proxies); - if (source_id == TileSet::INVALID_SOURCE) { - return nullptr; - } - - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - Ref<TileSetAtlasSource> source = tile_set->get_source(source_id); - if (source.is_valid()) { - return source->get_tile_data(get_cell_atlas_coords(p_coords, p_use_proxies), get_cell_alternative_tile(p_coords, p_use_proxies)); - } - - return nullptr; -} - -void TileMapLayer::clear() { - // Remove all tiles. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - erase_cell(kv.key); - } - used_rect_cache_dirty = true; -} - -Ref<TileMapPattern> TileMapLayer::get_pattern(TypedArray<Vector2i> p_coords_array) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr); - - Ref<TileMapPattern> output; - output.instantiate(); - if (p_coords_array.is_empty()) { - return output; - } - - Vector2i min = Vector2i(p_coords_array[0]); - for (int i = 1; i < p_coords_array.size(); i++) { - min = min.min(p_coords_array[i]); - } - - Vector<Vector2i> coords_in_pattern_array; - coords_in_pattern_array.resize(p_coords_array.size()); - Vector2i ensure_positive_offset; - for (int i = 0; i < p_coords_array.size(); i++) { - Vector2i coords = p_coords_array[i]; - Vector2i coords_in_pattern = coords - min; - if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) { - if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) { - if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) { - coords_in_pattern.x -= 1; - if (coords_in_pattern.x < 0) { - ensure_positive_offset.x = 1; - } - } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) { - coords_in_pattern.y -= 1; - if (coords_in_pattern.y < 0) { - ensure_positive_offset.y = 1; - } - } - } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) { - if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) { - coords_in_pattern.x += 1; - } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) { - coords_in_pattern.y += 1; - } - } - } - coords_in_pattern_array.write[i] = coords_in_pattern; - } - - for (int i = 0; i < coords_in_pattern_array.size(); i++) { - Vector2i coords = p_coords_array[i]; - Vector2i coords_in_pattern = coords_in_pattern_array[i]; - output->set_cell(coords_in_pattern + ensure_positive_offset, get_cell_source_id(coords), get_cell_atlas_coords(coords), get_cell_alternative_tile(coords)); - } - - return output; -} - -void TileMapLayer::set_pattern(const Vector2i &p_position, const Ref<TileMapPattern> p_pattern) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - ERR_FAIL_COND(tile_set.is_null()); - ERR_FAIL_COND(p_pattern.is_null()); - - TypedArray<Vector2i> used_cells = p_pattern->get_used_cells(); - for (int i = 0; i < used_cells.size(); i++) { - Vector2i coords = tile_map_node->map_pattern(p_position, used_cells[i], p_pattern); - set_cell(coords, p_pattern->get_cell_source_id(used_cells[i]), p_pattern->get_cell_atlas_coords(used_cells[i]), p_pattern->get_cell_alternative_tile(used_cells[i])); - } -} - -void TileMapLayer::set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - ERR_FAIL_COND(!tile_set.is_valid()); - ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); - - Vector<Vector2i> cells_vector; - HashSet<Vector2i> painted_set; - for (int i = 0; i < p_cells.size(); i++) { - cells_vector.push_back(p_cells[i]); - painted_set.insert(p_cells[i]); - } - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(cells_vector, p_terrain_set, p_terrain, p_ignore_empty_terrains); - for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) { - if (painted_set.has(kv.key)) { - // Paint a random tile with the correct terrain for the painted path. - TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); - set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); - } else { - // Avoids updating the painted path from the output if the new pattern is the same as before. - TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set); - TileMapCell cell = get_cell(kv.key); - if (cell.source_id != TileSet::INVALID_SOURCE) { - TileSetSource *source = *tile_set->get_source(cell.source_id); - TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); - if (atlas_source) { - // Get tile data. - TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); - if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { - in_map_terrain_pattern = tile_data->get_terrains_pattern(); - } - } - } - if (in_map_terrain_pattern != kv.value) { - TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); - set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); - } - } - } -} - -void TileMapLayer::set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - ERR_FAIL_COND(!tile_set.is_valid()); - ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); - - Vector<Vector2i> vector_path; - HashSet<Vector2i> painted_set; - for (int i = 0; i < p_path.size(); i++) { - vector_path.push_back(p_path[i]); - painted_set.insert(p_path[i]); - } - - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_path(vector_path, p_terrain_set, p_terrain, p_ignore_empty_terrains); - for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) { - if (painted_set.has(kv.key)) { - // Paint a random tile with the correct terrain for the painted path. - TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); - set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); - } else { - // Avoids updating the painted path from the output if the new pattern is the same as before. - TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set); - TileMapCell cell = get_cell(kv.key); - if (cell.source_id != TileSet::INVALID_SOURCE) { - TileSetSource *source = *tile_set->get_source(cell.source_id); - TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); - if (atlas_source) { - // Get tile data. - TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); - if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { - in_map_terrain_pattern = tile_data->get_terrains_pattern(); - } - } - } - if (in_map_terrain_pattern != kv.value) { - TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); - set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); - } - } - } -} - -TypedArray<Vector2i> TileMapLayer::get_used_cells() const { - // Returns the cells used in the tilemap. - TypedArray<Vector2i> a; - for (const KeyValue<Vector2i, CellData> &E : tile_map) { - const TileMapCell &c = E.value.cell; - if (c.source_id == TileSet::INVALID_SOURCE) { - continue; - } - a.push_back(E.key); - } - - return a; -} - -TypedArray<Vector2i> TileMapLayer::get_used_cells_by_id(int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) const { - // Returns the cells used in the tilemap. - TypedArray<Vector2i> a; - for (const KeyValue<Vector2i, CellData> &E : tile_map) { - const TileMapCell &c = E.value.cell; - if (c.source_id == TileSet::INVALID_SOURCE) { - continue; - } - if ((p_source_id == TileSet::INVALID_SOURCE || p_source_id == c.source_id) && - (p_atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || p_atlas_coords == c.get_atlas_coords()) && - (p_alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE || p_alternative_tile == c.alternative_tile)) { - a.push_back(E.key); - } - } - - return a; -} - -Rect2i TileMapLayer::get_used_rect() const { - // Return the rect of the currently used area. - if (used_rect_cache_dirty) { - used_rect_cache = Rect2i(); - - bool first = true; - for (const KeyValue<Vector2i, CellData> &E : tile_map) { - const TileMapCell &c = E.value.cell; - if (c.source_id == TileSet::INVALID_SOURCE) { - continue; - } - if (first) { - used_rect_cache = Rect2i(E.key.x, E.key.y, 0, 0); - first = false; - } else { - used_rect_cache.expand_to(E.key); - } - } - if (!first) { - // Only if we have at least one cell. - // The cache expands to top-left coordinate, so we add one full tile. - used_rect_cache.size += Vector2i(1, 1); - } - used_rect_cache_dirty = false; - } - - return used_rect_cache; -} - -void TileMapLayer::set_name(String p_name) { - if (name == p_name) { - return; - } - name = p_name; - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); -} - -String TileMapLayer::get_name() const { - return name; -} - -void TileMapLayer::set_enabled(bool p_enabled) { - if (enabled == p_enabled) { - return; - } - enabled = p_enabled; - dirty.flags[DIRTY_FLAGS_LAYER_ENABLED] = true; - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); - - tile_map_node->update_configuration_warnings(); -} - -bool TileMapLayer::is_enabled() const { - return enabled; -} - -void TileMapLayer::set_modulate(Color p_modulate) { - if (modulate == p_modulate) { - return; - } - modulate = p_modulate; - dirty.flags[DIRTY_FLAGS_LAYER_MODULATE] = true; - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); -} - -Color TileMapLayer::get_modulate() const { - return modulate; -} - -void TileMapLayer::set_y_sort_enabled(bool p_y_sort_enabled) { - if (y_sort_enabled == p_y_sort_enabled) { - return; - } - y_sort_enabled = p_y_sort_enabled; - dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] = true; - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); - - tile_map_node->update_configuration_warnings(); -} - -bool TileMapLayer::is_y_sort_enabled() const { - return y_sort_enabled; -} - -void TileMapLayer::set_y_sort_origin(int p_y_sort_origin) { - if (y_sort_origin == p_y_sort_origin) { - return; - } - y_sort_origin = p_y_sort_origin; - dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] = true; - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); -} - -int TileMapLayer::get_y_sort_origin() const { - return y_sort_origin; -} - -void TileMapLayer::set_z_index(int p_z_index) { - if (z_index == p_z_index) { - return; - } - z_index = p_z_index; - dirty.flags[DIRTY_FLAGS_LAYER_Z_INDEX] = true; - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); - - tile_map_node->update_configuration_warnings(); -} - -int TileMapLayer::get_z_index() const { - return z_index; -} - -void TileMapLayer::set_navigation_enabled(bool p_enabled) { - if (navigation_enabled == p_enabled) { - return; - } - navigation_enabled = p_enabled; - dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED] = true; - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); -} - -bool TileMapLayer::is_navigation_enabled() const { - return navigation_enabled; -} - -void TileMapLayer::set_navigation_map(RID p_map) { - ERR_FAIL_COND_MSG(!tile_map_node->is_inside_tree(), "A TileMap navigation map can only be changed while inside the SceneTree."); - navigation_map = p_map; - uses_world_navigation_map = p_map == tile_map_node->get_world_2d()->get_navigation_map(); -} - -RID TileMapLayer::get_navigation_map() const { - if (navigation_map.is_valid()) { - return navigation_map; - } - return RID(); -} - -void TileMapLayer::fix_invalid_tiles() { - Ref<TileSet> tileset = tile_map_node->get_tileset(); - ERR_FAIL_COND_MSG(tileset.is_null(), "Cannot call fix_invalid_tiles() on a TileMap without a valid TileSet."); - - RBSet<Vector2i> coords; - for (const KeyValue<Vector2i, CellData> &E : tile_map) { - TileSetSource *source = *tileset->get_source(E.value.cell.source_id); - if (!source || !source->has_tile(E.value.cell.get_atlas_coords()) || !source->has_alternative_tile(E.value.cell.get_atlas_coords(), E.value.cell.alternative_tile)) { - coords.insert(E.key); - } - } - for (const Vector2i &E : coords) { - set_cell(E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); - } -} - -bool TileMapLayer::has_body_rid(RID p_physics_body) const { - return bodies_coords.has(p_physics_body); -} - -Vector2i TileMapLayer::get_coords_for_body_rid(RID p_physics_body) const { - return bodies_coords[p_physics_body]; -} - -TileMapLayer::~TileMapLayer() { - if (!tile_map_node) { - // Temporary layer. - return; - } - - in_destructor = true; - clear(); - internal_update(); -} - -HashMap<Vector2i, TileSet::CellNeighbor> TerrainConstraint::get_overlapping_coords_and_peering_bits() const { - HashMap<Vector2i, TileSet::CellNeighbor> output; - - ERR_FAIL_COND_V(is_center_bit(), output); - - Ref<TileSet> ts = tile_map->get_tileset(); - ERR_FAIL_COND_V(!ts.is_valid(), output); - - TileSet::TileShape shape = ts->get_tile_shape(); - if (shape == TileSet::TILE_SHAPE_SQUARE) { - switch (bit) { - case 1: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE; - break; - case 2: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; - break; - case 3: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE; - break; - default: - ERR_FAIL_V(output); - } - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { - switch (bit) { - case 1: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; - break; - case 2: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER; - break; - case 3: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; - break; - default: - ERR_FAIL_V(output); - } - } else { - // Half offset shapes. - TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis(); - if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - switch (bit) { - case 1: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE; - break; - case 2: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER; - break; - case 3: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; - break; - case 4: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; - break; - case 5: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; - break; - default: - ERR_FAIL_V(output); - } - } else { - switch (bit) { - case 1: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; - break; - case 2: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; - break; - case 3: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; - break; - case 4: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE; - break; - case 5: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; - break; - default: - ERR_FAIL_V(output); - } - } - } - return output; -} - -TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain) { - tile_map = p_tile_map; - - Ref<TileSet> ts = tile_map->get_tileset(); - ERR_FAIL_COND(!ts.is_valid()); - - bit = 0; - base_cell_coords = p_position; - terrain = p_terrain; -} - -TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain) { - // The way we build the constraint make it easy to detect conflicting constraints. - tile_map = p_tile_map; - - Ref<TileSet> ts = tile_map->get_tileset(); - ERR_FAIL_COND(!ts.is_valid()); - - TileSet::TileShape shape = ts->get_tile_shape(); - if (shape == TileSet::TILE_SHAPE_SQUARE) { - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - bit = 1; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - bit = 2; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - bit = 3; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - bit = 1; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER); - break; - case TileSet::CELL_NEIGHBOR_TOP_SIDE: - bit = 3; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); - break; - default: - ERR_FAIL(); - break; - } - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: - bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - bit = 1; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: - bit = 2; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - bit = 3; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_LEFT_CORNER: - bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - bit = 1; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_CORNER: - bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_CORNER); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - bit = 3; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); - break; - default: - ERR_FAIL(); - break; - } - } else { - // Half-offset shapes. - TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis(); - if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - bit = 1; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - bit = 2; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - bit = 3; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: - bit = 4; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - bit = 5; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - bit = 1; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - bit = 4; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - bit = 3; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_CORNER: - bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - bit = 5; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - bit = 4; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); - break; - default: - ERR_FAIL(); - break; - } - } else { - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: - bit = 1; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - bit = 2; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - bit = 3; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - bit = 4; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - bit = 1; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - bit = 5; - base_cell_coords = p_position; - break; - case TileSet::CELL_NEIGHBOR_LEFT_CORNER: - bit = 3; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - bit = 1; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_SIDE: - bit = 4; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - bit = 3; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - bit = 5; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); - break; - default: - ERR_FAIL(); - break; - } - } - } - terrain = p_terrain; -} +#include "scene/2d/tile_map_layer.h" +#include "scene/gui/control.h" #define TILEMAP_CALL_FOR_LAYER(layer, function, ...) \ if (layer < 0) { \ @@ -3622,7 +772,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { Vector<String> components = String(p_name).split("/", true, 2); if (p_name == "format") { if (p_value.get_type() == Variant::INT) { - format = (TileMapLayer::DataFormat)(p_value.operator int64_t()); // Set format used for loading. + format = (TileMapDataFormat)(p_value.operator int64_t()); // Set format used for loading. return true; } } @@ -3701,7 +851,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { bool TileMap::_get(const StringName &p_name, Variant &r_ret) const { Vector<String> components = String(p_name).split("/", true, 2); if (p_name == "format") { - r_ret = TileMapLayer::FORMAT_MAX - 1; // When saving, always save highest format. + r_ret = TileMapDataFormat::FORMAT_MAX - 1; // When saving, always save highest format. return true; } #ifndef DISABLE_DEPRECATED @@ -4765,7 +1915,7 @@ void TileMap::_bind_methods() { ADD_ARRAY("layers", "layer_"); - ADD_PROPERTY_DEFAULT("format", TileMapLayer::FORMAT_1); + ADD_PROPERTY_DEFAULT("format", TileMapDataFormat::FORMAT_1); ADD_SIGNAL(MethodInfo(CoreStringNames::get_singleton()->changed)); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 1e4c6d0e66..29af0ad2b1 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -32,406 +32,17 @@ #define TILE_MAP_H #include "scene/2d/node_2d.h" -#include "scene/gui/control.h" #include "scene/resources/tile_set.h" -class TileSetAtlasSource; +class Control; +class TileMapLayer; +class TerrainConstraint; -class TerrainConstraint { -private: - const TileMap *tile_map = nullptr; - Vector2i base_cell_coords; - int bit = -1; - int terrain = -1; - - int priority = 1; - -public: - bool operator<(const TerrainConstraint &p_other) const { - if (base_cell_coords == p_other.base_cell_coords) { - return bit < p_other.bit; - } - return base_cell_coords < p_other.base_cell_coords; - } - - String to_string() const { - return vformat("Constraint {pos:%s, bit:%d, terrain:%d, priority:%d}", base_cell_coords, bit, terrain, priority); - } - - Vector2i get_base_cell_coords() const { - return base_cell_coords; - } - - bool is_center_bit() const { - return bit == 0; - } - - HashMap<Vector2i, TileSet::CellNeighbor> get_overlapping_coords_and_peering_bits() const; - - void set_terrain(int p_terrain) { - terrain = p_terrain; - } - - int get_terrain() const { - return terrain; - } - - void set_priority(int p_priority) { - priority = p_priority; - } - - int get_priority() const { - return priority; - } - - TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain); // For the center terrain bit - TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain); // For peering bits - TerrainConstraint(){}; -}; - -#ifdef DEBUG_ENABLED -class DebugQuadrant; -#endif // DEBUG_ENABLED -class RenderingQuadrant; - -struct CellData { - Vector2i coords; - TileMapCell cell; - - // Debug. - SelfList<CellData> debug_quadrant_list_element; - - // Rendering. - Ref<RenderingQuadrant> rendering_quadrant; - SelfList<CellData> rendering_quadrant_list_element; - LocalVector<RID> occluders; - - // Physics. - LocalVector<RID> bodies; - - // Navigation. - LocalVector<RID> navigation_regions; - - // Scenes. - String scene; - - // Runtime TileData cache. - TileData *runtime_tile_data_cache = nullptr; - - // List elements. - SelfList<CellData> dirty_list_element; - - bool operator<(const CellData &p_other) const { - return coords < p_other.coords; - } - - // For those, copy everything but SelfList elements. - void operator=(const CellData &p_other) { - coords = p_other.coords; - cell = p_other.cell; - occluders = p_other.occluders; - bodies = p_other.bodies; - navigation_regions = p_other.navigation_regions; - scene = p_other.scene; - runtime_tile_data_cache = p_other.runtime_tile_data_cache; - } - - CellData(const CellData &p_other) : - debug_quadrant_list_element(this), - rendering_quadrant_list_element(this), - dirty_list_element(this) { - coords = p_other.coords; - cell = p_other.cell; - occluders = p_other.occluders; - bodies = p_other.bodies; - navigation_regions = p_other.navigation_regions; - scene = p_other.scene; - runtime_tile_data_cache = p_other.runtime_tile_data_cache; - } - - CellData() : - debug_quadrant_list_element(this), - rendering_quadrant_list_element(this), - dirty_list_element(this) { - } -}; - -// For compatibility reasons, we use another comparator for Y-sorted layers. -struct CellDataYSortedComparator { - _FORCE_INLINE_ bool operator()(const CellData &p_a, const CellData &p_b) const { - return p_a.coords.x == p_b.coords.x ? (p_a.coords.y < p_b.coords.y) : (p_a.coords.x > p_b.coords.x); - } -}; - -#ifdef DEBUG_ENABLED -class DebugQuadrant : public RefCounted { - GDCLASS(DebugQuadrant, RefCounted); - -public: - Vector2i quadrant_coords; - SelfList<CellData>::List cells; - RID canvas_item; - - SelfList<DebugQuadrant> dirty_quadrant_list_element; - - // For those, copy everything but SelfList elements. - DebugQuadrant(const DebugQuadrant &p_other) : - dirty_quadrant_list_element(this) { - quadrant_coords = p_other.quadrant_coords; - cells = p_other.cells; - canvas_item = p_other.canvas_item; - } - - DebugQuadrant() : - dirty_quadrant_list_element(this) { - } - - ~DebugQuadrant() { - cells.clear(); - } -}; -#endif // DEBUG_ENABLED - -class RenderingQuadrant : public RefCounted { - GDCLASS(RenderingQuadrant, RefCounted); - -public: - struct CoordsWorldComparator { - _ALWAYS_INLINE_ bool operator()(const Vector2 &p_a, const Vector2 &p_b) const { - // We sort the cells by their local coords, as it is needed by rendering. - if (p_a.y == p_b.y) { - return p_a.x > p_b.x; - } else { - return p_a.y < p_b.y; - } - } - }; - - Vector2i quadrant_coords; - SelfList<CellData>::List cells; - List<RID> canvas_items; - Vector2 canvas_items_position; - - SelfList<RenderingQuadrant> dirty_quadrant_list_element; - - // For those, copy everything but SelfList elements. - RenderingQuadrant(const RenderingQuadrant &p_other) : - dirty_quadrant_list_element(this) { - quadrant_coords = p_other.quadrant_coords; - cells = p_other.cells; - canvas_items = p_other.canvas_items; - } - - RenderingQuadrant() : - dirty_quadrant_list_element(this) { - } - - ~RenderingQuadrant() { - cells.clear(); - } -}; - -class TileMapLayer : public RefCounted { - GDCLASS(TileMapLayer, RefCounted); - -public: - enum DataFormat { - FORMAT_1 = 0, - FORMAT_2, - FORMAT_3, - FORMAT_MAX, - }; - - enum DirtyFlags { - DIRTY_FLAGS_LAYER_ENABLED = 0, - DIRTY_FLAGS_LAYER_MODULATE, - DIRTY_FLAGS_LAYER_Y_SORT_ENABLED, - DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN, - DIRTY_FLAGS_LAYER_Z_INDEX, - DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED, - DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE, - DIRTY_FLAGS_TILE_MAP_IN_TREE, - DIRTY_FLAGS_TILE_MAP_IN_CANVAS, - DIRTY_FLAGS_TILE_MAP_VISIBILITY, - DIRTY_FLAGS_TILE_MAP_XFORM, - DIRTY_FLAGS_TILE_MAP_LOCAL_XFORM, - DIRTY_FLAGS_TILE_MAP_SELECTED_LAYER, - DIRTY_FLAGS_TILE_MAP_LIGHT_MASK, - DIRTY_FLAGS_TILE_MAP_MATERIAL, - DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL, - DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER, - DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT, - DIRTY_FLAGS_TILE_MAP_TILE_SET, - DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE, - DIRTY_FLAGS_TILE_MAP_COLLISION_ANIMATABLE, - DIRTY_FLAGS_TILE_MAP_COLLISION_VISIBILITY_MODE, - DIRTY_FLAGS_TILE_MAP_NAVIGATION_VISIBILITY_MODE, - DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED, - DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE, - DIRTY_FLAGS_MAX, - }; - -private: - // Exposed properties. - String name; - bool enabled = true; - Color modulate = Color(1, 1, 1, 1); - bool y_sort_enabled = false; - int y_sort_origin = 0; - int z_index = 0; - bool navigation_enabled = true; - RID navigation_map; - bool uses_world_navigation_map = false; - - // Internal. - TileMap *tile_map_node = nullptr; - int layer_index_in_tile_map_node = -1; - RID canvas_item; - HashMap<Vector2i, CellData> tile_map; - - // Dirty flag. Allows knowing what was modified since the last update. - struct { - bool flags[DIRTY_FLAGS_MAX] = { false }; - SelfList<CellData>::List cell_list; - } dirty; - bool in_destructor = false; - - // Rect cache. - mutable Rect2 rect_cache; - mutable bool rect_cache_dirty = true; - mutable Rect2i used_rect_cache; - mutable bool used_rect_cache_dirty = true; - - // Runtime tile data. - bool _runtime_update_tile_data_was_cleaned_up = false; - void _build_runtime_update_tile_data(); - void _build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_auto_add_to_dirty_list = false); - void _clear_runtime_update_tile_data(); - - // Per-system methods. -#ifdef DEBUG_ENABLED - HashMap<Vector2i, Ref<DebugQuadrant>> debug_quadrant_map; - Vector2i _coords_to_debug_quadrant_coords(const Vector2i &p_coords) const; - bool _debug_was_cleaned_up = false; - void _debug_update(); - void _debug_quadrants_update_cell(CellData &r_cell_data, SelfList<DebugQuadrant>::List &r_dirty_debug_quadrant_list); -#endif // DEBUG_ENABLED - - HashMap<Vector2i, Ref<RenderingQuadrant>> rendering_quadrant_map; - bool _rendering_was_cleaned_up = false; - void _rendering_update(); - void _rendering_quadrants_update_cell(CellData &r_cell_data, SelfList<RenderingQuadrant>::List &r_dirty_rendering_quadrant_list); - void _rendering_occluders_clear_cell(CellData &r_cell_data); - void _rendering_occluders_update_cell(CellData &r_cell_data); -#ifdef DEBUG_ENABLED - void _rendering_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data); -#endif // DEBUG_ENABLED - - HashMap<RID, Vector2i> bodies_coords; // Mapping for RID to coords. - bool _physics_was_cleaned_up = false; - void _physics_update(); - void _physics_notify_tilemap_change(DirtyFlags p_what); - void _physics_clear_cell(CellData &r_cell_data); - void _physics_update_cell(CellData &r_cell_data); -#ifdef DEBUG_ENABLED - void _physics_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data); -#endif // DEBUG_ENABLED - - bool _navigation_was_cleaned_up = false; - void _navigation_update(); - void _navigation_clear_cell(CellData &r_cell_data); - void _navigation_update_cell(CellData &r_cell_data); -#ifdef DEBUG_ENABLED - void _navigation_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data); -#endif // DEBUG_ENABLED - - bool _scenes_was_cleaned_up = false; - void _scenes_update(); - void _scenes_clear_cell(CellData &r_cell_data); - void _scenes_update_cell(CellData &r_cell_data); -#ifdef DEBUG_ENABLED - void _scenes_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data); -#endif // DEBUG_ENABLED - - // Terrains. - TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern); - RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const; - RBSet<TerrainConstraint> _get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const; - -public: - // TileMap node. - void set_tile_map(TileMap *p_tile_map); - void set_layer_index_in_tile_map_node(int p_index); - - // Rect caching. - Rect2 get_rect(bool &r_changed) const; - - // Terrains. - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints); // Not exposed. - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed. - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed. - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true); // Not exposed. - - // Not exposed to users. - TileMapCell get_cell(const Vector2i &p_coords, bool p_use_proxies = false) const; - - // For TileMap node's use. - void set_tile_data(DataFormat p_format, const Vector<int> &p_data); - Vector<int> get_tile_data() const; - void notify_tile_map_change(DirtyFlags p_what); - void internal_update(); - - // --- Exposed in TileMap --- - - // Cells manipulation. - void set_cell(const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0); - void erase_cell(const Vector2i &p_coords); - - int get_cell_source_id(const Vector2i &p_coords, bool p_use_proxies = false) const; - Vector2i get_cell_atlas_coords(const Vector2i &p_coords, bool p_use_proxies = false) const; - int get_cell_alternative_tile(const Vector2i &p_coords, bool p_use_proxies = false) const; - TileData *get_cell_tile_data(const Vector2i &p_coords, bool p_use_proxies = false) const; // Helper method to make accessing the data easier. - void clear(); - - // Patterns. - Ref<TileMapPattern> get_pattern(TypedArray<Vector2i> p_coords_array); - void set_pattern(const Vector2i &p_position, const Ref<TileMapPattern> p_pattern); - - // Terrains. - void set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); - void set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); - - // Cells usage. - TypedArray<Vector2i> get_used_cells() const; - TypedArray<Vector2i> get_used_cells_by_id(int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) const; - Rect2i get_used_rect() const; - - // Layer properties. - void set_name(String p_name); - String get_name() const; - void set_enabled(bool p_enabled); - bool is_enabled() const; - void set_modulate(Color p_modulate); - Color get_modulate() const; - void set_y_sort_enabled(bool p_y_sort_enabled); - bool is_y_sort_enabled() const; - void set_y_sort_origin(int p_y_sort_origin); - int get_y_sort_origin() const; - void set_z_index(int p_z_index); - int get_z_index() const; - void set_navigation_enabled(bool p_enabled); - bool is_navigation_enabled() const; - void set_navigation_map(RID p_map); - RID get_navigation_map() const; - - // Fixing and clearing methods. - void fix_invalid_tiles(); - - // Find coords for body. - bool has_body_rid(RID p_physics_body) const; - Vector2i get_coords_for_body_rid(RID p_physics_body) const; // For finding tiles from collision. - - ~TileMapLayer(); +enum TileMapDataFormat { + FORMAT_1 = 0, + FORMAT_2, + FORMAT_3, + FORMAT_MAX, }; class TileMap : public Node2D { @@ -448,7 +59,7 @@ private: friend class TileSetPlugin; // A compatibility enum to specify how is the data if formatted. - mutable TileMapLayer::DataFormat format = TileMapLayer::FORMAT_3; + mutable TileMapDataFormat format = TileMapDataFormat::FORMAT_3; static constexpr float FP_ADJUST = 0.00001; diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp new file mode 100644 index 0000000000..4ef47ba174 --- /dev/null +++ b/scene/2d/tile_map_layer.cpp @@ -0,0 +1,2886 @@ +/**************************************************************************/ +/* tile_map_layer.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "tile_map_layer.h" + +#include "core/core_string_names.h" +#include "core/io/marshalls.h" +#include "scene/gui/control.h" +#include "scene/resources/world_2d.h" +#include "servers/navigation_server_2d.h" + +#ifdef DEBUG_ENABLED +#include "servers/navigation_server_3d.h" +#endif // DEBUG_ENABLED + +#ifdef DEBUG_ENABLED +/////////////////////////////// Debug ////////////////////////////////////////// +constexpr int TILE_MAP_DEBUG_QUADRANT_SIZE = 16; + +Vector2i TileMapLayer::_coords_to_debug_quadrant_coords(const Vector2i &p_coords) const { + return Vector2i( + p_coords.x > 0 ? p_coords.x / TILE_MAP_DEBUG_QUADRANT_SIZE : (p_coords.x - (TILE_MAP_DEBUG_QUADRANT_SIZE - 1)) / TILE_MAP_DEBUG_QUADRANT_SIZE, + p_coords.y > 0 ? p_coords.y / TILE_MAP_DEBUG_QUADRANT_SIZE : (p_coords.y - (TILE_MAP_DEBUG_QUADRANT_SIZE - 1)) / TILE_MAP_DEBUG_QUADRANT_SIZE); +} + +void TileMapLayer::_debug_update() { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + RenderingServer *rs = RenderingServer::get_singleton(); + + // Check if we should cleanup everything. + bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree(); + + if (forced_cleanup) { + for (KeyValue<Vector2i, Ref<DebugQuadrant>> &kv : debug_quadrant_map) { + // Free the quadrant. + Ref<DebugQuadrant> &debug_quadrant = kv.value; + if (debug_quadrant->canvas_item.is_valid()) { + rs->free(debug_quadrant->canvas_item); + } + } + debug_quadrant_map.clear(); + _debug_was_cleaned_up = true; + return; + } + + // Check if anything is dirty, in such a case, redraw debug. + bool anything_changed = false; + for (int i = 0; i < DIRTY_FLAGS_MAX; i++) { + if (dirty.flags[i]) { + anything_changed = true; + break; + } + } + + // List all debug quadrants to update, creating new ones if needed. + SelfList<DebugQuadrant>::List dirty_debug_quadrant_list; + + if (_debug_was_cleaned_up || anything_changed) { + // Update all cells. + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + CellData &cell_data = kv.value; + _debug_quadrants_update_cell(cell_data, dirty_debug_quadrant_list); + } + } else { + // Update dirty cells. + for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + _debug_quadrants_update_cell(cell_data, dirty_debug_quadrant_list); + } + } + + // Update those quadrants. + for (SelfList<DebugQuadrant> *quadrant_list_element = dirty_debug_quadrant_list.first(); quadrant_list_element;) { + SelfList<DebugQuadrant> *next_quadrant_list_element = quadrant_list_element->next(); // "Hack" to clear the list while iterating. + + DebugQuadrant &debug_quadrant = *quadrant_list_element->self(); + + // Check if the quadrant has a tile. + bool has_a_tile = false; + RID &ci = debug_quadrant.canvas_item; + for (SelfList<CellData> *cell_data_list_element = debug_quadrant.cells.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + if (cell_data.cell.source_id != TileSet::INVALID_SOURCE) { + has_a_tile = true; + break; + } + } + + if (has_a_tile) { + // Update the quadrant. + if (ci.is_valid()) { + rs->canvas_item_clear(ci); + } else { + ci = rs->canvas_item_create(); + rs->canvas_item_set_z_index(ci, RS::CANVAS_ITEM_Z_MAX - 1); + rs->canvas_item_set_parent(ci, tile_map_node->get_canvas_item()); + } + + const Vector2 quadrant_pos = tile_map_node->map_to_local(debug_quadrant.quadrant_coords * TILE_MAP_DEBUG_QUADRANT_SIZE); + Transform2D xform(0, quadrant_pos); + rs->canvas_item_set_transform(ci, xform); + + for (SelfList<CellData> *cell_data_list_element = debug_quadrant.cells.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + if (cell_data.cell.source_id != TileSet::INVALID_SOURCE) { + _rendering_draw_cell_debug(ci, quadrant_pos, cell_data); + _physics_draw_cell_debug(ci, quadrant_pos, cell_data); + _navigation_draw_cell_debug(ci, quadrant_pos, cell_data); + _scenes_draw_cell_debug(ci, quadrant_pos, cell_data); + } + } + } else { + // Free the quadrant. + if (ci.is_valid()) { + rs->free(ci); + } + quadrant_list_element->remove_from_list(); + debug_quadrant_map.erase(debug_quadrant.quadrant_coords); + } + + quadrant_list_element = next_quadrant_list_element; + } + + dirty_debug_quadrant_list.clear(); + + _debug_was_cleaned_up = false; +} + +void TileMapLayer::_debug_quadrants_update_cell(CellData &r_cell_data, SelfList<DebugQuadrant>::List &r_dirty_debug_quadrant_list) { + Vector2i quadrant_coords = _coords_to_debug_quadrant_coords(r_cell_data.coords); + + if (!debug_quadrant_map.has(quadrant_coords)) { + // Create a new quadrant and add it to the quadrant map. + Ref<DebugQuadrant> new_quadrant; + new_quadrant.instantiate(); + new_quadrant->quadrant_coords = quadrant_coords; + debug_quadrant_map[quadrant_coords] = new_quadrant; + } + + // Add the cell to its quadrant, if it is not already in there. + Ref<DebugQuadrant> &debug_quadrant = debug_quadrant_map[quadrant_coords]; + if (!r_cell_data.debug_quadrant_list_element.in_list()) { + debug_quadrant->cells.add(&r_cell_data.debug_quadrant_list_element); + } + + // Mark the quadrant as dirty. + if (!debug_quadrant->dirty_quadrant_list_element.in_list()) { + r_dirty_debug_quadrant_list.add(&debug_quadrant->dirty_quadrant_list_element); + } +} +#endif // DEBUG_ENABLED + +/////////////////////////////// Rendering ////////////////////////////////////// +void TileMapLayer::_rendering_update() { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + RenderingServer *rs = RenderingServer::get_singleton(); + + // Check if we should cleanup everything. + bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree(); + + // ----------- Layer level processing ----------- + if (forced_cleanup) { + // Cleanup. + if (canvas_item.is_valid()) { + rs->free(canvas_item); + canvas_item = RID(); + } + } else { + // Create/Update the layer's CanvasItem. + if (!canvas_item.is_valid()) { + RID ci = rs->canvas_item_create(); + rs->canvas_item_set_parent(ci, tile_map_node->get_canvas_item()); + canvas_item = ci; + } + RID &ci = canvas_item; + rs->canvas_item_set_draw_index(ci, layer_index_in_tile_map_node - (int64_t)0x80000000); + rs->canvas_item_set_sort_children_by_y(ci, y_sort_enabled); + rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid()); + rs->canvas_item_set_z_index(ci, z_index); + rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree())); + rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree())); + rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask()); + + // Modulate the layer. + Color layer_modulate = modulate; + int selected_layer = tile_map_node->get_selected_layer(); + if (selected_layer >= 0 && layer_index_in_tile_map_node != selected_layer) { + int z_selected = tile_map_node->get_layer_z_index(selected_layer); + if (z_index < z_selected || (z_index == z_selected && layer_index_in_tile_map_node < selected_layer)) { + layer_modulate = layer_modulate.darkened(0.5); + } else if (z_index > z_selected || (z_index == z_selected && layer_index_in_tile_map_node > selected_layer)) { + layer_modulate = layer_modulate.darkened(0.5); + layer_modulate.a *= 0.3; + } + } + rs->canvas_item_set_modulate(ci, layer_modulate); + } + + // ----------- Quadrants processing ----------- + + // List all rendering quadrants to update, creating new ones if needed. + SelfList<RenderingQuadrant>::List dirty_rendering_quadrant_list; + + // Check if anything changed that might change the quadrant shape. + // If so, recreate everything. + bool quandrant_shape_changed = dirty.flags[DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE] || + (tile_map_node->is_y_sort_enabled() && y_sort_enabled && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] || dirty.flags[DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_TILE_MAP_LOCAL_XFORM] || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET])); + + // Free all quadrants. + if (forced_cleanup || quandrant_shape_changed) { + for (const KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) { + for (int i = 0; i < kv.value->canvas_items.size(); i++) { + const RID &ci = kv.value->canvas_items[i]; + if (ci.is_valid()) { + rs->free(ci); + } + } + kv.value->cells.clear(); + } + rendering_quadrant_map.clear(); + _rendering_was_cleaned_up = true; + } + + if (!forced_cleanup) { + // List all quadrants to update, recreating them if needed. + if (dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || _rendering_was_cleaned_up) { + // Update all cells. + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + CellData &cell_data = kv.value; + _rendering_quadrants_update_cell(cell_data, dirty_rendering_quadrant_list); + } + } else { + // Update dirty cells. + for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + _rendering_quadrants_update_cell(cell_data, dirty_rendering_quadrant_list); + } + } + + // Update all dirty quadrants. + for (SelfList<RenderingQuadrant> *quadrant_list_element = dirty_rendering_quadrant_list.first(); quadrant_list_element;) { + SelfList<RenderingQuadrant> *next_quadrant_list_element = quadrant_list_element->next(); // "Hack" to clear the list while iterating. + + const Ref<RenderingQuadrant> &rendering_quadrant = quadrant_list_element->self(); + + // Check if the quadrant has a tile. + bool has_a_tile = false; + for (SelfList<CellData> *cell_data_list_element = rendering_quadrant->cells.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + if (cell_data.cell.source_id != TileSet::INVALID_SOURCE) { + has_a_tile = true; + break; + } + } + + if (has_a_tile) { + // Process the quadrant. + + // First, clear the quadrant's canvas items. + for (RID &ci : rendering_quadrant->canvas_items) { + rs->free(ci); + } + rendering_quadrant->canvas_items.clear(); + + // Sort the quadrant cells. + if (tile_map_node->is_y_sort_enabled() && is_y_sort_enabled()) { + // For compatibility reasons, we use another comparator for Y-sorted layers. + rendering_quadrant->cells.sort_custom<CellDataYSortedComparator>(); + } else { + rendering_quadrant->cells.sort(); + } + + // Those allow to group cell per material or z-index. + Ref<Material> prev_material; + int prev_z_index = 0; + RID prev_ci; + + for (SelfList<CellData> *cell_data_quadrant_list_element = rendering_quadrant->cells.first(); cell_data_quadrant_list_element; cell_data_quadrant_list_element = cell_data_quadrant_list_element->next()) { + CellData &cell_data = *cell_data_quadrant_list_element->self(); + + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(*tile_set->get_source(cell_data.cell.source_id)); + + // Get the tile data. + const TileData *tile_data; + if (cell_data.runtime_tile_data_cache) { + tile_data = cell_data.runtime_tile_data_cache; + } else { + tile_data = atlas_source->get_tile_data(cell_data.cell.get_atlas_coords(), cell_data.cell.alternative_tile); + } + + Ref<Material> mat = tile_data->get_material(); + int tile_z_index = tile_data->get_z_index(); + + // Quandrant pos. + + // --- CanvasItems --- + RID ci; + + // Check if the material or the z_index changed. + if (prev_ci == RID() || prev_material != mat || prev_z_index != tile_z_index) { + // If so, create a new CanvasItem. + ci = rs->canvas_item_create(); + if (mat.is_valid()) { + rs->canvas_item_set_material(ci, mat->get_rid()); + } + rs->canvas_item_set_parent(ci, canvas_item); + rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid()); + + Transform2D xform(0, rendering_quadrant->canvas_items_position); + rs->canvas_item_set_transform(ci, xform); + + rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask()); + rs->canvas_item_set_z_as_relative_to_parent(ci, true); + rs->canvas_item_set_z_index(ci, tile_z_index); + + rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree())); + rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree())); + + rendering_quadrant->canvas_items.push_back(ci); + + prev_ci = ci; + prev_material = mat; + prev_z_index = tile_z_index; + + } else { + // Keep the same canvas_item to draw on. + ci = prev_ci; + } + + const Vector2 local_tile_pos = tile_map_node->map_to_local(cell_data.coords); + + // Random animation offset. + real_t random_animation_offset = 0.0; + if (atlas_source->get_tile_animation_mode(cell_data.cell.get_atlas_coords()) != TileSetAtlasSource::TILE_ANIMATION_MODE_DEFAULT) { + Array to_hash; + to_hash.push_back(local_tile_pos); + to_hash.push_back(get_instance_id()); // Use instance id as a random hash + random_animation_offset = RandomPCG(to_hash.hash()).randf(); + } + + // Drawing the tile in the canvas item. + tile_map_node->draw_tile(ci, local_tile_pos - rendering_quadrant->canvas_items_position, tile_set, cell_data.cell.source_id, cell_data.cell.get_atlas_coords(), cell_data.cell.alternative_tile, -1, tile_map_node->get_self_modulate(), tile_data, random_animation_offset); + } + } else { + // Free the quadrant. + for (int i = 0; i < rendering_quadrant->canvas_items.size(); i++) { + const RID &ci = rendering_quadrant->canvas_items[i]; + if (ci.is_valid()) { + rs->free(ci); + } + } + rendering_quadrant->cells.clear(); + rendering_quadrant_map.erase(rendering_quadrant->quadrant_coords); + } + + quadrant_list_element = next_quadrant_list_element; + } + + dirty_rendering_quadrant_list.clear(); + + // Reset the drawing indices. + { + int index = -(int64_t)0x80000000; // Always must be drawn below children. + + // Sort the quadrants coords per local coordinates. + RBMap<Vector2, Ref<RenderingQuadrant>, RenderingQuadrant::CoordsWorldComparator> local_to_map; + for (KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) { + Ref<RenderingQuadrant> &rendering_quadrant = kv.value; + local_to_map[tile_map_node->map_to_local(rendering_quadrant->quadrant_coords)] = rendering_quadrant; + } + + // Sort the quadrants. + for (const KeyValue<Vector2, Ref<RenderingQuadrant>> &E : local_to_map) { + for (const RID &ci : E.value->canvas_items) { + RS::get_singleton()->canvas_item_set_draw_index(ci, index++); + } + } + } + + // Updates on TileMap changes. + if (dirty.flags[DIRTY_FLAGS_TILE_MAP_LIGHT_MASK] || + dirty.flags[DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL] || + dirty.flags[DIRTY_FLAGS_TILE_MAP_MATERIAL] || + dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER] || + dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT]) { + for (KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) { + Ref<RenderingQuadrant> &rendering_quadrant = kv.value; + for (const RID &ci : rendering_quadrant->canvas_items) { + rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask()); + rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid()); + rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree())); + rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree())); + } + } + } + } + + // ----------- Occluders processing ----------- + if (forced_cleanup) { + // Clean everything. + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + _rendering_occluders_clear_cell(kv.value); + } + } else { + if (_rendering_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { + // Update all cells. + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + _rendering_occluders_update_cell(kv.value); + } + } else { + // Update dirty cells. + for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + _rendering_occluders_update_cell(cell_data); + } + } + + // Updates on TileMap changes. + if (dirty.flags[DIRTY_FLAGS_TILE_MAP_IN_CANVAS] || dirty.flags[DIRTY_FLAGS_TILE_MAP_VISIBILITY]) { + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + CellData &cell_data = kv.value; + for (const RID &occluder : cell_data.occluders) { + if (occluder.is_null()) { + continue; + } + Transform2D xform(0, tile_map_node->map_to_local(kv.key)); + rs->canvas_light_occluder_attach_to_canvas(occluder, tile_map_node->get_canvas()); + rs->canvas_light_occluder_set_transform(occluder, tile_map_node->get_global_transform() * xform); + } + } + } + } + + // ----------- + // Mark the rendering state as up to date. + _rendering_was_cleaned_up = forced_cleanup; +} + +void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfList<RenderingQuadrant>::List &r_dirty_rendering_quadrant_list) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + + // Check if the cell is valid and retrieve its y_sort_origin. + bool is_valid = false; + int tile_y_sort_origin = 0; + TileSetSource *source; + if (tile_set->has_source(r_cell_data.cell.source_id)) { + source = *tile_set->get_source(r_cell_data.cell.source_id); + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source && atlas_source->has_tile(r_cell_data.cell.get_atlas_coords()) && atlas_source->has_alternative_tile(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile)) { + is_valid = true; + const TileData *tile_data; + if (r_cell_data.runtime_tile_data_cache) { + tile_data = r_cell_data.runtime_tile_data_cache; + } else { + tile_data = atlas_source->get_tile_data(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile); + } + tile_y_sort_origin = tile_data->get_y_sort_origin(); + } + } + + if (is_valid) { + // Get the quadrant coords. + Vector2 canvas_items_position; + Vector2i quadrant_coords; + if (tile_map_node->is_y_sort_enabled() && is_y_sort_enabled()) { + canvas_items_position = Vector2(0, tile_map_node->map_to_local(r_cell_data.coords).y + tile_y_sort_origin + y_sort_origin); + quadrant_coords = canvas_items_position * 100; + } else { + int quad_size = tile_map_node->get_rendering_quadrant_size(); + const Vector2i &coords = r_cell_data.coords; + + // Rounding down, instead of simply rounding towards zero (truncating). + quadrant_coords = Vector2i( + coords.x > 0 ? coords.x / quad_size : (coords.x - (quad_size - 1)) / quad_size, + coords.y > 0 ? coords.y / quad_size : (coords.y - (quad_size - 1)) / quad_size); + canvas_items_position = tile_map_node->map_to_local(quad_size * quadrant_coords); + } + + Ref<RenderingQuadrant> rendering_quadrant; + if (rendering_quadrant_map.has(quadrant_coords)) { + // Reuse existing rendering quadrant. + rendering_quadrant = rendering_quadrant_map[quadrant_coords]; + } else { + // Create a new rendering quadrant. + rendering_quadrant.instantiate(); + rendering_quadrant->quadrant_coords = quadrant_coords; + rendering_quadrant->canvas_items_position = canvas_items_position; + rendering_quadrant_map[quadrant_coords] = rendering_quadrant; + } + + // Mark the old quadrant as dirty (if it exists). + if (r_cell_data.rendering_quadrant.is_valid()) { + if (!r_cell_data.rendering_quadrant->dirty_quadrant_list_element.in_list()) { + r_dirty_rendering_quadrant_list.add(&r_cell_data.rendering_quadrant->dirty_quadrant_list_element); + } + } + + // Remove the cell from that quadrant. + if (r_cell_data.rendering_quadrant_list_element.in_list()) { + r_cell_data.rendering_quadrant_list_element.remove_from_list(); + } + + // Add the cell to its new quadrant. + r_cell_data.rendering_quadrant = rendering_quadrant; + r_cell_data.rendering_quadrant->cells.add(&r_cell_data.rendering_quadrant_list_element); + + // Add the new quadrant to the dirty quadrant list. + if (!rendering_quadrant->dirty_quadrant_list_element.in_list()) { + r_dirty_rendering_quadrant_list.add(&rendering_quadrant->dirty_quadrant_list_element); + } + } else { + Ref<RenderingQuadrant> rendering_quadrant = r_cell_data.rendering_quadrant; + + // Remove the cell from its quadrant. + r_cell_data.rendering_quadrant = Ref<RenderingQuadrant>(); + if (r_cell_data.rendering_quadrant_list_element.in_list()) { + rendering_quadrant->cells.remove(&r_cell_data.rendering_quadrant_list_element); + } + + if (rendering_quadrant.is_valid()) { + // Add the quadrant to the dirty quadrant list. + if (!rendering_quadrant->dirty_quadrant_list_element.in_list()) { + r_dirty_rendering_quadrant_list.add(&rendering_quadrant->dirty_quadrant_list_element); + } + } + } +} + +void TileMapLayer::_rendering_occluders_clear_cell(CellData &r_cell_data) { + RenderingServer *rs = RenderingServer::get_singleton(); + + // Free the occluders. + for (const RID &rid : r_cell_data.occluders) { + rs->free(rid); + } + r_cell_data.occluders.clear(); +} + +void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) { + bool node_visible = tile_map_node->is_visible_in_tree(); + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + RenderingServer *rs = RenderingServer::get_singleton(); + + // Free unused occluders then resize the occluders array. + for (uint32_t i = tile_set->get_occlusion_layers_count(); i < r_cell_data.occluders.size(); i++) { + RID occluder_id = r_cell_data.occluders[i]; + if (occluder_id.is_valid()) { + rs->free(occluder_id); + } + } + r_cell_data.occluders.resize(tile_set->get_occlusion_layers_count()); + + TileSetSource *source; + if (tile_set->has_source(r_cell_data.cell.source_id)) { + source = *tile_set->get_source(r_cell_data.cell.source_id); + + if (source->has_tile(r_cell_data.cell.get_atlas_coords()) && source->has_alternative_tile(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile)) { + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + // Get the tile data. + const TileData *tile_data; + if (r_cell_data.runtime_tile_data_cache) { + tile_data = r_cell_data.runtime_tile_data_cache; + } else { + tile_data = atlas_source->get_tile_data(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile); + } + + // Transform flags. + bool flip_h = (r_cell_data.cell.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H); + bool flip_v = (r_cell_data.cell.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V); + bool transpose = (r_cell_data.cell.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); + + // Create, update or clear occluders. + for (uint32_t occlusion_layer_index = 0; occlusion_layer_index < r_cell_data.occluders.size(); occlusion_layer_index++) { + Ref<OccluderPolygon2D> occluder_polygon = tile_data->get_occluder(occlusion_layer_index); + + RID &occluder = r_cell_data.occluders[occlusion_layer_index]; + + if (occluder_polygon.is_valid()) { + // Create or update occluder. + Transform2D xform; + xform.set_origin(tile_map_node->map_to_local(r_cell_data.coords)); + if (!occluder.is_valid()) { + occluder = rs->canvas_light_occluder_create(); + } + rs->canvas_light_occluder_set_enabled(occluder, node_visible); + rs->canvas_light_occluder_set_transform(occluder, tile_map_node->get_global_transform() * xform); + rs->canvas_light_occluder_set_polygon(occluder, tile_data->get_occluder(occlusion_layer_index, flip_h, flip_v, transpose)->get_rid()); + rs->canvas_light_occluder_attach_to_canvas(occluder, tile_map_node->get_canvas()); + rs->canvas_light_occluder_set_light_mask(occluder, tile_set->get_occlusion_layer_light_mask(occlusion_layer_index)); + } else { + // Clear occluder. + if (occluder.is_valid()) { + rs->free(occluder); + occluder = RID(); + } + } + } + + return; + } + } + } + + // If we did not return earlier, clear the cell. + _rendering_occluders_clear_cell(r_cell_data); +} + +#ifdef DEBUG_ENABLED +void TileMapLayer::_rendering_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + ERR_FAIL_COND(!tile_set.is_valid()); + + if (!Engine::get_singleton()->is_editor_hint()) { + return; + } + + // Draw a placeholder for tiles needing one. + RenderingServer *rs = RenderingServer::get_singleton(); + const TileMapCell &c = r_cell_data.cell; + + TileSetSource *source; + if (tile_set->has_source(c.source_id)) { + source = *tile_set->get_source(c.source_id); + + if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + Vector2i grid_size = atlas_source->get_atlas_grid_size(); + if (!atlas_source->get_runtime_texture().is_valid() || c.get_atlas_coords().x >= grid_size.x || c.get_atlas_coords().y >= grid_size.y) { + // Generate a random color from the hashed values of the tiles. + Array to_hash; + to_hash.push_back(c.source_id); + to_hash.push_back(c.get_atlas_coords()); + to_hash.push_back(c.alternative_tile); + uint32_t hash = RandomPCG(to_hash.hash()).rand(); + + Color color; + color = color.from_hsv( + (float)((hash >> 24) & 0xFF) / 256.0, + Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0), + Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0), + 0.8); + + // Draw a placeholder tile. + Transform2D cell_to_quadrant; + cell_to_quadrant.set_origin(tile_map_node->map_to_local(r_cell_data.coords) - p_quadrant_pos); + rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant); + rs->canvas_item_add_circle(p_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color); + } + } + } + } +} +#endif // DEBUG_ENABLED + +/////////////////////////////// Physics ////////////////////////////////////// + +void TileMapLayer::_physics_update() { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + + // Check if we should cleanup everything. + bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid(); + if (forced_cleanup) { + // Clean everything. + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + _physics_clear_cell(kv.value); + } + } else { + if (_physics_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || dirty.flags[DIRTY_FLAGS_TILE_MAP_COLLISION_ANIMATABLE]) { + // Update all cells. + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + _physics_update_cell(kv.value); + } + } else { + // Update dirty cells. + for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + _physics_update_cell(cell_data); + } + } + } + + // ----------- + // Mark the physics state as up to date. + _physics_was_cleaned_up = forced_cleanup; +} + +void TileMapLayer::_physics_notify_tilemap_change(TileMapLayer::DirtyFlags p_what) { + Transform2D gl_transform = tile_map_node->get_global_transform(); + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); + + bool in_editor = false; +#ifdef TOOLS_ENABLED + in_editor = Engine::get_singleton()->is_editor_hint(); +#endif + + if (p_what == DIRTY_FLAGS_TILE_MAP_XFORM) { + if (tile_map_node->is_inside_tree() && (!tile_map_node->is_collision_animatable() || in_editor)) { + // Move the collisison shapes along with the TileMap. + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + const CellData &cell_data = kv.value; + + for (RID body : cell_data.bodies) { + if (body.is_valid()) { + Transform2D xform(0, tile_map_node->map_to_local(bodies_coords[body])); + xform = gl_transform * xform; + ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); + } + } + } + } + } else if (p_what == DIRTY_FLAGS_TILE_MAP_LOCAL_XFORM) { + // With collisions animatable, move the collisison shapes along with the TileMap only on local xform change (they are synchornized on physics tick instead). + if (tile_map_node->is_inside_tree() && tile_map_node->is_collision_animatable() && !in_editor) { + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + const CellData &cell_data = kv.value; + + for (RID body : cell_data.bodies) { + if (body.is_valid()) { + Transform2D xform(0, tile_map_node->map_to_local(bodies_coords[body])); + xform = gl_transform * xform; + ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); + } + } + } + } + } else if (p_what == DIRTY_FLAGS_TILE_MAP_IN_TREE) { + // Changes in the tree may cause the space to change (e.g. when reparenting to a SubViewport). + if (tile_map_node->is_inside_tree()) { + RID space = tile_map_node->get_world_2d()->get_space(); + + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + const CellData &cell_data = kv.value; + + for (RID body : cell_data.bodies) { + if (body.is_valid()) { + ps->body_set_space(body, space); + } + } + } + } + } +} + +void TileMapLayer::_physics_clear_cell(CellData &r_cell_data) { + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); + + // Clear bodies. + for (RID body : r_cell_data.bodies) { + if (body.is_valid()) { + bodies_coords.erase(body); + ps->free(body); + } + } + r_cell_data.bodies.clear(); +} + +void TileMapLayer::_physics_update_cell(CellData &r_cell_data) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + Transform2D gl_transform = tile_map_node->get_global_transform(); + RID space = tile_map_node->get_world_2d()->get_space(); + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); + + // Recreate bodies and shapes. + TileMapCell &c = r_cell_data.cell; + + TileSetSource *source; + if (tile_set->has_source(c.source_id)) { + source = *tile_set->get_source(c.source_id); + + if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + const TileData *tile_data; + if (r_cell_data.runtime_tile_data_cache) { + tile_data = r_cell_data.runtime_tile_data_cache; + } else { + tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); + } + + // Transform flags. + bool flip_h = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H); + bool flip_v = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V); + bool transpose = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); + + // Free unused bodies then resize the bodies array. + for (uint32_t i = tile_set->get_physics_layers_count(); i < r_cell_data.bodies.size(); i++) { + RID body = r_cell_data.bodies[i]; + if (body.is_valid()) { + bodies_coords.erase(body); + ps->free(body); + } + } + r_cell_data.bodies.resize(tile_set->get_physics_layers_count()); + + for (uint32_t tile_set_physics_layer = 0; tile_set_physics_layer < (uint32_t)tile_set->get_physics_layers_count(); tile_set_physics_layer++) { + Ref<PhysicsMaterial> physics_material = tile_set->get_physics_layer_physics_material(tile_set_physics_layer); + uint32_t physics_layer = tile_set->get_physics_layer_collision_layer(tile_set_physics_layer); + uint32_t physics_mask = tile_set->get_physics_layer_collision_mask(tile_set_physics_layer); + + RID body = r_cell_data.bodies[tile_set_physics_layer]; + if (tile_data->get_collision_polygons_count(tile_set_physics_layer) == 0) { + // No body needed, free it if it exists. + if (body.is_valid()) { + bodies_coords.erase(body); + ps->free(body); + } + body = RID(); + } else { + // Create or update the body. + if (!body.is_valid()) { + body = ps->body_create(); + } + bodies_coords[body] = r_cell_data.coords; + ps->body_set_mode(body, tile_map_node->is_collision_animatable() ? PhysicsServer2D::BODY_MODE_KINEMATIC : PhysicsServer2D::BODY_MODE_STATIC); + ps->body_set_space(body, space); + + Transform2D xform; + xform.set_origin(tile_map_node->map_to_local(r_cell_data.coords)); + xform = gl_transform * xform; + ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); + + ps->body_attach_object_instance_id(body, tile_map_node->get_instance_id()); + ps->body_set_collision_layer(body, physics_layer); + ps->body_set_collision_mask(body, physics_mask); + ps->body_set_pickable(body, false); + ps->body_set_state(body, PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, tile_data->get_constant_linear_velocity(tile_set_physics_layer)); + ps->body_set_state(body, PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, tile_data->get_constant_angular_velocity(tile_set_physics_layer)); + + if (!physics_material.is_valid()) { + ps->body_set_param(body, PhysicsServer2D::BODY_PARAM_BOUNCE, 0); + ps->body_set_param(body, PhysicsServer2D::BODY_PARAM_FRICTION, 1); + } else { + ps->body_set_param(body, PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material->computed_bounce()); + ps->body_set_param(body, PhysicsServer2D::BODY_PARAM_FRICTION, physics_material->computed_friction()); + } + + // Clear body's shape if needed. + ps->body_clear_shapes(body); + + // Add the shapes to the body. + int body_shape_index = 0; + for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(tile_set_physics_layer); polygon_index++) { + // Iterate over the polygons. + bool one_way_collision = tile_data->is_collision_polygon_one_way(tile_set_physics_layer, polygon_index); + float one_way_collision_margin = tile_data->get_collision_polygon_one_way_margin(tile_set_physics_layer, polygon_index); + int shapes_count = tile_data->get_collision_polygon_shapes_count(tile_set_physics_layer, polygon_index); + for (int shape_index = 0; shape_index < shapes_count; shape_index++) { + // Add decomposed convex shapes. + Ref<ConvexPolygonShape2D> shape = tile_data->get_collision_polygon_shape(tile_set_physics_layer, polygon_index, shape_index, flip_h, flip_v, transpose); + ps->body_add_shape(body, shape->get_rid()); + ps->body_set_shape_as_one_way_collision(body, body_shape_index, one_way_collision, one_way_collision_margin); + + body_shape_index++; + } + } + } + + // Set the body again. + r_cell_data.bodies[tile_set_physics_layer] = body; + } + + return; + } + } + } + + // If we did not return earlier, clear the cell. + _physics_clear_cell(r_cell_data); +} + +#ifdef DEBUG_ENABLED +void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data) { + // Draw the debug collision shapes. + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + ERR_FAIL_COND(!tile_set.is_valid()); + + if (!tile_map_node->get_tree()) { + return; + } + + bool show_collision = false; + switch (tile_map_node->get_collision_visibility_mode()) { + case TileMap::VISIBILITY_MODE_DEFAULT: + show_collision = !Engine::get_singleton()->is_editor_hint() && tile_map_node->get_tree()->is_debugging_collisions_hint(); + break; + case TileMap::VISIBILITY_MODE_FORCE_HIDE: + show_collision = false; + break; + case TileMap::VISIBILITY_MODE_FORCE_SHOW: + show_collision = true; + break; + } + if (!show_collision) { + return; + } + + RenderingServer *rs = RenderingServer::get_singleton(); + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); + + Color debug_collision_color = tile_map_node->get_tree()->get_debug_collisions_color(); + Vector<Color> color; + color.push_back(debug_collision_color); + + Transform2D quadrant_to_local(0, p_quadrant_pos); + Transform2D global_to_quadrant = (tile_map_node->get_global_transform() * quadrant_to_local).affine_inverse(); + + for (RID body : r_cell_data.bodies) { + if (body.is_valid()) { + Transform2D body_to_quadrant = global_to_quadrant * Transform2D(ps->body_get_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM)); + rs->canvas_item_add_set_transform(p_canvas_item, body_to_quadrant); + for (int shape_index = 0; shape_index < ps->body_get_shape_count(body); shape_index++) { + const RID &shape = ps->body_get_shape(body, shape_index); + const PhysicsServer2D::ShapeType &type = ps->shape_get_type(shape); + if (type == PhysicsServer2D::SHAPE_CONVEX_POLYGON) { + rs->canvas_item_add_polygon(p_canvas_item, ps->shape_get_data(shape), color); + } else { + WARN_PRINT("Wrong shape type for a tile, should be SHAPE_CONVEX_POLYGON."); + } + } + rs->canvas_item_add_set_transform(p_canvas_item, Transform2D()); + } + } +}; +#endif // DEBUG_ENABLED + +/////////////////////////////// Navigation ////////////////////////////////////// + +void TileMapLayer::_navigation_update() { + ERR_FAIL_NULL(NavigationServer2D::get_singleton()); + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + NavigationServer2D *ns = NavigationServer2D::get_singleton(); + + // Check if we should cleanup everything. + bool forced_cleanup = in_destructor || !enabled || !navigation_enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid(); + + // ----------- Layer level processing ----------- + if (forced_cleanup) { + if (navigation_map.is_valid() && !uses_world_navigation_map) { + ns->free(navigation_map); + navigation_map = RID(); + } + } else { + // Update navigation maps. + if (!navigation_map.is_valid()) { + if (layer_index_in_tile_map_node == 0) { + // Use the default World2D navigation map for the first layer when empty. + navigation_map = tile_map_node->get_world_2d()->get_navigation_map(); + uses_world_navigation_map = true; + } else { + RID new_layer_map = ns->map_create(); + // Set the default NavigationPolygon cell_size on the new map as a mismatch causes an error. + ns->map_set_cell_size(new_layer_map, 1.0); + ns->map_set_active(new_layer_map, true); + navigation_map = new_layer_map; + uses_world_navigation_map = false; + } + } + } + + // ----------- Navigation regions processing ----------- + if (forced_cleanup) { + // Clean everything. + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + _navigation_clear_cell(kv.value); + } + } else { + if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { + // Update all cells. + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + _navigation_update_cell(kv.value); + } + } else { + // Update dirty cells. + for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + _navigation_update_cell(cell_data); + } + } + + if (dirty.flags[DIRTY_FLAGS_TILE_MAP_XFORM]) { + Transform2D tilemap_xform = tile_map_node->get_global_transform(); + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + const CellData &cell_data = kv.value; + // Update navigation regions transform. + for (const RID ®ion : cell_data.navigation_regions) { + if (!region.is_valid()) { + continue; + } + Transform2D tile_transform; + tile_transform.set_origin(tile_map_node->map_to_local(kv.key)); + NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform); + } + } + } + } + + // ----------- + // Mark the navigation state as up to date. + _navigation_was_cleaned_up = forced_cleanup; +} + +void TileMapLayer::_navigation_clear_cell(CellData &r_cell_data) { + NavigationServer2D *ns = NavigationServer2D::get_singleton(); + // Clear navigation shapes. + for (uint32_t i = 0; i < r_cell_data.navigation_regions.size(); i++) { + const RID ®ion = r_cell_data.navigation_regions[i]; + if (region.is_valid()) { + ns->region_set_map(region, RID()); + ns->free(region); + } + } + r_cell_data.navigation_regions.clear(); +} + +void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + NavigationServer2D *ns = NavigationServer2D::get_singleton(); + Transform2D tilemap_xform = tile_map_node->get_global_transform(); + + // Get the navigation polygons and create regions. + TileMapCell &c = r_cell_data.cell; + + TileSetSource *source; + if (tile_set->has_source(c.source_id)) { + source = *tile_set->get_source(c.source_id); + + if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + const TileData *tile_data; + if (r_cell_data.runtime_tile_data_cache) { + tile_data = r_cell_data.runtime_tile_data_cache; + } else { + tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); + } + + // Transform flags. + bool flip_h = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H); + bool flip_v = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V); + bool transpose = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); + + // Free unused regions then resize the regions array. + for (uint32_t i = tile_set->get_navigation_layers_count(); i < r_cell_data.navigation_regions.size(); i++) { + RID ®ion = r_cell_data.navigation_regions[i]; + if (region.is_valid()) { + ns->region_set_map(region, RID()); + ns->free(region); + region = RID(); + } + } + r_cell_data.navigation_regions.resize(tile_set->get_navigation_layers_count()); + + // Create, update or clear regions. + for (uint32_t navigation_layer_index = 0; navigation_layer_index < r_cell_data.navigation_regions.size(); navigation_layer_index++) { + Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer_index, flip_h, flip_v, transpose); + + RID ®ion = r_cell_data.navigation_regions[navigation_layer_index]; + + if (navigation_polygon.is_valid() && (navigation_polygon->get_polygon_count() > 0 || navigation_polygon->get_outline_count() > 0)) { + // Create or update regions. + Transform2D tile_transform; + tile_transform.set_origin(tile_map_node->map_to_local(r_cell_data.coords)); + if (!region.is_valid()) { + region = ns->region_create(); + } + ns->region_set_owner_id(region, tile_map_node->get_instance_id()); + ns->region_set_map(region, navigation_map); + ns->region_set_transform(region, tilemap_xform * tile_transform); + ns->region_set_navigation_layers(region, tile_set->get_navigation_layer_layers(navigation_layer_index)); + ns->region_set_navigation_polygon(region, navigation_polygon); + } else { + // Clear region. + if (region.is_valid()) { + ns->region_set_map(region, RID()); + ns->free(region); + region = RID(); + } + } + } + + return; + } + } + } + + // If we did not return earlier, clear the cell. + _navigation_clear_cell(r_cell_data); +} + +#ifdef DEBUG_ENABLED +void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data) { + // Draw the debug collision shapes. + bool show_navigation = false; + switch (tile_map_node->get_navigation_visibility_mode()) { + case TileMap::VISIBILITY_MODE_DEFAULT: + show_navigation = !Engine::get_singleton()->is_editor_hint() && tile_map_node->get_tree()->is_debugging_navigation_hint(); + break; + case TileMap::VISIBILITY_MODE_FORCE_HIDE: + show_navigation = false; + break; + case TileMap::VISIBILITY_MODE_FORCE_SHOW: + show_navigation = true; + break; + } + if (!show_navigation) { + return; + } + + // Check if the navigation is used. + if (r_cell_data.navigation_regions.is_empty()) { + return; + } + + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + + RenderingServer *rs = RenderingServer::get_singleton(); + const NavigationServer2D *ns2d = NavigationServer2D::get_singleton(); + + bool enabled_geometry_face_random_color = ns2d->get_debug_navigation_enable_geometry_face_random_color(); + bool enabled_edge_lines = ns2d->get_debug_navigation_enable_edge_lines(); + + Color debug_face_color = ns2d->get_debug_navigation_geometry_face_color(); + Color debug_edge_color = ns2d->get_debug_navigation_geometry_edge_color(); + + RandomPCG rand; + + const TileMapCell &c = r_cell_data.cell; + + TileSetSource *source; + if (tile_set->has_source(c.source_id)) { + source = *tile_set->get_source(c.source_id); + + if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + const TileData *tile_data; + if (r_cell_data.runtime_tile_data_cache) { + tile_data = r_cell_data.runtime_tile_data_cache; + } else { + tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); + } + + Transform2D cell_to_quadrant; + cell_to_quadrant.set_origin(tile_map_node->map_to_local(r_cell_data.coords) - p_quadrant_pos); + rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant); + + for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) { + bool flip_h = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H); + bool flip_v = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V); + bool transpose = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); + Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(layer_index, flip_h, flip_v, transpose); + if (navigation_polygon.is_valid()) { + Vector<Vector2> navigation_polygon_vertices = navigation_polygon->get_vertices(); + if (navigation_polygon_vertices.size() < 3) { + continue; + } + + for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) { + // An array of vertices for this polygon. + Vector<int> polygon = navigation_polygon->get_polygon(i); + Vector<Vector2> debug_polygon_vertices; + debug_polygon_vertices.resize(polygon.size()); + for (int j = 0; j < polygon.size(); j++) { + ERR_FAIL_INDEX(polygon[j], navigation_polygon_vertices.size()); + debug_polygon_vertices.write[j] = navigation_polygon_vertices[polygon[j]]; + } + + // Generate the polygon color, slightly randomly modified from the settings one. + Color random_variation_color = debug_face_color; + if (enabled_geometry_face_random_color) { + random_variation_color.set_hsv( + debug_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1, + debug_face_color.get_s(), + debug_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2); + } + random_variation_color.a = debug_face_color.a; + + Vector<Color> debug_face_colors; + debug_face_colors.push_back(random_variation_color); + rs->canvas_item_add_polygon(p_canvas_item, debug_polygon_vertices, debug_face_colors); + + if (enabled_edge_lines) { + Vector<Color> debug_edge_colors; + debug_edge_colors.push_back(debug_edge_color); + debug_polygon_vertices.push_back(debug_polygon_vertices[0]); // Add first again for closing polyline. + rs->canvas_item_add_polyline(p_canvas_item, debug_polygon_vertices, debug_edge_colors); + } + } + } + } + } + } + } +} +#endif // DEBUG_ENABLED + +/////////////////////////////// Scenes ////////////////////////////////////// + +void TileMapLayer::_scenes_update() { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + + // Check if we should cleanup everything. + bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid(); + + if (forced_cleanup) { + // Clean everything. + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + _scenes_clear_cell(kv.value); + } + } else { + if (_scenes_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { + // Update all cells. + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + _scenes_update_cell(kv.value); + } + } else { + // Update dirty cells. + for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + _scenes_update_cell(cell_data); + } + } + } + + // ----------- + // Mark the scenes state as up to date. + _scenes_was_cleaned_up = forced_cleanup; +} + +void TileMapLayer::_scenes_clear_cell(CellData &r_cell_data) { + // Cleanup existing scene. + Node *node = tile_map_node->get_node_or_null(r_cell_data.scene); + if (node) { + node->queue_free(); + } + r_cell_data.scene = ""; +} + +void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + + // Clear the scene in any case. + _scenes_clear_cell(r_cell_data); + + // Create the scene. + const TileMapCell &c = r_cell_data.cell; + + TileSetSource *source; + if (tile_set->has_source(c.source_id)) { + source = *tile_set->get_source(c.source_id); + + if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { + TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source); + if (scenes_collection_source) { + Ref<PackedScene> packed_scene = scenes_collection_source->get_scene_tile_scene(c.alternative_tile); + if (packed_scene.is_valid()) { + Node *scene = packed_scene->instantiate(); + Control *scene_as_control = Object::cast_to<Control>(scene); + Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene); + if (scene_as_control) { + scene_as_control->set_position(tile_map_node->map_to_local(r_cell_data.coords) + scene_as_control->get_position()); + } else if (scene_as_node2d) { + Transform2D xform; + xform.set_origin(tile_map_node->map_to_local(r_cell_data.coords)); + scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform()); + } + tile_map_node->add_child(scene); + r_cell_data.scene = scene->get_name(); + } + } + } + } +} + +#ifdef DEBUG_ENABLED +void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + ERR_FAIL_COND(!tile_set.is_valid()); + + if (!Engine::get_singleton()->is_editor_hint()) { + return; + } + + // Draw a placeholder for scenes needing one. + RenderingServer *rs = RenderingServer::get_singleton(); + + const TileMapCell &c = r_cell_data.cell; + + TileSetSource *source; + if (tile_set->has_source(c.source_id)) { + source = *tile_set->get_source(c.source_id); + + if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { + return; + } + + TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source); + if (scenes_collection_source) { + if (!scenes_collection_source->get_scene_tile_scene(c.alternative_tile).is_valid() || scenes_collection_source->get_scene_tile_display_placeholder(c.alternative_tile)) { + // Generate a random color from the hashed values of the tiles. + Array to_hash; + to_hash.push_back(c.source_id); + to_hash.push_back(c.alternative_tile); + uint32_t hash = RandomPCG(to_hash.hash()).rand(); + + Color color; + color = color.from_hsv( + (float)((hash >> 24) & 0xFF) / 256.0, + Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0), + Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0), + 0.8); + + // Draw a placeholder tile. + Transform2D cell_to_quadrant; + cell_to_quadrant.set_origin(tile_map_node->map_to_local(r_cell_data.coords) - p_quadrant_pos); + rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant); + rs->canvas_item_add_circle(p_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color); + } + } + } +} +#endif // DEBUG_ENABLED + +///////////////////////////////////////////////////////////////////// + +void TileMapLayer::_build_runtime_update_tile_data() { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + + // Check if we should cleanup everything. + bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree(); + if (!forced_cleanup) { + if (tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update)) { + if (_runtime_update_tile_data_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { + for (KeyValue<Vector2i, CellData> &E : tile_map) { + _build_runtime_update_tile_data_for_cell(E.value); + } + } else if (dirty.flags[DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE]) { + for (KeyValue<Vector2i, CellData> &E : tile_map) { + _build_runtime_update_tile_data_for_cell(E.value, true); + } + } else { + for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + _build_runtime_update_tile_data_for_cell(cell_data); + } + } + } + } + + // ----------- + // Mark the navigation state as up to date. + _runtime_update_tile_data_was_cleaned_up = forced_cleanup; +} + +void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_auto_add_to_dirty_list) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + + TileMapCell &c = r_cell_data.cell; + TileSetSource *source; + if (tile_set->has_source(c.source_id)) { + source = *tile_set->get_source(c.source_id); + + if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + bool ret = false; + if (tile_map_node->GDVIRTUAL_CALL(_use_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, ret) && ret) { + TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); + + // Create the runtime TileData. + TileData *tile_data_runtime_use = tile_data->duplicate(); + tile_data_runtime_use->set_allow_transform(true); + r_cell_data.runtime_tile_data_cache = tile_data_runtime_use; + + tile_map_node->GDVIRTUAL_CALL(_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, tile_data_runtime_use); + + if (p_auto_add_to_dirty_list) { + dirty.cell_list.add(&r_cell_data.dirty_list_element); + } + } + } + } + } +} + +void TileMapLayer::_clear_runtime_update_tile_data() { + for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + + // Clear the runtime tile data. + if (cell_data.runtime_tile_data_cache) { + memdelete(cell_data.runtime_tile_data_cache); + cell_data.runtime_tile_data_cache = nullptr; + } + } +} + +TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + if (!tile_set.is_valid()) { + return TileSet::TerrainsPattern(); + } + // Returns all tiles compatible with the given constraints. + RBMap<TileSet::TerrainsPattern, int> terrain_pattern_score; + RBSet<TileSet::TerrainsPattern> pattern_set = tile_set->get_terrains_pattern_set(p_terrain_set); + ERR_FAIL_COND_V(pattern_set.is_empty(), TileSet::TerrainsPattern()); + for (TileSet::TerrainsPattern &terrain_pattern : pattern_set) { + int score = 0; + + // Check the center bit constraint. + TerrainConstraint terrain_constraint = TerrainConstraint(tile_map_node, p_position, terrain_pattern.get_terrain()); + const RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_constraint); + if (in_set_constraint_element) { + if (in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) { + score += in_set_constraint_element->get().get_priority(); + } + } else if (p_current_pattern.get_terrain() != terrain_pattern.get_terrain()) { + continue; // Ignore a pattern that cannot keep bits without constraints unmodified. + } + + // Check the surrounding bits + bool invalid_pattern = false; + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { + // Check if the bit is compatible with the constraints. + TerrainConstraint terrain_bit_constraint = TerrainConstraint(tile_map_node, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit)); + in_set_constraint_element = p_constraints.find(terrain_bit_constraint); + if (in_set_constraint_element) { + if (in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) { + score += in_set_constraint_element->get().get_priority(); + } + } else if (p_current_pattern.get_terrain_peering_bit(bit) != terrain_pattern.get_terrain_peering_bit(bit)) { + invalid_pattern = true; // Ignore a pattern that cannot keep bits without constraints unmodified. + break; + } + } + } + if (invalid_pattern) { + continue; + } + + terrain_pattern_score[terrain_pattern] = score; + } + + // Compute the minimum score. + TileSet::TerrainsPattern min_score_pattern = p_current_pattern; + int min_score = INT32_MAX; + for (KeyValue<TileSet::TerrainsPattern, int> E : terrain_pattern_score) { + if (E.value < min_score) { + min_score_pattern = E.key; + min_score = E.value; + } + } + + return min_score_pattern; +} + +RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + if (!tile_set.is_valid()) { + return RBSet<TerrainConstraint>(); + } + + // Compute the constraints needed from the surrounding tiles. + RBSet<TerrainConstraint> output; + output.insert(TerrainConstraint(tile_map_node, p_position, p_terrains_pattern.get_terrain())); + + for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor side = TileSet::CellNeighbor(i); + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, side)) { + TerrainConstraint c = TerrainConstraint(tile_map_node, p_position, side, p_terrains_pattern.get_terrain_peering_bit(side)); + output.insert(c); + } + } + + return output; +} + +RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + if (!tile_set.is_valid()) { + return RBSet<TerrainConstraint>(); + } + + ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), RBSet<TerrainConstraint>()); + + // Build a set of dummy constraints to get the constrained points. + RBSet<TerrainConstraint> dummy_constraints; + for (const Vector2i &E : p_painted) { + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over neighbor bits. + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { + dummy_constraints.insert(TerrainConstraint(tile_map_node, E, bit, -1)); + } + } + } + + // For each constrained point, we get all overlapping tiles, and select the most adequate terrain for it. + RBSet<TerrainConstraint> constraints; + for (const TerrainConstraint &E_constraint : dummy_constraints) { + HashMap<int, int> terrain_count; + + // Count the number of occurrences per terrain. + HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = E_constraint.get_overlapping_coords_and_peering_bits(); + for (const KeyValue<Vector2i, TileSet::CellNeighbor> &E_overlapping : overlapping_terrain_bits) { + TileData *neighbor_tile_data = nullptr; + TileMapCell neighbor_cell = get_cell(E_overlapping.key); + if (neighbor_cell.source_id != TileSet::INVALID_SOURCE) { + Ref<TileSetSource> source = tile_set->get_source(neighbor_cell.source_id); + Ref<TileSetAtlasSource> atlas_source = source; + if (atlas_source.is_valid()) { + TileData *tile_data = atlas_source->get_tile_data(neighbor_cell.get_atlas_coords(), neighbor_cell.alternative_tile); + if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { + neighbor_tile_data = tile_data; + } + } + } + + int terrain = neighbor_tile_data ? neighbor_tile_data->get_terrain_peering_bit(TileSet::CellNeighbor(E_overlapping.value)) : -1; + if (!p_ignore_empty_terrains || terrain >= 0) { + if (!terrain_count.has(terrain)) { + terrain_count[terrain] = 0; + } + terrain_count[terrain] += 1; + } + } + + // Get the terrain with the max number of occurrences. + int max = 0; + int max_terrain = -1; + for (const KeyValue<int, int> &E_terrain_count : terrain_count) { + if (E_terrain_count.value > max) { + max = E_terrain_count.value; + max_terrain = E_terrain_count.key; + } + } + + // Set the adequate terrain. + if (max > 0) { + TerrainConstraint c = E_constraint; + c.set_terrain(max_terrain); + constraints.insert(c); + } + } + + // Add the centers as constraints. + for (Vector2i E_coords : p_painted) { + TileData *tile_data = nullptr; + TileMapCell cell = get_cell(E_coords); + if (cell.source_id != TileSet::INVALID_SOURCE) { + Ref<TileSetSource> source = tile_set->get_source(cell.source_id); + Ref<TileSetAtlasSource> atlas_source = source; + if (atlas_source.is_valid()) { + tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); + } + } + + int terrain = (tile_data && tile_data->get_terrain_set() == p_terrain_set) ? tile_data->get_terrain() : -1; + if (!p_ignore_empty_terrains || terrain >= 0) { + constraints.insert(TerrainConstraint(tile_map_node, E_coords, terrain)); + } + } + + return constraints; +} + +void TileMapLayer::set_tile_map(TileMap *p_tile_map) { + tile_map_node = p_tile_map; +} + +void TileMapLayer::set_layer_index_in_tile_map_node(int p_index) { + if (p_index == layer_index_in_tile_map_node) { + return; + } + layer_index_in_tile_map_node = p_index; + dirty.flags[DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE] = true; + tile_map_node->queue_internal_update(); +} + +Rect2 TileMapLayer::get_rect(bool &r_changed) const { + // Compute the displayed area of the tilemap. + r_changed = false; +#ifdef DEBUG_ENABLED + + if (rect_cache_dirty) { + Rect2 r_total; + bool first = true; + for (const KeyValue<Vector2i, CellData> &E : tile_map) { + Rect2 r; + r.position = tile_map_node->map_to_local(E.key); + r.size = Size2(); + if (first) { + r_total = r; + first = false; + } else { + r_total = r_total.merge(r); + } + } + + r_changed = rect_cache != r_total; + + rect_cache = r_total; + rect_cache_dirty = false; + } +#endif + return rect_cache; +} + +HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + if (!tile_set.is_valid()) { + return HashMap<Vector2i, TileSet::TerrainsPattern>(); + } + + // Copy the constraints set. + RBSet<TerrainConstraint> constraints = p_constraints; + + // Output map. + HashMap<Vector2i, TileSet::TerrainsPattern> output; + + // Add all positions to a set. + for (int i = 0; i < p_to_replace.size(); i++) { + const Vector2i &coords = p_to_replace[i]; + + // Select the best pattern for the given constraints. + TileSet::TerrainsPattern current_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set); + TileMapCell cell = get_cell(coords); + if (cell.source_id != TileSet::INVALID_SOURCE) { + TileSetSource *source = *tile_set->get_source(cell.source_id); + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + // Get tile data. + TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); + if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { + current_pattern = tile_data->get_terrains_pattern(); + } + } + } + TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints, current_pattern); + + // Update the constraint set with the new ones. + RBSet<TerrainConstraint> new_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, pattern); + for (const TerrainConstraint &E_constraint : new_constraints) { + if (constraints.has(E_constraint)) { + constraints.erase(E_constraint); + } + TerrainConstraint c = E_constraint; + c.set_priority(5); + constraints.insert(c); + } + + output[coords] = pattern; + } + return output; +} + +HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { + HashMap<Vector2i, TileSet::TerrainsPattern> output; + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + ERR_FAIL_COND_V(!tile_set.is_valid(), output); + ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); + + // Build list and set of tiles that can be modified (painted and their surroundings). + Vector<Vector2i> can_modify_list; + RBSet<Vector2i> can_modify_set; + RBSet<Vector2i> painted_set; + for (int i = p_coords_array.size() - 1; i >= 0; i--) { + const Vector2i &coords = p_coords_array[i]; + can_modify_list.push_back(coords); + can_modify_set.insert(coords); + painted_set.insert(coords); + } + for (Vector2i coords : p_coords_array) { + // Find the adequate neighbor. + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + if (tile_map_node->is_existing_neighbor(bit)) { + Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit); + if (!can_modify_set.has(neighbor)) { + can_modify_list.push_back(neighbor); + can_modify_set.insert(neighbor); + } + } + } + } + + // Build a set, out of the possibly modified tiles, of the one with a center bit that is set (or will be) to the painted terrain. + RBSet<Vector2i> cells_with_terrain_center_bit; + for (Vector2i coords : can_modify_set) { + bool connect = false; + if (painted_set.has(coords)) { + connect = true; + } else { + // Get the center bit of the cell. + TileData *tile_data = nullptr; + TileMapCell cell = get_cell(coords); + if (cell.source_id != TileSet::INVALID_SOURCE) { + Ref<TileSetSource> source = tile_set->get_source(cell.source_id); + Ref<TileSetAtlasSource> atlas_source = source; + if (atlas_source.is_valid()) { + tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); + } + } + + if (tile_data && tile_data->get_terrain_set() == p_terrain_set && tile_data->get_terrain() == p_terrain) { + connect = true; + } + } + if (connect) { + cells_with_terrain_center_bit.insert(coords); + } + } + + RBSet<TerrainConstraint> constraints; + + // Add new constraints from the path drawn. + for (Vector2i coords : p_coords_array) { + // Constraints on the center bit. + TerrainConstraint c = TerrainConstraint(tile_map_node, coords, p_terrain); + c.set_priority(10); + constraints.insert(c); + + // Constraints on the connecting bits. + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { + c = TerrainConstraint(tile_map_node, coords, bit, p_terrain); + c.set_priority(10); + if ((int(bit) % 2) == 0) { + // Side peering bits: add the constraint if the center is of the same terrain. + Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit); + if (cells_with_terrain_center_bit.has(neighbor)) { + constraints.insert(c); + } + } else { + // Corner peering bits: add the constraint if all tiles on the constraint has the same center bit. + HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = c.get_overlapping_coords_and_peering_bits(); + bool valid = true; + for (KeyValue<Vector2i, TileSet::CellNeighbor> kv : overlapping_terrain_bits) { + if (!cells_with_terrain_center_bit.has(kv.key)) { + valid = false; + break; + } + } + if (valid) { + constraints.insert(c); + } + } + } + } + } + + // Fills in the constraint list from existing tiles. + for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(painted_set, p_terrain_set, p_ignore_empty_terrains)) { + constraints.insert(c); + } + + // Fill the terrains. + output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints); + return output; +} + +HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { + HashMap<Vector2i, TileSet::TerrainsPattern> output; + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + ERR_FAIL_COND_V(!tile_set.is_valid(), output); + ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); + + // Make sure the path is correct and build the peering bit list while doing it. + Vector<TileSet::CellNeighbor> neighbor_list; + for (int i = 0; i < p_coords_array.size() - 1; i++) { + // Find the adequate neighbor. + TileSet::CellNeighbor found_bit = TileSet::CELL_NEIGHBOR_MAX; + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + if (tile_map_node->is_existing_neighbor(bit)) { + if (tile_map_node->get_neighbor_cell(p_coords_array[i], bit) == p_coords_array[i + 1]) { + found_bit = bit; + break; + } + } + } + ERR_FAIL_COND_V_MSG(found_bit == TileSet::CELL_NEIGHBOR_MAX, output, vformat("Invalid terrain path, %s is not a neighboring tile of %s", p_coords_array[i + 1], p_coords_array[i])); + neighbor_list.push_back(found_bit); + } + + // Build list and set of tiles that can be modified (painted and their surroundings). + Vector<Vector2i> can_modify_list; + RBSet<Vector2i> can_modify_set; + RBSet<Vector2i> painted_set; + for (int i = p_coords_array.size() - 1; i >= 0; i--) { + const Vector2i &coords = p_coords_array[i]; + can_modify_list.push_back(coords); + can_modify_set.insert(coords); + painted_set.insert(coords); + } + for (Vector2i coords : p_coords_array) { + // Find the adequate neighbor. + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { + Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit); + if (!can_modify_set.has(neighbor)) { + can_modify_list.push_back(neighbor); + can_modify_set.insert(neighbor); + } + } + } + } + + RBSet<TerrainConstraint> constraints; + + // Add new constraints from the path drawn. + for (Vector2i coords : p_coords_array) { + // Constraints on the center bit. + TerrainConstraint c = TerrainConstraint(tile_map_node, coords, p_terrain); + c.set_priority(10); + constraints.insert(c); + } + for (int i = 0; i < p_coords_array.size() - 1; i++) { + // Constraints on the peering bits. + TerrainConstraint c = TerrainConstraint(tile_map_node, p_coords_array[i], neighbor_list[i], p_terrain); + c.set_priority(10); + constraints.insert(c); + } + + // Fills in the constraint list from existing tiles. + for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(painted_set, p_terrain_set, p_ignore_empty_terrains)) { + constraints.insert(c); + } + + // Fill the terrains. + output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints); + return output; +} + +HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains) { + HashMap<Vector2i, TileSet::TerrainsPattern> output; + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + ERR_FAIL_COND_V(!tile_set.is_valid(), output); + ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); + + // Build list and set of tiles that can be modified (painted and their surroundings). + Vector<Vector2i> can_modify_list; + RBSet<Vector2i> can_modify_set; + RBSet<Vector2i> painted_set; + for (int i = p_coords_array.size() - 1; i >= 0; i--) { + const Vector2i &coords = p_coords_array[i]; + can_modify_list.push_back(coords); + can_modify_set.insert(coords); + painted_set.insert(coords); + } + for (Vector2i coords : p_coords_array) { + // Find the adequate neighbor. + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { + Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit); + if (!can_modify_set.has(neighbor)) { + can_modify_list.push_back(neighbor); + can_modify_set.insert(neighbor); + } + } + } + } + + // Add constraint by the new ones. + RBSet<TerrainConstraint> constraints; + + // Add new constraints from the path drawn. + for (Vector2i coords : p_coords_array) { + // Constraints on the center bit. + RBSet<TerrainConstraint> added_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, p_terrains_pattern); + for (TerrainConstraint c : added_constraints) { + c.set_priority(10); + constraints.insert(c); + } + } + + // Fills in the constraint list from modified tiles border. + for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(painted_set, p_terrain_set, p_ignore_empty_terrains)) { + constraints.insert(c); + } + + // Fill the terrains. + output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints); + return output; +} + +TileMapCell TileMapLayer::get_cell(const Vector2i &p_coords, bool p_use_proxies) const { + if (!tile_map.has(p_coords)) { + return TileMapCell(); + } else { + TileMapCell c = tile_map.find(p_coords)->value.cell; + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + if (p_use_proxies && tile_set.is_valid()) { + Array proxyed = tile_set->map_tile_proxy(c.source_id, c.get_atlas_coords(), c.alternative_tile); + c.source_id = proxyed[0]; + c.set_atlas_coords(proxyed[1]); + c.alternative_tile = proxyed[2]; + } + return c; + } +} + +void TileMapLayer::set_tile_data(TileMapDataFormat p_format, const Vector<int> &p_data) { + ERR_FAIL_COND(p_format > TileMapDataFormat::FORMAT_3); + + // Set data for a given tile from raw data. + + int c = p_data.size(); + const int *r = p_data.ptr(); + + int offset = (p_format >= TileMapDataFormat::FORMAT_2) ? 3 : 2; + ERR_FAIL_COND_MSG(c % offset != 0, vformat("Corrupted tile data. Got size: %s. Expected modulo: %s", offset)); + + clear(); + +#ifdef DISABLE_DEPRECATED + ERR_FAIL_COND_MSG(p_format != TileMapDataFormat::FORMAT_3, vformat("Cannot handle deprecated TileMap data format version %d. This Godot version was compiled with no support for deprecated data.", p_format)); +#endif + + for (int i = 0; i < c; i += offset) { + const uint8_t *ptr = (const uint8_t *)&r[i]; + uint8_t local[12]; + for (int j = 0; j < ((p_format >= TileMapDataFormat::FORMAT_2) ? 12 : 8); j++) { + local[j] = ptr[j]; + } + +#ifdef BIG_ENDIAN_ENABLED + + SWAP(local[0], local[3]); + SWAP(local[1], local[2]); + SWAP(local[4], local[7]); + SWAP(local[5], local[6]); + //TODO: ask someone to check this... + if (FORMAT >= FORMAT_2) { + SWAP(local[8], local[11]); + SWAP(local[9], local[10]); + } +#endif + // Extracts position in TileMap. + int16_t x = decode_uint16(&local[0]); + int16_t y = decode_uint16(&local[2]); + + if (p_format == TileMapDataFormat::FORMAT_3) { + uint16_t source_id = decode_uint16(&local[4]); + uint16_t atlas_coords_x = decode_uint16(&local[6]); + uint16_t atlas_coords_y = decode_uint16(&local[8]); + uint16_t alternative_tile = decode_uint16(&local[10]); + set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile); + } else { +#ifndef DISABLE_DEPRECATED + // Previous decated format. + + uint32_t v = decode_uint32(&local[4]); + // Extract the transform flags that used to be in the tilemap. + bool flip_h = v & (1UL << 29); + bool flip_v = v & (1UL << 30); + bool transpose = v & (1UL << 31); + v &= (1UL << 29) - 1; + + // Extract autotile/atlas coords. + int16_t coord_x = 0; + int16_t coord_y = 0; + if (p_format == TileMapDataFormat::FORMAT_2) { + coord_x = decode_uint16(&local[8]); + coord_y = decode_uint16(&local[10]); + } + + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + if (tile_set.is_valid()) { + Array a = tile_set->compatibility_tilemap_map(v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose); + if (a.size() == 3) { + set_cell(Vector2i(x, y), a[0], a[1], a[2]); + } else { + ERR_PRINT(vformat("No valid tile in Tileset for: tile:%s coords:%s flip_h:%s flip_v:%s transpose:%s", v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose)); + } + } else { + int compatibility_alternative_tile = ((int)flip_h) + ((int)flip_v << 1) + ((int)transpose << 2); + set_cell(Vector2i(x, y), v, Vector2i(coord_x, coord_y), compatibility_alternative_tile); + } +#endif + } + } +} + +Vector<int> TileMapLayer::get_tile_data() const { + // Export tile data to raw format. + Vector<int> tile_data; + tile_data.resize(tile_map.size() * 3); + int *w = tile_data.ptrw(); + + // Save in highest format. + + int idx = 0; + for (const KeyValue<Vector2i, CellData> &E : tile_map) { + uint8_t *ptr = (uint8_t *)&w[idx]; + encode_uint16((int16_t)(E.key.x), &ptr[0]); + encode_uint16((int16_t)(E.key.y), &ptr[2]); + encode_uint16(E.value.cell.source_id, &ptr[4]); + encode_uint16(E.value.cell.coord_x, &ptr[6]); + encode_uint16(E.value.cell.coord_y, &ptr[8]); + encode_uint16(E.value.cell.alternative_tile, &ptr[10]); + idx += 3; + } + + return tile_data; +} + +void TileMapLayer::notify_tile_map_change(DirtyFlags p_what) { + dirty.flags[p_what] = true; + tile_map_node->queue_internal_update(); + _physics_notify_tilemap_change(p_what); +} + +void TileMapLayer::internal_update() { + // Find TileData that need a runtime modification. + // This may add cells to the dirty list is a runtime modification has been notified. + _build_runtime_update_tile_data(); + + // Update all subsystems. + _rendering_update(); + _physics_update(); + _navigation_update(); + _scenes_update(); +#ifdef DEBUG_ENABLED + _debug_update(); +#endif // DEBUG_ENABLED + + _clear_runtime_update_tile_data(); + + // Clear the "what is dirty" flags. + for (int i = 0; i < DIRTY_FLAGS_MAX; i++) { + dirty.flags[i] = false; + } + + // List the cells to delete definitely. + Vector<Vector2i> to_delete; + for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + // Select the the cell from tile_map if it is invalid. + if (cell_data.cell.source_id == TileSet::INVALID_SOURCE) { + to_delete.push_back(cell_data.coords); + } + } + + // Remove cells that are empty after the cleanup. + for (const Vector2i &coords : to_delete) { + tile_map.erase(coords); + } + + // Clear the dirty cells list. + dirty.cell_list.clear(); +} + +void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) { + // Set the current cell tile (using integer position). + Vector2i pk(p_coords); + HashMap<Vector2i, CellData>::Iterator E = tile_map.find(pk); + + int source_id = p_source_id; + Vector2i atlas_coords = p_atlas_coords; + int alternative_tile = p_alternative_tile; + + if ((source_id == TileSet::INVALID_SOURCE || atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE) && + (source_id != TileSet::INVALID_SOURCE || atlas_coords != TileSetSource::INVALID_ATLAS_COORDS || alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE)) { + source_id = TileSet::INVALID_SOURCE; + atlas_coords = TileSetSource::INVALID_ATLAS_COORDS; + alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE; + } + + if (!E) { + if (source_id == TileSet::INVALID_SOURCE) { + return; // Nothing to do, the tile is already empty. + } + + // Insert a new cell in the tile map. + CellData new_cell_data; + new_cell_data.coords = pk; + E = tile_map.insert(pk, new_cell_data); + } else { + if (E->value.cell.source_id == source_id && E->value.cell.get_atlas_coords() == atlas_coords && E->value.cell.alternative_tile == alternative_tile) { + return; // Nothing changed. + } + } + + TileMapCell &c = E->value.cell; + c.source_id = source_id; + c.set_atlas_coords(atlas_coords); + c.alternative_tile = alternative_tile; + + // Make the given cell dirty. + if (!E->value.dirty_list_element.in_list()) { + dirty.cell_list.add(&(E->value.dirty_list_element)); + } + tile_map_node->queue_internal_update(); + + used_rect_cache_dirty = true; +} + +void TileMapLayer::erase_cell(const Vector2i &p_coords) { + set_cell(p_coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); +} + +int TileMapLayer::get_cell_source_id(const Vector2i &p_coords, bool p_use_proxies) const { + // Get a cell source id from position. + HashMap<Vector2i, CellData>::ConstIterator E = tile_map.find(p_coords); + + if (!E) { + return TileSet::INVALID_SOURCE; + } + + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + if (p_use_proxies && tile_set.is_valid()) { + Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); + return proxyed[0]; + } + + return E->value.cell.source_id; +} + +Vector2i TileMapLayer::get_cell_atlas_coords(const Vector2i &p_coords, bool p_use_proxies) const { + // Get a cell source id from position. + HashMap<Vector2i, CellData>::ConstIterator E = tile_map.find(p_coords); + + if (!E) { + return TileSetSource::INVALID_ATLAS_COORDS; + } + + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + if (p_use_proxies && tile_set.is_valid()) { + Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); + return proxyed[1]; + } + + return E->value.cell.get_atlas_coords(); +} + +int TileMapLayer::get_cell_alternative_tile(const Vector2i &p_coords, bool p_use_proxies) const { + // Get a cell source id from position. + HashMap<Vector2i, CellData>::ConstIterator E = tile_map.find(p_coords); + + if (!E) { + return TileSetSource::INVALID_TILE_ALTERNATIVE; + } + + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + if (p_use_proxies && tile_set.is_valid()) { + Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); + return proxyed[2]; + } + + return E->value.cell.alternative_tile; +} + +TileData *TileMapLayer::get_cell_tile_data(const Vector2i &p_coords, bool p_use_proxies) const { + int source_id = get_cell_source_id(p_coords, p_use_proxies); + if (source_id == TileSet::INVALID_SOURCE) { + return nullptr; + } + + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + Ref<TileSetAtlasSource> source = tile_set->get_source(source_id); + if (source.is_valid()) { + return source->get_tile_data(get_cell_atlas_coords(p_coords, p_use_proxies), get_cell_alternative_tile(p_coords, p_use_proxies)); + } + + return nullptr; +} + +void TileMapLayer::clear() { + // Remove all tiles. + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + erase_cell(kv.key); + } + used_rect_cache_dirty = true; +} + +Ref<TileMapPattern> TileMapLayer::get_pattern(TypedArray<Vector2i> p_coords_array) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr); + + Ref<TileMapPattern> output; + output.instantiate(); + if (p_coords_array.is_empty()) { + return output; + } + + Vector2i min = Vector2i(p_coords_array[0]); + for (int i = 1; i < p_coords_array.size(); i++) { + min = min.min(p_coords_array[i]); + } + + Vector<Vector2i> coords_in_pattern_array; + coords_in_pattern_array.resize(p_coords_array.size()); + Vector2i ensure_positive_offset; + for (int i = 0; i < p_coords_array.size(); i++) { + Vector2i coords = p_coords_array[i]; + Vector2i coords_in_pattern = coords - min; + if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) { + if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) { + if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) { + coords_in_pattern.x -= 1; + if (coords_in_pattern.x < 0) { + ensure_positive_offset.x = 1; + } + } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) { + coords_in_pattern.y -= 1; + if (coords_in_pattern.y < 0) { + ensure_positive_offset.y = 1; + } + } + } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) { + if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) { + coords_in_pattern.x += 1; + } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) { + coords_in_pattern.y += 1; + } + } + } + coords_in_pattern_array.write[i] = coords_in_pattern; + } + + for (int i = 0; i < coords_in_pattern_array.size(); i++) { + Vector2i coords = p_coords_array[i]; + Vector2i coords_in_pattern = coords_in_pattern_array[i]; + output->set_cell(coords_in_pattern + ensure_positive_offset, get_cell_source_id(coords), get_cell_atlas_coords(coords), get_cell_alternative_tile(coords)); + } + + return output; +} + +void TileMapLayer::set_pattern(const Vector2i &p_position, const Ref<TileMapPattern> p_pattern) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + ERR_FAIL_COND(tile_set.is_null()); + ERR_FAIL_COND(p_pattern.is_null()); + + TypedArray<Vector2i> used_cells = p_pattern->get_used_cells(); + for (int i = 0; i < used_cells.size(); i++) { + Vector2i coords = tile_map_node->map_pattern(p_position, used_cells[i], p_pattern); + set_cell(coords, p_pattern->get_cell_source_id(used_cells[i]), p_pattern->get_cell_atlas_coords(used_cells[i]), p_pattern->get_cell_alternative_tile(used_cells[i])); + } +} + +void TileMapLayer::set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + ERR_FAIL_COND(!tile_set.is_valid()); + ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); + + Vector<Vector2i> cells_vector; + HashSet<Vector2i> painted_set; + for (int i = 0; i < p_cells.size(); i++) { + cells_vector.push_back(p_cells[i]); + painted_set.insert(p_cells[i]); + } + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(cells_vector, p_terrain_set, p_terrain, p_ignore_empty_terrains); + for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) { + if (painted_set.has(kv.key)) { + // Paint a random tile with the correct terrain for the painted path. + TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); + set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); + } else { + // Avoids updating the painted path from the output if the new pattern is the same as before. + TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set); + TileMapCell cell = get_cell(kv.key); + if (cell.source_id != TileSet::INVALID_SOURCE) { + TileSetSource *source = *tile_set->get_source(cell.source_id); + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + // Get tile data. + TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); + if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { + in_map_terrain_pattern = tile_data->get_terrains_pattern(); + } + } + } + if (in_map_terrain_pattern != kv.value) { + TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); + set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); + } + } + } +} + +void TileMapLayer::set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { + const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + ERR_FAIL_COND(!tile_set.is_valid()); + ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); + + Vector<Vector2i> vector_path; + HashSet<Vector2i> painted_set; + for (int i = 0; i < p_path.size(); i++) { + vector_path.push_back(p_path[i]); + painted_set.insert(p_path[i]); + } + + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_path(vector_path, p_terrain_set, p_terrain, p_ignore_empty_terrains); + for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) { + if (painted_set.has(kv.key)) { + // Paint a random tile with the correct terrain for the painted path. + TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); + set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); + } else { + // Avoids updating the painted path from the output if the new pattern is the same as before. + TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set); + TileMapCell cell = get_cell(kv.key); + if (cell.source_id != TileSet::INVALID_SOURCE) { + TileSetSource *source = *tile_set->get_source(cell.source_id); + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + // Get tile data. + TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); + if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { + in_map_terrain_pattern = tile_data->get_terrains_pattern(); + } + } + } + if (in_map_terrain_pattern != kv.value) { + TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); + set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); + } + } + } +} + +TypedArray<Vector2i> TileMapLayer::get_used_cells() const { + // Returns the cells used in the tilemap. + TypedArray<Vector2i> a; + for (const KeyValue<Vector2i, CellData> &E : tile_map) { + const TileMapCell &c = E.value.cell; + if (c.source_id == TileSet::INVALID_SOURCE) { + continue; + } + a.push_back(E.key); + } + + return a; +} + +TypedArray<Vector2i> TileMapLayer::get_used_cells_by_id(int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) const { + // Returns the cells used in the tilemap. + TypedArray<Vector2i> a; + for (const KeyValue<Vector2i, CellData> &E : tile_map) { + const TileMapCell &c = E.value.cell; + if (c.source_id == TileSet::INVALID_SOURCE) { + continue; + } + if ((p_source_id == TileSet::INVALID_SOURCE || p_source_id == c.source_id) && + (p_atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || p_atlas_coords == c.get_atlas_coords()) && + (p_alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE || p_alternative_tile == c.alternative_tile)) { + a.push_back(E.key); + } + } + + return a; +} + +Rect2i TileMapLayer::get_used_rect() const { + // Return the rect of the currently used area. + if (used_rect_cache_dirty) { + used_rect_cache = Rect2i(); + + bool first = true; + for (const KeyValue<Vector2i, CellData> &E : tile_map) { + const TileMapCell &c = E.value.cell; + if (c.source_id == TileSet::INVALID_SOURCE) { + continue; + } + if (first) { + used_rect_cache = Rect2i(E.key.x, E.key.y, 0, 0); + first = false; + } else { + used_rect_cache.expand_to(E.key); + } + } + if (!first) { + // Only if we have at least one cell. + // The cache expands to top-left coordinate, so we add one full tile. + used_rect_cache.size += Vector2i(1, 1); + } + used_rect_cache_dirty = false; + } + + return used_rect_cache; +} + +void TileMapLayer::set_name(String p_name) { + if (name == p_name) { + return; + } + name = p_name; + tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); +} + +String TileMapLayer::get_name() const { + return name; +} + +void TileMapLayer::set_enabled(bool p_enabled) { + if (enabled == p_enabled) { + return; + } + enabled = p_enabled; + dirty.flags[DIRTY_FLAGS_LAYER_ENABLED] = true; + tile_map_node->queue_internal_update(); + tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); + + tile_map_node->update_configuration_warnings(); +} + +bool TileMapLayer::is_enabled() const { + return enabled; +} + +void TileMapLayer::set_modulate(Color p_modulate) { + if (modulate == p_modulate) { + return; + } + modulate = p_modulate; + dirty.flags[DIRTY_FLAGS_LAYER_MODULATE] = true; + tile_map_node->queue_internal_update(); + tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); +} + +Color TileMapLayer::get_modulate() const { + return modulate; +} + +void TileMapLayer::set_y_sort_enabled(bool p_y_sort_enabled) { + if (y_sort_enabled == p_y_sort_enabled) { + return; + } + y_sort_enabled = p_y_sort_enabled; + dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] = true; + tile_map_node->queue_internal_update(); + tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); + + tile_map_node->update_configuration_warnings(); +} + +bool TileMapLayer::is_y_sort_enabled() const { + return y_sort_enabled; +} + +void TileMapLayer::set_y_sort_origin(int p_y_sort_origin) { + if (y_sort_origin == p_y_sort_origin) { + return; + } + y_sort_origin = p_y_sort_origin; + dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] = true; + tile_map_node->queue_internal_update(); + tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); +} + +int TileMapLayer::get_y_sort_origin() const { + return y_sort_origin; +} + +void TileMapLayer::set_z_index(int p_z_index) { + if (z_index == p_z_index) { + return; + } + z_index = p_z_index; + dirty.flags[DIRTY_FLAGS_LAYER_Z_INDEX] = true; + tile_map_node->queue_internal_update(); + tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); + + tile_map_node->update_configuration_warnings(); +} + +int TileMapLayer::get_z_index() const { + return z_index; +} + +void TileMapLayer::set_navigation_enabled(bool p_enabled) { + if (navigation_enabled == p_enabled) { + return; + } + navigation_enabled = p_enabled; + dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED] = true; + tile_map_node->queue_internal_update(); + tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); +} + +bool TileMapLayer::is_navigation_enabled() const { + return navigation_enabled; +} + +void TileMapLayer::set_navigation_map(RID p_map) { + ERR_FAIL_COND_MSG(!tile_map_node->is_inside_tree(), "A TileMap navigation map can only be changed while inside the SceneTree."); + navigation_map = p_map; + uses_world_navigation_map = p_map == tile_map_node->get_world_2d()->get_navigation_map(); +} + +RID TileMapLayer::get_navigation_map() const { + if (navigation_map.is_valid()) { + return navigation_map; + } + return RID(); +} + +void TileMapLayer::fix_invalid_tiles() { + Ref<TileSet> tileset = tile_map_node->get_tileset(); + ERR_FAIL_COND_MSG(tileset.is_null(), "Cannot call fix_invalid_tiles() on a TileMap without a valid TileSet."); + + RBSet<Vector2i> coords; + for (const KeyValue<Vector2i, CellData> &E : tile_map) { + TileSetSource *source = *tileset->get_source(E.value.cell.source_id); + if (!source || !source->has_tile(E.value.cell.get_atlas_coords()) || !source->has_alternative_tile(E.value.cell.get_atlas_coords(), E.value.cell.alternative_tile)) { + coords.insert(E.key); + } + } + for (const Vector2i &E : coords) { + set_cell(E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); + } +} + +bool TileMapLayer::has_body_rid(RID p_physics_body) const { + return bodies_coords.has(p_physics_body); +} + +Vector2i TileMapLayer::get_coords_for_body_rid(RID p_physics_body) const { + return bodies_coords[p_physics_body]; +} + +TileMapLayer::~TileMapLayer() { + if (!tile_map_node) { + // Temporary layer. + return; + } + + in_destructor = true; + clear(); + internal_update(); +} + +HashMap<Vector2i, TileSet::CellNeighbor> TerrainConstraint::get_overlapping_coords_and_peering_bits() const { + HashMap<Vector2i, TileSet::CellNeighbor> output; + + ERR_FAIL_COND_V(is_center_bit(), output); + + Ref<TileSet> ts = tile_map->get_tileset(); + ERR_FAIL_COND_V(!ts.is_valid(), output); + + TileSet::TileShape shape = ts->get_tile_shape(); + if (shape == TileSet::TILE_SHAPE_SQUARE) { + switch (bit) { + case 1: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE; + break; + case 2: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; + break; + case 3: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE; + break; + default: + ERR_FAIL_V(output); + } + } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { + switch (bit) { + case 1: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; + break; + case 2: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER; + break; + case 3: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; + break; + default: + ERR_FAIL_V(output); + } + } else { + // Half offset shapes. + TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis(); + if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + switch (bit) { + case 1: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE; + break; + case 2: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER; + break; + case 3: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; + break; + case 4: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; + break; + case 5: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; + break; + default: + ERR_FAIL_V(output); + } + } else { + switch (bit) { + case 1: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; + break; + case 2: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; + break; + case 3: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; + break; + case 4: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE; + break; + case 5: + output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE; + output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; + break; + default: + ERR_FAIL_V(output); + } + } + } + return output; +} + +TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain) { + tile_map = p_tile_map; + + Ref<TileSet> ts = tile_map->get_tileset(); + ERR_FAIL_COND(!ts.is_valid()); + + bit = 0; + base_cell_coords = p_position; + terrain = p_terrain; +} + +TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain) { + // The way we build the constraint make it easy to detect conflicting constraints. + tile_map = p_tile_map; + + Ref<TileSet> ts = tile_map->get_tileset(); + ERR_FAIL_COND(!ts.is_valid()); + + TileSet::TileShape shape = ts->get_tile_shape(); + if (shape == TileSet::TILE_SHAPE_SQUARE) { + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: + bit = 1; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + bit = 2; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: + bit = 3; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + bit = 2; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_LEFT_SIDE: + bit = 1; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + bit = 2; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER); + break; + case TileSet::CELL_NEIGHBOR_TOP_SIDE: + bit = 3; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + bit = 2; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); + break; + default: + ERR_FAIL(); + break; + } + } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: + bit = 2; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + bit = 1; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: + bit = 2; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + bit = 3; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_LEFT_CORNER: + bit = 2; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + bit = 1; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_CORNER: + bit = 2; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_CORNER); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + bit = 3; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); + break; + default: + ERR_FAIL(); + break; + } + } else { + // Half-offset shapes. + TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis(); + if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: + bit = 1; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + bit = 2; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + bit = 3; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: + bit = 4; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + bit = 5; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + bit = 2; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_LEFT_SIDE: + bit = 1; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + bit = 4; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + bit = 3; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_CORNER: + bit = 2; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + bit = 5; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + bit = 4; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); + break; + default: + ERR_FAIL(); + break; + } + } else { + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: + bit = 1; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + bit = 2; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + bit = 3; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: + bit = 4; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + bit = 1; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + bit = 5; + base_cell_coords = p_position; + break; + case TileSet::CELL_NEIGHBOR_LEFT_CORNER: + bit = 3; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + bit = 2; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + bit = 1; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_SIDE: + bit = 4; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + bit = 3; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + bit = 5; + base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); + break; + default: + ERR_FAIL(); + break; + } + } + } + terrain = p_terrain; +}
\ No newline at end of file diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h new file mode 100644 index 0000000000..3125fcb488 --- /dev/null +++ b/scene/2d/tile_map_layer.h @@ -0,0 +1,413 @@ +/**************************************************************************/ +/* tile_map_layer.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef TILE_MAP_LAYER_H +#define TILE_MAP_LAYER_H + +#include "scene/2d/tile_map.h" +#include "scene/resources/tile_set.h" + +class TileSetAtlasSource; + +class TerrainConstraint { +private: + const TileMap *tile_map = nullptr; + Vector2i base_cell_coords; + int bit = -1; + int terrain = -1; + + int priority = 1; + +public: + bool operator<(const TerrainConstraint &p_other) const { + if (base_cell_coords == p_other.base_cell_coords) { + return bit < p_other.bit; + } + return base_cell_coords < p_other.base_cell_coords; + } + + String to_string() const { + return vformat("Constraint {pos:%s, bit:%d, terrain:%d, priority:%d}", base_cell_coords, bit, terrain, priority); + } + + Vector2i get_base_cell_coords() const { + return base_cell_coords; + } + + bool is_center_bit() const { + return bit == 0; + } + + HashMap<Vector2i, TileSet::CellNeighbor> get_overlapping_coords_and_peering_bits() const; + + void set_terrain(int p_terrain) { + terrain = p_terrain; + } + + int get_terrain() const { + return terrain; + } + + void set_priority(int p_priority) { + priority = p_priority; + } + + int get_priority() const { + return priority; + } + + TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain); // For the center terrain bit + TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain); // For peering bits + TerrainConstraint(){}; +}; + +#ifdef DEBUG_ENABLED +class DebugQuadrant; +#endif // DEBUG_ENABLED +class RenderingQuadrant; + +struct CellData { + Vector2i coords; + TileMapCell cell; + + // Debug. + SelfList<CellData> debug_quadrant_list_element; + + // Rendering. + Ref<RenderingQuadrant> rendering_quadrant; + SelfList<CellData> rendering_quadrant_list_element; + LocalVector<RID> occluders; + + // Physics. + LocalVector<RID> bodies; + + // Navigation. + LocalVector<RID> navigation_regions; + + // Scenes. + String scene; + + // Runtime TileData cache. + TileData *runtime_tile_data_cache = nullptr; + + // List elements. + SelfList<CellData> dirty_list_element; + + bool operator<(const CellData &p_other) const { + return coords < p_other.coords; + } + + // For those, copy everything but SelfList elements. + void operator=(const CellData &p_other) { + coords = p_other.coords; + cell = p_other.cell; + occluders = p_other.occluders; + bodies = p_other.bodies; + navigation_regions = p_other.navigation_regions; + scene = p_other.scene; + runtime_tile_data_cache = p_other.runtime_tile_data_cache; + } + + CellData(const CellData &p_other) : + debug_quadrant_list_element(this), + rendering_quadrant_list_element(this), + dirty_list_element(this) { + coords = p_other.coords; + cell = p_other.cell; + occluders = p_other.occluders; + bodies = p_other.bodies; + navigation_regions = p_other.navigation_regions; + scene = p_other.scene; + runtime_tile_data_cache = p_other.runtime_tile_data_cache; + } + + CellData() : + debug_quadrant_list_element(this), + rendering_quadrant_list_element(this), + dirty_list_element(this) { + } +}; + +// For compatibility reasons, we use another comparator for Y-sorted layers. +struct CellDataYSortedComparator { + _FORCE_INLINE_ bool operator()(const CellData &p_a, const CellData &p_b) const { + return p_a.coords.x == p_b.coords.x ? (p_a.coords.y < p_b.coords.y) : (p_a.coords.x > p_b.coords.x); + } +}; + +#ifdef DEBUG_ENABLED +class DebugQuadrant : public RefCounted { + GDCLASS(DebugQuadrant, RefCounted); + +public: + Vector2i quadrant_coords; + SelfList<CellData>::List cells; + RID canvas_item; + + SelfList<DebugQuadrant> dirty_quadrant_list_element; + + DebugQuadrant() : + dirty_quadrant_list_element(this) { + } + + ~DebugQuadrant() { + cells.clear(); + } +}; +#endif // DEBUG_ENABLED + +class RenderingQuadrant : public RefCounted { + GDCLASS(RenderingQuadrant, RefCounted); + +public: + struct CoordsWorldComparator { + _ALWAYS_INLINE_ bool operator()(const Vector2 &p_a, const Vector2 &p_b) const { + // We sort the cells by their local coords, as it is needed by rendering. + if (p_a.y == p_b.y) { + return p_a.x > p_b.x; + } else { + return p_a.y < p_b.y; + } + } + }; + + Vector2i quadrant_coords; + SelfList<CellData>::List cells; + List<RID> canvas_items; + Vector2 canvas_items_position; + + SelfList<RenderingQuadrant> dirty_quadrant_list_element; + + RenderingQuadrant() : + dirty_quadrant_list_element(this) { + } + + ~RenderingQuadrant() { + cells.clear(); + } +}; + +class TileMapLayer : public RefCounted { + GDCLASS(TileMapLayer, RefCounted); + +public: + enum DirtyFlags { + DIRTY_FLAGS_LAYER_ENABLED = 0, + DIRTY_FLAGS_LAYER_MODULATE, + DIRTY_FLAGS_LAYER_Y_SORT_ENABLED, + DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN, + DIRTY_FLAGS_LAYER_Z_INDEX, + DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED, + DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE, + DIRTY_FLAGS_TILE_MAP_IN_TREE, + DIRTY_FLAGS_TILE_MAP_IN_CANVAS, + DIRTY_FLAGS_TILE_MAP_VISIBILITY, + DIRTY_FLAGS_TILE_MAP_XFORM, + DIRTY_FLAGS_TILE_MAP_LOCAL_XFORM, + DIRTY_FLAGS_TILE_MAP_SELECTED_LAYER, + DIRTY_FLAGS_TILE_MAP_LIGHT_MASK, + DIRTY_FLAGS_TILE_MAP_MATERIAL, + DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL, + DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER, + DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT, + DIRTY_FLAGS_TILE_MAP_TILE_SET, + DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE, + DIRTY_FLAGS_TILE_MAP_COLLISION_ANIMATABLE, + DIRTY_FLAGS_TILE_MAP_COLLISION_VISIBILITY_MODE, + DIRTY_FLAGS_TILE_MAP_NAVIGATION_VISIBILITY_MODE, + DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED, + DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE, + DIRTY_FLAGS_MAX, + }; + +private: + // Exposed properties. + String name; + bool enabled = true; + Color modulate = Color(1, 1, 1, 1); + bool y_sort_enabled = false; + int y_sort_origin = 0; + int z_index = 0; + bool navigation_enabled = true; + RID navigation_map; + bool uses_world_navigation_map = false; + + // Internal. + TileMap *tile_map_node = nullptr; + int layer_index_in_tile_map_node = -1; + RID canvas_item; + HashMap<Vector2i, CellData> tile_map; + + // Dirty flag. Allows knowing what was modified since the last update. + struct { + bool flags[DIRTY_FLAGS_MAX] = { false }; + SelfList<CellData>::List cell_list; + } dirty; + bool in_destructor = false; + + // Rect cache. + mutable Rect2 rect_cache; + mutable bool rect_cache_dirty = true; + mutable Rect2i used_rect_cache; + mutable bool used_rect_cache_dirty = true; + + // Runtime tile data. + bool _runtime_update_tile_data_was_cleaned_up = false; + void _build_runtime_update_tile_data(); + void _build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_auto_add_to_dirty_list = false); + void _clear_runtime_update_tile_data(); + + // Per-system methods. +#ifdef DEBUG_ENABLED + HashMap<Vector2i, Ref<DebugQuadrant>> debug_quadrant_map; + Vector2i _coords_to_debug_quadrant_coords(const Vector2i &p_coords) const; + bool _debug_was_cleaned_up = false; + void _debug_update(); + void _debug_quadrants_update_cell(CellData &r_cell_data, SelfList<DebugQuadrant>::List &r_dirty_debug_quadrant_list); +#endif // DEBUG_ENABLED + + HashMap<Vector2i, Ref<RenderingQuadrant>> rendering_quadrant_map; + bool _rendering_was_cleaned_up = false; + void _rendering_update(); + void _rendering_quadrants_update_cell(CellData &r_cell_data, SelfList<RenderingQuadrant>::List &r_dirty_rendering_quadrant_list); + void _rendering_occluders_clear_cell(CellData &r_cell_data); + void _rendering_occluders_update_cell(CellData &r_cell_data); +#ifdef DEBUG_ENABLED + void _rendering_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data); +#endif // DEBUG_ENABLED + + HashMap<RID, Vector2i> bodies_coords; // Mapping for RID to coords. + bool _physics_was_cleaned_up = false; + void _physics_update(); + void _physics_notify_tilemap_change(DirtyFlags p_what); + void _physics_clear_cell(CellData &r_cell_data); + void _physics_update_cell(CellData &r_cell_data); +#ifdef DEBUG_ENABLED + void _physics_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data); +#endif // DEBUG_ENABLED + + bool _navigation_was_cleaned_up = false; + void _navigation_update(); + void _navigation_clear_cell(CellData &r_cell_data); + void _navigation_update_cell(CellData &r_cell_data); +#ifdef DEBUG_ENABLED + void _navigation_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data); +#endif // DEBUG_ENABLED + + bool _scenes_was_cleaned_up = false; + void _scenes_update(); + void _scenes_clear_cell(CellData &r_cell_data); + void _scenes_update_cell(CellData &r_cell_data); +#ifdef DEBUG_ENABLED + void _scenes_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data); +#endif // DEBUG_ENABLED + + // Terrains. + TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern); + RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const; + RBSet<TerrainConstraint> _get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const; + +public: + // TileMap node. + void set_tile_map(TileMap *p_tile_map); + void set_layer_index_in_tile_map_node(int p_index); + + // Rect caching. + Rect2 get_rect(bool &r_changed) const; + + // Terrains. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints); // Not exposed. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true); // Not exposed. + + // Not exposed to users. + TileMapCell get_cell(const Vector2i &p_coords, bool p_use_proxies = false) const; + + // For TileMap node's use. + void set_tile_data(TileMapDataFormat p_format, const Vector<int> &p_data); + Vector<int> get_tile_data() const; + void notify_tile_map_change(DirtyFlags p_what); + void internal_update(); + + // --- Exposed in TileMap --- + + // Cells manipulation. + void set_cell(const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0); + void erase_cell(const Vector2i &p_coords); + + int get_cell_source_id(const Vector2i &p_coords, bool p_use_proxies = false) const; + Vector2i get_cell_atlas_coords(const Vector2i &p_coords, bool p_use_proxies = false) const; + int get_cell_alternative_tile(const Vector2i &p_coords, bool p_use_proxies = false) const; + TileData *get_cell_tile_data(const Vector2i &p_coords, bool p_use_proxies = false) const; // Helper method to make accessing the data easier. + void clear(); + + // Patterns. + Ref<TileMapPattern> get_pattern(TypedArray<Vector2i> p_coords_array); + void set_pattern(const Vector2i &p_position, const Ref<TileMapPattern> p_pattern); + + // Terrains. + void set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); + void set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); + + // Cells usage. + TypedArray<Vector2i> get_used_cells() const; + TypedArray<Vector2i> get_used_cells_by_id(int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) const; + Rect2i get_used_rect() const; + + // Layer properties. + void set_name(String p_name); + String get_name() const; + void set_enabled(bool p_enabled); + bool is_enabled() const; + void set_modulate(Color p_modulate); + Color get_modulate() const; + void set_y_sort_enabled(bool p_y_sort_enabled); + bool is_y_sort_enabled() const; + void set_y_sort_origin(int p_y_sort_origin); + int get_y_sort_origin() const; + void set_z_index(int p_z_index); + int get_z_index() const; + void set_navigation_enabled(bool p_enabled); + bool is_navigation_enabled() const; + void set_navigation_map(RID p_map); + RID get_navigation_map() const; + + // Fixing and clearing methods. + void fix_invalid_tiles(); + + // Find coords for body. + bool has_body_rid(RID p_physics_body) const; + Vector2i get_coords_for_body_rid(RID p_physics_body) const; // For finding tiles from collision. + + ~TileMapLayer(); +}; + +#endif // TILE_MAP_LAYER_H diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp index 45de9b907c..5683fb7306 100644 --- a/scene/3d/bone_attachment_3d.cpp +++ b/scene/3d/bone_attachment_3d.cpp @@ -150,7 +150,7 @@ void BoneAttachment3D::_check_bind() { if (bone_idx != -1) { sk->connect(SNAME("bone_pose_changed"), callable_mp(this, &BoneAttachment3D::on_bone_pose_update)); bound = true; - call_deferred(SNAME("on_bone_pose_update"), bone_idx); + callable_mp(this, &BoneAttachment3D::on_bone_pose_update).call_deferred(bone_idx); } } } diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index 4562ecfb5f..97b1e282ad 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -295,16 +295,12 @@ void CollisionObject3D::_input_event_call(Camera3D *p_camera, const Ref<InputEve } void CollisionObject3D::_mouse_enter() { - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_enter); - } + GDVIRTUAL_CALL(_mouse_enter); emit_signal(SceneStringNames::get_singleton()->mouse_entered); } void CollisionObject3D::_mouse_exit() { - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_exit); - } + GDVIRTUAL_CALL(_mouse_exit); emit_signal(SceneStringNames::get_singleton()->mouse_exited); } diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index 0bb0382301..61941a0e53 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -35,6 +35,7 @@ #include "scene/resources/concave_polygon_shape_3d.h" #include "scene/resources/convex_polygon_shape_3d.h" #include "scene/resources/world_boundary_shape_3d.h" +#include "vehicle_body_3d.h" void CollisionShape3D::make_convex_from_siblings() { Node *p = get_parent(); @@ -130,13 +131,24 @@ PackedStringArray CollisionShape3D::get_configuration_warnings() const { } if (shape.is_valid() && Object::cast_to<RigidBody3D>(col_object)) { + String body_type = "RigidBody3D"; + if (Object::cast_to<VehicleBody3D>(col_object)) { + body_type = "VehicleBody3D"; + } + if (Object::cast_to<ConcavePolygonShape3D>(*shape)) { - warnings.push_back(RTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.")); + warnings.push_back(vformat(RTR("When used for collision, ConcavePolygonShape3D is intended to work with static CollisionObject3D nodes like StaticBody3D.\nIt will likely not behave well for %ss (except when frozen and freeze_mode set to FREEZE_MODE_STATIC)."), body_type)); } else if (Object::cast_to<WorldBoundaryShape3D>(*shape)) { warnings.push_back(RTR("WorldBoundaryShape3D doesn't support RigidBody3D in another mode than static.")); } } + if (shape.is_valid() && Object::cast_to<CharacterBody3D>(col_object)) { + if (Object::cast_to<ConcavePolygonShape3D>(*shape)) { + warnings.push_back(RTR("When used for collision, ConcavePolygonShape3D is intended to work with static CollisionObject3D nodes like StaticBody3D.\nIt will likely not behave well for CharacterBody3Ds.")); + } + } + Vector3 scale = get_transform().get_basis().get_scale(); if (!(Math::is_zero_approx(scale.x - scale.y) && Math::is_zero_approx(scale.y - scale.z))) { warnings.push_back(RTR("A non-uniformly scaled CollisionShape3D node will probably not function as expected.\nPlease make its scale uniform (i.e. the same on all axes), and change the size of its shape resource instead.")); diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index fc84b3308e..dfb039d709 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -460,7 +460,12 @@ void GPUParticles3D::_notification(int p_what) { // Use internal process when emitting and one_shot is on so that when // the shot ends the editor can properly update. case NOTIFICATION_INTERNAL_PROCESS: { - RS::get_singleton()->particles_set_emitter_velocity(particles, (get_global_position() - previous_position) / get_process_delta_time()); + const Vector3 velocity = (get_global_position() - previous_position) / get_process_delta_time(); + + if (velocity != previous_velocity) { + RS::get_singleton()->particles_set_emitter_velocity(particles, velocity); + previous_velocity = velocity; + } previous_position = get_global_position(); if (one_shot) { diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index ae9349817c..0c9f2c1378 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -95,6 +95,7 @@ private: double emission_time = 0.0; double active_time = 0.0; float interp_to_end_factor = 0; + Vector3 previous_velocity; Vector3 previous_position; void _attach_sub_emitter(); diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 76933cd956..92b783392d 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -734,15 +734,15 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa MeshesFound &mf = meshes_found.write[m_i]; - Size2i lightmap_size = mf.mesh->get_lightmap_size_hint(); - - if (lightmap_size == Size2i(0, 0)) { + Size2i mesh_lightmap_size = mf.mesh->get_lightmap_size_hint(); + if (mesh_lightmap_size == Size2i(0, 0)) { // TODO we should compute a size if no lightmap hint is set, as we did in 3.x. // For now set to basic size to avoid crash. - lightmap_size = Size2i(64, 64); + mesh_lightmap_size = Size2i(64, 64); } + Size2i lightmap_size = Size2i(Size2(mesh_lightmap_size) * mf.lightmap_scale * texel_scale); + ERR_FAIL_COND_V(lightmap_size.x == 0 || lightmap_size.y == 0, BAKE_ERROR_LIGHTMAP_TOO_SMALL); - lightmap_size *= mf.lightmap_scale; TypedArray<RID> overrides; overrides.resize(mf.overrides.size()); for (int i = 0; i < mf.overrides.size(); i++) { @@ -1493,6 +1493,15 @@ float LightmapGI::get_bias() const { return bias; } +void LightmapGI::set_texel_scale(float p_multiplier) { + ERR_FAIL_COND(p_multiplier < (0.01 - CMP_EPSILON)); + texel_scale = p_multiplier; +} + +float LightmapGI::get_texel_scale() const { + return texel_scale; +} + void LightmapGI::set_max_texture_size(int p_size) { 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)); @@ -1576,6 +1585,9 @@ void LightmapGI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_environment_custom_energy", "energy"), &LightmapGI::set_environment_custom_energy); ClassDB::bind_method(D_METHOD("get_environment_custom_energy"), &LightmapGI::get_environment_custom_energy); + ClassDB::bind_method(D_METHOD("set_texel_scale", "texel_scale"), &LightmapGI::set_texel_scale); + ClassDB::bind_method(D_METHOD("get_texel_scale"), &LightmapGI::get_texel_scale); + ClassDB::bind_method(D_METHOD("set_max_texture_size", "max_texture_size"), &LightmapGI::set_max_texture_size); ClassDB::bind_method(D_METHOD("get_max_texture_size"), &LightmapGI::get_max_texture_size); @@ -1609,6 +1621,7 @@ void LightmapGI::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_denoiser"), "set_use_denoiser", "is_using_denoiser"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "denoiser_strength", PROPERTY_HINT_RANGE, "0.001,0.2,0.001,or_greater"), "set_denoiser_strength", "get_denoiser_strength"); 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::FLOAT, "texel_scale", PROPERTY_HINT_RANGE, "0.01,100.0,0.01"), "set_texel_scale", "get_texel_scale"); 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"); diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h index fec0075693..765e4a731d 100644 --- a/scene/3d/lightmap_gi.h +++ b/scene/3d/lightmap_gi.h @@ -142,6 +142,7 @@ public: BAKE_ERROR_CANT_CREATE_IMAGE, BAKE_ERROR_USER_ABORTED, BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL, + BAKE_ERROR_LIGHTMAP_TOO_SMALL, }; enum EnvironmentMode { @@ -158,6 +159,7 @@ private: int bounces = 3; float bounce_indirect_energy = 1.0; float bias = 0.0005; + float texel_scale = 1.0; int max_texture_size = 16384; bool interior = false; EnvironmentMode environment_mode = ENVIRONMENT_MODE_SCENE; @@ -284,6 +286,9 @@ public: void set_bias(float p_bias); float get_bias() const; + void set_texel_scale(float p_multiplier); + float get_texel_scale() const; + void set_max_texture_size(int p_size); int get_max_texture_size() const; diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 94c0a2279a..fa5c8f820d 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -258,7 +258,7 @@ void NavigationRegion3D::bake_navigation_mesh(bool p_on_thread) { void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_navigation_mesh) { if (!Thread::is_main_thread()) { - call_deferred(SNAME("_bake_finished"), p_navigation_mesh); + callable_mp(this, &NavigationRegion3D::_bake_finished).call_deferred(p_navigation_mesh); return; } @@ -308,7 +308,6 @@ void NavigationRegion3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion3D::get_travel_cost); ClassDB::bind_method(D_METHOD("bake_navigation_mesh", "on_thread"), &NavigationRegion3D::bake_navigation_mesh, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("_bake_finished", "navigation_mesh"), &NavigationRegion3D::_bake_finished); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navigation_mesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index cb8279d534..c4d1e6bef7 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -30,7 +30,6 @@ #include "node_3d.h" -#include "core/object/message_queue.h" #include "scene/3d/visual_instance_3d.h" #include "scene/main/viewport.h" #include "scene/property_utils.h" @@ -124,7 +123,7 @@ void Node3D::_propagate_transform_changed(Node3D *p_origin) { get_tree()->xform_change_list.add(&xform_change); } else { // This should very rarely happen, but if it does at least make sure the notification is received eventually. - MessageQueue::get_singleton()->push_callable(callable_mp(this, &Node3D::_propagate_transform_changed_deferred)); + callable_mp(this, &Node3D::_propagate_transform_changed_deferred).call_deferred(); } } _set_dirty_bits(DIRTY_GLOBAL_TRANSFORM); @@ -568,7 +567,7 @@ void Node3D::update_gizmos() { return; } data.gizmos_dirty = true; - MessageQueue::get_singleton()->push_callable(callable_mp(this, &Node3D::_update_gizmos)); + callable_mp(this, &Node3D::_update_gizmos).call_deferred(); #endif } diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 445c1003b5..ec5f8187a9 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -30,7 +30,6 @@ #include "skeleton_3d.h" -#include "core/object/message_queue.h" #include "core/variant/type_info.h" #include "scene/3d/physics_body_3d.h" #include "scene/resources/surface_tool.h" diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index db2c0e1387..3f1878f30f 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -416,8 +416,8 @@ void SoftBody3D::_draw_soft_mesh() { /// Necessary in order to render the mesh correctly (Soft body nodes are in global space) simulation_started = true; - call_deferred(SNAME("set_as_top_level"), true); - call_deferred(SNAME("set_transform"), Transform3D()); + callable_mp((Node3D *)this, &Node3D::set_as_top_level).call_deferred(true); + callable_mp((Node3D *)this, &Node3D::set_transform).call_deferred(Transform3D()); } _update_physics_server(); diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index b8b0d31d45..8e76e75d0e 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -1439,14 +1439,16 @@ PackedStringArray AnimatedSprite3D::get_configuration_warnings() const { } void AnimatedSprite3D::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { - if (p_idx == 0 && p_function == "play" && frames.is_valid()) { - List<StringName> al; - frames->get_animation_list(&al); - for (const StringName &name : al) { - r_options->push_back(String(name).quote()); + if (p_idx == 0 && frames.is_valid()) { + if (p_function == "play" || p_function == "play_backwards" || p_function == "set_animation" || p_function == "set_autoplay") { + List<StringName> al; + frames->get_animation_list(&al); + for (const StringName &name : al) { + r_options->push_back(String(name).quote()); + } } } - Node::get_argument_options(p_function, p_idx, r_options); + SpriteBase3D::get_argument_options(p_function, p_idx, r_options); } #ifndef DISABLE_DEPRECATED diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 33f865382d..503c39ae3e 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -250,7 +250,7 @@ GeometryInstance3D::VisibilityRangeFadeMode GeometryInstance3D::get_visibility_r return visibility_range_fade_mode; } -const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringName p_name) const { +const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringName &p_name) const { StringName *r = instance_shader_parameter_property_remap.getptr(p_name); if (!r) { String s = p_name; diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index ef0f7966e2..59ede26ac1 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -135,7 +135,7 @@ private: GIMode gi_mode = GI_MODE_STATIC; bool ignore_occlusion_culling = false; - const StringName *_instance_uniform_get_remap(const StringName p_name) const; + const StringName *_instance_uniform_get_remap(const StringName &p_name) const; protected: bool _set(const StringName &p_name, const Variant &p_value); diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index c12e78eddc..70e32c1a31 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -58,13 +58,13 @@ void XRCamera3D::_unbind_tracker() { tracker.unref(); } -void XRCamera3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) { +void XRCamera3D::_changed_tracker(const StringName &p_tracker_name, int p_tracker_type) { if (p_tracker_name == tracker_name) { _bind_tracker(); } } -void XRCamera3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) { +void XRCamera3D::_removed_tracker(const StringName &p_tracker_name, int p_tracker_type) { if (p_tracker_name == tracker_name) { _unbind_tracker(); } @@ -258,7 +258,7 @@ void XRNode3D::_validate_property(PropertyInfo &p_property) const { } } -void XRNode3D::set_tracker(const StringName p_tracker_name) { +void XRNode3D::set_tracker(const StringName &p_tracker_name) { if (tracker.is_valid() && tracker->get_tracker_name() == p_tracker_name) { // didn't change return; @@ -282,7 +282,7 @@ StringName XRNode3D::get_tracker() const { return tracker_name; } -void XRNode3D::set_pose_name(const StringName p_pose_name) { +void XRNode3D::set_pose_name(const StringName &p_pose_name) { pose_name = p_pose_name; // Update pose if we are bound to a tracker with a valid pose @@ -363,7 +363,7 @@ void XRNode3D::_unbind_tracker() { } } -void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) { +void XRNode3D::_changed_tracker(const StringName &p_tracker_name, int p_tracker_type) { if (tracker_name == p_tracker_name) { // just in case unref our current tracker _unbind_tracker(); @@ -373,7 +373,7 @@ void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_t } } -void XRNode3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) { +void XRNode3D::_removed_tracker(const StringName &p_tracker_name, int p_tracker_type) { if (tracker_name == p_tracker_name) { // unref our tracker, it's no longer available _unbind_tracker(); diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index 185a6361d3..ad52cf113d 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -50,8 +50,8 @@ protected: void _bind_tracker(); void _unbind_tracker(); - void _changed_tracker(const StringName p_tracker_name, int p_tracker_type); - void _removed_tracker(const StringName p_tracker_name, int p_tracker_type); + void _changed_tracker(const StringName &p_tracker_name, int p_tracker_type); + void _removed_tracker(const StringName &p_tracker_name, int p_tracker_type); void _pose_changed(const Ref<XRPose> &p_pose); public: @@ -87,8 +87,8 @@ protected: virtual void _bind_tracker(); virtual void _unbind_tracker(); - void _changed_tracker(const StringName p_tracker_name, int p_tracker_type); - void _removed_tracker(const StringName p_tracker_name, int p_tracker_type); + void _changed_tracker(const StringName &p_tracker_name, int p_tracker_type); + void _removed_tracker(const StringName &p_tracker_name, int p_tracker_type); void _pose_changed(const Ref<XRPose> &p_pose); void _pose_lost_tracking(const Ref<XRPose> &p_pose); @@ -96,10 +96,10 @@ protected: public: void _validate_property(PropertyInfo &p_property) const; - void set_tracker(const StringName p_tracker_name); + void set_tracker(const StringName &p_tracker_name); StringName get_tracker() const; - void set_pose_name(const StringName p_pose); + void set_pose_name(const StringName &p_pose); StringName get_pose_name() const; bool get_is_active() const; diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index 37c360b8f8..dbec2be0ba 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -332,7 +332,7 @@ void AnimationNodeBlendSpace2D::_queue_auto_triangles() { } trianges_dirty = true; - call_deferred(SNAME("_update_triangles")); + callable_mp(this, &AnimationNodeBlendSpace2D::_update_triangles).call_deferred(); } void AnimationNodeBlendSpace2D::_update_triangles() { @@ -689,8 +689,6 @@ void AnimationNodeBlendSpace2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlendSpace2D::set_use_sync); ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace2D::is_using_sync); - ClassDB::bind_method(D_METHOD("_update_triangles"), &AnimationNodeBlendSpace2D::_update_triangles); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_auto_triangles", "get_auto_triangles"); for (int i = 0; i < MAX_BLEND_POINTS; i++) { diff --git a/scene/animation/animation_mixer.compat.inc b/scene/animation/animation_mixer.compat.inc new file mode 100644 index 0000000000..09c7d7a977 --- /dev/null +++ b/scene/animation/animation_mixer.compat.inc @@ -0,0 +1,44 @@ +/**************************************************************************/ +/* animation_mixer.compat.inc */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef DISABLE_DEPRECATED + +Variant AnimationMixer::_post_process_key_value_bind_compat_86687(const Ref<Animation> &p_anim, int p_track, Variant p_value, Object *p_object, int p_object_idx) { + if (!p_object) { + return Variant(); + } + return _post_process_key_value(p_anim, p_track, p_value, p_object->get_instance_id(), p_object_idx); +} + +void AnimationMixer::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("_post_process_key_value_bind_compat", "animation", "track", "value", "object", "object_idx"), &AnimationMixer::_post_process_key_value_bind_compat_86687); +} + +#endif // DISABLE_DEPRECATED diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index da00d1dd7b..2adb3695a7 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -29,8 +29,12 @@ /**************************************************************************/ #include "animation_mixer.h" +#include "animation_mixer.compat.inc" #include "core/config/engine.h" +#include "scene/3d/mesh_instance_3d.h" +#include "scene/3d/node_3d.h" +#include "scene/3d/skeleton_3d.h" #include "scene/animation/animation_player.h" #include "scene/resources/animation.h" #include "scene/scene_string_names.h" @@ -543,7 +547,7 @@ void AnimationMixer::_clear_caches() { _init_root_motion_cache(); _clear_audio_streams(); _clear_playing_caches(); - for (KeyValue<NodePath, TrackCache *> &K : track_cache) { + for (KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) { memdelete(K.value); } track_cache.clear(); @@ -562,8 +566,9 @@ void AnimationMixer::_clear_audio_streams() { void AnimationMixer::_clear_playing_caches() { for (const TrackCache *E : playing_caches) { - if (ObjectDB::get_instance(E->object_id)) { - E->object->call(SNAME("stop"), true); + Object *t_obj = ObjectDB::get_instance(E->object_id); + if (t_obj) { + t_obj->call(SNAME("stop"), true); } } playing_caches.clear(); @@ -606,23 +611,20 @@ bool AnimationMixer::_update_caches() { Ref<Animation> anim = get_animation(E); for (int i = 0; i < anim->get_track_count(); i++) { NodePath path = anim->track_get_path(i); - Animation::TrackType track_type = anim->track_get_type(i); - - Animation::TrackType track_cache_type = track_type; - if (track_cache_type == Animation::TYPE_POSITION_3D || track_cache_type == Animation::TYPE_ROTATION_3D || track_cache_type == Animation::TYPE_SCALE_3D) { - track_cache_type = Animation::TYPE_POSITION_3D; // Reference them as position3D tracks, even if they modify rotation or scale. - } + Animation::TypeHash thash = anim->track_get_type_hash(i); + Animation::TrackType track_src_type = anim->track_get_type(i); + Animation::TrackType track_cache_type = Animation::get_cache_type(track_src_type); TrackCache *track = nullptr; - if (track_cache.has(path)) { - track = track_cache.get(path); + if (track_cache.has(thash)) { + track = track_cache.get(thash); } // If not valid, delete track. if (track && (track->type != track_cache_type || ObjectDB::get_instance(track->object_id) == nullptr)) { playing_caches.erase(track); memdelete(track); - track_cache.erase(path); + track_cache.erase(thash); track = nullptr; } @@ -636,7 +638,8 @@ bool AnimationMixer::_update_caches() { continue; } - switch (track_type) { + switch (track_src_type) { + case Animation::TYPE_BEZIER: case Animation::TYPE_VALUE: { // If a value track without a key is cached first, the initial value cannot be determined. // It is a corner case, but which may cause problems with blending. @@ -645,16 +648,20 @@ bool AnimationMixer::_update_caches() { TrackCacheValue *track_value = memnew(TrackCacheValue); if (resource.is_valid()) { - track_value->object = resource.ptr(); + track_value->object_id = resource->get_instance_id(); } else { - track_value->object = child; + track_value->object_id = child->get_instance_id(); } - track_value->is_continuous = anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE; - track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE; + if (track_src_type == Animation::TYPE_VALUE) { + track_value->is_continuous = anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE; + track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE; + } else { + track_value->is_continuous = true; + track_value->is_using_angle = false; + } track_value->subpath = leftover_path; - track_value->object_id = track_value->object->get_instance_id(); track = track_value; @@ -663,9 +670,9 @@ bool AnimationMixer::_update_caches() { // If there is a Reset Animation, it takes precedence by overwriting. if (has_reset_anim) { - int rt = reset_anim->find_track(path, track_type); + int rt = reset_anim->find_track(path, track_src_type); if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) { - track_value->init_value = reset_anim->track_get_key_value(rt, 0); + track_value->init_value = track_src_type == Animation::TYPE_VALUE ? reset_anim->track_get_key_value(rt, 0) : (reset_anim->track_get_key_value(rt, 0).operator Array())[0]; } } @@ -684,14 +691,12 @@ bool AnimationMixer::_update_caches() { TrackCacheTransform *track_xform = memnew(TrackCacheTransform); track_xform->type = Animation::TYPE_POSITION_3D; - track_xform->node_3d = node_3d; - track_xform->skeleton = nullptr; track_xform->bone_idx = -1; bool has_rest = false; - if (path.get_subname_count() == 1 && Object::cast_to<Skeleton3D>(node_3d)) { - Skeleton3D *sk = Object::cast_to<Skeleton3D>(node_3d); - track_xform->skeleton = sk; + Skeleton3D *sk = Object::cast_to<Skeleton3D>(node_3d); + if (sk && path.get_subname_count() == 1) { + track_xform->skeleton_id = sk->get_instance_id(); int bone_idx = sk->find_bone(path.get_subname(0)); if (bone_idx != -1) { has_rest = true; @@ -703,12 +708,11 @@ bool AnimationMixer::_update_caches() { } } - track_xform->object = node_3d; - track_xform->object_id = track_xform->object->get_instance_id(); + track_xform->object_id = node_3d->get_instance_id(); track = track_xform; - switch (track_type) { + switch (track_src_type) { case Animation::TYPE_POSITION_3D: { track_xform->loc_used = true; } break; @@ -724,9 +728,9 @@ bool AnimationMixer::_update_caches() { // For non Skeleton3D bone animation. if (has_reset_anim && !has_rest) { - int rt = reset_anim->find_track(path, track_type); + int rt = reset_anim->find_track(path, track_src_type); if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) { - switch (track_type) { + switch (track_src_type) { case Animation::TYPE_POSITION_3D: { track_xform->init_loc = reset_anim->track_get_key_value(rt, 0); } break; @@ -765,15 +769,12 @@ bool AnimationMixer::_update_caches() { TrackCacheBlendShape *track_bshape = memnew(TrackCacheBlendShape); - track_bshape->mesh_3d = mesh_3d; track_bshape->shape_index = blend_shape_idx; - - track_bshape->object = mesh_3d; track_bshape->object_id = mesh_3d->get_instance_id(); track = track_bshape; if (has_reset_anim) { - int rt = reset_anim->find_track(path, track_type); + int rt = reset_anim->find_track(path, track_src_type); if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) { track_bshape->init_value = reset_anim->track_get_key_value(rt, 0); } @@ -784,43 +785,18 @@ bool AnimationMixer::_update_caches() { TrackCacheMethod *track_method = memnew(TrackCacheMethod); if (resource.is_valid()) { - track_method->object = resource.ptr(); + track_method->object_id = resource->get_instance_id(); } else { - track_method->object = child; + track_method->object_id = child->get_instance_id(); } - track_method->object_id = track_method->object->get_instance_id(); - track = track_method; } break; - case Animation::TYPE_BEZIER: { - TrackCacheBezier *track_bezier = memnew(TrackCacheBezier); - - if (resource.is_valid()) { - track_bezier->object = resource.ptr(); - } else { - track_bezier->object = child; - } - - track_bezier->subpath = leftover_path; - track_bezier->object_id = track_bezier->object->get_instance_id(); - - track = track_bezier; - - if (has_reset_anim) { - int rt = reset_anim->find_track(path, track_type); - if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) { - track_bezier->init_value = (reset_anim->track_get_key_value(rt, 0).operator Array())[0]; - } - } - - } break; case Animation::TYPE_AUDIO: { TrackCacheAudio *track_audio = memnew(TrackCacheAudio); - track_audio->object = child; - track_audio->object_id = track_audio->object->get_instance_id(); + track_audio->object_id = child->get_instance_id(); track_audio->audio_stream.instantiate(); track_audio->audio_stream->set_polyphony(audio_max_polyphony); @@ -830,8 +806,7 @@ bool AnimationMixer::_update_caches() { case Animation::TYPE_ANIMATION: { TrackCacheAnimation *track_animation = memnew(TrackCacheAnimation); - track_animation->object = child; - track_animation->object_id = track_animation->object->get_instance_id(); + track_animation->object_id = child->get_instance_id(); track = track_animation; @@ -841,8 +816,8 @@ bool AnimationMixer::_update_caches() { continue; } } - - track_cache[path] = track; + track->path = path; + track_cache[thash] = track; } else if (track_cache_type == Animation::TYPE_POSITION_3D) { TrackCacheTransform *track_xform = static_cast<TrackCacheTransform *>(track); if (track->setup_pass != setup_pass) { @@ -850,7 +825,7 @@ bool AnimationMixer::_update_caches() { track_xform->rot_used = false; track_xform->scale_used = false; } - switch (track_type) { + switch (track_src_type) { case Animation::TYPE_POSITION_3D: { track_xform->loc_used = true; } break; @@ -868,8 +843,13 @@ bool AnimationMixer::_update_caches() { TrackCacheValue *track_value = static_cast<TrackCacheValue *>(track); bool was_continuous = track_value->is_continuous; bool was_using_angle = track_value->is_using_angle; - track_value->is_continuous |= anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE; - track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE; + + if (track_src_type == Animation::TYPE_VALUE) { + track_value->is_continuous |= anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE; + track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE; + } else { + track_value->is_continuous |= true; + } // TODO: Currently, misc type cannot be blended. // In the future, it should have a separate blend weight, just as bool is converted to 0 and 1. @@ -898,27 +878,26 @@ bool AnimationMixer::_update_caches() { } } - List<NodePath> to_delete; + List<Animation::TypeHash> to_delete; - for (const KeyValue<NodePath, TrackCache *> &K : track_cache) { - TrackCache *tc = track_cache[K.key]; - if (tc->setup_pass != setup_pass) { + for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) { + if (K.value->setup_pass != setup_pass) { to_delete.push_back(K.key); } } while (to_delete.front()) { - NodePath np = to_delete.front()->get(); - memdelete(track_cache[np]); - track_cache.erase(np); + Animation::TypeHash thash = to_delete.front()->get(); + memdelete(track_cache[thash]); + track_cache.erase(thash); to_delete.pop_front(); } track_map.clear(); int idx = 0; - for (const KeyValue<NodePath, TrackCache *> &K : track_cache) { - track_map[K.key] = idx; + for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) { + track_map[K.value->path] = idx; idx++; } @@ -944,28 +923,30 @@ void AnimationMixer::_process_animation(double p_delta, bool p_update_only) { clear_animation_instances(); } -Variant AnimationMixer::post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx) { +Variant AnimationMixer::post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx) { Variant res; - if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, const_cast<Object *>(p_object), p_object_idx, res)) { + if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, p_object_id, p_object_sub_idx, res)) { return res; } - return _post_process_key_value(p_anim, p_track, p_value, p_object, p_object_idx); + return _post_process_key_value(p_anim, p_track, p_value, p_object_id, p_object_sub_idx); } -Variant AnimationMixer::_post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx) { - switch (p_anim->track_get_type(p_track)) { +Variant AnimationMixer::_post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx) { #ifndef _3D_DISABLED + switch (p_anim->track_get_type(p_track)) { case Animation::TYPE_POSITION_3D: { - if (p_object_idx >= 0) { - const Skeleton3D *skel = Object::cast_to<Skeleton3D>(p_object); - return Vector3(p_value) * skel->get_motion_scale(); + if (p_object_sub_idx >= 0) { + Skeleton3D *skel = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(p_object_id)); + if (skel) { + return Vector3(p_value) * skel->get_motion_scale(); + } } return p_value; } break; -#endif // _3D_DISABLED default: { } break; } +#endif // _3D_DISABLED return p_value; } @@ -985,7 +966,7 @@ void AnimationMixer::_blend_init() { } // Init all value/transform/blend/bezier tracks that track_cache has. - for (const KeyValue<NodePath, TrackCache *> &K : track_cache) { + for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) { TrackCache *track = K.value; track->total_weight = 0.0; @@ -1011,10 +992,6 @@ void AnimationMixer::_blend_init() { t->value = Animation::cast_to_blendwise(t->init_value); t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0; } break; - case Animation::TYPE_BEZIER: { - TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track); - t->value = t->init_value; - } break; case Animation::TYPE_AUDIO: { TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track); for (KeyValue<ObjectID, PlayingAudioTrackInfo> &L : t->playing_streams) { @@ -1046,12 +1023,12 @@ void AnimationMixer::_blend_calc_total_weight() { if (!a->track_is_enabled(i)) { continue; } - NodePath path = a->track_get_path(i); - if (!track_cache.has(path)) { + Animation::TypeHash thash = a->track_get_type_hash(i); + if (!track_cache.has(thash)) { continue; // No path, but avoid error spamming. } - TrackCache *track = track_cache[path]; - int blend_idx = track_map[path]; + TrackCache *track = track_cache[thash]; + int blend_idx = track_map[track->path]; if (processed_indices.has(blend_idx)) { continue; // There is the case different track type with same path... Is there more faster iterating way than has()? } @@ -1086,13 +1063,13 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (!a->track_is_enabled(i)) { continue; } - NodePath path = a->track_get_path(i); - if (!track_cache.has(path)) { + Animation::TypeHash thash = a->track_get_type_hash(i); + if (!track_cache.has(thash)) { continue; // No path, but avoid error spamming. } - TrackCache *track = track_cache[path]; - ERR_CONTINUE(!track_map.has(path)); - int blend_idx = track_map[path]; + TrackCache *track = track_cache[thash]; + ERR_CONTINUE(!track_map.has(track->path)); + int blend_idx = track_map[track->path]; ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count); real_t blend = blend_idx < track_weights.size() ? track_weights[blend_idx] * weight : weight; if (!deterministic) { @@ -1104,11 +1081,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { blend = blend / track->total_weight; } Animation::TrackType ttype = a->track_get_type(i); - if (ttype != Animation::TYPE_POSITION_3D && ttype != Animation::TYPE_ROTATION_3D && ttype != Animation::TYPE_SCALE_3D && track->type != ttype) { - // Broken animation, but avoid error spamming. - continue; - } - track->root_motion = root_motion_track == path; + track->root_motion = root_motion_track == a->track_get_path(i); switch (ttype) { case Animation::TYPE_POSITION_3D: { #ifndef _3D_DISABLED @@ -1158,9 +1131,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - loc[0] = post_process_key_value(a, i, loc[0], t->object, t->bone_idx); + loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx); a->try_position_track_interpolate(i, (double)a->get_length(), &loc[1]); - loc[1] = post_process_key_value(a, i, loc[1], t->object, t->bone_idx); + loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx); root_motion_cache.loc += (loc[1] - loc[0]) * blend; prev_time = 0; } @@ -1170,9 +1143,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - loc[0] = post_process_key_value(a, i, loc[0], t->object, t->bone_idx); + loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx); a->try_position_track_interpolate(i, 0, &loc[1]); - loc[1] = post_process_key_value(a, i, loc[1], t->object, t->bone_idx); + loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx); root_motion_cache.loc += (loc[1] - loc[0]) * blend; prev_time = (double)a->get_length(); } @@ -1181,9 +1154,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - loc[0] = post_process_key_value(a, i, loc[0], t->object, t->bone_idx); + loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx); a->try_position_track_interpolate(i, time, &loc[1]); - loc[1] = post_process_key_value(a, i, loc[1], t->object, t->bone_idx); + loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx); root_motion_cache.loc += (loc[1] - loc[0]) * blend; prev_time = !backward ? 0 : (double)a->get_length(); } @@ -1193,7 +1166,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - loc = post_process_key_value(a, i, loc, t->object, t->bone_idx); + loc = post_process_key_value(a, i, loc, t->object_id, t->bone_idx); t->loc += (loc - t->init_loc) * blend; } #endif // _3D_DISABLED @@ -1246,9 +1219,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - rot[0] = post_process_key_value(a, i, rot[0], t->object, t->bone_idx); + rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx); a->try_rotation_track_interpolate(i, (double)a->get_length(), &rot[1]); - rot[1] = post_process_key_value(a, i, rot[1], t->object, t->bone_idx); + rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx); root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized(); prev_time = 0; } @@ -1258,7 +1231,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - rot[0] = post_process_key_value(a, i, rot[0], t->object, t->bone_idx); + rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx); a->try_rotation_track_interpolate(i, 0, &rot[1]); root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized(); prev_time = (double)a->get_length(); @@ -1268,9 +1241,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - rot[0] = post_process_key_value(a, i, rot[0], t->object, t->bone_idx); + rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx); a->try_rotation_track_interpolate(i, time, &rot[1]); - rot[1] = post_process_key_value(a, i, rot[1], t->object, t->bone_idx); + rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx); root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized(); prev_time = !backward ? 0 : (double)a->get_length(); } @@ -1280,7 +1253,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - rot = post_process_key_value(a, i, rot, t->object, t->bone_idx); + rot = post_process_key_value(a, i, rot, t->object_id, t->bone_idx); t->rot = (t->rot * Quaternion().slerp(t->init_rot.inverse() * rot, blend)).normalized(); } #endif // _3D_DISABLED @@ -1333,10 +1306,10 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - scale[0] = post_process_key_value(a, i, scale[0], t->object, t->bone_idx); + scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx); a->try_scale_track_interpolate(i, (double)a->get_length(), &scale[1]); root_motion_cache.scale += (scale[1] - scale[0]) * blend; - scale[1] = post_process_key_value(a, i, scale[1], t->object, t->bone_idx); + scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx); prev_time = 0; } } else { @@ -1345,9 +1318,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - scale[0] = post_process_key_value(a, i, scale[0], t->object, t->bone_idx); + scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx); a->try_scale_track_interpolate(i, 0, &scale[1]); - scale[1] = post_process_key_value(a, i, scale[1], t->object, t->bone_idx); + scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx); root_motion_cache.scale += (scale[1] - scale[0]) * blend; prev_time = (double)a->get_length(); } @@ -1356,9 +1329,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - scale[0] = post_process_key_value(a, i, scale[0], t->object, t->bone_idx); + scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx); a->try_scale_track_interpolate(i, time, &scale[1]); - scale[1] = post_process_key_value(a, i, scale[1], t->object, t->bone_idx); + scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx); root_motion_cache.scale += (scale[1] - scale[0]) * blend; prev_time = !backward ? 0 : (double)a->get_length(); } @@ -1368,7 +1341,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - scale = post_process_key_value(a, i, scale, t->object, t->bone_idx); + scale = post_process_key_value(a, i, scale, t->object_id, t->bone_idx); t->scale += (scale - t->init_scale) * blend; } #endif // _3D_DISABLED @@ -1385,18 +1358,19 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - value = post_process_key_value(a, i, value, t->object, t->shape_index); + value = post_process_key_value(a, i, value, t->object_id, t->shape_index); t->value += (value - t->init_value) * blend; #endif // _3D_DISABLED } break; + case Animation::TYPE_BEZIER: case Animation::TYPE_VALUE: { if (Math::is_zero_approx(blend)) { continue; // Nothing to blend. } TrackCacheValue *t = static_cast<TrackCacheValue *>(track); if (t->is_continuous) { - Variant value = a->value_track_interpolate(i, time); - value = post_process_key_value(a, i, value, t->object); + Variant value = ttype == Animation::TYPE_VALUE ? a->value_track_interpolate(i, time) : Variant(a->bezier_track_interpolate(i, time)); + value = post_process_key_value(a, i, value, t->object_id); if (value == Variant()) { continue; } @@ -1436,15 +1410,21 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { continue; } Variant value = a->track_get_key_value(i, idx); - value = post_process_key_value(a, i, value, t->object); - t->object->set_indexed(t->subpath, value); + value = post_process_key_value(a, i, value, t->object_id); + Object *t_obj = ObjectDB::get_instance(t->object_id); + if (t_obj) { + t_obj->set_indexed(t->subpath, value); + } } else { List<int> indices; a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag); for (int &F : indices) { Variant value = a->track_get_key_value(i, F); - value = post_process_key_value(a, i, value, t->object); - t->object->set_indexed(t->subpath, value); + value = post_process_key_value(a, i, value, t->object_id); + Object *t_obj = ObjectDB::get_instance(t->object_id); + if (t_obj) { + t_obj->set_indexed(t->subpath, value); + } } } } @@ -1466,31 +1446,23 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { } StringName method = a->method_track_get_name(i, idx); Vector<Variant> params = a->method_track_get_params(i, idx); - _call_object(t->object, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED); + _call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED); } else { List<int> indices; a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag); for (int &F : indices) { StringName method = a->method_track_get_name(i, F); Vector<Variant> params = a->method_track_get_params(i, F); - _call_object(t->object, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED); + _call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED); } } } break; - case Animation::TYPE_BEZIER: { - if (Math::is_zero_approx(blend)) { - continue; // Nothing to blend. - } - TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track); - real_t bezier = a->bezier_track_interpolate(i, time); - bezier = post_process_key_value(a, i, bezier, t->object); - t->value += (bezier - t->init_value) * blend; - } break; case Animation::TYPE_AUDIO: { // The end of audio should be observed even if the blend value is 0, build up the information and store to the cache for that. TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track); - Node *asp = Object::cast_to<Node>(t->object); - if (!asp) { + Object *t_obj = ObjectDB::get_instance(t->object_id); + Node *asp = t_obj ? Object::cast_to<Node>(t_obj) : nullptr; + if (!t_obj || !asp) { t->playing_streams.clear(); continue; } @@ -1540,22 +1512,22 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (seeked) { start_ofs += time - a->track_get_key_time(i, idx); } - if (t->object->call(SNAME("get_stream")) != t->audio_stream) { - t->object->call(SNAME("set_stream"), t->audio_stream); + if (t_obj->call(SNAME("get_stream")) != t->audio_stream) { + t_obj->call(SNAME("set_stream"), t->audio_stream); t->audio_stream_playback.unref(); if (!playing_audio_stream_players.has(asp)) { playing_audio_stream_players.push_back(asp); } } - if (!t->object->call(SNAME("is_playing"))) { - t->object->call(SNAME("play")); + if (!t_obj->call(SNAME("is_playing"))) { + t_obj->call(SNAME("play")); } - if (!t->object->call(SNAME("has_stream_playback"))) { + if (!t_obj->call(SNAME("has_stream_playback"))) { t->audio_stream_playback.unref(); continue; } if (t->audio_stream_playback.is_null()) { - t->audio_stream_playback = t->object->call(SNAME("get_stream_playback")); + t->audio_stream_playback = t_obj->call(SNAME("get_stream_playback")); } PlayingAudioStreamInfo pasi; pasi.index = t->audio_stream_playback->play_stream(stream, start_ofs); @@ -1573,7 +1545,11 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { continue; } TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track); - AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t->object); + Object *t_obj = ObjectDB::get_instance(t->object_id); + if (!t_obj) { + continue; + } + AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t_obj); if (!player2) { continue; } @@ -1640,7 +1616,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { void AnimationMixer::_blend_apply() { // Finally, set the tracks. - for (const KeyValue<NodePath, TrackCache *> &K : track_cache) { + for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) { TrackCache *track = K.value; if (!deterministic && Math::is_zero_approx(track->total_weight)) { continue; @@ -1657,26 +1633,34 @@ void AnimationMixer::_blend_apply() { root_motion_position_accumulator = t->loc; root_motion_rotation_accumulator = t->rot; root_motion_scale_accumulator = t->scale; - } else if (t->skeleton && t->bone_idx >= 0) { + } else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) { + Skeleton3D *t_skeleton = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(t->skeleton_id)); + if (!t_skeleton) { + return; + } if (t->loc_used) { - t->skeleton->set_bone_pose_position(t->bone_idx, t->loc); + t_skeleton->set_bone_pose_position(t->bone_idx, t->loc); } if (t->rot_used) { - t->skeleton->set_bone_pose_rotation(t->bone_idx, t->rot); + t_skeleton->set_bone_pose_rotation(t->bone_idx, t->rot); } if (t->scale_used) { - t->skeleton->set_bone_pose_scale(t->bone_idx, t->scale); + t_skeleton->set_bone_pose_scale(t->bone_idx, t->scale); } - } else if (!t->skeleton) { + } else if (!t->skeleton_id.is_valid()) { + Node3D *t_node_3d = Object::cast_to<Node3D>(ObjectDB::get_instance(t->object_id)); + if (!t_node_3d) { + return; + } if (t->loc_used) { - t->node_3d->set_position(t->loc); + t_node_3d->set_position(t->loc); } if (t->rot_used) { - t->node_3d->set_rotation(t->rot.get_euler()); + t_node_3d->set_rotation(t->rot.get_euler()); } if (t->scale_used) { - t->node_3d->set_scale(t->scale); + t_node_3d->set_scale(t->scale); } } #endif // _3D_DISABLED @@ -1685,8 +1669,9 @@ void AnimationMixer::_blend_apply() { #ifndef _3D_DISABLED TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track); - if (t->mesh_3d) { - t->mesh_3d->set_blend_shape_value(t->shape_index, t->value); + MeshInstance3D *t_mesh_3d = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(t->object_id)); + if (t_mesh_3d) { + t_mesh_3d->set_blend_shape_value(t->shape_index, t->value); } #endif // _3D_DISABLED } break; @@ -1710,19 +1695,12 @@ void AnimationMixer::_blend_apply() { } } - // t->object isn't safe here, get instance from id (GH-85365). - Object *obj = ObjectDB::get_instance(t->object_id); - if (obj) { - obj->set_indexed(t->subpath, Animation::cast_from_blendwise(t->value, t->init_value.get_type())); + Object *t_obj = ObjectDB::get_instance(t->object_id); + if (t_obj) { + t_obj->set_indexed(t->subpath, Animation::cast_from_blendwise(t->value, t->init_value.get_type())); } } break; - case Animation::TYPE_BEZIER: { - TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track); - - t->object->set_indexed(t->subpath, t->value); - - } break; case Animation::TYPE_AUDIO: { TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track); @@ -1787,7 +1765,7 @@ void AnimationMixer::_blend_apply() { } } -void AnimationMixer::_call_object(Object *p_object, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) { +void AnimationMixer::_call_object(ObjectID p_object_id, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) { // Separate function to use alloca() more efficiently const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * p_params.size()); const Variant *args = p_params.ptr(); @@ -1795,11 +1773,15 @@ void AnimationMixer::_call_object(Object *p_object, const StringName &p_method, for (uint32_t i = 0; i < argcount; i++) { argptrs[i] = &args[i]; } + Object *t_obj = ObjectDB::get_instance(p_object_id); + if (!t_obj) { + return; + } if (p_deferred) { - MessageQueue::get_singleton()->push_callp(p_object, p_method, argptrs, argcount); + Callable(t_obj, p_method).call_deferredp(argptrs, argcount); } else { Callable::CallError ce; - p_object->callp(p_method, argptrs, argcount, ce); + t_obj->callp(p_method, argptrs, argcount, ce); } } @@ -1879,7 +1861,7 @@ bool AnimationMixer::can_apply_reset() const { } void AnimationMixer::_build_backup_track_cache() { - for (const KeyValue<NodePath, TrackCache *> &K : track_cache) { + for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) { TrackCache *track = K.value; track->total_weight = 1.0; switch (track->type) { @@ -1888,25 +1870,33 @@ void AnimationMixer::_build_backup_track_cache() { TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); if (t->root_motion) { // Do nothing. - } else if (t->skeleton && t->bone_idx >= 0) { + } else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) { + Skeleton3D *t_skeleton = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(t->skeleton_id)); + if (!t_skeleton) { + return; + } if (t->loc_used) { - t->loc = t->skeleton->get_bone_pose_position(t->bone_idx); + t->loc = t_skeleton->get_bone_pose_position(t->bone_idx); } if (t->rot_used) { - t->rot = t->skeleton->get_bone_pose_rotation(t->bone_idx); + t->rot = t_skeleton->get_bone_pose_rotation(t->bone_idx); } if (t->scale_used) { - t->scale = t->skeleton->get_bone_pose_scale(t->bone_idx); + t->scale = t_skeleton->get_bone_pose_scale(t->bone_idx); + } + } else if (!t->skeleton_id.is_valid()) { + Node3D *t_node_3d = Object::cast_to<Node3D>(ObjectDB::get_instance(t->object_id)); + if (!t_node_3d) { + return; } - } else if (!t->skeleton) { if (t->loc_used) { - t->loc = t->node_3d->get_position(); + t->loc = t_node_3d->get_position(); } if (t->rot_used) { - t->rot = t->node_3d->get_quaternion(); + t->rot = t_node_3d->get_quaternion(); } if (t->scale_used) { - t->scale = t->node_3d->get_scale(); + t->scale = t_node_3d->get_scale(); } } #endif // _3D_DISABLED @@ -1914,25 +1904,28 @@ void AnimationMixer::_build_backup_track_cache() { case Animation::TYPE_BLEND_SHAPE: { #ifndef _3D_DISABLED TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track); - if (t->mesh_3d) { - t->value = t->mesh_3d->get_blend_shape_value(t->shape_index); + MeshInstance3D *t_mesh_3d = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(t->object_id)); + if (t_mesh_3d) { + t->value = t_mesh_3d->get_blend_shape_value(t->shape_index); } #endif // _3D_DISABLED } break; case Animation::TYPE_VALUE: { TrackCacheValue *t = static_cast<TrackCacheValue *>(track); - t->value = t->object->get_indexed(t->subpath); + Object *t_obj = ObjectDB::get_instance(t->object_id); + if (t_obj) { + t->value = t_obj->get_indexed(t->subpath); + } t->is_continuous = true; } break; - case Animation::TYPE_BEZIER: { - TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track); - t->value = t->object->get_indexed(t->subpath); - } break; case Animation::TYPE_AUDIO: { TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track); - Node *asp = Object::cast_to<Node>(t->object); - if (asp) { - t->object->call(SNAME("set_stream"), Ref<AudioStream>()); + Object *t_obj = ObjectDB::get_instance(t->object_id); + if (t_obj) { + Node *asp = Object::cast_to<Node>(t_obj); + if (asp) { + asp->call(SNAME("set_stream"), Ref<AudioStream>()); + } } } break; default: { @@ -1989,7 +1982,7 @@ void AnimationMixer::restore(const Ref<AnimatedValuesBackup> &p_backup) { ERR_FAIL_COND(p_backup.is_null()); track_cache = p_backup->get_data(); _blend_apply(); - track_cache = HashMap<NodePath, AnimationMixer::TrackCache *>(); + track_cache = HashMap<Animation::TypeHash, AnimationMixer::TrackCache *>(); cache_valid = false; } @@ -2054,6 +2047,26 @@ void AnimationMixer::_notification(int p_what) { } } +void AnimationMixer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { + String pf = p_function; + if (p_idx == 0) { + if (pf == "get_animation" || pf == "has_animation") { + List<StringName> al; + get_animation_list(&al); + for (const StringName &name : al) { + r_options->push_back(String(name).quote()); + } + } else if (pf == "get_animation_library" || pf == "has_animation_library" || pf == "remove_animation_library" || pf == "rename_animation_library") { + List<StringName> al; + get_animation_library_list(&al); + for (const StringName &name : al) { + r_options->push_back(String(name).quote()); + } + } + } + Node::get_argument_options(p_function, p_idx, r_options); +} + void AnimationMixer::_bind_methods() { /* ---- Data lists ---- */ ClassDB::bind_method(D_METHOD("add_animation_library", "name", "library"), &AnimationMixer::add_animation_library); @@ -2100,7 +2113,7 @@ void AnimationMixer::_bind_methods() { /* ---- Blending processor ---- */ ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationMixer::clear_caches); ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationMixer::advance); - GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object", "object_idx"); + GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object_id", "object_sub_idx"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deterministic"), "set_deterministic", "is_deterministic"); @@ -2146,10 +2159,10 @@ AnimationMixer::AnimationMixer() { AnimationMixer::~AnimationMixer() { } -void AnimatedValuesBackup::set_data(const HashMap<NodePath, AnimationMixer::TrackCache *> p_data) { +void AnimatedValuesBackup::set_data(const HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> p_data) { clear_data(); - for (const KeyValue<NodePath, AnimationMixer::TrackCache *> &E : p_data) { + for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : p_data) { AnimationMixer::TrackCache *track = get_cache_copy(E.value); if (!track) { continue; // Some types of tracks do not get a copy and must be ignored. @@ -2159,9 +2172,9 @@ void AnimatedValuesBackup::set_data(const HashMap<NodePath, AnimationMixer::Trac } } -HashMap<NodePath, AnimationMixer::TrackCache *> AnimatedValuesBackup::get_data() const { - HashMap<NodePath, AnimationMixer::TrackCache *> ret; - for (const KeyValue<NodePath, AnimationMixer::TrackCache *> &E : data) { +HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> AnimatedValuesBackup::get_data() const { + HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> ret; + for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : data) { AnimationMixer::TrackCache *track = get_cache_copy(E.value); ERR_CONTINUE(!track); // Backup shouldn't contain tracks that cannot be copied, this is a mistake. @@ -2171,7 +2184,7 @@ HashMap<NodePath, AnimationMixer::TrackCache *> AnimatedValuesBackup::get_data() } void AnimatedValuesBackup::clear_data() { - for (KeyValue<NodePath, AnimationMixer::TrackCache *> &K : data) { + for (KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &K : data) { memdelete(K.value); } data.clear(); @@ -2179,6 +2192,7 @@ void AnimatedValuesBackup::clear_data() { AnimationMixer::TrackCache *AnimatedValuesBackup::get_cache_copy(AnimationMixer::TrackCache *p_cache) const { switch (p_cache->type) { + case Animation::TYPE_BEZIER: case Animation::TYPE_VALUE: { AnimationMixer::TrackCacheValue *src = static_cast<AnimationMixer::TrackCacheValue *>(p_cache); AnimationMixer::TrackCacheValue *tc = memnew(AnimationMixer::TrackCacheValue(*src)); @@ -2199,12 +2213,6 @@ AnimationMixer::TrackCache *AnimatedValuesBackup::get_cache_copy(AnimationMixer: return tc; } - case Animation::TYPE_BEZIER: { - AnimationMixer::TrackCacheBezier *src = static_cast<AnimationMixer::TrackCacheBezier *>(p_cache); - AnimationMixer::TrackCacheBezier *tc = memnew(AnimationMixer::TrackCacheBezier(*src)); - return tc; - } - case Animation::TYPE_AUDIO: { AnimationMixer::TrackCacheAudio *src = static_cast<AnimationMixer::TrackCacheAudio *>(p_cache); AnimationMixer::TrackCacheAudio *tc = memnew(AnimationMixer::TrackCacheAudio(*src)); diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h index 0cd204b384..098c2c3b86 100644 --- a/scene/animation/animation_mixer.h +++ b/scene/animation/animation_mixer.h @@ -31,9 +31,7 @@ #ifndef ANIMATION_MIXER_H #define ANIMATION_MIXER_H -#include "scene/3d/mesh_instance_3d.h" -#include "scene/3d/node_3d.h" -#include "scene/3d/skeleton_3d.h" +#include "scene/main/node.h" #include "scene/resources/animation.h" #include "scene/resources/animation_library.h" #include "scene/resources/audio_stream_polyphonic.h" @@ -138,7 +136,7 @@ protected: bool root_motion = false; uint64_t setup_pass = 0; Animation::TrackType type = Animation::TrackType::TYPE_ANIMATION; - Object *object = nullptr; + NodePath path; ObjectID object_id; real_t total_weight = 0.0; @@ -147,7 +145,6 @@ protected: root_motion(p_other.root_motion), setup_pass(p_other.setup_pass), type(p_other.type), - object(p_other.object), object_id(p_other.object_id), total_weight(p_other.total_weight) {} @@ -156,8 +153,7 @@ protected: struct TrackCacheTransform : public TrackCache { #ifndef _3D_DISABLED - Node3D *node_3d = nullptr; - Skeleton3D *skeleton = nullptr; + ObjectID skeleton_id; #endif // _3D_DISABLED int bone_idx = -1; bool loc_used = false; @@ -173,8 +169,7 @@ protected: TrackCacheTransform(const TrackCacheTransform &p_other) : TrackCache(p_other), #ifndef _3D_DISABLED - node_3d(p_other.node_3d), - skeleton(p_other.skeleton), + skeleton_id(p_other.skeleton_id), #endif bone_idx(p_other.bone_idx), loc_used(p_other.loc_used), @@ -201,14 +196,12 @@ protected: }; struct TrackCacheBlendShape : public TrackCache { - MeshInstance3D *mesh_3d = nullptr; float init_value = 0; float value = 0; int shape_index = -1; TrackCacheBlendShape(const TrackCacheBlendShape &p_other) : TrackCache(p_other), - mesh_3d(p_other.mesh_3d), init_value(p_other.init_value), value(p_other.value), shape_index(p_other.shape_index) {} @@ -247,23 +240,6 @@ protected: ~TrackCacheMethod() {} }; - struct TrackCacheBezier : public TrackCache { - real_t init_value = 0.0; - real_t value = 0.0; - Vector<StringName> subpath; - - TrackCacheBezier(const TrackCacheBezier &p_other) : - TrackCache(p_other), - init_value(p_other.init_value), - value(p_other.value), - subpath(p_other.subpath) {} - - TrackCacheBezier() { - type = Animation::TYPE_BEZIER; - } - ~TrackCacheBezier() {} - }; - // Audio stream information for each audio stream placed on the track. struct PlayingAudioStreamInfo { AudioStreamPlaybackPolyphonic::ID index = -1; // ID retrieved from AudioStreamPlaybackPolyphonic. @@ -309,7 +285,7 @@ protected: }; RootMotionCache root_motion_cache; - HashMap<NodePath, TrackCache *> track_cache; + HashMap<Animation::TypeHash, TrackCache *> track_cache; HashSet<TrackCache *> playing_caches; Vector<Node *> playing_audio_stream_players; @@ -340,6 +316,7 @@ protected: void _get_property_list(List<PropertyInfo> *p_list) const; void _notification(int p_what); virtual void _validate_property(PropertyInfo &p_property) const; + virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; static void _bind_methods(); void _node_removed(Node *p_node); @@ -351,9 +328,9 @@ protected: /* ---- Blending processor ---- */ virtual void _process_animation(double p_delta, bool p_update_only = false); - virtual Variant _post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx = -1); - Variant post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx = -1); - GDVIRTUAL5RC(Variant, _post_process_key_value, Ref<Animation>, int, Variant, Object *, int); + virtual Variant _post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx = -1); + Variant post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx = -1); + GDVIRTUAL5RC(Variant, _post_process_key_value, Ref<Animation>, int, Variant, ObjectID, int); void _blend_init(); virtual bool _blend_pre_process(double p_delta, int p_track_count, const HashMap<NodePath, int> &p_track_map); @@ -361,7 +338,13 @@ protected: void _blend_process(double p_delta, bool p_update_only = false); void _blend_apply(); virtual void _blend_post_process(); - void _call_object(Object *p_object, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred); + void _call_object(ObjectID p_object_id, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred); + +#ifndef DISABLE_DEPRECATED + virtual Variant _post_process_key_value_bind_compat_86687(const Ref<Animation> &p_anim, int p_track, Variant p_value, Object *p_object, int p_object_idx = -1); + + static void _bind_compatibility_methods(); +#endif // DISABLE_DEPRECATED public: /* ---- Data lists ---- */ @@ -443,11 +426,11 @@ public: class AnimatedValuesBackup : public RefCounted { GDCLASS(AnimatedValuesBackup, RefCounted); - HashMap<NodePath, AnimationMixer::TrackCache *> data; + HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> data; public: - void set_data(const HashMap<NodePath, AnimationMixer::TrackCache *> p_data); - HashMap<NodePath, AnimationMixer::TrackCache *> get_data() const; + void set_data(const HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> p_data); + HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> get_data() const; void clear_data(); AnimationMixer::TrackCache *get_cache_copy(AnimationMixer::TrackCache *p_cache) const; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 02b74c9188..b7bed59c00 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -233,7 +233,9 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f pi.delta = delta; pi.seeked = p_seeked; } - pi.is_external_seeking = true; // AnimationPlayer doesn't have internal seeking. + // AnimationPlayer doesn't have internal seeking. + // However, immediately after playback, discrete keys should be retrieved with EXACT mode since behind keys must be ignored at that time. + pi.is_external_seeking = !p_started; pi.looped_flag = looped_flag; pi.weight = p_blend; make_animation_instance(cd.from->name, pi); @@ -665,7 +667,7 @@ void AnimationPlayer::get_argument_options(const StringName &p_function, int p_i r_options->push_back(String(name).quote()); } } - Node::get_argument_options(p_function, p_idx, r_options); + AnimationMixer::get_argument_options(p_function, p_idx, r_options); } void AnimationPlayer::_animation_removed(const StringName &p_name, const StringName &p_library) { diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index da0687dd70..17fbc68973 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -619,7 +619,7 @@ void AnimationTree::_tree_changed() { return; } - call_deferred(SNAME("_update_properties")); + callable_mp(this, &AnimationTree::_update_properties).call_deferred(); properties_dirty = true; } @@ -886,8 +886,6 @@ void AnimationTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_animation_player", "path"), &AnimationTree::set_animation_player); ClassDB::bind_method(D_METHOD("get_animation_player"), &AnimationTree::get_animation_player); - ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode"), "set_tree_root", "get_tree_root"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "advance_expression_base_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node"), "set_advance_expression_base_node", "get_advance_expression_base_node"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player"); diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp index 645850015b..fd520dadd6 100644 --- a/scene/animation/root_motion_view.cpp +++ b/scene/animation/root_motion_view.cpp @@ -28,6 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ +#ifndef _3D_DISABLED + #include "root_motion_view.h" #include "scene/animation/animation_tree.h" @@ -203,3 +205,5 @@ RootMotionView::RootMotionView() { RootMotionView::~RootMotionView() { set_base(RID()); } + +#endif // _3D_DISABLED diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 1d5c1c0ade..9d24595916 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -219,7 +219,7 @@ void ColorPicker::finish_shaders() { } void ColorPicker::set_focus_on_line_edit() { - c_text->call_deferred(SNAME("grab_focus")); + callable_mp((Control *)c_text, &Control::grab_focus).call_deferred(); } void ColorPicker::_update_controls() { @@ -557,6 +557,24 @@ void ColorPicker::_html_submitted(const String &p_html) { } Color new_color = Color::from_string(p_html.strip_edges(), color); + String html_no_prefix = p_html.strip_edges().trim_prefix("#"); + if (html_no_prefix.is_valid_hex_number(false)) { + // Convert invalid HTML color codes that software like Figma supports. + if (html_no_prefix.length() == 1) { + // Turn `#1` into `#111111`. + html_no_prefix = html_no_prefix.repeat(6); + } else if (html_no_prefix.length() == 2) { + // Turn `#12` into `#121212`. + html_no_prefix = html_no_prefix.repeat(3); + } else if (html_no_prefix.length() == 5) { + // Turn `#12345` into `#11223344`. + html_no_prefix = html_no_prefix.left(4); + } else if (html_no_prefix.length() == 7) { + // Turn `#1234567` into `#123456`. + html_no_prefix = html_no_prefix.left(6); + } + } + new_color = Color::from_string(html_no_prefix, new_color); if (!is_editing_alpha()) { new_color.a = color.a; @@ -1046,6 +1064,14 @@ void ColorPicker::_sample_draw() { sample->draw_rect(rect_old, old_color); + if (!old_color.is_equal_approx(color)) { + // Draw a revert indicator to indicate that the old sample can be clicked to revert to this old color. + // Adapt icon color to the background color (taking alpha checkerboard into account) so that it's always visible. + sample->draw_texture(theme_cache.sample_revert, + rect_old.size * 0.5 - theme_cache.sample_revert->get_size() * 0.5, + Math::lerp(0.75f, old_color.get_luminance(), old_color.a) < 0.455 ? Color(1, 1, 1) : (Color(0.01, 0.01, 0.01))); + } + if (old_color.r > 1 || old_color.g > 1 || old_color.b > 1) { // Draw an indicator to denote that the old color is "overbright" and can't be displayed accurately in the preview. sample->draw_texture(theme_cache.overbright_indicator, Point2()); @@ -1744,6 +1770,7 @@ void ColorPicker::_bind_methods() { BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, bar_arrow); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, sample_bg); + BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, sample_revert); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, overbright_indicator); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, picker_cursor); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, color_hue); diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index dc547c8b0c..282926d1ff 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -237,6 +237,7 @@ private: Ref<Texture2D> bar_arrow; Ref<Texture2D> sample_bg; + Ref<Texture2D> sample_revert; Ref<Texture2D> overbright_indicator; Ref<Texture2D> picker_cursor; Ref<Texture2D> color_hue; diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index 4e23db4cae..c6e66c95c6 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -30,7 +30,6 @@ #include "container.h" -#include "core/object/message_queue.h" #include "scene/scene_string_names.h" void Container::_child_minsize_changed() { @@ -138,7 +137,7 @@ void Container::queue_sort() { return; } - MessageQueue::get_singleton()->push_callable(callable_mp(this, &Container::_sort_children)); + callable_mp(this, &Container::_sort_children).call_deferred(); pending_sort = true; } diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 84ca6bac5b..349102fafb 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -33,7 +33,6 @@ #include "container.h" #include "core/config/project_settings.h" #include "core/math/geometry_2d.h" -#include "core/object/message_queue.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/string/print_string.h" @@ -205,7 +204,7 @@ void Control::set_root_layout_direction(int p_root_dir) { void Control::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { ERR_READ_THREAD_GUARD; - Node::get_argument_options(p_function, p_idx, r_options); + CanvasItem::get_argument_options(p_function, p_idx, r_options); if (p_idx == 0) { List<StringName> sn; @@ -1631,7 +1630,7 @@ void Control::update_minimum_size() { } data.updating_last_minimum_size = true; - MessageQueue::get_singleton()->push_callable(callable_mp(this, &Control::_update_minimum_size)); + callable_mp(this, &Control::_update_minimum_size).call_deferred(); } void Control::set_block_minimum_size_adjust(bool p_block) { diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 3e827e76dc..8339d34f83 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -129,7 +129,7 @@ void AcceptDialog::_cancel_pressed() { parent_visible = nullptr; } - call_deferred(SNAME("hide")); + callable_mp((Window *)this, &Window::hide).call_deferred(); emit_signal(SNAME("canceled")); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index d721ee3ec3..5d770c2eb2 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -89,7 +89,7 @@ void FileDialog::set_visible(bool p_visible) { void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter) { if (p_ok) { if (p_files.size() > 0) { - String f = p_files[0]; + const String &f = p_files[0]; if (mode == FILE_MODE_OPEN_FILES) { emit_signal(SNAME("files_selected"), p_files); } else { diff --git a/scene/gui/graph_edit_arranger.cpp b/scene/gui/graph_edit_arranger.cpp index 3f2007f7e0..29c3056b3b 100644 --- a/scene/gui/graph_edit_arranger.cpp +++ b/scene/gui/graph_edit_arranger.cpp @@ -287,13 +287,13 @@ Vector<StringName> GraphEditArranger::_split(const Vector<StringName> &r_layer, return Vector<StringName>(); } - StringName p = r_layer[Math::random(0, r_layer.size() - 1)]; + const StringName &p = r_layer[Math::random(0, r_layer.size() - 1)]; Vector<StringName> left; Vector<StringName> right; for (int i = 0; i < r_layer.size(); i++) { if (p != r_layer[i]) { - StringName q = r_layer[i]; + const StringName &q = r_layer[i]; int cross_pq = r_crossings[p][q]; int cross_qp = r_crossings[q][p]; if (cross_pq > cross_qp) { @@ -326,9 +326,9 @@ void GraphEditArranger::_horizontal_alignment(Dictionary &r_root, Dictionary &r_ for (int j = 0; j < lower_layer.size(); j++) { Vector<Pair<int, StringName>> up; - StringName current_node = lower_layer[j]; + const StringName ¤t_node = lower_layer[j]; for (int k = 0; k < upper_layer.size(); k++) { - StringName adjacent_neighbour = upper_layer[k]; + const StringName &adjacent_neighbour = upper_layer[k]; if (r_upper_neighbours[current_node].has(adjacent_neighbour)) { up.push_back(Pair<int, StringName>(k, adjacent_neighbour)); } @@ -360,12 +360,12 @@ void GraphEditArranger::_crossing_minimisation(HashMap<int, Vector<StringName>> HashMap<StringName, Dictionary> c; for (int j = 0; j < lower_layer.size(); j++) { - StringName p = lower_layer[j]; + const StringName &p = lower_layer[j]; Dictionary d; for (int k = 0; k < lower_layer.size(); k++) { unsigned int crossings = 0; - StringName q = lower_layer[k]; + const StringName &q = lower_layer[k]; if (j != k) { for (int h = 1; h < upper_layer.size(); h++) { @@ -421,7 +421,7 @@ void GraphEditArranger::_calculate_inner_shifts(Dictionary &r_inner_shifts, cons } } -float GraphEditArranger::_calculate_threshold(StringName p_v, StringName p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions) { +float GraphEditArranger::_calculate_threshold(const StringName &p_v, const StringName &p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions) { #define MAX_ORDER 2147483647 #define ORDER(node, layers) \ for (unsigned int i = 0; i < layers.size(); i++) { \ @@ -503,7 +503,7 @@ float GraphEditArranger::_calculate_threshold(StringName p_v, StringName p_w, co return threshold; } -void GraphEditArranger::_place_block(StringName p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions) { +void GraphEditArranger::_place_block(const StringName &p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions) { #define PRED(node, layers) \ for (unsigned int i = 0; i < layers.size(); i++) { \ int index = layers[i].find(node); \ diff --git a/scene/gui/graph_edit_arranger.h b/scene/gui/graph_edit_arranger.h index e79944e5dd..925b58d428 100644 --- a/scene/gui/graph_edit_arranger.h +++ b/scene/gui/graph_edit_arranger.h @@ -54,8 +54,8 @@ class GraphEditArranger : public RefCounted { void _horizontal_alignment(Dictionary &r_root, Dictionary &r_align, const HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours, const HashSet<StringName> &r_selected_nodes); void _crossing_minimisation(HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours); void _calculate_inner_shifts(Dictionary &r_inner_shifts, const Dictionary &r_root, const Dictionary &r_node_names, const Dictionary &r_align, const HashSet<StringName> &r_block_heads, const HashMap<StringName, Pair<int, int>> &r_port_info); - float _calculate_threshold(StringName p_v, StringName p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions); - void _place_block(StringName p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions); + float _calculate_threshold(const StringName &p_v, const StringName &p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions); + void _place_block(const StringName &p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions); public: void arrange_nodes(); diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 3b1c1a153f..1b960a9b62 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -482,6 +482,27 @@ Color GraphNode::get_slot_color_left(int p_slot_index) const { return slot_table[p_slot_index].color_left; } +void GraphNode::set_slot_custom_icon_left(int p_slot_index, const Ref<Texture2D> &p_custom_icon) { + ERR_FAIL_COND_MSG(!slot_table.has(p_slot_index), vformat("Cannot set custom_port_icon_left for the slot with index '%d' because it hasn't been enabled.", p_slot_index)); + + if (slot_table[p_slot_index].custom_port_icon_left == p_custom_icon) { + return; + } + + slot_table[p_slot_index].custom_port_icon_left = p_custom_icon; + queue_redraw(); + port_pos_dirty = true; + + emit_signal(SNAME("slot_updated"), p_slot_index); +} + +Ref<Texture2D> GraphNode::get_slot_custom_icon_left(int p_slot_index) const { + if (!slot_table.has(p_slot_index)) { + return Ref<Texture2D>(); + } + return slot_table[p_slot_index].custom_port_icon_left; +} + bool GraphNode::is_slot_enabled_right(int p_slot_index) const { if (!slot_table.has(p_slot_index)) { return false; @@ -545,6 +566,27 @@ Color GraphNode::get_slot_color_right(int p_slot_index) const { return slot_table[p_slot_index].color_right; } +void GraphNode::set_slot_custom_icon_right(int p_slot_index, const Ref<Texture2D> &p_custom_icon) { + ERR_FAIL_COND_MSG(!slot_table.has(p_slot_index), vformat("Cannot set custom_port_icon_right for the slot with index '%d' because it hasn't been enabled.", p_slot_index)); + + if (slot_table[p_slot_index].custom_port_icon_right == p_custom_icon) { + return; + } + + slot_table[p_slot_index].custom_port_icon_right = p_custom_icon; + queue_redraw(); + port_pos_dirty = true; + + emit_signal(SNAME("slot_updated"), p_slot_index); +} + +Ref<Texture2D> GraphNode::get_slot_custom_icon_right(int p_slot_index) const { + if (!slot_table.has(p_slot_index)) { + return Ref<Texture2D>(); + } + return slot_table[p_slot_index].custom_port_icon_right; +} + bool GraphNode::is_slot_draw_stylebox(int p_slot_index) const { if (!slot_table.has(p_slot_index)) { return false; @@ -797,6 +839,9 @@ void GraphNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_slot_color_left", "slot_index", "color"), &GraphNode::set_slot_color_left); ClassDB::bind_method(D_METHOD("get_slot_color_left", "slot_index"), &GraphNode::get_slot_color_left); + ClassDB::bind_method(D_METHOD("set_slot_custom_icon_left", "slot_index", "custom_icon"), &GraphNode::set_slot_custom_icon_left); + ClassDB::bind_method(D_METHOD("get_slot_custom_icon_left", "slot_index"), &GraphNode::get_slot_custom_icon_left); + ClassDB::bind_method(D_METHOD("is_slot_enabled_right", "slot_index"), &GraphNode::is_slot_enabled_right); ClassDB::bind_method(D_METHOD("set_slot_enabled_right", "slot_index", "enable"), &GraphNode::set_slot_enabled_right); @@ -806,6 +851,9 @@ void GraphNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_slot_color_right", "slot_index", "color"), &GraphNode::set_slot_color_right); ClassDB::bind_method(D_METHOD("get_slot_color_right", "slot_index"), &GraphNode::get_slot_color_right); + ClassDB::bind_method(D_METHOD("set_slot_custom_icon_right", "slot_index", "custom_icon"), &GraphNode::set_slot_custom_icon_right); + ClassDB::bind_method(D_METHOD("get_slot_custom_icon_right", "slot_index"), &GraphNode::get_slot_custom_icon_right); + ClassDB::bind_method(D_METHOD("is_slot_draw_stylebox", "slot_index"), &GraphNode::is_slot_draw_stylebox); ClassDB::bind_method(D_METHOD("set_slot_draw_stylebox", "slot_index", "enable"), &GraphNode::set_slot_draw_stylebox); diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 04ca9e7cb4..a0610b37fb 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -129,6 +129,9 @@ public: void set_slot_color_left(int p_slot_index, const Color &p_color); Color get_slot_color_left(int p_slot_index) const; + void set_slot_custom_icon_left(int p_slot_index, const Ref<Texture2D> &p_custom_icon); + Ref<Texture2D> get_slot_custom_icon_left(int p_slot_index) const; + bool is_slot_enabled_right(int p_slot_index) const; void set_slot_enabled_right(int p_slot_index, bool p_enable); @@ -138,6 +141,9 @@ public: void set_slot_color_right(int p_slot_index, const Color &p_color); Color get_slot_color_right(int p_slot_index) const; + void set_slot_custom_icon_right(int p_slot_index, const Ref<Texture2D> &p_custom_icon); + Ref<Texture2D> get_slot_custom_icon_right(int p_slot_index) const; + bool is_slot_draw_stylebox(int p_slot_index) const; void set_slot_draw_stylebox(int p_slot_index, bool p_enable); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 02d44caa1c..e9d34fae3b 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -44,7 +44,7 @@ void ItemList::_shape_text(int p_idx) { } else { item.text_buf->set_direction((TextServer::Direction)item.text_direction); } - item.text_buf->add_string(item.text, theme_cache.font, theme_cache.font_size, item.language); + item.text_buf->add_string(item.xl_text, theme_cache.font, theme_cache.font_size, item.language); if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) { item.text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_TRIM_EDGE_SPACES); } else { @@ -58,6 +58,7 @@ int ItemList::add_item(const String &p_item, const Ref<Texture2D> &p_texture, bo Item item; item.icon = p_texture; item.text = p_item; + item.xl_text = atr(p_item); item.selectable = p_selectable; items.push_back(item); int item_id = items.size() - 1; @@ -94,6 +95,7 @@ void ItemList::set_item_text(int p_idx, const String &p_text) { } items.write[p_idx].text = p_text; + items.write[p_idx].xl_text = atr(p_text); _shape_text(p_idx); queue_redraw(); shape_changed = true; @@ -1001,7 +1003,6 @@ void ItemList::_notification(int p_what) { } break; case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: - case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_THEME_CHANGED: { for (int i = 0; i < items.size(); i++) { _shape_text(i); @@ -1009,6 +1010,14 @@ void ItemList::_notification(int p_what) { shape_changed = true; queue_redraw(); } break; + case NOTIFICATION_TRANSLATION_CHANGED: { + for (int i = 0; i < items.size(); i++) { + items.write[i].xl_text = atr(items[i].text); + _shape_text(i); + } + shape_changed = true; + queue_redraw(); + } break; case NOTIFICATION_DRAW: { force_update_list_size(); diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 796e0eb687..28f9012058 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -57,6 +57,7 @@ private: Color icon_modulate = Color(1, 1, 1, 1); Ref<Texture2D> tag_icon; String text; + String xl_text; Ref<TextParagraph> text_buf; String language; TextDirection text_direction = TEXT_DIRECTION_AUTO; diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 1b1905e793..56da1332e7 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -813,6 +813,19 @@ Size2 Label::get_minimum_size() const { } } +#ifndef DISABLE_DEPRECATED +bool Label::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == SNAME("valign")) { + set_vertical_alignment((VerticalAlignment)p_value.operator int()); + return true; + } else if (p_name == SNAME("align")) { + set_horizontal_alignment((HorizontalAlignment)p_value.operator int()); + return true; + } + return false; +} +#endif + int Label::get_line_count() const { if (!is_inside_tree()) { return 1; diff --git a/scene/gui/label.h b/scene/gui/label.h index 9306033dd0..4bd0e53605 100644 --- a/scene/gui/label.h +++ b/scene/gui/label.h @@ -91,6 +91,9 @@ private: protected: void _notification(int p_what); static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + bool _set(const StringName &p_name, const Variant &p_value); +#endif public: virtual Size2 get_minimum_size() const override; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 5cca09bcf6..d11c4813b2 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -31,7 +31,6 @@ #include "line_edit.h" #include "core/input/input_map.h" -#include "core/object/message_queue.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/string/print_string.h" @@ -270,7 +269,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { if (!text_changed_dirty) { if (is_inside_tree()) { - MessageQueue::get_singleton()->push_call(this, "_text_changed"); + callable_mp(this, &LineEdit::_text_changed).call_deferred(); } text_changed_dirty = true; } @@ -624,7 +623,12 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { int prev_len = text.length(); insert_text_at_caret(ucodestr); if (text.length() != prev_len) { - _text_changed(); + if (!text_changed_dirty) { + if (is_inside_tree()) { + callable_mp(this, &LineEdit::_text_changed).call_deferred(); + } + text_changed_dirty = true; + } } accept_event(); return; @@ -709,7 +713,7 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) { select(caret_column_tmp, caret_column); if (!text_changed_dirty) { if (is_inside_tree()) { - MessageQueue::get_singleton()->push_call(this, "_text_changed"); + callable_mp(this, &LineEdit::_text_changed).call_deferred(); } text_changed_dirty = true; } @@ -1185,7 +1189,7 @@ void LineEdit::paste_text() { if (!text_changed_dirty) { if (is_inside_tree() && text.length() != prev_len) { - MessageQueue::get_singleton()->push_call(this, "_text_changed"); + callable_mp(this, &LineEdit::_text_changed).call_deferred(); } text_changed_dirty = true; } @@ -1499,7 +1503,7 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) { if (!text_changed_dirty) { if (is_inside_tree()) { - MessageQueue::get_singleton()->push_call(this, "_text_changed"); + callable_mp(this, &LineEdit::_text_changed).call_deferred(); } text_changed_dirty = true; } @@ -1713,6 +1717,12 @@ void LineEdit::set_caret_column(int p_column) { } else if (MAX(primary_caret_offset.x, primary_caret_offset.y) >= ofs_max) { scroll_offset += ofs_max - MAX(primary_caret_offset.x, primary_caret_offset.y); } + + // Scroll to show as much text as possible + if (text_width + scroll_offset + x_ofs < ofs_max) { + scroll_offset = ofs_max - x_ofs - text_width; + } + scroll_offset = MIN(0, scroll_offset); queue_redraw(); @@ -2501,8 +2511,6 @@ void LineEdit::_validate_property(PropertyInfo &p_property) const { } void LineEdit::_bind_methods() { - ClassDB::bind_method(D_METHOD("_text_changed"), &LineEdit::_text_changed); - ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &LineEdit::set_horizontal_alignment); ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &LineEdit::get_horizontal_alignment); diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index f9740b1217..6386bb20c3 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -159,7 +159,7 @@ void OptionButton::_notification(int p_what) { bool OptionButton::_set(const StringName &p_name, const Variant &p_value) { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0] == "popup") { - String property = components[2]; + const String &property = components[2]; if (property != "text" && property != "icon" && property != "id" && property != "disabled" && property != "separator") { return false; } @@ -186,7 +186,7 @@ bool OptionButton::_set(const StringName &p_name, const Variant &p_value) { bool OptionButton::_get(const StringName &p_name, Variant &r_ret) const { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0] == "popup") { - String property = components[2]; + const String &property = components[2]; if (property != "text" && property != "icon" && property != "id" && property != "disabled" && property != "separator") { return false; } diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 8369bedda9..0c5a882044 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -123,7 +123,7 @@ void Popup::_close_pressed() { _deinitialize_visible_parents(); - call_deferred(SNAME("hide")); + callable_mp((Window *)this, &Window::hide).call_deferred(); } void Popup::_post_popup() { diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index d9c633b238..1923322c22 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -42,6 +42,21 @@ HashMap<String, PopupMenu *> PopupMenu::system_menus; +bool PopupMenu::_set_item_accelerator(int p_index, const Ref<InputEventKey> &p_ie) { + DisplayServer *ds = DisplayServer::get_singleton(); + if (p_ie->get_physical_keycode() == Key::NONE && p_ie->get_keycode() == Key::NONE && p_ie->get_key_label() != Key::NONE) { + ds->global_menu_set_item_accelerator(global_menu_name, p_index, p_ie->get_key_label_with_modifiers()); + return true; + } else if (p_ie->get_keycode() != Key::NONE) { + ds->global_menu_set_item_accelerator(global_menu_name, p_index, p_ie->get_keycode_with_modifiers()); + return true; + } else if (p_ie->get_physical_keycode() != Key::NONE) { + ds->global_menu_set_item_accelerator(global_menu_name, p_index, ds->keyboard_get_keycode_from_physical(p_ie->get_physical_keycode_with_modifiers())); + return true; + } + return false; +} + String PopupMenu::bind_global_menu() { #ifdef TOOLS_ENABLED if (is_part_of_edited_scene()) { @@ -76,7 +91,7 @@ String PopupMenu::bind_global_menu() { if (item.separator) { ds->global_menu_add_separator(global_menu_name); } else { - int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), Callable(), i); + int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), item.shortcut_is_global ? callable_mp(this, &PopupMenu::activate_item) : Callable(), i); if (!item.submenu.is_empty()) { PopupMenu *pm = Object::cast_to<PopupMenu>(get_node_or_null(item.submenu)); if (pm) { @@ -101,8 +116,7 @@ String PopupMenu::bind_global_menu() { Array events = item.shortcut->get_events(); for (int j = 0; j < events.size(); j++) { Ref<InputEventKey> ie = events[j]; - if (ie.is_valid()) { - ds->global_menu_set_item_accelerator(global_menu_name, index, ie->get_keycode_with_modifiers()); + if (ie.is_valid() && _set_item_accelerator(index, ie)) { break; } } @@ -273,8 +287,7 @@ int PopupMenu::_get_items_total_height() const { items_total_height += _get_item_height(i) + theme_cache.v_separation; } - // Subtract a separator which is not needed for the last item. - return items_total_height - theme_cache.v_separation; + return items_total_height; } int PopupMenu::_get_mouse_over(const Point2 &p_over) const { @@ -283,14 +296,14 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const { } // Accounts for margin in the margin container - Point2 ofs = theme_cache.panel_style->get_offset() + Point2(0, theme_cache.v_separation / 2); + Point2 ofs = theme_cache.panel_style->get_offset(); if (ofs.y > p_over.y) { return -1; } for (int i = 0; i < items.size(); i++) { - ofs.y += i > 0 ? theme_cache.v_separation : (float)theme_cache.v_separation / 2; + ofs.y += theme_cache.v_separation; ofs.y += _get_item_height(i); @@ -780,9 +793,7 @@ void PopupMenu::_draw_items() { } } - Color icon_color(1, 1, 1, items[i].disabled && !items[i].separator ? 0.5 : 1); - - icon_color *= items[i].icon_modulate; + Color icon_color = items[i].icon_modulate; // For non-separator items, add some padding for the content. if (!items[i].separator) { @@ -1363,13 +1374,12 @@ void PopupMenu::add_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_g if (!global_menu_name.is_empty()) { DisplayServer *ds = DisplayServer::get_singleton(); - int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), Callable(), items.size() - 1); + int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), p_global ? callable_mp(this, &PopupMenu::activate_item) : Callable(), items.size() - 1); if (!item.shortcut_is_disabled && item.shortcut.is_valid() && item.shortcut->has_valid_event()) { Array events = item.shortcut->get_events(); for (int j = 0; j < events.size(); j++) { Ref<InputEventKey> ie = events[j]; - if (ie.is_valid()) { - ds->global_menu_set_item_accelerator(global_menu_name, index, ie->get_keycode_with_modifiers()); + if (ie.is_valid() && _set_item_accelerator(index, ie)) { break; } } @@ -1392,13 +1402,12 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortc if (!global_menu_name.is_empty()) { DisplayServer *ds = DisplayServer::get_singleton(); - int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), Callable(), items.size() - 1); + int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), p_global ? callable_mp(this, &PopupMenu::activate_item) : Callable(), items.size() - 1); if (!item.shortcut_is_disabled && item.shortcut.is_valid() && item.shortcut->has_valid_event()) { Array events = item.shortcut->get_events(); for (int j = 0; j < events.size(); j++) { Ref<InputEventKey> ie = events[j]; - if (ie.is_valid()) { - ds->global_menu_set_item_accelerator(global_menu_name, index, ie->get_keycode_with_modifiers()); + if (ie.is_valid() && _set_item_accelerator(index, ie)) { break; } } @@ -1422,13 +1431,12 @@ void PopupMenu::add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bo if (!global_menu_name.is_empty()) { DisplayServer *ds = DisplayServer::get_singleton(); - int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), Callable(), items.size() - 1); + int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), p_global ? callable_mp(this, &PopupMenu::activate_item) : Callable(), items.size() - 1); if (!item.shortcut_is_disabled && item.shortcut.is_valid() && item.shortcut->has_valid_event()) { Array events = item.shortcut->get_events(); for (int j = 0; j < events.size(); j++) { Ref<InputEventKey> ie = events[j]; - if (ie.is_valid()) { - ds->global_menu_set_item_accelerator(global_menu_name, index, ie->get_keycode_with_modifiers()); + if (ie.is_valid() && _set_item_accelerator(index, ie)) { break; } } @@ -1453,13 +1461,12 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref< if (!global_menu_name.is_empty()) { DisplayServer *ds = DisplayServer::get_singleton(); - int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), Callable(), items.size() - 1); + int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), p_global ? callable_mp(this, &PopupMenu::activate_item) : Callable(), items.size() - 1); if (!item.shortcut_is_disabled && item.shortcut.is_valid() && item.shortcut->has_valid_event()) { Array events = item.shortcut->get_events(); for (int j = 0; j < events.size(); j++) { Ref<InputEventKey> ie = events[j]; - if (ie.is_valid()) { - ds->global_menu_set_item_accelerator(global_menu_name, index, ie->get_keycode_with_modifiers()); + if (ie.is_valid() && _set_item_accelerator(index, ie)) { break; } } @@ -1484,13 +1491,12 @@ void PopupMenu::add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_ if (!global_menu_name.is_empty()) { DisplayServer *ds = DisplayServer::get_singleton(); - int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), Callable(), items.size() - 1); + int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), p_global ? callable_mp(this, &PopupMenu::activate_item) : Callable(), items.size() - 1); if (!item.shortcut_is_disabled && item.shortcut.is_valid() && item.shortcut->has_valid_event()) { Array events = item.shortcut->get_events(); for (int j = 0; j < events.size(); j++) { Ref<InputEventKey> ie = events[j]; - if (ie.is_valid()) { - ds->global_menu_set_item_accelerator(global_menu_name, index, ie->get_keycode_with_modifiers()); + if (ie.is_valid() && _set_item_accelerator(index, ie)) { break; } } @@ -1515,13 +1521,12 @@ void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, cons if (!global_menu_name.is_empty()) { DisplayServer *ds = DisplayServer::get_singleton(); - int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), Callable(), items.size() - 1); + int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), p_global ? callable_mp(this, &PopupMenu::activate_item) : Callable(), items.size() - 1); if (!item.shortcut_is_disabled && item.shortcut.is_valid() && item.shortcut->has_valid_event()) { Array events = item.shortcut->get_events(); for (int j = 0; j < events.size(); j++) { Ref<InputEventKey> ie = events[j]; - if (ie.is_valid()) { - ds->global_menu_set_item_accelerator(global_menu_name, index, ie->get_keycode_with_modifiers()); + if (ie.is_valid() && _set_item_accelerator(index, ie)) { break; } } @@ -2045,11 +2050,15 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bo Array events = items[p_idx].shortcut->get_events(); for (int j = 0; j < events.size(); j++) { Ref<InputEventKey> ie = events[j]; - if (ie.is_valid()) { - ds->global_menu_set_item_accelerator(global_menu_name, p_idx, ie->get_keycode_with_modifiers()); + if (ie.is_valid() && _set_item_accelerator(p_idx, ie)) { break; } } + if (p_global) { + ds->global_menu_set_item_key_callback(global_menu_name, p_idx, callable_mp(this, &PopupMenu::activate_item)); + } else { + ds->global_menu_set_item_key_callback(global_menu_name, p_idx, Callable()); + } } } @@ -2116,8 +2125,7 @@ void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) { Array events = items[p_idx].shortcut->get_events(); for (int j = 0; j < events.size(); j++) { Ref<InputEventKey> ie = events[j]; - if (ie.is_valid()) { - ds->global_menu_set_item_accelerator(global_menu_name, p_idx, ie->get_keycode_with_modifiers()); + if (ie.is_valid() && _set_item_accelerator(p_idx, ie)) { break; } } @@ -2535,7 +2543,7 @@ bool PopupMenu::_set(const StringName &p_name, const Variant &p_value) { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0].begins_with("item_") && components[0].trim_prefix("item_").is_valid_int()) { int item_index = components[0].trim_prefix("item_").to_int(); - String property = components[1]; + const String &property = components[1]; if (property == "text") { set_item_text(item_index, p_value); return true; @@ -2614,7 +2622,7 @@ bool PopupMenu::_get(const StringName &p_name, Variant &r_ret) const { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0].begins_with("item_") && components[0].trim_prefix("item_").is_valid_int()) { int item_index = components[0].trim_prefix("item_").to_int(); - String property = components[1]; + const String &property = components[1]; if (property == "text") { r_ret = get_item_text(item_index); return true; diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index c1ab9544ea..9783f9d57b 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -194,6 +194,7 @@ class PopupMenu : public Popup { void _close_pressed(); void _menu_changed(); void _input_from_window_internal(const Ref<InputEvent> &p_event); + bool _set_item_accelerator(int p_index, const Ref<InputEventKey> &p_ie); protected: virtual void add_child_notify(Node *p_child) override; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index fbc374e89e..c5d1a6cd3c 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -2805,7 +2805,7 @@ void RichTextLabel::_thread_function(void *p_userdata) { set_current_thread_safe_for_nodes(true); _process_line_caches(); updating.store(false); - call_deferred(SNAME("thread_end")); + callable_mp(this, &RichTextLabel::_thread_end).call_deferred(); } void RichTextLabel::_thread_end() { @@ -4532,7 +4532,7 @@ void RichTextLabel::append_text(const String &p_bbcode) { if (subtag_a.size() == 2) { if (subtag_a[0] == "font" || subtag_a[0] == "f") { - String fnt = subtag_a[1]; + const String &fnt = subtag_a[1]; Ref<Font> font = ResourceLoader::load(fnt, "Font"); if (font.is_valid()) { f = font; @@ -4776,7 +4776,7 @@ void RichTextLabel::append_text(const String &p_bbcode) { if (subtag_a.size() == 2) { if (subtag_a[0] == "name" || subtag_a[0] == "n") { - String fnt = subtag_a[1]; + const String &fnt = subtag_a[1]; Ref<Font> font_data = ResourceLoader::load(fnt, "Font"); if (font_data.is_valid()) { font = font_data; @@ -5945,8 +5945,6 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("is_menu_visible"), &RichTextLabel::is_menu_visible); ClassDB::bind_method(D_METHOD("menu_option", "option"), &RichTextLabel::menu_option); - ClassDB::bind_method(D_METHOD("_thread_end"), &RichTextLabel::_thread_end); - #ifndef DISABLE_DEPRECATED ClassDB::bind_compatibility_method(D_METHOD("push_font", "font", "font_size"), &RichTextLabel::push_font); ClassDB::bind_compatibility_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand); diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index b4e28a1f1b..89d308de3f 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -346,7 +346,7 @@ void ScrollContainer::_notification(int p_what) { case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_TRANSLATION_CHANGED: { _updating_scrollbars = true; - call_deferred(SNAME("_update_scrollbar_position")); + callable_mp(this, &ScrollContainer::_update_scrollbar_position).call_deferred(); } break; case NOTIFICATION_READY: { @@ -573,8 +573,6 @@ VScrollBar *ScrollContainer::get_v_scroll_bar() { } void ScrollContainer::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update_scrollbar_position"), &ScrollContainer::_update_scrollbar_position); - ClassDB::bind_method(D_METHOD("set_h_scroll", "value"), &ScrollContainer::set_h_scroll); ClassDB::bind_method(D_METHOD("get_h_scroll"), &ScrollContainer::get_h_scroll); diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index bd549a6e4a..d482495ca0 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -280,8 +280,8 @@ void SpinBox::_notification(int p_what) { } break; case NOTIFICATION_THEME_CHANGED: { - call_deferred(SNAME("update_minimum_size")); - get_line_edit()->call_deferred(SNAME("update_minimum_size")); + callable_mp((Control *)this, &Control::update_minimum_size).call_deferred(); + callable_mp((Control *)get_line_edit(), &Control::update_minimum_size).call_deferred(); } break; case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index e9fbdbb312..c153f8bd7d 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -30,7 +30,6 @@ #include "tab_bar.h" -#include "core/object/message_queue.h" #include "core/string/translation.h" #include "scene/gui/box_container.h" #include "scene/gui/label.h" @@ -516,7 +515,13 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in bool rtl = is_layout_rtl(); Rect2 sb_rect = Rect2(p_x, 0, tabs[p_index].size_cache, get_size().height); + if (tab_style_v_flip) { + draw_set_transform(Point2(0.0, p_tab_style->get_draw_rect(sb_rect).size.y), 0.0, Size2(1.0, -1.0)); + } p_tab_style->draw(ci, sb_rect); + if (tab_style_v_flip) { + draw_set_transform(Point2(), 0.0, Size2(1.0, 1.0)); + } if (p_focus) { Ref<StyleBox> focus_style = theme_cache.tab_focus_style; focus_style->draw(ci, sb_rect); @@ -1367,6 +1372,10 @@ bool TabBar::get_clip_tabs() const { return clip_tabs; } +void TabBar::set_tab_style_v_flip(bool p_tab_style_v_flip) { + tab_style_v_flip = p_tab_style_v_flip; +} + void TabBar::move_tab(int p_from, int p_to) { if (p_from == p_to) { return; @@ -1657,7 +1666,7 @@ bool TabBar::_set(const StringName &p_name, const Variant &p_value) { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0].begins_with("tab_") && components[0].trim_prefix("tab_").is_valid_int()) { int tab_index = components[0].trim_prefix("tab_").to_int(); - String property = components[1]; + const String &property = components[1]; if (property == "title") { set_tab_title(tab_index, p_value); return true; @@ -1676,7 +1685,7 @@ bool TabBar::_get(const StringName &p_name, Variant &r_ret) const { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0].begins_with("tab_") && components[0].trim_prefix("tab_").is_valid_int()) { int tab_index = components[0].trim_prefix("tab_").to_int(); - String property = components[1]; + const String &property = components[1]; if (property == "title") { r_ret = get_tab_title(tab_index); return true; diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h index 28e3411f3d..9674187fb3 100644 --- a/scene/gui/tab_bar.h +++ b/scene/gui/tab_bar.h @@ -91,6 +91,7 @@ private: bool clip_tabs = true; int rb_hover = -1; bool rb_pressing = false; + bool tab_style_v_flip = false; bool select_with_rmb = false; @@ -210,6 +211,8 @@ public: void set_clip_tabs(bool p_clip_tabs); bool get_clip_tabs() const; + void set_tab_style_v_flip(bool p_tab_style_v_flip); + void move_tab(int p_from, int p_to); void set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 0f461f4865..ef01d9ec5d 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -35,7 +35,7 @@ #include "scene/gui/texture_rect.h" #include "scene/theme/theme_db.h" -int TabContainer::_get_top_margin() const { +int TabContainer::_get_tab_height() const { int height = 0; if (tabs_visible && get_tab_count() > 0) { height = tab_bar->get_minimum_size().height; @@ -54,31 +54,33 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) { if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { Point2 pos = mb->get_position(); Size2 size = get_size(); + real_t content_height = size.height - _get_tab_height(); // Click must be on tabs in the tab header area. - if (pos.y > _get_top_margin()) { + if (tabs_position == POSITION_TOP && pos.y > _get_tab_height()) { + return; + } + if (tabs_position == POSITION_BOTTOM && pos.y < content_height) { return; } // Handle menu button. - if (is_layout_rtl()) { - if (popup && pos.x < theme_cache.menu_icon->get_width()) { - emit_signal(SNAME("pre_popup_pressed")); - - Vector2 popup_pos = get_screen_position(); - popup_pos.y += theme_cache.menu_icon->get_height(); - - popup->set_position(popup_pos); - popup->popup(); - return; - } - } else { - if (popup && pos.x > size.width - theme_cache.menu_icon->get_width()) { + if (popup) { + if (is_layout_rtl() ? pos.x < theme_cache.menu_icon->get_width() : pos.x > size.width - theme_cache.menu_icon->get_width()) { emit_signal(SNAME("pre_popup_pressed")); Vector2 popup_pos = get_screen_position(); - popup_pos.x += size.width - popup->get_size().width; - popup_pos.y += theme_cache.menu_icon->get_height(); + if (!is_layout_rtl()) { + popup_pos.x += size.width - popup->get_size().width; + } + popup_pos.y += _get_tab_height() / 2.0; + if (tabs_position == POSITION_BOTTOM) { + popup_pos.y += content_height; + popup_pos.y -= popup->get_size().height; + popup_pos.y -= theme_cache.menu_icon->get_height() / 2.0; + } else { + popup_pos.y += theme_cache.menu_icon->get_height() / 2.0; + } popup->set_position(popup_pos); popup->popup(); @@ -94,7 +96,14 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) { Size2 size = get_size(); // Mouse must be on tabs in the tab header area. - if (pos.y > _get_top_margin()) { + if (tabs_position == POSITION_TOP && pos.y > _get_tab_height()) { + if (menu_hovered) { + menu_hovered = false; + queue_redraw(); + } + return; + } + if (tabs_position == POSITION_BOTTOM && pos.y < size.height - _get_tab_height()) { if (menu_hovered) { menu_hovered = false; queue_redraw(); @@ -165,21 +174,22 @@ void TabContainer::_notification(int p_what) { return; } - int header_height = _get_top_margin(); + int header_height = _get_tab_height(); + int header_voffset = int(tabs_position == POSITION_BOTTOM) * (size.height - header_height); // Draw background for the tabbar. - theme_cache.tabbar_style->draw(canvas, Rect2(0, 0, size.width, header_height)); + theme_cache.tabbar_style->draw(canvas, Rect2(0, header_voffset, size.width, header_height)); // Draw the background for the tab's content. - theme_cache.panel_style->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height)); + theme_cache.panel_style->draw(canvas, Rect2(0, int(tabs_position == POSITION_TOP) * header_height, size.width, size.height - header_height)); // Draw the popup menu. if (get_popup()) { int x = is_layout_rtl() ? 0 : get_size().width - theme_cache.menu_icon->get_width(); if (menu_hovered) { - theme_cache.menu_hl_icon->draw(get_canvas_item(), Point2(x, (header_height - theme_cache.menu_hl_icon->get_height()) / 2)); + theme_cache.menu_hl_icon->draw(get_canvas_item(), Point2(x, header_voffset + (header_height - theme_cache.menu_hl_icon->get_height()) / 2)); } else { - theme_cache.menu_icon->draw(get_canvas_item(), Point2(x, (header_height - theme_cache.menu_icon->get_height()) / 2)); + theme_cache.menu_icon->draw(get_canvas_item(), Point2(x, header_voffset + (header_height - theme_cache.menu_icon->get_height()) / 2)); } } } break; @@ -243,6 +253,12 @@ void TabContainer::_repaint() { Vector<Control *> controls = _get_tab_controls(); int current = get_current_tab(); + if (tabs_position == POSITION_BOTTOM) { + tab_bar->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE); + } else { + tab_bar->set_anchors_and_offsets_preset(PRESET_TOP_WIDE); + } + for (int i = 0; i < controls.size(); i++) { Control *c = controls[i]; @@ -251,7 +267,11 @@ void TabContainer::_repaint() { c->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); if (tabs_visible) { - c->set_offset(SIDE_TOP, _get_top_margin()); + if (tabs_position == POSITION_BOTTOM) { + c->set_offset(SIDE_BOTTOM, -_get_tab_height()); + } else { + c->set_offset(SIDE_TOP, _get_tab_height()); + } } c->set_offset(SIDE_TOP, c->get_offset(SIDE_TOP) + theme_cache.panel_style->get_margin(SIDE_TOP)); @@ -263,6 +283,7 @@ void TabContainer::_repaint() { } } + _update_margins(); update_minimum_size(); } @@ -609,6 +630,23 @@ TabBar::AlignmentMode TabContainer::get_tab_alignment() const { return tab_bar->get_tab_alignment(); } +void TabContainer::set_tabs_position(TabPosition p_tabs_position) { + ERR_FAIL_INDEX(p_tabs_position, POSITION_MAX); + if (p_tabs_position == tabs_position) { + return; + } + tabs_position = p_tabs_position; + + tab_bar->set_tab_style_v_flip(tabs_position == POSITION_BOTTOM); + + callable_mp(this, &TabContainer::_repaint).call_deferred(); + queue_redraw(); +} + +TabContainer::TabPosition TabContainer::get_tabs_position() const { + return tabs_position; +} + void TabContainer::set_tab_focus_mode(Control::FocusMode p_focus_mode) { tab_bar->set_focus_mode(p_focus_mode); } @@ -633,18 +671,8 @@ void TabContainer::set_tabs_visible(bool p_visible) { tabs_visible = p_visible; tab_bar->set_visible(tabs_visible); - Vector<Control *> controls = _get_tab_controls(); - for (int i = 0; i < controls.size(); i++) { - Control *c = controls[i]; - if (tabs_visible) { - c->set_offset(SIDE_TOP, _get_top_margin()); - } else { - c->set_offset(SIDE_TOP, 0); - } - } - + callable_mp(this, &TabContainer::_repaint).call_deferred(); queue_redraw(); - update_minimum_size(); } bool TabContainer::are_tabs_visible() const { @@ -890,6 +918,8 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tab_control", "tab_idx"), &TabContainer::get_tab_control); ClassDB::bind_method(D_METHOD("set_tab_alignment", "alignment"), &TabContainer::set_tab_alignment); ClassDB::bind_method(D_METHOD("get_tab_alignment"), &TabContainer::get_tab_alignment); + ClassDB::bind_method(D_METHOD("set_tabs_position", "tabs_position"), &TabContainer::set_tabs_position); + ClassDB::bind_method(D_METHOD("get_tabs_position"), &TabContainer::get_tabs_position); ClassDB::bind_method(D_METHOD("set_clip_tabs", "clip_tabs"), &TabContainer::set_clip_tabs); ClassDB::bind_method(D_METHOD("get_clip_tabs"), &TabContainer::get_clip_tabs); ClassDB::bind_method(D_METHOD("set_tabs_visible", "visible"), &TabContainer::set_tabs_visible); @@ -931,6 +961,7 @@ void TabContainer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_alignment", "get_tab_alignment"); ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1"), "set_current_tab", "get_current_tab"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "tabs_position", PROPERTY_HINT_ENUM, "Top,Bottom"), "set_tabs_position", "get_tabs_position"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_tabs"), "set_clip_tabs", "get_clip_tabs"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_visible"), "set_tabs_visible", "are_tabs_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "all_tabs_in_front"), "set_all_tabs_in_front", "is_all_tabs_in_front"); @@ -939,6 +970,10 @@ void TabContainer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hidden_tabs_for_min_size"), "set_use_hidden_tabs_for_min_size", "get_use_hidden_tabs_for_min_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_tab_focus_mode", "get_tab_focus_mode"); + BIND_ENUM_CONSTANT(POSITION_TOP); + BIND_ENUM_CONSTANT(POSITION_BOTTOM); + BIND_ENUM_CONSTANT(POSITION_MAX); + BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, TabContainer, side_margin); BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabContainer, panel_style, "panel"); diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index 450143cd0c..0c645b4598 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -38,9 +38,18 @@ class TabContainer : public Container { GDCLASS(TabContainer, Container); +public: + enum TabPosition { + POSITION_TOP, + POSITION_BOTTOM, + POSITION_MAX, + }; + +private: TabBar *tab_bar = nullptr; bool tabs_visible = true; bool all_tabs_in_front = false; + TabPosition tabs_position = POSITION_TOP; bool menu_hovered = false; mutable ObjectID popup_obj_id; bool use_hidden_tabs_for_min_size = false; @@ -86,7 +95,7 @@ class TabContainer : public Container { int tab_font_size; } theme_cache; - int _get_top_margin() const; + int _get_tab_height() const; Vector<Control *> _get_tab_controls() const; void _on_theme_changed(); void _repaint(); @@ -124,6 +133,9 @@ public: void set_tab_alignment(TabBar::AlignmentMode p_alignment); TabBar::AlignmentMode get_tab_alignment() const; + void set_tabs_position(TabPosition p_tab_position); + TabPosition get_tabs_position() const; + void set_tab_focus_mode(FocusMode p_focus_mode); FocusMode get_tab_focus_mode() const; @@ -185,4 +197,6 @@ public: TabContainer(); }; +VARIANT_ENUM_CAST(TabContainer::TabPosition); + #endif // TAB_CONTAINER_H diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index cd1450b879..540c999131 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -33,7 +33,6 @@ #include "core/config/project_settings.h" #include "core/input/input.h" #include "core/input/input_map.h" -#include "core/object/message_queue.h" #include "core/object/script_language.h" #include "core/os/keyboard.h" #include "core/os/os.h" @@ -428,10 +427,10 @@ void TextEdit::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { _update_caches(); if (caret_pos_dirty) { - MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed"); + callable_mp(this, &TextEdit::_emit_caret_changed).call_deferred(); } if (text_changed_dirty) { - MessageQueue::get_singleton()->push_call(this, "_text_changed_emit"); + callable_mp(this, &TextEdit::_text_changed_emit).call_deferred(); } _update_wrap_at_column(true); } break; @@ -443,8 +442,8 @@ void TextEdit::_notification(int p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { if (is_visible()) { - call_deferred(SNAME("_update_scrollbars")); - call_deferred(SNAME("_update_wrap_at_column")); + callable_mp(this, &TextEdit::_update_scrollbars).call_deferred(); + callable_mp(this, &TextEdit::_update_wrap_at_column).call_deferred(false); } } break; @@ -989,18 +988,6 @@ void TextEdit::_notification(int p_what) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); } } - - // Give visual indication of empty selected line. - for (int c = 0; c < carets.size(); c++) { - if (has_selection(c) && line >= get_selection_from_line(c) && line <= get_selection_to_line(c) && char_margin >= xmargin_beg) { - float char_w = theme_cache.font->get_char_size(' ', theme_cache.font_size).width; - if (rtl) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - xmargin_beg - ofs_x - char_w, ofs_y, char_w, row_height), theme_cache.selection_color); - } else { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, row_height), theme_cache.selection_color); - } - } - } } else { // If it has text, then draw current line marker in the margin, as line number etc will draw over it, draw the rest of line marker later. if (caret_line_wrap_index_map.has(line) && caret_line_wrap_index_map[line].has(line_wrap_index) && highlight_current_line) { @@ -1093,13 +1080,26 @@ void TextEdit::_notification(int p_what) { char_margin = size.width - char_margin - TS->shaped_text_get_size(rid).x; } + // Draw selections. + float char_w = theme_cache.font->get_char_size(' ', theme_cache.font_size).width; for (int c = 0; c < carets.size(); c++) { - if (!clipped && has_selection(c) && line >= get_selection_from_line(c) && line <= get_selection_to_line(c)) { // Selection + if (!clipped && has_selection(c) && line >= get_selection_from_line(c) && line <= get_selection_to_line(c)) { int sel_from = (line > get_selection_from_line(c)) ? TS->shaped_text_get_range(rid).x : get_selection_from_column(c); int sel_to = (line < get_selection_to_line(c)) ? TS->shaped_text_get_range(rid).y : get_selection_to_column(c); Vector<Vector2> sel = TS->shaped_text_get_selection(rid, sel_from, sel_to); + + // Show selection at the end of line. + if (line < get_selection_to_line(c)) { + if (rtl) { + sel.push_back(Vector2(-char_w, 0)); + } else { + float line_end = TS->shaped_text_get_size(rid).width; + sel.push_back(Vector2(line_end, line_end + char_w)); + } + } + for (int j = 0; j < sel.size(); j++) { - Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, row_height); + Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, Math::ceil(sel[j].y - sel[j].x), row_height); if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) { continue; } @@ -4007,7 +4007,7 @@ void TextEdit::undo() { if (dirty_carets && !caret_pos_dirty) { if (is_inside_tree()) { - MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed"); + callable_mp(this, &TextEdit::_emit_caret_changed).call_deferred(); } caret_pos_dirty = true; } @@ -4062,7 +4062,7 @@ void TextEdit::redo() { if (dirty_carets && !caret_pos_dirty) { if (is_inside_tree()) { - MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed"); + callable_mp(this, &TextEdit::_emit_caret_changed).call_deferred(); } caret_pos_dirty = true; } @@ -4868,7 +4868,7 @@ void TextEdit::set_caret_line(int p_line, bool p_adjust_viewport, bool p_can_be_ if (caret_moved && !caret_pos_dirty) { if (is_inside_tree()) { - MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed"); + callable_mp(this, &TextEdit::_emit_caret_changed).call_deferred(); } caret_pos_dirty = true; } @@ -4899,7 +4899,7 @@ void TextEdit::set_caret_column(int p_col, bool p_adjust_viewport, int p_caret) if (caret_moved && !caret_pos_dirty) { if (is_inside_tree()) { - MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed"); + callable_mp(this, &TextEdit::_emit_caret_changed).call_deferred(); } caret_pos_dirty = true; } @@ -6026,10 +6026,6 @@ Color TextEdit::get_font_color() const { } void TextEdit::_bind_methods() { - /* Internal. */ - - ClassDB::bind_method(D_METHOD("_text_changed_emit"), &TextEdit::_text_changed_emit); - /* Text */ // Text properties ClassDB::bind_method(D_METHOD("has_ime_text"), &TextEdit::has_ime_text); @@ -6200,9 +6196,6 @@ void TextEdit::_bind_methods() { BIND_ENUM_CONSTANT(CARET_TYPE_LINE); BIND_ENUM_CONSTANT(CARET_TYPE_BLOCK); - // Internal. - ClassDB::bind_method(D_METHOD("_emit_caret_changed"), &TextEdit::_emit_caret_changed); - ClassDB::bind_method(D_METHOD("set_caret_type", "type"), &TextEdit::set_caret_type); ClassDB::bind_method(D_METHOD("get_caret_type"), &TextEdit::get_caret_type); @@ -6290,9 +6283,6 @@ void TextEdit::_bind_methods() { BIND_ENUM_CONSTANT(LINE_WRAPPING_NONE); BIND_ENUM_CONSTANT(LINE_WRAPPING_BOUNDARY); - // Internal. - ClassDB::bind_method(D_METHOD("_update_wrap_at_column", "force"), &TextEdit::_update_wrap_at_column, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("set_line_wrapping_mode", "mode"), &TextEdit::set_line_wrapping_mode); ClassDB::bind_method(D_METHOD("get_line_wrapping_mode"), &TextEdit::get_line_wrapping_mode); @@ -7826,7 +7816,7 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i if (!text_changed_dirty && !setting_text) { if (is_inside_tree()) { - MessageQueue::get_singleton()->push_call(this, "_text_changed_emit"); + callable_mp(this, &TextEdit::_text_changed_emit).call_deferred(); } text_changed_dirty = true; } @@ -7872,7 +7862,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li if (!text_changed_dirty && !setting_text) { if (is_inside_tree()) { - MessageQueue::get_singleton()->push_call(this, "_text_changed_emit"); + callable_mp(this, &TextEdit::_text_changed_emit).call_deferred(); } text_changed_dirty = true; } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 6936bcb441..c67c3cd98d 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -4784,7 +4784,7 @@ void Tree::ensure_cursor_is_visible() { if (cell_h > screen_h) { // Screen size is too small, maybe it was not resized yet. v_scroll->set_value(y_offset); } else if (y_offset + cell_h > v_scroll->get_value() + screen_h) { - v_scroll->call_deferred(SNAME("set_value"), y_offset - screen_h + cell_h); + callable_mp((Range *)v_scroll, &Range::set_value).call_deferred(y_offset - screen_h + cell_h); } else if (y_offset < v_scroll->get_value()) { v_scroll->set_value(y_offset); } @@ -4802,7 +4802,7 @@ void Tree::ensure_cursor_is_visible() { if (cell_w > screen_w) { h_scroll->set_value(x_offset); } else if (x_offset + cell_w > h_scroll->get_value() + screen_w) { - h_scroll->call_deferred(SNAME("set_value"), x_offset - screen_w + cell_w); + callable_mp((Range *)h_scroll, &Range::set_value).call_deferred(x_offset - screen_w + cell_w); } else if (x_offset < h_scroll->get_value()) { h_scroll->set_value(x_offset); } diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 4ee81e5cb0..a35ee17868 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -30,7 +30,6 @@ #include "canvas_item.h" -#include "core/object/message_queue.h" #include "scene/2d/canvas_group.h" #include "scene/main/canvas_layer.h" #include "scene/main/window.h" @@ -407,7 +406,7 @@ void CanvasItem::queue_redraw() { pending_update = true; - MessageQueue::get_singleton()->push_callable(callable_mp(this, &CanvasItem::_redraw_callback)); + callable_mp(this, &CanvasItem::_redraw_callback).call_deferred(); } void CanvasItem::move_to_front() { @@ -904,7 +903,7 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) { get_tree()->xform_change_list.add(&p_node->xform_change); } else { // Should be rare, but still needs to be handled. - MessageQueue::get_singleton()->push_callable(callable_mp(p_node, &CanvasItem::_notify_transform_deferred)); + callable_mp(p_node, &CanvasItem::_notify_transform_deferred).call_deferred(); } } } diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index ddc694f894..1972e62659 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -472,7 +472,7 @@ bool HTTPRequest::_update_connection() { } 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); + callable_mp(this, &HTTPRequest::_request_done).call_deferred(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) { @@ -621,8 +621,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("_request_done"), &HTTPRequest::_request_done); - ClassDB::bind_method(D_METHOD("set_timeout", "timeout"), &HTTPRequest::set_timeout); ClassDB::bind_method(D_METHOD("get_timeout"), &HTTPRequest::get_timeout); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 3cb06e769f..a6b7ca8188 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1736,8 +1736,40 @@ void Node::reparent(Node *p_parent, bool p_keep_global_transform) { return; } + bool preserve_owner = data.owner && (data.owner == p_parent || data.owner->is_ancestor_of(p_parent)); + Node *owner_temp = data.owner; + LocalVector<Node *> common_parents; + + // If the new parent is related to the owner, find all children of the reparented node who have the same owner so that we can reassign them. + if (preserve_owner) { + LocalVector<Node *> to_visit; + + to_visit.push_back(this); + common_parents.push_back(this); + + while (to_visit.size() > 0) { + Node *check = to_visit[to_visit.size() - 1]; + to_visit.resize(to_visit.size() - 1); + + for (int i = 0; i < check->get_child_count(); i++) { + Node *child = check->get_child(i, false); + to_visit.push_back(child); + if (child->data.owner == owner_temp) { + common_parents.push_back(child); + } + } + } + } + data.parent->remove_child(this); p_parent->add_child(this); + + // Reassign the old owner to those found nodes. + if (preserve_owner) { + for (Node *E : common_parents) { + E->set_owner(owner_temp); + } + } } Node *Node::get_parent() const { @@ -1925,7 +1957,7 @@ void Node::set_owner(Node *p_owner) { return; } - Node *check = this->get_parent(); + Node *check = get_parent(); bool owner_valid = false; while (check) { @@ -2311,11 +2343,7 @@ void Node::set_editor_description(const String &p_editor_description) { } data.editor_description = p_editor_description; - - if (Engine::get_singleton()->is_editor_hint() && is_inside_tree()) { - // Update tree so the tooltip in the Scene tree dock is also updated in the editor. - get_tree()->tree_changed(); - } + emit_signal(SNAME("editor_description_changed"), this); } String Node::get_editor_description() const { @@ -2832,7 +2860,7 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) { } Node *parent = data.parent; - int index_in_parent = get_index(); + int index_in_parent = get_index(false); if (data.parent) { parent->remove_child(this); @@ -3069,7 +3097,7 @@ static void _add_nodes_to_options(const Node *p_base, const Node *p_node, List<S void Node::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { String pf = p_function; - if (p_idx == 0 && (pf == "has_node" || pf == "get_node")) { + if (p_idx == 0 && (pf == "has_node" || pf == "get_node" || pf == "get_node_or_null")) { _add_nodes_to_options(this, this, r_options); } else if (p_idx == 0 && (pf == "add_to_group" || pf == "remove_from_group" || pf == "is_in_group")) { HashMap<StringName, String> global_groups = ProjectSettings::get_singleton()->get_global_groups_list(); @@ -3536,6 +3564,7 @@ void Node::_bind_methods() { ADD_SIGNAL(MethodInfo("child_order_changed")); ADD_SIGNAL(MethodInfo("replacing_by", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT, "Node"))); + ADD_SIGNAL(MethodInfo("editor_description_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT, "Node"))); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_name", "get_name"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "unique_name_in_owner", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_unique_name_in_owner", "is_unique_name_in_owner"); diff --git a/scene/main/node.h b/scene/main/node.h index cd1c31d784..8130c61a34 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -558,7 +558,9 @@ public: _FORCE_INLINE_ bool is_readable_from_caller_thread() const { if (current_process_thread_group == nullptr) { // No thread processing. - return is_current_thread_safe_for_nodes(); + // Only accessible if node is outside the scene tree + // or access will happen from a node-safe thread. + return !data.inside_tree || is_current_thread_safe_for_nodes(); } else { // Thread processing. return true; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index b6fbd70e14..ee0e7721a0 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1728,6 +1728,7 @@ void SceneTree::get_argument_options(const StringName &p_function, int p_idx, Li } } } + MainLoop::get_argument_options(p_function, p_idx, r_options); } void SceneTree::set_disable_node_threading(bool p_disable) { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 89ec5636ab..fe02d97586 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -32,7 +32,6 @@ #include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" -#include "core/object/message_queue.h" #include "core/string/translation.h" #include "core/templates/pair.h" #include "core/templates/sort_array.h" @@ -1054,7 +1053,7 @@ void Viewport::canvas_parent_mark_dirty(Node *p_node) { bool request_update = gui.canvas_parents_with_dirty_order.is_empty(); gui.canvas_parents_with_dirty_order.insert(p_node->get_instance_id()); if (request_update) { - MessageQueue::get_singleton()->push_callable(callable_mp(this, &Viewport::_process_dirty_canvas_parent_orders)); + callable_mp(this, &Viewport::_process_dirty_canvas_parent_orders).call_deferred(); } } @@ -2073,7 +2072,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Window *w = Object::cast_to<Window>(ObjectDB::get_instance(object_under)); if (w) { viewport_under = w; - viewport_pos = screen_mouse_pos - w->get_position(); + viewport_pos = w->get_final_transform().affine_inverse().xform(screen_mouse_pos - w->get_position()); } } } @@ -2700,7 +2699,7 @@ void Viewport::_cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paus void Viewport::_gui_grab_click_focus(Control *p_control) { gui.mouse_click_grabber = p_control; - call_deferred(SNAME("_post_gui_grab_click_focus")); + callable_mp(this, &Viewport::_post_gui_grab_click_focus).call_deferred(); } void Viewport::_post_gui_grab_click_focus() { @@ -2748,7 +2747,7 @@ void Viewport::_post_gui_grab_click_focus() { mb->set_button_index(MouseButton(i + 1)); mb->set_pressed(true); mb->set_device(InputEvent::DEVICE_ID_INTERNAL); - MessageQueue::get_singleton()->push_callable(callable_mp(gui.mouse_focus, &Control::_call_gui_input), mb); + callable_mp(gui.mouse_focus, &Control::_call_gui_input).call_deferred(mb); } } } @@ -3853,7 +3852,66 @@ Viewport *Viewport::get_parent_viewport() const { void Viewport::set_embedding_subwindows(bool p_embed) { ERR_THREAD_GUARD; - gui.embed_subwindows_hint = p_embed; + if (gui.embed_subwindows_hint == p_embed) { + return; + } + + bool allow_change = true; + + if (!is_inside_tree()) { + // Change can happen since no child window is displayed. + } else if (gui.embed_subwindows_hint) { + if (!gui.sub_windows.is_empty()) { + // Prevent change when this viewport has embedded windows. + allow_change = false; + } + } else { + Viewport *vp = this; + while (true) { + if (!vp->get_parent()) { + // Root window reached. + break; + } + vp = vp->get_parent()->get_viewport(); + if (vp->is_embedding_subwindows()) { + for (int i = 0; i < vp->gui.sub_windows.size(); i++) { + if (is_ancestor_of(vp->gui.sub_windows[i].window)) { + // Prevent change when this viewport has child windows that are displayed in an ancestor viewport. + allow_change = false; + break; + } + } + } + } + + if (allow_change) { + Vector<int> wl = DisplayServer::get_singleton()->get_window_list(); + for (int index = 0; index < wl.size(); index++) { + DisplayServer::WindowID wid = wl[index]; + if (wid == DisplayServer::INVALID_WINDOW_ID) { + continue; + } + + ObjectID woid = DisplayServer::get_singleton()->window_get_attached_instance_id(wid); + if (woid.is_null()) { + continue; + } + + Window *w = Object::cast_to<Window>(ObjectDB::get_instance(woid)); + if (w && is_ancestor_of(w)) { + // Prevent change when this viewport has child windows that are displayed as native windows. + allow_change = false; + break; + } + } + } + } + + if (allow_change) { + gui.embed_subwindows_hint = p_embed; + } else { + WARN_PRINT("Can't change \"gui_embed_subwindows\" while a child window is displayed. Consider hiding all child windows before changing this value."); + } } bool Viewport::is_embedding_subwindows() const { @@ -4568,7 +4626,6 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled); ClassDB::bind_method(D_METHOD("_gui_remove_focus_for_window"), &Viewport::_gui_remove_focus_for_window); - ClassDB::bind_method(D_METHOD("_post_gui_grab_click_focus"), &Viewport::_post_gui_grab_click_focus); ClassDB::bind_method(D_METHOD("set_positional_shadow_atlas_size", "size"), &Viewport::set_positional_shadow_atlas_size); ClassDB::bind_method(D_METHOD("get_positional_shadow_atlas_size"), &Viewport::get_positional_shadow_atlas_size); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index eb431445ed..70b70b8928 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -520,15 +520,12 @@ void Window::request_attention() { } } +#ifndef DISABLE_DEPRECATED void Window::move_to_foreground() { - ERR_MAIN_THREAD_GUARD; - if (embedder) { - embedder->_sub_window_grab_focus(this); - - } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { - DisplayServer::get_singleton()->window_move_to_foreground(window_id); - } + WARN_DEPRECATED_MSG(R"*(The "move_to_foreground()" method is deprecated, use "grab_focus()" instead.)*"); + grab_focus(); } +#endif // DISABLE_DEPRECATED bool Window::can_draw() const { ERR_READ_THREAD_GUARD_V(false); @@ -573,6 +570,10 @@ bool Window::is_in_edited_scene_root() const { void Window::_make_window() { ERR_FAIL_COND(window_id != DisplayServer::INVALID_WINDOW_ID); + if (transient && transient_to_focused) { + _make_transient(); + } + uint32_t f = 0; for (int i = 0; i < FLAG_MAX; i++) { if (flags[i]) { @@ -665,6 +666,10 @@ void Window::_clear_window() { _update_viewport_size(); RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); + + if (transient && transient_to_focused) { + _clear_transient(); + } } void Window::_rect_changed_callback(const Rect2i &p_callback) { @@ -864,18 +869,29 @@ void Window::_make_transient() { return; } //find transient parent - Viewport *vp = get_parent()->get_viewport(); + Window *window = nullptr; - while (vp) { - window = Object::cast_to<Window>(vp); - if (window) { - break; - } - if (!vp->get_parent()) { - break; + + if (!is_embedded() && transient_to_focused) { + DisplayServer::WindowID focused_window_id = DisplayServer::get_singleton()->get_focused_window(); + if (focused_window_id != DisplayServer::INVALID_WINDOW_ID) { + window = Object::cast_to<Window>(ObjectDB::get_instance(DisplayServer::get_singleton()->window_get_attached_instance_id(focused_window_id))); } + } - vp = vp->get_parent()->get_viewport(); + if (!window) { + Viewport *vp = get_parent()->get_viewport(); + while (vp) { + window = Object::cast_to<Window>(vp); + if (window) { + break; + } + if (!vp->get_parent()) { + break; + } + + vp = vp->get_parent()->get_viewport(); + } } if (window) { @@ -919,17 +935,32 @@ void Window::set_transient(bool p_transient) { } if (transient) { - _make_transient(); + if (!transient_to_focused) { + _make_transient(); + } } else { _clear_transient(); } } bool Window::is_transient() const { - ERR_READ_THREAD_GUARD_V(false); return transient; } +void Window::set_transient_to_focused(bool p_transient_to_focused) { + ERR_MAIN_THREAD_GUARD; + if (transient_to_focused == p_transient_to_focused) { + return; + } + + transient_to_focused = p_transient_to_focused; +} + +bool Window::is_transient_to_focused() const { + ERR_READ_THREAD_GUARD_V(false); + return transient_to_focused; +} + void Window::set_exclusive(bool p_exclusive) { ERR_MAIN_THREAD_GUARD; if (exclusive == p_exclusive) { @@ -1160,7 +1191,10 @@ void Window::_update_viewport_size() { } } - notification(NOTIFICATION_WM_SIZE_CHANGED); + if (old_size != size) { + old_size = size; + notification(NOTIFICATION_WM_SIZE_CHANGED); + } if (embedder) { embedder->_sub_window_update(this); @@ -1259,7 +1293,7 @@ void Window::_notification(int p_what) { } } - if (transient) { + if (transient && !transient_to_focused) { _make_transient(); } if (visible) { @@ -1513,7 +1547,7 @@ void Window::child_controls_changed() { } updating_child_controls = true; - call_deferred(SNAME("_update_child_controls")); + callable_mp(this, &Window::_update_child_controls).call_deferred(); } void Window::_update_child_controls() { @@ -1994,7 +2028,7 @@ void Window::_update_theme_item_cache() { // Updating without a delay can cause a lot of lag. if (!wrap_controls) { updating_embedded_window = true; - call_deferred(SNAME("_update_embedded_window")); + callable_mp(this, &Window::_update_embedded_window).call_deferred(); } else { child_controls_changed(); } @@ -2742,7 +2776,9 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("request_attention"), &Window::request_attention); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("move_to_foreground"), &Window::move_to_foreground); +#endif // DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Window::set_visible); ClassDB::bind_method(D_METHOD("is_visible"), &Window::is_visible); @@ -2753,6 +2789,9 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transient", "transient"), &Window::set_transient); ClassDB::bind_method(D_METHOD("is_transient"), &Window::is_transient); + ClassDB::bind_method(D_METHOD("set_transient_to_focused", "enable"), &Window::set_transient_to_focused); + ClassDB::bind_method(D_METHOD("is_transient_to_focused"), &Window::is_transient_to_focused); + ClassDB::bind_method(D_METHOD("set_exclusive", "exclusive"), &Window::set_exclusive); ClassDB::bind_method(D_METHOD("is_exclusive"), &Window::is_exclusive); @@ -2797,9 +2836,6 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("is_wrapping_controls"), &Window::is_wrapping_controls); ClassDB::bind_method(D_METHOD("child_controls_changed"), &Window::child_controls_changed); - ClassDB::bind_method(D_METHOD("_update_child_controls"), &Window::_update_child_controls); - ClassDB::bind_method(D_METHOD("_update_embedded_window"), &Window::_update_embedded_window); - ClassDB::bind_method(D_METHOD("set_theme", "theme"), &Window::set_theme); ClassDB::bind_method(D_METHOD("get_theme"), &Window::get_theme); @@ -2884,6 +2920,7 @@ void Window::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_controls"), "set_wrap_controls", "is_wrapping_controls"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transient"), "set_transient", "is_transient"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transient_to_focused"), "set_transient_to_focused", "is_transient_to_focused"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclusive"), "set_exclusive", "is_exclusive"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unresizable"), "set_flag", "get_flag", FLAG_RESIZE_DISABLED); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "borderless"), "set_flag", "get_flag", FLAG_BORDERLESS); diff --git a/scene/main/window.h b/scene/main/window.h index 0682abc3c7..4ae535848a 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -117,6 +117,7 @@ private: mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE); mutable Size2i min_size; mutable Size2i max_size; + mutable Size2i old_size = size; mutable Vector<Vector2> mpath; mutable Mode mode = MODE_WINDOWED; mutable bool flags[FLAG_MAX] = {}; @@ -126,6 +127,7 @@ private: bool use_font_oversampling = false; bool transient = false; + bool transient_to_focused = false; bool exclusive = false; bool wrap_controls = false; bool updating_child_controls = false; @@ -300,7 +302,9 @@ public: bool is_maximize_allowed() const; void request_attention(); +#ifndef DISABLE_DEPRECATED void move_to_foreground(); +#endif // DISABLE_DEPRECATED virtual void set_visible(bool p_visible); bool is_visible() const; @@ -313,6 +317,9 @@ public: void set_transient(bool p_transient); bool is_transient() const; + void set_transient_to_focused(bool p_transient_to_focused); + bool is_transient_to_focused() const; + void set_exclusive(bool p_exclusive); bool is_exclusive() const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index baaa78f9f2..111d6447a0 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -78,7 +78,6 @@ #include "scene/animation/animation_node_state_machine.h" #include "scene/animation/animation_player.h" #include "scene/animation/animation_tree.h" -#include "scene/animation/root_motion_view.h" #include "scene/animation/tween.h" #include "scene/audio/audio_stream_player.h" #include "scene/debugger/scene_debugger.h" @@ -273,6 +272,7 @@ #include "scene/3d/voxel_gi.h" #include "scene/3d/world_environment.h" #include "scene/3d/xr_nodes.h" +#include "scene/animation/root_motion_view.h" #include "scene/resources/environment.h" #include "scene/resources/fog_material.h" #include "scene/resources/importer_mesh.h" diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 52850cac4a..e503c79bed 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -979,6 +979,7 @@ Animation::TrackType Animation::track_get_type(int p_track) const { void Animation::track_set_path(int p_track, const NodePath &p_path) { ERR_FAIL_INDEX(p_track, tracks.size()); tracks[p_track]->path = p_path; + _track_update_hash(p_track); emit_changed(); } @@ -996,6 +997,27 @@ int Animation::find_track(const NodePath &p_path, const TrackType p_type) const return -1; }; +Animation::TrackType Animation::get_cache_type(TrackType p_type) { + if (p_type == Animation::TYPE_BEZIER) { + return Animation::TYPE_VALUE; + } + if (p_type == Animation::TYPE_ROTATION_3D || p_type == Animation::TYPE_SCALE_3D) { + return Animation::TYPE_POSITION_3D; // Reference them as position3D tracks, even if they modify rotation or scale. + } + return p_type; +} + +void Animation::_track_update_hash(int p_track) { + NodePath track_path = tracks[p_track]->path; + TrackType track_cache_type = get_cache_type(tracks[p_track]->type); + tracks[p_track]->thash = StringName(String(track_path.get_concatenated_names()) + String(track_path.get_concatenated_subnames()) + itos(track_cache_type)).hash(); +} + +Animation::TypeHash Animation::track_get_type_hash(int p_track) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); + return tracks[p_track]->thash; +} + void Animation::track_set_interpolation_type(int p_track, InterpolationType p_interp) { ERR_FAIL_INDEX(p_track, tracks.size()); tracks[p_track]->interpolation = p_interp; @@ -2394,79 +2416,7 @@ Quaternion Animation::_cubic_interpolate_in_time(const Quaternion &p_pre_a, cons } Variant Animation::_cubic_interpolate_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const { - Variant::Type type_a = p_a.get_type(); - Variant::Type type_b = p_b.get_type(); - Variant::Type type_pa = p_pre_a.get_type(); - Variant::Type type_pb = p_post_b.get_type(); - - //make int and real play along - - uint32_t vformat = 1 << type_a; - vformat |= 1 << type_b; - vformat |= 1 << type_pa; - vformat |= 1 << type_pb; - - if (vformat == ((1 << Variant::INT) | (1 << Variant::FLOAT)) || vformat == (1 << Variant::FLOAT)) { - //mix of real and int - real_t a = p_a; - real_t b = p_b; - real_t pa = p_pre_a; - real_t pb = p_post_b; - - return Math::cubic_interpolate_in_time(a, b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t); - } else if ((vformat & (vformat - 1))) { - return p_a; //can't interpolate, mix of types - } - - switch (type_a) { - case Variant::VECTOR2: { - Vector2 a = p_a; - Vector2 b = p_b; - Vector2 pa = p_pre_a; - Vector2 pb = p_post_b; - - return a.cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t); - } - case Variant::RECT2: { - Rect2 a = p_a; - Rect2 b = p_b; - Rect2 pa = p_pre_a; - Rect2 pb = p_post_b; - - return Rect2( - a.position.cubic_interpolate_in_time(b.position, pa.position, pb.position, p_c, p_b_t, p_pre_a_t, p_post_b_t), - a.size.cubic_interpolate_in_time(b.size, pa.size, pb.size, p_c, p_b_t, p_pre_a_t, p_post_b_t)); - } - case Variant::VECTOR3: { - Vector3 a = p_a; - Vector3 b = p_b; - Vector3 pa = p_pre_a; - Vector3 pb = p_post_b; - - return a.cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t); - } - case Variant::QUATERNION: { - Quaternion a = p_a; - Quaternion b = p_b; - Quaternion pa = p_pre_a; - Quaternion pb = p_post_b; - - return a.spherical_cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t); - } - case Variant::AABB: { - AABB a = p_a; - AABB b = p_b; - AABB pa = p_pre_a; - AABB pb = p_post_b; - - return AABB( - a.position.cubic_interpolate_in_time(b.position, pa.position, pb.position, p_c, p_b_t, p_pre_a_t, p_post_b_t), - a.size.cubic_interpolate_in_time(b.size, pa.size, pb.size, p_c, p_b_t, p_pre_a_t, p_post_b_t)); - } - default: { - return _interpolate(p_a, p_b, p_c); - } - } + return cubic_interpolate_in_time_variant(p_pre_a, p_a, p_b, p_post_b, p_c, p_pre_a_t, p_b_t, p_post_b_t); } real_t Animation::_cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const { @@ -2489,7 +2439,7 @@ Variant Animation::_cubic_interpolate_angle_in_time(const Variant &p_pre_a, cons real_t pb = p_post_b; return Math::fposmod((float)Math::cubic_interpolate_angle_in_time(a, b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t), (float)Math_TAU); } - return _interpolate(p_a, p_b, p_c); + return _cubic_interpolate_in_time(p_pre_a, p_a, p_b, p_post_b, p_c, p_pre_a_t, p_b_t, p_post_b_t); } template <class T> @@ -5972,8 +5922,7 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float return Variant(); } break; case Variant::FLOAT: { - const double va = a.operator double(); - return va + ((b.operator double()) - va) * c; + return Math::lerp(a.operator double(), b.operator double(), (double)c); } break; case Variant::VECTOR2: { return (a.operator Vector2()).lerp(b.operator Vector2(), c); @@ -5992,7 +5941,7 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float 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); + return Plane(pa.normal.lerp(pb.normal, c), Math::lerp((double)pa.d, (double)pb.d, (double)c)); } break; case Variant::COLOR: { return (a.operator Color()).lerp(b.operator Color(), c); @@ -6102,6 +6051,194 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float return c < 0.5 ? a : b; } +Variant Animation::cubic_interpolate_in_time_variant(const Variant &pre_a, const Variant &a, const Variant &b, const Variant &post_b, float c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t, bool p_snap_array_element) { + if (pre_a.get_type() != a.get_type() || pre_a.get_type() != b.get_type() || pre_a.get_type() != post_b.get_type()) { + if (pre_a.is_num() && a.is_num() && b.is_num() && post_b.is_num()) { + return cubic_interpolate_in_time_variant(cast_to_blendwise(pre_a), cast_to_blendwise(a), cast_to_blendwise(b), cast_to_blendwise(post_b), c, p_pre_a_t, p_b_t, p_post_b_t, p_snap_array_element); + } else if (!a.is_array()) { + return a; + } + } + + switch (a.get_type()) { + case Variant::NIL: { + return Variant(); + } break; + case Variant::FLOAT: { + return Math::cubic_interpolate_in_time(a.operator double(), b.operator double(), pre_a.operator double(), post_b.operator double(), (double)c, (double)p_pre_a_t, (double)p_b_t, (double)p_post_b_t); + } break; + case Variant::VECTOR2: { + return (a.operator Vector2()).cubic_interpolate_in_time(b.operator Vector2(), pre_a.operator Vector2(), post_b.operator Vector2(), c, p_b_t, p_pre_a_t, p_post_b_t); + } break; + case Variant::RECT2: { + const Rect2 rpa = pre_a.operator Rect2(); + const Rect2 ra = a.operator Rect2(); + const Rect2 rb = b.operator Rect2(); + const Rect2 rpb = post_b.operator Rect2(); + return Rect2( + ra.position.cubic_interpolate_in_time(rb.position, rpa.position, rpb.position, c, p_b_t, p_pre_a_t, p_post_b_t), + ra.size.cubic_interpolate_in_time(rb.size, rpa.size, rpb.size, c, p_b_t, p_pre_a_t, p_post_b_t)); + } break; + case Variant::VECTOR3: { + return (a.operator Vector3()).cubic_interpolate_in_time(b.operator Vector3(), pre_a.operator Vector3(), post_b.operator Vector3(), c, p_b_t, p_pre_a_t, p_post_b_t); + } break; + case Variant::VECTOR4: { + return (a.operator Vector4()).cubic_interpolate_in_time(b.operator Vector4(), pre_a.operator Vector4(), post_b.operator Vector4(), c, p_b_t, p_pre_a_t, p_post_b_t); + } break; + case Variant::PLANE: { + const Plane ppa = pre_a.operator Plane(); + const Plane pa = a.operator Plane(); + const Plane pb = b.operator Plane(); + const Plane ppb = post_b.operator Plane(); + return Plane( + pa.normal.cubic_interpolate_in_time(pb.normal, ppa.normal, ppb.normal, c, p_b_t, p_pre_a_t, p_post_b_t), + Math::cubic_interpolate_in_time((double)pa.d, (double)pb.d, (double)ppa.d, (double)ppb.d, (double)c, (double)p_b_t, (double)p_pre_a_t, (double)p_post_b_t)); + } break; + case Variant::COLOR: { + const Color cpa = pre_a.operator Color(); + const Color ca = a.operator Color(); + const Color cb = b.operator Color(); + const Color cpb = post_b.operator Color(); + return Color( + Math::cubic_interpolate_in_time((double)ca.r, (double)cb.r, (double)cpa.r, (double)cpb.r, (double)c, (double)p_pre_a_t, (double)p_b_t, (double)p_post_b_t), + Math::cubic_interpolate_in_time((double)ca.g, (double)cb.g, (double)cpa.g, (double)cpb.g, (double)c, (double)p_pre_a_t, (double)p_b_t, (double)p_post_b_t), + Math::cubic_interpolate_in_time((double)ca.b, (double)cb.b, (double)cpa.b, (double)cpb.b, (double)c, (double)p_pre_a_t, (double)p_b_t, (double)p_post_b_t), + Math::cubic_interpolate_in_time((double)ca.a, (double)cb.a, (double)cpa.a, (double)cpb.a, (double)c, (double)p_pre_a_t, (double)p_b_t, (double)p_post_b_t)); + } break; + case Variant::AABB: { + const ::AABB apa = pre_a.operator ::AABB(); + const ::AABB aa = a.operator ::AABB(); + const ::AABB ab = b.operator ::AABB(); + const ::AABB apb = post_b.operator ::AABB(); + return AABB( + aa.position.cubic_interpolate_in_time(ab.position, apa.position, apb.position, c, p_b_t, p_pre_a_t, p_post_b_t), + aa.size.cubic_interpolate_in_time(ab.size, apa.size, apb.size, c, p_b_t, p_pre_a_t, p_post_b_t)); + } break; + case Variant::BASIS: { + const Basis bpa = pre_a.operator Basis(); + const Basis ba = a.operator Basis(); + const Basis bb = b.operator Basis(); + const Basis bpb = post_b.operator Basis(); + return Basis( + ba.rows[0].cubic_interpolate_in_time(bb.rows[0], bpa.rows[0], bpb.rows[0], c, p_pre_a_t, p_b_t, p_post_b_t), + ba.rows[1].cubic_interpolate_in_time(bb.rows[1], bpa.rows[1], bpb.rows[1], c, p_pre_a_t, p_b_t, p_post_b_t), + ba.rows[2].cubic_interpolate_in_time(bb.rows[2], bpa.rows[2], bpb.rows[2], c, p_pre_a_t, p_b_t, p_post_b_t)); + } break; + case Variant::QUATERNION: { + return (a.operator Quaternion()).spherical_cubic_interpolate_in_time(b.operator Quaternion(), pre_a.operator Quaternion(), post_b.operator Quaternion(), c, p_b_t, p_pre_a_t, p_post_b_t); + } break; + case Variant::TRANSFORM2D: { + const Transform2D tpa = pre_a.operator Transform2D(); + const Transform2D ta = a.operator Transform2D(); + const Transform2D tb = b.operator Transform2D(); + const Transform2D tpb = post_b.operator Transform2D(); + // TODO: May cause unintended skew, we needs spherical_cubic_interpolate_in_time() for angle and Transform2D::cubic_interpolate_with(). + return Transform2D( + ta[0].cubic_interpolate_in_time(tb[0], tpa[0], tpb[0], c, p_pre_a_t, p_b_t, p_post_b_t), + ta[1].cubic_interpolate_in_time(tb[1], tpa[1], tpb[1], c, p_pre_a_t, p_b_t, p_post_b_t), + ta[2].cubic_interpolate_in_time(tb[2], tpa[2], tpb[2], c, p_pre_a_t, p_b_t, p_post_b_t)); + } break; + case Variant::TRANSFORM3D: { + const Transform3D tpa = pre_a.operator Transform3D(); + const Transform3D ta = a.operator Transform3D(); + const Transform3D tb = b.operator Transform3D(); + const Transform3D tpb = post_b.operator Transform3D(); + // TODO: May cause unintended skew, we needs Transform3D::cubic_interpolate_with(). + return Transform3D( + ta.basis.rows[0].cubic_interpolate_in_time(tb.basis.rows[0], tpa.basis.rows[0], tpb.basis.rows[0], c, p_pre_a_t, p_b_t, p_post_b_t), + ta.basis.rows[1].cubic_interpolate_in_time(tb.basis.rows[1], tpa.basis.rows[1], tpb.basis.rows[1], c, p_pre_a_t, p_b_t, p_post_b_t), + ta.basis.rows[2].cubic_interpolate_in_time(tb.basis.rows[2], tpa.basis.rows[2], tpb.basis.rows[2], c, p_pre_a_t, p_b_t, p_post_b_t), + ta.origin.cubic_interpolate_in_time(tb.origin, tpa.origin, tpb.origin, c, p_pre_a_t, p_b_t, p_post_b_t)); + } break; + case Variant::BOOL: + case Variant::INT: + case Variant::RECT2I: + case Variant::VECTOR2I: + case Variant::VECTOR3I: + case Variant::VECTOR4I: + case Variant::PACKED_INT32_ARRAY: + case Variant::PACKED_INT64_ARRAY: { + // Fallback the interpolatable value which needs casting. + return cast_from_blendwise(cubic_interpolate_in_time_variant(cast_to_blendwise(pre_a), cast_to_blendwise(a), cast_to_blendwise(b), cast_to_blendwise(post_b), c, p_pre_a_t, p_b_t, p_post_b_t, p_snap_array_element), a.get_type()); + } break; + case Variant::STRING: + case Variant::STRING_NAME: { + // TODO: + // String interpolation works on both the character array size and the character code, to apply cubic interpolation neatly, + // we need to figure out how to interpolate well in cases where there are fewer than 4 keys. So, for now, fallback to linear interpolation. + return interpolate_variant(a, b, c); + } break; + case Variant::PACKED_BYTE_ARRAY: { + // Skip. + } break; + default: { + if (a.is_array()) { + const Array arr_pa = pre_a.operator Array(); + const Array arr_a = a.operator Array(); + const Array arr_b = b.operator Array(); + const Array arr_pb = post_b.operator Array(); + + int min_size = arr_a.size(); + int max_size = arr_b.size(); + bool is_a_larger = inform_variant_array(min_size, max_size); + + Array result; + result.set_typed(MAX(arr_a.get_typed_builtin(), arr_b.get_typed_builtin()), StringName(), Variant()); + result.resize(min_size); + + if (min_size == 0 && max_size == 0) { + return result; + } + + Variant vz; + if (is_a_larger) { + vz = arr_a[0]; + } else { + vz = arr_b[0]; + } + vz.zero(); + Variant pre_last = arr_pa.size() ? arr_pa[arr_pa.size() - 1] : vz; + Variant post_last = arr_pb.size() ? arr_pb[arr_pb.size() - 1] : vz; + + int i = 0; + for (; i < min_size; i++) { + result[i] = cubic_interpolate_in_time_variant(i >= arr_pa.size() ? pre_last : arr_pa[i], arr_a[i], arr_b[i], i >= arr_pb.size() ? post_last : arr_pb[i], c, p_pre_a_t, p_b_t, p_post_b_t); + } + if (min_size != max_size) { + // Process with last element of the lesser array. + // This is pretty funny and bizarre, but artists like to use it for polygon animation. + Variant lesser_last = vz; + if (is_a_larger && !Math::is_equal_approx(c, 1.0f)) { + result.resize(max_size); + if (p_snap_array_element) { + c = 0; + } + if (i > 0) { + lesser_last = arr_b[i - 1]; + } + for (; i < max_size; i++) { + result[i] = cubic_interpolate_in_time_variant(i >= arr_pa.size() ? pre_last : arr_pa[i], arr_a[i], lesser_last, i >= arr_pb.size() ? post_last : arr_pb[i], c, p_pre_a_t, p_b_t, p_post_b_t); + } + } else if (!is_a_larger && !Math::is_zero_approx(c)) { + result.resize(max_size); + if (p_snap_array_element) { + c = 1; + } + if (i > 0) { + lesser_last = arr_a[i - 1]; + } + for (; i < max_size; i++) { + result[i] = cubic_interpolate_in_time_variant(i >= arr_pa.size() ? pre_last : arr_pa[i], lesser_last, arr_b[i], i >= arr_pb.size() ? post_last : arr_pb[i], c, p_pre_a_t, p_b_t, p_post_b_t); + } + } + } + return result; + } + } break; + } + return c < 0.5 ? a : b; +} + bool Animation::inform_variant_array(int &r_min, int &r_max) { if (r_min <= r_max) { return false; diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 2579b6c8ce..6c31bbcd29 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -41,6 +41,8 @@ class Animation : public Resource { RES_BASE_EXTENSION("anim"); public: + typedef uint32_t TypeHash; + enum TrackType { TYPE_VALUE, ///< Set a value in a property, can be interpolated. TYPE_POSITION_3D, ///< Position 3D track @@ -104,7 +106,8 @@ private: TrackType type = TrackType::TYPE_ANIMATION; InterpolationType interpolation = INTERPOLATION_LINEAR; bool loop_wrap = true; - NodePath path; // path to something + NodePath path; // Path to something. + TypeHash thash = 0; // Hash by Path + SubPath + TrackType. bool imported = false; bool enabled = true; Track() {} @@ -268,6 +271,8 @@ private: real_t step = 0.1; LoopMode loop_mode = LOOP_NONE; + void _track_update_hash(int p_track); + /* Animation compression page format (version 1): * * Animation uses bitwidth based compression separated into small pages. The intention is that pages fit easily in the cache, so decoding is cache efficient. @@ -386,6 +391,8 @@ public: NodePath track_get_path(int p_track) const; int find_track(const NodePath &p_path, const TrackType p_type) const; + TypeHash track_get_type_hash(int p_track) const; + void track_move_up(int p_track); void track_move_down(int p_track); void track_move_to(int p_track, int p_to_index); @@ -502,6 +509,9 @@ public: 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, bool p_snap_array_element = false); + static Variant cubic_interpolate_in_time_variant(const Variant &pre_a, const Variant &a, const Variant &b, const Variant &post_b, float c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t, bool p_snap_array_element = false); + + static TrackType get_cache_type(TrackType p_type); Animation(); ~Animation(); diff --git a/scene/resources/animation_library.cpp b/scene/resources/animation_library.cpp index 436bf88ec9..fac72a3150 100644 --- a/scene/resources/animation_library.cpp +++ b/scene/resources/animation_library.cpp @@ -143,6 +143,18 @@ Dictionary AnimationLibrary::_get_data() const { return ret; } +void AnimationLibrary::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { + String pf = p_function; + if (p_idx == 0 && (pf == "get_animation" || pf == "has_animation" || pf == "rename_animation" || pf == "remove_animation")) { + List<StringName> names; + get_animation_list(&names); + for (const StringName &E : names) { + r_options->push_back(E.operator String().quote()); + } + } + Resource::get_argument_options(p_function, p_idx, r_options); +} + void AnimationLibrary::_bind_methods() { ClassDB::bind_method(D_METHOD("add_animation", "name", "animation"), &AnimationLibrary::add_animation); ClassDB::bind_method(D_METHOD("remove_animation", "name"), &AnimationLibrary::remove_animation); diff --git a/scene/resources/animation_library.h b/scene/resources/animation_library.h index b2152fd7c5..c1d78068bb 100644 --- a/scene/resources/animation_library.h +++ b/scene/resources/animation_library.h @@ -62,6 +62,8 @@ public: Ref<Animation> get_animation(const StringName &p_name) const; void get_animation_list(List<StringName> *p_animations) const; + virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; + AnimationLibrary(); }; diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index dd20dc1c66..653a4f4949 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -39,7 +39,7 @@ void BitMap::create(const Size2i &p_size) { ERR_FAIL_COND(static_cast<int64_t>(p_size.width) * static_cast<int64_t>(p_size.height) > INT32_MAX); - Error err = bitmask.resize((((p_size.width * p_size.height) - 1) / 8) + 1); + Error err = bitmask.resize(Math::division_round_up(p_size.width * p_size.height, 8)); ERR_FAIL_COND(err != OK); width = p_size.width; diff --git a/scene/resources/bone_map.cpp b/scene/resources/bone_map.cpp index 5363b8ec79..97e3af726a 100644 --- a/scene/resources/bone_map.cpp +++ b/scene/resources/bone_map.cpp @@ -77,22 +77,22 @@ void BoneMap::set_profile(const Ref<SkeletonProfile> &p_profile) { notify_property_list_changed(); } -StringName BoneMap::get_skeleton_bone_name(StringName p_profile_bone_name) const { +StringName BoneMap::get_skeleton_bone_name(const StringName &p_profile_bone_name) const { ERR_FAIL_COND_V(!bone_map.has(p_profile_bone_name), StringName()); return bone_map.get(p_profile_bone_name); } -void BoneMap::_set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) { +void BoneMap::_set_skeleton_bone_name(const StringName &p_profile_bone_name, const StringName &p_skeleton_bone_name) { ERR_FAIL_COND(!bone_map.has(p_profile_bone_name)); bone_map.insert(p_profile_bone_name, p_skeleton_bone_name); } -void BoneMap::set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) { +void BoneMap::set_skeleton_bone_name(const StringName &p_profile_bone_name, const StringName &p_skeleton_bone_name) { _set_skeleton_bone_name(p_profile_bone_name, p_skeleton_bone_name); emit_signal("bone_map_updated"); } -StringName BoneMap::find_profile_bone_name(StringName p_skeleton_bone_name) const { +StringName BoneMap::find_profile_bone_name(const StringName &p_skeleton_bone_name) const { StringName profile_bone_name; HashMap<StringName, StringName>::ConstIterator E = bone_map.begin(); while (E) { @@ -105,7 +105,7 @@ StringName BoneMap::find_profile_bone_name(StringName p_skeleton_bone_name) cons return profile_bone_name; } -int BoneMap::get_skeleton_bone_name_count(const StringName p_skeleton_bone_name) const { +int BoneMap::get_skeleton_bone_name_count(const StringName &p_skeleton_bone_name) const { int count = 0; HashMap<StringName, StringName>::ConstIterator E = bone_map.begin(); while (E) { diff --git a/scene/resources/bone_map.h b/scene/resources/bone_map.h index 983a3b7b5a..fbd2f92dee 100644 --- a/scene/resources/bone_map.h +++ b/scene/resources/bone_map.h @@ -53,13 +53,13 @@ public: Ref<SkeletonProfile> get_profile() const; void set_profile(const Ref<SkeletonProfile> &p_profile); - int get_skeleton_bone_name_count(const StringName p_skeleton_bone_name) const; + int get_skeleton_bone_name_count(const StringName &p_skeleton_bone_name) const; - StringName get_skeleton_bone_name(StringName p_profile_bone_name) const; - void set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name); - void _set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name); // Avoid to emit signal for editor. + StringName get_skeleton_bone_name(const StringName &p_profile_bone_name) const; + void set_skeleton_bone_name(const StringName &p_profile_bone_name, const StringName &p_skeleton_bone_name); + void _set_skeleton_bone_name(const StringName &p_profile_bone_name, const StringName &p_skeleton_bone_name); // Avoid to emit signal for editor. - StringName find_profile_bone_name(StringName p_skeleton_bone_name) const; + StringName find_profile_bone_name(const StringName &p_skeleton_bone_name) const; BoneMap(); ~BoneMap(); diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index d2aabf7d5c..2b54acef75 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -527,7 +527,7 @@ bool Curve::_set(const StringName &p_name, const Variant &p_value) { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) { int point_index = components[0].trim_prefix("point_").to_int(); - String property = components[1]; + const String &property = components[1]; if (property == "position") { Vector2 position = p_value.operator Vector2(); set_point_offset(point_index, position.x); @@ -556,7 +556,7 @@ bool Curve::_get(const StringName &p_name, Variant &r_ret) const { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) { int point_index = components[0].trim_prefix("point_").to_int(); - String property = components[1]; + const String &property = components[1]; if (property == "position") { r_ret = get_point_position(point_index); return true; @@ -977,7 +977,7 @@ Transform2D Curve2D::_sample_posture(Interval p_interval) const { const Vector2 forward = forward_begin.slerp(forward_end, frac).normalized(); const Vector2 side = Vector2(-forward.y, forward.x); - return Transform2D(side, forward, Vector2(0.0, 0.0)); + return Transform2D(forward, side, Vector2(0.0, 0.0)); } Vector2 Curve2D::sample_baked(real_t p_offset, bool p_cubic) const { @@ -1046,6 +1046,10 @@ real_t Curve2D::get_bake_interval() const { return bake_interval; } +PackedVector2Array Curve2D::get_points() const { + return _get_data()["points"]; +} + Vector2 Curve2D::get_closest_point(const Vector2 &p_to_point) const { // Brute force method. @@ -1255,7 +1259,7 @@ bool Curve2D::_set(const StringName &p_name, const Variant &p_value) { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) { int point_index = components[0].trim_prefix("point_").to_int(); - String property = components[1]; + const String &property = components[1]; if (property == "position") { set_point_position(point_index, p_value); return true; @@ -1274,7 +1278,7 @@ bool Curve2D::_get(const StringName &p_name, Variant &r_ret) const { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) { int point_index = components[0].trim_prefix("point_").to_int(); - String property = components[1]; + const String &property = components[1]; if (property == "position") { r_ret = get_point_position(point_index); return true; @@ -2220,7 +2224,7 @@ bool Curve3D::_set(const StringName &p_name, const Variant &p_value) { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) { int point_index = components[0].trim_prefix("point_").to_int(); - String property = components[1]; + const String &property = components[1]; if (property == "position") { set_point_position(point_index, p_value); return true; @@ -2242,7 +2246,7 @@ bool Curve3D::_get(const StringName &p_name, Variant &r_ret) const { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) { int point_index = components[0].trim_prefix("point_").to_int(); - String property = components[1]; + const String &property = components[1]; if (property == "position") { r_ret = get_point_position(point_index); return true; diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 440e4466f5..e085dfedbd 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -237,6 +237,7 @@ public: real_t get_baked_length() const; Vector2 sample_baked(real_t p_offset, bool p_cubic = false) const; Transform2D sample_baked_with_rotation(real_t p_offset, bool p_cubic = false) const; + PackedVector2Array get_points() const; PackedVector2Array get_baked_points() const; //useful for going through Vector2 get_closest_point(const Vector2 &p_to_point) const; real_t get_closest_offset(const Vector2 &p_to_point) const; diff --git a/scene/resources/curve_texture.cpp b/scene/resources/curve_texture.cpp index 3578b46308..488a527bbb 100644 --- a/scene/resources/curve_texture.cpp +++ b/scene/resources/curve_texture.cpp @@ -41,8 +41,6 @@ void CurveTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture_mode", "texture_mode"), &CurveTexture::set_texture_mode); ClassDB::bind_method(D_METHOD("get_texture_mode"), &CurveTexture::get_texture_mode); - ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update); - ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width"); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "RGB,Red"), "set_texture_mode", "get_texture_mode"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve"); @@ -190,8 +188,6 @@ void CurveXYZTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_curve_z", "curve"), &CurveXYZTexture::set_curve_z); ClassDB::bind_method(D_METHOD("get_curve_z"), &CurveXYZTexture::get_curve_z); - ClassDB::bind_method(D_METHOD("_update"), &CurveXYZTexture::_update); - ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_x", "get_curve_x"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_y", "get_curve_y"); diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 13b22ae12c..60c3816020 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -1118,11 +1118,11 @@ bool FontFile::_set(const StringName &p_name, const Variant &p_value) { #endif // DISABLE_DEPRECATED if (tokens.size() == 2 && tokens[0] == "language_support_override") { - String lang_code = tokens[1]; + const String &lang_code = tokens[1]; set_language_support_override(lang_code, p_value); return true; } else if (tokens.size() == 2 && tokens[0] == "script_support_override") { - String script_code = tokens[1]; + const String &script_code = tokens[1]; set_script_support_override(script_code, p_value); return true; } else if (tokens.size() >= 3 && tokens[0] == "cache") { @@ -1209,11 +1209,11 @@ bool FontFile::_set(const StringName &p_name, const Variant &p_value) { bool FontFile::_get(const StringName &p_name, Variant &r_ret) const { Vector<String> tokens = p_name.operator String().split("/"); if (tokens.size() == 2 && tokens[0] == "language_support_override") { - String lang_code = tokens[1]; + const String &lang_code = tokens[1]; r_ret = get_language_support_override(lang_code); return true; } else if (tokens.size() == 2 && tokens[0] == "script_support_override") { - String script_code = tokens[1]; + const String &script_code = tokens[1]; r_ret = get_script_support_override(script_code); return true; } else if (tokens.size() >= 3 && tokens[0] == "cache") { diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 1b74063ff4..74b1157e5f 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -468,7 +468,7 @@ void ShaderMaterial::get_argument_options(const StringName &p_function, int p_id } } } - Resource::get_argument_options(p_function, p_idx, r_options); + Material::get_argument_options(p_function, p_idx, r_options); } bool ShaderMaterial::_can_do_next_pass() const { @@ -1947,7 +1947,7 @@ Ref<Texture2D> BaseMaterial3D::get_texture(TextureParam p_param) const { return textures[p_param]; } -Ref<Texture2D> BaseMaterial3D::get_texture_by_name(StringName p_name) const { +Ref<Texture2D> BaseMaterial3D::get_texture_by_name(const StringName &p_name) const { for (int i = 0; i < (int)BaseMaterial3D::TEXTURE_MAX; i++) { TextureParam param = TextureParam(i); if (p_name == shader_names->texture_names[param]) { diff --git a/scene/resources/material.h b/scene/resources/material.h index 1c698cb104..06522e6470 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -682,7 +682,7 @@ public: void set_texture(TextureParam p_param, const Ref<Texture2D> &p_texture); Ref<Texture2D> get_texture(TextureParam p_param) const; // Used only for shader material conversion - Ref<Texture2D> get_texture_by_name(StringName p_name) const; + Ref<Texture2D> get_texture_by_name(const StringName &p_name) const; void set_texture_filter(TextureFilter p_filter); TextureFilter get_texture_filter() const; diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index 82b5c6257c..dd2e7ef268 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -127,7 +127,7 @@ NavigationMesh::SourceGeometryMode NavigationMesh::get_source_geometry_mode() co return source_geometry_mode; } -void NavigationMesh::set_source_group_name(StringName p_group_name) { +void NavigationMesh::set_source_group_name(const StringName &p_group_name) { source_group_name = p_group_name; } diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h index 8b9b810038..cb8880eb94 100644 --- a/scene/resources/navigation_mesh.h +++ b/scene/resources/navigation_mesh.h @@ -122,7 +122,7 @@ public: void set_source_geometry_mode(SourceGeometryMode p_geometry_mode); SourceGeometryMode get_source_geometry_mode() const; - void set_source_group_name(StringName p_group_name); + void set_source_group_name(const StringName &p_group_name); StringName get_source_group_name() const; void set_cell_size(float p_value); diff --git a/scene/resources/navigation_polygon.cpp b/scene/resources/navigation_polygon.cpp index 52840eaa65..2770cb0b87 100644 --- a/scene/resources/navigation_polygon.cpp +++ b/scene/resources/navigation_polygon.cpp @@ -393,7 +393,7 @@ NavigationPolygon::SourceGeometryMode NavigationPolygon::get_source_geometry_mod return source_geometry_mode; } -void NavigationPolygon::set_source_geometry_group_name(StringName p_group_name) { +void NavigationPolygon::set_source_geometry_group_name(const StringName &p_group_name) { source_geometry_group_name = p_group_name; } diff --git a/scene/resources/navigation_polygon.h b/scene/resources/navigation_polygon.h index 4a6a97e2e7..e589ad6dce 100644 --- a/scene/resources/navigation_polygon.h +++ b/scene/resources/navigation_polygon.h @@ -127,7 +127,7 @@ public: void set_source_geometry_mode(SourceGeometryMode p_geometry_mode); SourceGeometryMode get_source_geometry_mode() const; - void set_source_geometry_group_name(StringName p_group_name); + void set_source_geometry_group_name(const StringName &p_group_name); StringName get_source_geometry_group_name() const; void set_agent_radius(real_t p_value); diff --git a/scene/resources/portable_compressed_texture.cpp b/scene/resources/portable_compressed_texture.cpp index a61799c7d6..918b5c0b41 100644 --- a/scene/resources/portable_compressed_texture.cpp +++ b/scene/resources/portable_compressed_texture.cpp @@ -30,6 +30,7 @@ #include "portable_compressed_texture.h" +#include "core/config/project_settings.h" #include "core/io/marshalls.h" #include "scene/resources/bit_map.h" @@ -41,7 +42,8 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) { const uint8_t *data = p_data.ptr(); uint32_t data_size = p_data.size(); ERR_FAIL_COND(data_size < 20); - compression_mode = CompressionMode(decode_uint32(data + 0)); + compression_mode = CompressionMode(decode_uint16(data)); + DataFormat data_format = DataFormat(decode_uint16(data + 2)); format = Image::Format(decode_uint32(data + 4)); uint32_t mipmap_count = decode_uint32(data + 8); size.width = decode_uint32(data + 12); @@ -56,6 +58,16 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) { switch (compression_mode) { case COMPRESSION_MODE_LOSSLESS: case COMPRESSION_MODE_LOSSY: { + ImageMemLoadFunc loader_func; + if (data_format == DATA_FORMAT_UNDEFINED) { + loader_func = nullptr; + } else if (data_format == DATA_FORMAT_PNG) { + loader_func = Image::_png_mem_unpacker_func; + } else if (data_format == DATA_FORMAT_WEBP) { + loader_func = Image::_webp_mem_loader_func; + } else { + ERR_FAIL(); + } Vector<uint8_t> image_data; ERR_FAIL_COND(data_size < 4); @@ -63,8 +75,10 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) { uint32_t mipsize = decode_uint32(data); data += 4; data_size -= 4; - ERR_FAIL_COND(mipsize < data_size); - Ref<Image> img = memnew(Image(data, data_size)); + ERR_FAIL_COND(mipsize > data_size); + Ref<Image> img = loader_func == nullptr + ? memnew(Image(data, data_size)) + : Ref<Image>(loader_func(data, data_size)); ERR_FAIL_COND(img->is_empty()); if (img->get_format() != format) { // May happen due to webp/png in the tiny mipmaps. img->convert(format); @@ -75,7 +89,7 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) { data_size -= mipsize; } - image = Ref<Image>(memnew(Image(size.width, size.height, mipmap_count > 1, format, image_data))); + image = Ref<Image>(memnew(Image(size.width, size.height, mipmaps, format, image_data))); } break; case COMPRESSION_MODE_BASIS_UNIVERSAL: { @@ -86,7 +100,7 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) { case COMPRESSION_MODE_S3TC: case COMPRESSION_MODE_ETC2: case COMPRESSION_MODE_BPTC: { - image = Ref<Image>(memnew(Image(size.width, size.height, mipmap_count > 1, format, p_data.slice(20)))); + image = Ref<Image>(memnew(Image(size.width, size.height, mipmaps, format, p_data.slice(20)))); } break; } ERR_FAIL_COND(image.is_null()); @@ -99,6 +113,7 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) { } image_stored = true; + size_override = size; RenderingServer::get_singleton()->texture_set_size_override(texture, size_override.width, size_override.height); alpha_cache.unref(); @@ -122,7 +137,8 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C Vector<uint8_t> buffer; buffer.resize(20); - encode_uint32(p_compression_mode, buffer.ptrw()); + encode_uint16(p_compression_mode, buffer.ptrw()); + encode_uint16(DATA_FORMAT_UNDEFINED, buffer.ptrw() + 2); encode_uint32(p_image->get_format(), buffer.ptrw() + 4); encode_uint32(p_image->get_mipmap_count() + 1, buffer.ptrw() + 8); encode_uint32(p_image->get_width(), buffer.ptrw() + 12); @@ -131,12 +147,22 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C switch (p_compression_mode) { case COMPRESSION_MODE_LOSSLESS: case COMPRESSION_MODE_LOSSY: { + bool lossless_force_png = GLOBAL_GET("rendering/textures/lossless_compression/force_png") || + !Image::_webp_mem_loader_func; // WebP module disabled. + bool use_webp = !lossless_force_png && p_image->get_width() <= 16383 && p_image->get_height() <= 16383; // WebP has a size limit. for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) { Vector<uint8_t> data; if (p_compression_mode == COMPRESSION_MODE_LOSSY) { data = Image::webp_lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality); + encode_uint16(DATA_FORMAT_WEBP, buffer.ptrw() + 2); } else { - data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i)); + if (use_webp) { + data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i)); + encode_uint16(DATA_FORMAT_WEBP, buffer.ptrw() + 2); + } else { + data = Image::png_packer(p_image->get_image_from_mipmap(i)); + encode_uint16(DATA_FORMAT_PNG, buffer.ptrw() + 2); + } } int data_len = data.size(); buffer.resize(buffer.size() + 4); @@ -145,6 +171,7 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C } } break; case COMPRESSION_MODE_BASIS_UNIVERSAL: { + encode_uint16(DATA_FORMAT_BASIS_UNIVERSAL, buffer.ptrw() + 2); Image::UsedChannels uc = p_image->detect_used_channels(p_normal_map ? Image::COMPRESS_SOURCE_NORMAL : Image::COMPRESS_SOURCE_GENERIC); Vector<uint8_t> budata = Image::basis_universal_packer(p_image, uc); buffer.append_array(budata); @@ -153,6 +180,7 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C case COMPRESSION_MODE_S3TC: case COMPRESSION_MODE_ETC2: case COMPRESSION_MODE_BPTC: { + encode_uint16(DATA_FORMAT_IMAGE, buffer.ptrw() + 2); Ref<Image> copy = p_image->duplicate(); switch (p_compression_mode) { case COMPRESSION_MODE_S3TC: diff --git a/scene/resources/portable_compressed_texture.h b/scene/resources/portable_compressed_texture.h index 86d80e39f7..3103c2daba 100644 --- a/scene/resources/portable_compressed_texture.h +++ b/scene/resources/portable_compressed_texture.h @@ -39,6 +39,14 @@ class PortableCompressedTexture2D : public Texture2D { GDCLASS(PortableCompressedTexture2D, Texture2D); public: + enum DataFormat { + DATA_FORMAT_UNDEFINED, + DATA_FORMAT_IMAGE, + DATA_FORMAT_PNG, + DATA_FORMAT_WEBP, + DATA_FORMAT_BASIS_UNIVERSAL, + }; + enum CompressionMode { COMPRESSION_MODE_LOSSLESS, COMPRESSION_MODE_LOSSY, diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 8ad9eec25f..eb28c9e601 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -232,8 +232,6 @@ RID PrimitiveMesh::get_rid() const { } void PrimitiveMesh::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update"), &PrimitiveMesh::_update); - ClassDB::bind_method(D_METHOD("set_material", "material"), &PrimitiveMesh::set_material); ClassDB::bind_method(D_METHOD("get_material"), &PrimitiveMesh::get_material); @@ -1478,15 +1476,15 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const { thisrow = point; prevrow = 0; for (j = 0; j <= (subdivide_h + 1); j++) { - float scale = (y - start_pos.y) / size.y; + float scale = j / (subdivide_h + 1.0); float scaled_size_x = size.x * scale; float start_x = start_pos.x + (1.0 - scale) * size.x * left_to_right; float offset_front = (1.0 - scale) * onethird * left_to_right; float offset_back = (1.0 - scale) * onethird * (1.0 - left_to_right); float v = j; - float v2 = j / (subdivide_h + 1.0); - v /= (2.0 * (subdivide_h + 1.0)); + float v2 = scale; + v /= 2.0 * (subdivide_h + 1.0); x = 0.0; for (i = 0; i <= (subdivide_w + 1); i++) { @@ -1568,16 +1566,16 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const { thisrow = point; prevrow = 0; for (j = 0; j <= (subdivide_h + 1); j++) { - float v = j; - float v2 = j / (subdivide_h + 1.0); - v /= (2.0 * (subdivide_h + 1.0)); - float left, right; - float scale = (y - start_pos.y) / size.y; + float scale = j / (subdivide_h + 1.0); left = start_pos.x + (size.x * (1.0 - scale) * left_to_right); right = left + (size.x * scale); + float v = j; + float v2 = scale; + v /= 2.0 * (subdivide_h + 1.0); + z = start_pos.z; for (i = 0; i <= (subdivide_d + 1); i++) { float u = i; @@ -3342,7 +3340,6 @@ void TextMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_uppercase", "enable"), &TextMesh::set_uppercase); ClassDB::bind_method(D_METHOD("is_uppercase"), &TextMesh::is_uppercase); - ClassDB::bind_method(D_METHOD("_font_changed"), &TextMesh::_font_changed); ClassDB::bind_method(D_METHOD("_request_update"), &TextMesh::_request_update); ADD_GROUP("Text", ""); @@ -3446,14 +3443,16 @@ void TextMesh::_font_changed() { void TextMesh::set_font(const Ref<Font> &p_font) { if (font_override != p_font) { + const Callable font_changed = callable_mp(this, &TextMesh::_font_changed); + if (font_override.is_valid()) { - font_override->disconnect_changed(Callable(this, "_font_changed")); + font_override->disconnect_changed(font_changed); } font_override = p_font; dirty_font = true; dirty_cache = true; if (font_override.is_valid()) { - font_override->connect_changed(Callable(this, "_font_changed")); + font_override->connect_changed(font_changed); } _request_update(); } diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 037cd32f10..a97ff5054d 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -281,7 +281,7 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars if (error == ERR_FILE_MISSING_DEPENDENCIES) { // Resource loading error, just skip it. } else if (error != ERR_FILE_EOF) { - _printerr(); + ERR_PRINT(vformat("Parse Error: %s. [Resource file %s:%d]", error_names[error], res_path, lines)); return Ref<PackedScene>(); } else { error = OK; @@ -2289,10 +2289,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso } String connstr = "[connection"; - connstr += " signal=\"" + String(state->get_connection_signal(i)) + "\""; - connstr += " from=\"" + String(state->get_connection_source(i).simplified()) + "\""; - connstr += " to=\"" + String(state->get_connection_target(i).simplified()) + "\""; - connstr += " method=\"" + String(state->get_connection_method(i)) + "\""; + connstr += " signal=\"" + String(state->get_connection_signal(i)).c_escape() + "\""; + connstr += " from=\"" + String(state->get_connection_source(i).simplified()).c_escape() + "\""; + connstr += " to=\"" + String(state->get_connection_target(i).simplified()).c_escape() + "\""; + connstr += " method=\"" + String(state->get_connection_method(i)).c_escape() + "\""; int flags = state->get_connection_flags(i); if (flags != Object::CONNECT_PERSIST) { connstr += " flags=" + itos(flags); @@ -2319,7 +2319,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso if (i == 0) { f->store_line(""); } - f->store_line("[editable path=\"" + editable_instances[i].operator String() + "\"]"); + f->store_line("[editable path=\"" + editable_instances[i].operator String().c_escape() + "\"]"); } } diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp index da4b1f7311..24ed480289 100644 --- a/scene/resources/skeleton_profile.cpp +++ b/scene/resources/skeleton_profile.cpp @@ -180,7 +180,7 @@ StringName SkeletonProfile::get_root_bone() { return root_bone; } -void SkeletonProfile::set_root_bone(StringName p_bone_name) { +void SkeletonProfile::set_root_bone(const StringName &p_bone_name) { if (is_read_only) { return; } @@ -191,7 +191,7 @@ StringName SkeletonProfile::get_scale_base_bone() { return scale_base_bone; } -void SkeletonProfile::set_scale_base_bone(StringName p_bone_name) { +void SkeletonProfile::set_scale_base_bone(const StringName &p_bone_name) { if (is_read_only) { return; } @@ -217,7 +217,7 @@ StringName SkeletonProfile::get_group_name(int p_group_idx) const { return groups[p_group_idx].group_name; } -void SkeletonProfile::set_group_name(int p_group_idx, const StringName p_group_name) { +void SkeletonProfile::set_group_name(int p_group_idx, const StringName &p_group_name) { if (is_read_only) { return; } @@ -254,7 +254,7 @@ void SkeletonProfile::set_bone_size(int p_size) { notify_property_list_changed(); } -int SkeletonProfile::find_bone(StringName p_bone_name) const { +int SkeletonProfile::find_bone(const StringName &p_bone_name) const { if (p_bone_name == StringName()) { return -1; } @@ -271,7 +271,7 @@ StringName SkeletonProfile::get_bone_name(int p_bone_idx) const { return bones[p_bone_idx].bone_name; } -void SkeletonProfile::set_bone_name(int p_bone_idx, const StringName p_bone_name) { +void SkeletonProfile::set_bone_name(int p_bone_idx, const StringName &p_bone_name) { if (is_read_only) { return; } @@ -285,7 +285,7 @@ StringName SkeletonProfile::get_bone_parent(int p_bone_idx) const { return bones[p_bone_idx].bone_parent; } -void SkeletonProfile::set_bone_parent(int p_bone_idx, const StringName p_bone_parent) { +void SkeletonProfile::set_bone_parent(int p_bone_idx, const StringName &p_bone_parent) { if (is_read_only) { return; } @@ -314,7 +314,7 @@ StringName SkeletonProfile::get_bone_tail(int p_bone_idx) const { return bones[p_bone_idx].bone_tail; } -void SkeletonProfile::set_bone_tail(int p_bone_idx, const StringName p_bone_tail) { +void SkeletonProfile::set_bone_tail(int p_bone_idx, const StringName &p_bone_tail) { if (is_read_only) { return; } @@ -356,7 +356,7 @@ StringName SkeletonProfile::get_group(int p_bone_idx) const { return bones[p_bone_idx].group; } -void SkeletonProfile::set_group(int p_bone_idx, const StringName p_group) { +void SkeletonProfile::set_group(int p_bone_idx, const StringName &p_group) { if (is_read_only) { return; } @@ -379,7 +379,7 @@ void SkeletonProfile::set_require(int p_bone_idx, const bool p_require) { emit_signal("profile_updated"); } -bool SkeletonProfile::has_bone(StringName p_bone_name) { +bool SkeletonProfile::has_bone(const StringName &p_bone_name) { bool is_found = false; for (int i = 0; i < bones.size(); i++) { if (bones[i].bone_name == p_bone_name) { diff --git a/scene/resources/skeleton_profile.h b/scene/resources/skeleton_profile.h index 418a051976..143f495c61 100644 --- a/scene/resources/skeleton_profile.h +++ b/scene/resources/skeleton_profile.h @@ -78,16 +78,16 @@ protected: public: StringName get_root_bone(); - void set_root_bone(StringName p_bone_name); + void set_root_bone(const StringName &p_bone_name); StringName get_scale_base_bone(); - void set_scale_base_bone(StringName p_bone_name); + void set_scale_base_bone(const StringName &p_bone_name); int get_group_size(); void set_group_size(int p_size); StringName get_group_name(int p_group_idx) const; - void set_group_name(int p_group_idx, const StringName p_group_name); + void set_group_name(int p_group_idx, const StringName &p_group_name); Ref<Texture2D> get_texture(int p_group_idx) const; void set_texture(int p_group_idx, const Ref<Texture2D> &p_texture); @@ -95,19 +95,19 @@ public: int get_bone_size(); void set_bone_size(int p_size); - int find_bone(const StringName p_bone_name) const; + int find_bone(const StringName &p_bone_name) const; StringName get_bone_name(int p_bone_idx) const; - void set_bone_name(int p_bone_idx, const StringName p_bone_name); + void set_bone_name(int p_bone_idx, const StringName &p_bone_name); StringName get_bone_parent(int p_bone_idx) const; - void set_bone_parent(int p_bone_idx, const StringName p_bone_parent); + void set_bone_parent(int p_bone_idx, const StringName &p_bone_parent); TailDirection get_tail_direction(int p_bone_idx) const; void set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction); StringName get_bone_tail(int p_bone_idx) const; - void set_bone_tail(int p_bone_idx, const StringName p_bone_tail); + void set_bone_tail(int p_bone_idx, const StringName &p_bone_tail); Transform3D get_reference_pose(int p_bone_idx) const; void set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose); @@ -116,12 +116,12 @@ public: void set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset); StringName get_group(int p_bone_idx) const; - void set_group(int p_bone_idx, const StringName p_group); + void set_group(int p_bone_idx, const StringName &p_group); bool is_require(int p_bone_idx) const; void set_require(int p_bone_idx, const bool p_require); - bool has_bone(StringName p_bone_name); + bool has_bone(const StringName &p_bone_name); SkeletonProfile(); ~SkeletonProfile(); diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp index 17aaf579dd..fc8bff1f25 100644 --- a/scene/resources/sprite_frames.cpp +++ b/scene/resources/sprite_frames.cpp @@ -224,6 +224,23 @@ void SpriteFrames::_set_animations(const Array &p_animations) { } } +void SpriteFrames::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { + String pf = p_function; + if (p_idx == 0) { + if (pf == "has_animation" || pf == "remove_animation" || pf == "rename_animation" || + pf == "set_animation_speed" || pf == "get_animation_speed" || + pf == "set_animation_loop" || pf == "get_animation_loop" || + pf == "add_frame" || pf == "set_frame" || pf == "remove_frame" || + pf == "get_frame_count" || pf == "get_frame_texture" || pf == "get_frame_duration" || + pf == "clear") { + for (const String &E : get_animation_names()) { + r_options->push_back(E.quote()); + } + } + } + Resource::get_argument_options(p_function, p_idx, r_options); +} + void SpriteFrames::_bind_methods() { ClassDB::bind_method(D_METHOD("add_animation", "anim"), &SpriteFrames::add_animation); ClassDB::bind_method(D_METHOD("has_animation", "anim"), &SpriteFrames::has_animation); diff --git a/scene/resources/sprite_frames.h b/scene/resources/sprite_frames.h index 6de2b4a37b..dc980f8321 100644 --- a/scene/resources/sprite_frames.h +++ b/scene/resources/sprite_frames.h @@ -103,6 +103,8 @@ public: void clear(const StringName &p_anim); void clear_all(); + virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; + SpriteFrames(); }; diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index d57a0f6b38..b6cd6f6dfe 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -322,7 +322,7 @@ void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type) _emit_theme_changed(true); } -void Theme::get_icon_list(StringName p_theme_type, List<StringName> *p_list) const { +void Theme::get_icon_list(const StringName &p_theme_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); if (!icon_map.has(p_theme_type)) { @@ -432,7 +432,7 @@ void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_t _emit_theme_changed(true); } -void Theme::get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) const { +void Theme::get_stylebox_list(const StringName &p_theme_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); if (!style_map.has(p_theme_type)) { @@ -544,7 +544,7 @@ void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type) _emit_theme_changed(true); } -void Theme::get_font_list(StringName p_theme_type, List<StringName> *p_list) const { +void Theme::get_font_list(const StringName &p_theme_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); if (!font_map.has(p_theme_type)) { @@ -643,7 +643,7 @@ void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_ _emit_theme_changed(true); } -void Theme::get_font_size_list(StringName p_theme_type, List<StringName> *p_list) const { +void Theme::get_font_size_list(const StringName &p_theme_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); if (!font_size_map.has(p_theme_type)) { @@ -729,7 +729,7 @@ void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type _emit_theme_changed(true); } -void Theme::get_color_list(StringName p_theme_type, List<StringName> *p_list) const { +void Theme::get_color_list(const StringName &p_theme_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); if (!color_map.has(p_theme_type)) { @@ -815,7 +815,7 @@ void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_t _emit_theme_changed(true); } -void Theme::get_constant_list(StringName p_theme_type, List<StringName> *p_list) const { +void Theme::get_constant_list(const StringName &p_theme_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); if (!constant_map.has(p_theme_type)) { @@ -1009,7 +1009,7 @@ void Theme::clear_theme_item(DataType p_data_type, const StringName &p_name, con } } -void Theme::get_theme_item_list(DataType p_data_type, StringName p_theme_type, List<StringName> *p_list) const { +void Theme::get_theme_item_list(DataType p_data_type, const StringName &p_theme_type, List<StringName> *p_list) const { switch (p_data_type) { case DATA_TYPE_COLOR: get_color_list(p_theme_type, p_list); @@ -1613,6 +1613,17 @@ void Theme::merge_with(const Ref<Theme> &p_other) { } } + // Defaults. + if (p_other->has_default_font()) { + set_default_font(p_other->default_font); + } + if (p_other->has_default_font_size()) { + set_default_font_size(p_other->default_font_size); + } + if (p_other->has_default_base_scale()) { + set_default_base_scale(p_other->default_base_scale); + } + _unfreeze_and_propagate_changes(); } diff --git a/scene/resources/theme.h b/scene/resources/theme.h index b26b5b5e84..73f1167c29 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -136,7 +136,7 @@ public: bool has_icon_nocheck(const StringName &p_name, const StringName &p_theme_type) const; void rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type); void clear_icon(const StringName &p_name, const StringName &p_theme_type); - void get_icon_list(StringName p_theme_type, List<StringName> *p_list) const; + void get_icon_list(const StringName &p_theme_type, List<StringName> *p_list) const; void add_icon_type(const StringName &p_theme_type); void remove_icon_type(const StringName &p_theme_type); void get_icon_type_list(List<StringName> *p_list) const; @@ -147,7 +147,7 @@ public: bool has_stylebox_nocheck(const StringName &p_name, const StringName &p_theme_type) const; void rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type); void clear_stylebox(const StringName &p_name, const StringName &p_theme_type); - void get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) const; + void get_stylebox_list(const StringName &p_theme_type, List<StringName> *p_list) const; void add_stylebox_type(const StringName &p_theme_type); void remove_stylebox_type(const StringName &p_theme_type); void get_stylebox_type_list(List<StringName> *p_list) const; @@ -158,7 +158,7 @@ public: bool has_font_nocheck(const StringName &p_name, const StringName &p_theme_type) const; void rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type); void clear_font(const StringName &p_name, const StringName &p_theme_type); - void get_font_list(StringName p_theme_type, List<StringName> *p_list) const; + void get_font_list(const StringName &p_theme_type, List<StringName> *p_list) const; void add_font_type(const StringName &p_theme_type); void remove_font_type(const StringName &p_theme_type); void get_font_type_list(List<StringName> *p_list) const; @@ -169,7 +169,7 @@ public: bool has_font_size_nocheck(const StringName &p_name, const StringName &p_theme_type) const; void rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type); void clear_font_size(const StringName &p_name, const StringName &p_theme_type); - void get_font_size_list(StringName p_theme_type, List<StringName> *p_list) const; + void get_font_size_list(const StringName &p_theme_type, List<StringName> *p_list) const; void add_font_size_type(const StringName &p_theme_type); void remove_font_size_type(const StringName &p_theme_type); void get_font_size_type_list(List<StringName> *p_list) const; @@ -180,7 +180,7 @@ public: bool has_color_nocheck(const StringName &p_name, const StringName &p_theme_type) const; void rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type); void clear_color(const StringName &p_name, const StringName &p_theme_type); - void get_color_list(StringName p_theme_type, List<StringName> *p_list) const; + void get_color_list(const StringName &p_theme_type, List<StringName> *p_list) const; void add_color_type(const StringName &p_theme_type); void remove_color_type(const StringName &p_theme_type); void get_color_type_list(List<StringName> *p_list) const; @@ -191,7 +191,7 @@ public: bool has_constant_nocheck(const StringName &p_name, const StringName &p_theme_type) const; void rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type); void clear_constant(const StringName &p_name, const StringName &p_theme_type); - void get_constant_list(StringName p_theme_type, List<StringName> *p_list) const; + void get_constant_list(const StringName &p_theme_type, List<StringName> *p_list) const; void add_constant_type(const StringName &p_theme_type); void remove_constant_type(const StringName &p_theme_type); void get_constant_type_list(List<StringName> *p_list) const; @@ -202,7 +202,7 @@ public: bool has_theme_item_nocheck(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const; void rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type); void clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type); - void get_theme_item_list(DataType p_data_type, StringName p_theme_type, List<StringName> *p_list) const; + void get_theme_item_list(DataType p_data_type, const StringName &p_theme_type, List<StringName> *p_list) const; void add_theme_item_type(DataType p_data_type, const StringName &p_theme_type); void remove_theme_item_type(DataType p_data_type, const StringName &p_theme_type); void get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 2de7cce5c7..a99102e847 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -4675,7 +4675,6 @@ void TileSetAtlasSource::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_tile_texture_region, DEFVAL(0)); // Getters for texture and tile region (padded or not) - ClassDB::bind_method(D_METHOD("_update_padded_texture"), &TileSetAtlasSource::_update_padded_texture); ClassDB::bind_method(D_METHOD("get_runtime_texture"), &TileSetAtlasSource::get_runtime_texture); ClassDB::bind_method(D_METHOD("get_runtime_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_runtime_tile_texture_region); @@ -4761,7 +4760,7 @@ void TileSetAtlasSource::_create_coords_mapping_cache(Vector2i p_atlas_coords) { void TileSetAtlasSource::_queue_update_padded_texture() { padded_texture_needs_update = true; - call_deferred(SNAME("_update_padded_texture")); + callable_mp(this, &TileSetAtlasSource::_update_padded_texture).call_deferred(); } Ref<ImageTexture> TileSetAtlasSource::_create_padded_image_texture(const Ref<Texture2D> &p_source) { diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 9fb6b364a7..8ff5b54fbe 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -3139,7 +3139,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec4(1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "UV" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "vec2(1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, @@ -3166,7 +3166,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec3(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "UV" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Canvas Item, Light @@ -3176,7 +3176,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "vec3(0.0, 0.0, 1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec4(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "UV" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Particles @@ -3189,7 +3189,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { // Sky - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "UV" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Fog diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp index 09fb5aba0d..2a1894e690 100644 --- a/scene/theme/default_theme.cpp +++ b/scene/theme/default_theme.cpp @@ -299,13 +299,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("focus", "CheckBox", cbx_focus); theme->set_icon("checked", "CheckBox", icons["checked"]); - theme->set_icon("checked_disabled", "CheckBox", icons["checked"]); + theme->set_icon("checked_disabled", "CheckBox", icons["checked_disabled"]); theme->set_icon("unchecked", "CheckBox", icons["unchecked"]); - theme->set_icon("unchecked_disabled", "CheckBox", icons["unchecked"]); + theme->set_icon("unchecked_disabled", "CheckBox", icons["unchecked_disabled"]); theme->set_icon("radio_checked", "CheckBox", icons["radio_checked"]); - theme->set_icon("radio_checked_disabled", "CheckBox", icons["radio_checked"]); + theme->set_icon("radio_checked_disabled", "CheckBox", icons["radio_checked_disabled"]); theme->set_icon("radio_unchecked", "CheckBox", icons["radio_unchecked"]); - theme->set_icon("radio_unchecked_disabled", "CheckBox", icons["radio_unchecked"]); + theme->set_icon("radio_unchecked_disabled", "CheckBox", icons["radio_unchecked_disabled"]); theme->set_font("font", "CheckBox", Ref<Font>()); theme->set_font_size("font_size", "CheckBox", -1); @@ -685,13 +685,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("labeled_separator_right", "PopupMenu", separator_horizontal); theme->set_icon("checked", "PopupMenu", icons["checked"]); - theme->set_icon("checked_disabled", "PopupMenu", icons["checked"]); + theme->set_icon("checked_disabled", "PopupMenu", icons["checked_disabled"]); theme->set_icon("unchecked", "PopupMenu", icons["unchecked"]); - theme->set_icon("unchecked_disabled", "PopupMenu", icons["unchecked"]); + theme->set_icon("unchecked_disabled", "PopupMenu", icons["unchecked_disabled"]); theme->set_icon("radio_checked", "PopupMenu", icons["radio_checked"]); - theme->set_icon("radio_checked_disabled", "PopupMenu", icons["radio_checked"]); + theme->set_icon("radio_checked_disabled", "PopupMenu", icons["radio_checked_disabled"]); theme->set_icon("radio_unchecked", "PopupMenu", icons["radio_unchecked"]); - theme->set_icon("radio_unchecked_disabled", "PopupMenu", icons["radio_unchecked"]); + theme->set_icon("radio_unchecked_disabled", "PopupMenu", icons["radio_unchecked_disabled"]); theme->set_icon("submenu", "PopupMenu", icons["popup_menu_arrow_right"]); theme->set_icon("submenu_mirrored", "PopupMenu", icons["popup_menu_arrow_left"]); @@ -958,6 +958,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("shape_rect_wheel", "ColorPicker", icons["picker_shape_rectangle_wheel"]); theme->set_icon("add_preset", "ColorPicker", icons["add"]); theme->set_icon("sample_bg", "ColorPicker", icons["mini_checkerboard"]); + theme->set_icon("sample_revert", "ColorPicker", icons["reload"]); theme->set_icon("overbright_indicator", "ColorPicker", icons["color_picker_overbright"]); theme->set_icon("bar_arrow", "ColorPicker", icons["color_picker_bar_arrow"]); theme->set_icon("picker_cursor", "ColorPicker", icons["color_picker_cursor"]); diff --git a/scene/theme/theme_owner.cpp b/scene/theme/theme_owner.cpp index 2852a64e39..b559c8c58d 100644 --- a/scene/theme/theme_owner.cpp +++ b/scene/theme/theme_owner.cpp @@ -249,7 +249,7 @@ void ThemeOwner::get_theme_type_dependencies(const Node *p_for_node, const Strin ThemeDB::get_singleton()->get_native_type_dependencies(p_theme_type, r_list); } -Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) { +Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, const List<StringName> &p_theme_types) { ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, Variant(), "At least one theme type must be specified."); // First, look through each control or window node in the branch, until no valid parent can be found. @@ -285,7 +285,7 @@ Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const S return global_context->get_fallback_theme()->get_theme_item(p_data_type, p_name, StringName()); } -bool ThemeOwner::has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) { +bool ThemeOwner::has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, const List<StringName> &p_theme_types) { ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified."); // First, look through each control or window node in the branch, until no valid parent can be found. diff --git a/scene/theme/theme_owner.h b/scene/theme/theme_owner.h index 4923ccb00b..7e19279c2a 100644 --- a/scene/theme/theme_owner.h +++ b/scene/theme/theme_owner.h @@ -71,8 +71,8 @@ public: void get_theme_type_dependencies(const Node *p_for_node, const StringName &p_theme_type, List<StringName> *r_list) const; - Variant get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types); - bool has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types); + Variant get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, const List<StringName> &p_theme_types); + bool has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, const List<StringName> &p_theme_types); float get_theme_default_base_scale(); Ref<Font> get_theme_default_font(); diff --git a/scu_builders.py b/scu_builders.py index 71427eb717..56effb393c 100644 --- a/scu_builders.py +++ b/scu_builders.py @@ -277,6 +277,7 @@ def generate_scu_files(max_includes_per_scu): process_folder(["editor/export"]) process_folder(["editor/gui"]) process_folder(["editor/import"]) + process_folder(["editor/import/3d"]) process_folder(["editor/plugins"]) process_folder(["editor/plugins/gizmos"]) process_folder(["editor/plugins/tiles"]) diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 511a8b3122..86bdd13c80 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -122,8 +122,10 @@ int AudioDriver::_get_configured_mix_rate() { // In the case of invalid mix rate, let's default to a sensible value.. if (mix_rate <= 0) { +#ifndef WEB_ENABLED WARN_PRINT(vformat("Invalid mix rate of %d, consider reassigning setting \'%s\'. \nDefaulting mix rate to value %d.", mix_rate, audio_driver_setting, AudioDriverManager::DEFAULT_MIX_RATE)); +#endif mix_rate = AudioDriverManager::DEFAULT_MIX_RATE; } @@ -199,8 +201,8 @@ int AudioDriverManager::get_driver_count() { void AudioDriverManager::initialize(int p_driver) { GLOBAL_DEF_RST("audio/driver/enable_input", false); - GLOBAL_DEF_RST("audio/driver/mix_rate", DEFAULT_MIX_RATE); - GLOBAL_DEF_RST("audio/driver/mix_rate.web", 0); // Safer default output_latency for web (use browser default). + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "audio/driver/mix_rate", PROPERTY_HINT_RANGE, "11025,192000,1,or_greater,suffix:Hz"), DEFAULT_MIX_RATE); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "audio/driver/mix_rate.web", PROPERTY_HINT_RANGE, "0,192000,1,or_greater,suffix:Hz"), 0); // Safer default output_latency for web (use browser default). int failed_driver = -1; @@ -1118,7 +1120,7 @@ float AudioServer::get_playback_speed_scale() const { return playback_speed_scale; } -void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time, float p_pitch_scale) { +void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, const StringName &p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time, float p_pitch_scale) { ERR_FAIL_COND(p_playback.is_null()); HashMap<StringName, Vector<AudioFrame>> map; @@ -1127,7 +1129,7 @@ void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Str start_playback_stream(p_playback, map, p_start_time, p_pitch_scale); } -void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, HashMap<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time, float p_pitch_scale, float p_highshelf_gain, float p_attenuation_cutoff_hz) { +void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, const HashMap<StringName, Vector<AudioFrame>> &p_bus_volumes, float p_start_time, float p_pitch_scale, float p_highshelf_gain, float p_attenuation_cutoff_hz) { ERR_FAIL_COND(p_playback.is_null()); AudioStreamPlaybackListNode *playback_node = new AudioStreamPlaybackListNode(); @@ -1147,6 +1149,7 @@ void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Has for (int channel_idx = 0; channel_idx < MAX_CHANNELS_PER_BUS; channel_idx++) { new_bus_details->volume[idx][channel_idx] = pair.value[channel_idx]; } + idx++; } playback_node->bus_details = new_bus_details; playback_node->prev_bus_details = new AudioStreamPlaybackBusDetails(); @@ -1185,7 +1188,7 @@ void AudioServer::stop_playback_stream(Ref<AudioStreamPlayback> p_playback) { } while (!playback_node->state.compare_exchange_strong(old_state, new_state)); } -void AudioServer::set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volumes) { +void AudioServer::set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback, const StringName &p_bus, Vector<AudioFrame> p_volumes) { ERR_FAIL_COND(p_volumes.size() != MAX_CHANNELS_PER_BUS); HashMap<StringName, Vector<AudioFrame>> map; @@ -1194,7 +1197,7 @@ void AudioServer::set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback set_playback_bus_volumes_linear(p_playback, map); } -void AudioServer::set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_playback, HashMap<StringName, Vector<AudioFrame>> p_bus_volumes) { +void AudioServer::set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_playback, const HashMap<StringName, Vector<AudioFrame>> &p_bus_volumes) { ERR_FAIL_COND(p_bus_volumes.size() > MAX_BUSES_PER_PLAYBACK); AudioStreamPlaybackListNode *playback_node = _find_playback_list_node(p_playback); diff --git a/servers/audio_server.h b/servers/audio_server.h index 9ffa95bc00..4606299c47 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -372,13 +372,13 @@ public: float get_playback_speed_scale() const; // Convenience method. - void start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time = 0, float p_pitch_scale = 1); + void start_playback_stream(Ref<AudioStreamPlayback> p_playback, const StringName &p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time = 0, float p_pitch_scale = 1); // Expose all parameters. - void start_playback_stream(Ref<AudioStreamPlayback> p_playback, HashMap<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time = 0, float p_pitch_scale = 1, float p_highshelf_gain = 0, float p_attenuation_cutoff_hz = 0); + void start_playback_stream(Ref<AudioStreamPlayback> p_playback, const HashMap<StringName, Vector<AudioFrame>> &p_bus_volumes, float p_start_time = 0, float p_pitch_scale = 1, float p_highshelf_gain = 0, float p_attenuation_cutoff_hz = 0); void stop_playback_stream(Ref<AudioStreamPlayback> p_playback); - void set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volumes); - void set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_playback, HashMap<StringName, Vector<AudioFrame>> p_bus_volumes); + void set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback, const StringName &p_bus, Vector<AudioFrame> p_volumes); + void set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_playback, const HashMap<StringName, Vector<AudioFrame>> &p_bus_volumes); void set_playback_all_bus_volumes_linear(Ref<AudioStreamPlayback> p_playback, Vector<AudioFrame> p_volumes); void set_playback_pitch_scale(Ref<AudioStreamPlayback> p_playback, float p_pitch_scale); void set_playback_paused(Ref<AudioStreamPlayback> p_playback, bool p_paused); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index bb28bc0eb8..a587f72d02 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -596,6 +596,10 @@ DisplayServer::VSyncMode DisplayServer::window_get_vsync_mode(WindowID p_window) return VSyncMode::VSYNC_ENABLED; } +DisplayServer::WindowID DisplayServer::get_focused_window() const { + return MAIN_WINDOW_ID; // Proper value for single windows. +} + void DisplayServer::set_context(Context p_context) { } diff --git a/servers/display_server.h b/servers/display_server.h index 4450677f71..92a4a4a699 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -436,6 +436,8 @@ public: virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) = 0; virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const = 0; + virtual WindowID get_focused_window() const; + virtual void window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window = MAIN_WINDOW_ID) {} virtual Vector3i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const { return Vector3i(); } diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 258a799d34..412b12e145 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -213,12 +213,12 @@ NavigationServer3D::NavigationServer3D() { ERR_FAIL_COND(singleton != nullptr); singleton = this; - GLOBAL_DEF_BASIC("navigation/2d/default_cell_size", 1.0); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::FLOAT, "navigation/2d/default_cell_size", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), 1.0); GLOBAL_DEF("navigation/2d/use_edge_connections", true); GLOBAL_DEF_BASIC("navigation/2d/default_edge_connection_margin", 1.0); GLOBAL_DEF_BASIC("navigation/2d/default_link_connection_radius", 4.0); - GLOBAL_DEF_BASIC("navigation/3d/default_cell_size", 0.25); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::FLOAT, "navigation/3d/default_cell_size", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), 0.25); GLOBAL_DEF_BASIC("navigation/3d/default_cell_height", 0.25); GLOBAL_DEF("navigation/3d/default_up", Vector3(0, 1, 0)); GLOBAL_DEF("navigation/3d/use_edge_connections", true); @@ -286,7 +286,7 @@ void NavigationServer3D::set_debug_enabled(bool p_enabled) { debug_enabled = p_enabled; if (debug_dirty) { - call_deferred("_emit_navigation_debug_changed_signal"); + callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred(); } #endif // DEBUG_ENABLED } @@ -693,7 +693,7 @@ Color NavigationServer3D::get_debug_navigation_agent_path_color() const { void NavigationServer3D::set_debug_navigation_enable_edge_connections(const bool p_value) { debug_navigation_enable_edge_connections = p_value; navigation_debug_dirty = true; - call_deferred("_emit_navigation_debug_changed_signal"); + callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred(); } bool NavigationServer3D::get_debug_navigation_enable_edge_connections() const { @@ -714,7 +714,7 @@ bool NavigationServer3D::get_debug_navigation_enable_edge_connections_xray() con void NavigationServer3D::set_debug_navigation_enable_edge_lines(const bool p_value) { debug_navigation_enable_edge_lines = p_value; navigation_debug_dirty = true; - call_deferred("_emit_navigation_debug_changed_signal"); + callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred(); } bool NavigationServer3D::get_debug_navigation_enable_edge_lines() const { @@ -735,7 +735,7 @@ bool NavigationServer3D::get_debug_navigation_enable_edge_lines_xray() const { void NavigationServer3D::set_debug_navigation_enable_geometry_face_random_color(const bool p_value) { debug_navigation_enable_geometry_face_random_color = p_value; navigation_debug_dirty = true; - call_deferred("_emit_navigation_debug_changed_signal"); + callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred(); } bool NavigationServer3D::get_debug_navigation_enable_geometry_face_random_color() const { @@ -745,7 +745,7 @@ bool NavigationServer3D::get_debug_navigation_enable_geometry_face_random_color( void NavigationServer3D::set_debug_navigation_enable_link_connections(const bool p_value) { debug_navigation_enable_link_connections = p_value; navigation_debug_dirty = true; - call_deferred("_emit_navigation_debug_changed_signal"); + callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred(); } bool NavigationServer3D::get_debug_navigation_enable_link_connections() const { @@ -766,7 +766,7 @@ bool NavigationServer3D::get_debug_navigation_enable_link_connections_xray() con void NavigationServer3D::set_debug_navigation_avoidance_enable_agents_radius(const bool p_value) { debug_navigation_avoidance_enable_agents_radius = p_value; avoidance_debug_dirty = true; - call_deferred("_emit_avoidance_debug_changed_signal"); + callable_mp(this, &NavigationServer3D::_emit_avoidance_debug_changed_signal).call_deferred(); } bool NavigationServer3D::get_debug_navigation_avoidance_enable_agents_radius() const { @@ -776,7 +776,7 @@ bool NavigationServer3D::get_debug_navigation_avoidance_enable_agents_radius() c void NavigationServer3D::set_debug_navigation_avoidance_enable_obstacles_radius(const bool p_value) { debug_navigation_avoidance_enable_obstacles_radius = p_value; avoidance_debug_dirty = true; - call_deferred("_emit_avoidance_debug_changed_signal"); + callable_mp(this, &NavigationServer3D::_emit_avoidance_debug_changed_signal).call_deferred(); } bool NavigationServer3D::get_debug_navigation_avoidance_enable_obstacles_radius() const { @@ -786,7 +786,7 @@ bool NavigationServer3D::get_debug_navigation_avoidance_enable_obstacles_radius( void NavigationServer3D::set_debug_navigation_avoidance_enable_obstacles_static(const bool p_value) { debug_navigation_avoidance_enable_obstacles_static = p_value; avoidance_debug_dirty = true; - call_deferred("_emit_avoidance_debug_changed_signal"); + callable_mp(this, &NavigationServer3D::_emit_avoidance_debug_changed_signal).call_deferred(); } bool NavigationServer3D::get_debug_navigation_avoidance_enable_obstacles_static() const { @@ -867,7 +867,7 @@ void NavigationServer3D::set_debug_navigation_enable_agent_paths(const bool p_va debug_navigation_enable_agent_paths = p_value; if (debug_dirty) { - call_deferred("_emit_navigation_debug_changed_signal"); + callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred(); } } @@ -892,7 +892,7 @@ bool NavigationServer3D::get_debug_navigation_enable_agent_paths_xray() const { void NavigationServer3D::set_debug_navigation_enabled(bool p_enabled) { debug_navigation_enabled = p_enabled; navigation_debug_dirty = true; - call_deferred("_emit_navigation_debug_changed_signal"); + callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred(); } bool NavigationServer3D::get_debug_navigation_enabled() const { @@ -902,7 +902,7 @@ bool NavigationServer3D::get_debug_navigation_enabled() const { void NavigationServer3D::set_debug_avoidance_enabled(bool p_enabled) { debug_avoidance_enabled = p_enabled; avoidance_debug_dirty = true; - call_deferred("_emit_avoidance_debug_changed_signal"); + callable_mp(this, &NavigationServer3D::_emit_avoidance_debug_changed_signal).call_deferred(); } bool NavigationServer3D::get_debug_avoidance_enabled() const { diff --git a/servers/physics_server_2d_wrap_mt.cpp b/servers/physics_server_2d_wrap_mt.cpp index f4682b7c14..a23bb5e701 100644 --- a/servers/physics_server_2d_wrap_mt.cpp +++ b/servers/physics_server_2d_wrap_mt.cpp @@ -120,8 +120,6 @@ PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool physics_server_2d = p_contained; create_thread = p_create_thread; - pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc"); - if (!p_create_thread) { server_thread = Thread::get_caller_id(); } else { diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h index 0ae004da19..3bebe5df85 100644 --- a/servers/physics_server_2d_wrap_mt.h +++ b/servers/physics_server_2d_wrap_mt.h @@ -66,7 +66,6 @@ class PhysicsServer2DWrapMT : public PhysicsServer2D { bool first_frame = true; Mutex alloc_mutex; - int pool_max_size = 0; public: #define ServerName PhysicsServer2D diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index d523f4b1ec..addd1a5663 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -343,7 +343,7 @@ void PhysicsShapeQueryParameters3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude", "get_exclude"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "set_motion", "get_motion"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion"), "set_motion", "get_motion"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape"); ADD_PROPERTY(PropertyInfo(Variant::RID, "shape_rid"), "set_shape_rid", "get_shape_rid"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform"), "set_transform", "get_transform"); diff --git a/servers/physics_server_3d_wrap_mt.cpp b/servers/physics_server_3d_wrap_mt.cpp index 59db4617d0..feb17cad84 100644 --- a/servers/physics_server_3d_wrap_mt.cpp +++ b/servers/physics_server_3d_wrap_mt.cpp @@ -120,8 +120,6 @@ PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool physics_server_3d = p_contained; create_thread = p_create_thread; - pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc"); - if (!p_create_thread) { server_thread = Thread::get_caller_id(); } else { diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h index 99179d8248..fc8930977d 100644 --- a/servers/physics_server_3d_wrap_mt.h +++ b/servers/physics_server_3d_wrap_mt.h @@ -65,7 +65,6 @@ class PhysicsServer3DWrapMT : public PhysicsServer3D { bool first_frame = true; Mutex alloc_mutex; - int pool_max_size = 0; public: #define ServerName PhysicsServer3D diff --git a/servers/rendering/dummy/rasterizer_dummy.h b/servers/rendering/dummy/rasterizer_dummy.h index 179c41f286..929c661009 100644 --- a/servers/rendering/dummy/rasterizer_dummy.h +++ b/servers/rendering/dummy/rasterizer_dummy.h @@ -89,6 +89,8 @@ public: void prepare_for_blitting_render_targets() override {} void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) override {} + void end_viewport(bool p_swap_buffers) override {} + void end_frame(bool p_swap_buffers) override { if (p_swap_buffers) { DisplayServer::get_singleton()->swap_buffers(); diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index cc51d44042..caeac5cd95 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -37,17 +37,17 @@ #include "rendering_server_globals.h" #include "servers/rendering/storage/texture_storage.h" -void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info) { +void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info) { RENDER_TIMESTAMP("Cull CanvasItem Tree"); memset(z_list, 0, z_range * sizeof(RendererCanvasRender::Item *)); memset(z_last_list, 0, z_range * sizeof(RendererCanvasRender::Item *)); for (int i = 0; i < p_child_item_count; i++) { - _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, canvas_cull_mask); + _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, p_canvas_cull_mask); } if (p_canvas_item) { - _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, canvas_cull_mask); + _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, p_canvas_cull_mask); } RendererCanvasRender::Item *list = nullptr; @@ -114,29 +114,29 @@ void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_Owner<Renderer } while (ysort_owner && ysort_owner->sort_y); } -void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool p_use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform) { +void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, const Transform2D &p_transform, const Rect2 &p_clip_rect, Rect2 p_global_rect, const Color &p_modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool p_use_canvas_group, RendererCanvasRender::Item *r_canvas_group_from) { if (ci->copy_back_buffer) { - ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect); + ci->copy_back_buffer->screen_rect = p_transform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect); } if (p_use_canvas_group) { int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; - if (canvas_group_from == nullptr) { + if (r_canvas_group_from == nullptr) { // no list before processing this item, means must put stuff in group from the beginning of list. - canvas_group_from = r_z_list[zidx]; + r_canvas_group_from = r_z_list[zidx]; } else { // there was a list before processing, so begin group from this one. - canvas_group_from = canvas_group_from->next; + r_canvas_group_from = r_canvas_group_from->next; } - if (canvas_group_from) { + if (r_canvas_group_from) { // Has a place to begin the group from! //compute a global rect (in global coords) for children in the same z layer Rect2 rect_accum; - RendererCanvasRender::Item *c = canvas_group_from; + RendererCanvasRender::Item *c = r_canvas_group_from; while (c) { - if (c == canvas_group_from) { + if (c == r_canvas_group_from) { rect_accum = c->global_rect_cache; } else { rect_accum = rect_accum.merge(c->global_rect_cache); @@ -161,28 +161,28 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item * RendererCanvasRender::Item::CommandRect *crect = ci->alloc_command<RendererCanvasRender::Item::CommandRect>(); crect->flags = RendererCanvasRender::CANVAS_RECT_IS_GROUP; // so we can recognize it later - crect->rect = xform.affine_inverse().xform(rect_accum); + crect->rect = p_transform.affine_inverse().xform(rect_accum); crect->modulate = Color(1, 1, 1, 1); //the global rect is used to do the copying, so update it - global_rect = rect_accum.grow(ci->canvas_group->clear_margin); //grow again by clear margin - global_rect.position += p_clip_rect.position; + p_global_rect = rect_accum.grow(ci->canvas_group->clear_margin); //grow again by clear margin + p_global_rect.position += p_clip_rect.position; } else { - global_rect.position -= p_clip_rect.position; + p_global_rect.position -= p_clip_rect.position; - global_rect = global_rect.merge(rect_accum); //must use both rects for this - global_rect = global_rect.grow(ci->canvas_group->clear_margin); //grow by clear margin + p_global_rect = p_global_rect.merge(rect_accum); //must use both rects for this + p_global_rect = p_global_rect.grow(ci->canvas_group->clear_margin); //grow by clear margin - global_rect.position += p_clip_rect.position; + p_global_rect.position += p_clip_rect.position; } // Very important that this is cleared after used in RendererCanvasRender to avoid // potential crashes. - canvas_group_from->canvas_group_owner = ci; + r_canvas_group_from->canvas_group_owner = ci; } } - if (((ci->commands != nullptr || ci->visibility_notifier) && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) { + if (((ci->commands != nullptr || ci->visibility_notifier) && p_clip_rect.intersects(p_global_rect, true)) || ci->vp_render || ci->copy_back_buffer) { //something to draw? if (ci->update_when_visible) { @@ -190,9 +190,9 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item * } 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; + ci->final_transform = p_transform; + ci->final_modulate = p_modulate * ci->self_modulate; + ci->global_rect_cache = p_global_rect; ci->global_rect_cache.position -= p_clip_rect.position; ci->light_masked = false; @@ -223,14 +223,14 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item * } } -void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort, uint32_t canvas_cull_mask) { +void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_allow_y_sort, uint32_t p_canvas_cull_mask) { Item *ci = p_canvas_item; if (!ci->visible) { return; } - if (!(ci->visibility_layer & canvas_cull_mask)) { + if (!(ci->visibility_layer & p_canvas_cull_mask)) { return; } @@ -298,7 +298,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 } if (ci->sort_y) { - if (allow_y_sort) { + if (p_allow_y_sort) { if (ci->ysort_children_count == -1) { ci->ysort_children_count = 0; _collect_ysort_children(ci, Transform2D(), p_material_owner, Color(1, 1, 1, 1), nullptr, ci->ysort_children_count, p_z); @@ -318,7 +318,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 sorter.sort(child_items, child_item_count); for (i = 0; i < child_item_count; i++) { - _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, canvas_cull_mask); + _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask); } } else { RendererCanvasRender::Item *canvas_group_from = nullptr; @@ -328,7 +328,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 canvas_group_from = r_z_last_list[zidx]; } - _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform); + _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from); } } else { RendererCanvasRender::Item *canvas_group_from = nullptr; @@ -342,14 +342,14 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 if (!child_items[i]->behind && !use_canvas_group) { continue; } - _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, canvas_cull_mask); + _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask); } - _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform); + _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from); for (int i = 0; i < child_item_count; i++) { if (child_items[i]->behind || use_canvas_group) { continue; } - _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, canvas_cull_mask); + _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask); } } } @@ -2165,6 +2165,30 @@ bool RendererCanvasCull::free(RID p_rid) { return true; } +template <class T> +void RendererCanvasCull::_free_rids(T &p_owner, const char *p_type) { + List<RID> owned; + p_owner.get_owned_list(&owned); + if (owned.size()) { + if (owned.size() == 1) { + WARN_PRINT(vformat("1 RID of type \"%s\" was leaked.", p_type)); + } else { + WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type)); + } + for (const RID &E : owned) { + free(E); + } + } +} + +void RendererCanvasCull::finalize() { + _free_rids(canvas_owner, "Canvas"); + _free_rids(canvas_item_owner, "CanvasItem"); + _free_rids(canvas_light_owner, "CanvasLight"); + _free_rids(canvas_light_occluder_owner, "CanvasLightOccluder"); + _free_rids(canvas_light_occluder_polygon_owner, "CanvasLightOccluderPolygon"); +} + RendererCanvasCull::RendererCanvasCull() { z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index ba013e667f..de61e28204 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -170,6 +170,9 @@ public: RID_Owner<Item, true> canvas_item_owner; RID_Owner<RendererCanvasRender::Light, true> canvas_light_owner; + template <class T> + void _free_rids(T &p_owner, const char *p_type); + bool disable_scale; bool sdf_used = false; bool snapping_2d_transforms_to_pixel = false; @@ -181,11 +184,11 @@ public: PagedAllocator<Item::VisibilityNotifierData> visibility_notifier_allocator; SelfList<Item::VisibilityNotifierData>::List visibility_notifier_list; - _FORCE_INLINE_ void _attach_canvas_item_for_draw(Item *ci, Item *p_canvas_clip, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool p_use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform); + _FORCE_INLINE_ void _attach_canvas_item_for_draw(Item *ci, Item *p_canvas_clip, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, const Transform2D &p_transform, const Rect2 &p_clip_rect, Rect2 p_global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool p_use_canvas_group, RendererCanvasRender::Item *r_canvas_group_from); private: - void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info = nullptr); - void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort, uint32_t canvas_cull_mask); + void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info = nullptr); + void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_allow_y_sort, uint32_t p_canvas_cull_mask); static constexpr int z_range = RS::CANVAS_ITEM_Z_MAX - RS::CANVAS_ITEM_Z_MIN + 1; @@ -193,7 +196,7 @@ private: RendererCanvasRender::Item **z_last_list; public: - void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info = nullptr); + void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info = nullptr); bool was_sdf_used(); @@ -329,6 +332,9 @@ public: Rect2 _debug_canvas_item_get_rect(RID p_item); bool free(RID p_rid); + + void finalize(); + RendererCanvasCull(); ~RendererCanvasCull(); }; diff --git a/servers/rendering/renderer_canvas_render.cpp b/servers/rendering/renderer_canvas_render.cpp index af0ec621e5..6eb7bab9c9 100644 --- a/servers/rendering/renderer_canvas_render.cpp +++ b/servers/rendering/renderer_canvas_render.cpp @@ -31,6 +31,8 @@ #include "renderer_canvas_render.h" #include "servers/rendering/rendering_server_globals.h" +RendererCanvasRender *RendererCanvasRender::singleton = nullptr; + const Rect2 &RendererCanvasRender::Item::get_rect() const { if (custom_rect || (!rect_dirty && !update_when_visible && skeleton == RID())) { return rect; diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp index a6083fe70d..c36da51e50 100644 --- a/servers/rendering/renderer_compositor.cpp +++ b/servers/rendering/renderer_compositor.cpp @@ -31,8 +31,6 @@ #include "renderer_compositor.h" #include "core/config/project_settings.h" -#include "core/os/os.h" -#include "core/string/print_string.h" #include "servers/xr_server.h" RendererCompositor *RendererCompositor::singleton = nullptr; @@ -57,5 +55,3 @@ RendererCompositor::RendererCompositor() { xr_enabled = XRServer::get_xr_mode() == XRServer::XRMODE_ON; } } - -RendererCanvasRender *RendererCanvasRender::singleton = nullptr; diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h index ff7792741c..13767a3875 100644 --- a/servers/rendering/renderer_compositor.h +++ b/servers/rendering/renderer_compositor.h @@ -99,6 +99,7 @@ public: virtual void prepare_for_blitting_render_targets() = 0; virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0; + virtual void end_viewport(bool p_swap_buffers) = 0; virtual void end_frame(bool p_swap_buffers) = 0; virtual void finalize() = 0; virtual uint64_t get_frame_number() const = 0; diff --git a/servers/rendering/renderer_rd/api_context_rd.h b/servers/rendering/renderer_rd/api_context_rd.h index 22167be3c1..fd3be80605 100644 --- a/servers/rendering/renderer_rd/api_context_rd.h +++ b/servers/rendering/renderer_rd/api_context_rd.h @@ -58,16 +58,12 @@ public: virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) = 0; virtual void append_command_buffer(RDD::CommandBufferID p_command_buffer) = 0; - virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false) = 0; + virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false, bool p_sync = true) = 0; virtual Error prepare_buffers(RDD::CommandBufferID p_command_buffer) = 0; virtual void postpare_buffers(RDD::CommandBufferID p_command_buffer) = 0; virtual Error swap_buffers() = 0; virtual Error initialize() = 0; - virtual void command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) = 0; - virtual void command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) = 0; - virtual void command_end_label(RDD::CommandBufferID p_command_buffer) = 0; - virtual String get_device_vendor_name() const = 0; virtual String get_device_name() const = 0; virtual RDD::DeviceType get_device_type() const = 0; @@ -78,6 +74,7 @@ public: virtual DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const = 0; virtual RenderingDeviceDriver *get_driver(RID p_local_device = RID()) = 0; + virtual bool is_debug_utils_enabled() const = 0; virtual ~ApiContextRD(); }; diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp index 7554e478bb..e661fd9217 100644 --- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp +++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp @@ -266,8 +266,8 @@ void ClusterBuilderRD::setup(Size2i p_screen_size, uint32_t p_max_elements, RID screen_size = p_screen_size; - cluster_screen_size.width = (p_screen_size.width - 1) / cluster_size + 1; - cluster_screen_size.height = (p_screen_size.height - 1) / cluster_size + 1; + cluster_screen_size.width = Math::division_round_up((uint32_t)p_screen_size.width, cluster_size); + cluster_screen_size.height = Math::division_round_up((uint32_t)p_screen_size.height, cluster_size); max_elements_by_type = p_max_elements; if (max_elements_by_type % 32) { // Needs to be aligned to 32. @@ -420,11 +420,11 @@ void ClusterBuilderRD::bake_cluster() { RD::get_singleton()->draw_command_begin_label("Bake Light Cluster"); // Clear cluster buffer. - RD::get_singleton()->buffer_clear(cluster_buffer, 0, cluster_buffer_size, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_clear(cluster_buffer, 0, cluster_buffer_size); if (render_element_count > 0) { // Clear render buffer. - RD::get_singleton()->buffer_clear(cluster_render_buffer, 0, cluster_render_buffer_size, RD::BARRIER_MASK_RASTER); + RD::get_singleton()->buffer_clear(cluster_render_buffer, 0, cluster_render_buffer_size); { // Fill state uniform. @@ -439,18 +439,18 @@ void ClusterBuilderRD::bake_cluster() { state.cluster_depth_offset = (render_element_max / 32); state.cluster_data_size = state.cluster_depth_offset + render_element_max; - RD::get_singleton()->buffer_update(state_uniform, 0, sizeof(StateUniform), &state, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(state_uniform, 0, sizeof(StateUniform), &state); } // Update instances. - RD::get_singleton()->buffer_update(element_buffer, 0, sizeof(RenderElementData) * render_element_count, render_elements, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(element_buffer, 0, sizeof(RenderElementData) * render_element_count, render_elements); RENDER_TIMESTAMP("Render 3D Cluster Elements"); // Render elements. { - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD); ClusterBuilderSharedDataRD::ClusterRender::PushConstant push_constant = {}; RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shared->cluster_render.shader_pipelines[use_msaa ? ClusterBuilderSharedDataRD::ClusterRender::PIPELINE_MSAA : ClusterBuilderSharedDataRD::ClusterRender::PIPELINE_NORMAL]); @@ -488,7 +488,7 @@ void ClusterBuilderRD::bake_cluster() { RD::get_singleton()->draw_list_draw(draw_list, true, instances); i += instances; } - RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->draw_list_end(); } // Store elements. RENDER_TIMESTAMP("Pack 3D Cluster Elements"); @@ -503,7 +503,8 @@ void ClusterBuilderRD::bake_cluster() { push_constant.max_render_element_count_div_32 = render_element_max / 32; push_constant.cluster_screen_size[0] = cluster_screen_size.x; push_constant.cluster_screen_size[1] = cluster_screen_size.y; - push_constant.render_element_count_div_32 = render_element_count > 0 ? (render_element_count - 1) / 32 + 1 : 0; + + push_constant.render_element_count_div_32 = Math::division_round_up(render_element_count, 32U); push_constant.max_cluster_element_count_div_32 = max_elements_by_type / 32; push_constant.pad1 = 0; push_constant.pad2 = 0; @@ -512,10 +513,8 @@ void ClusterBuilderRD::bake_cluster() { RD::get_singleton()->compute_list_dispatch_threads(compute_list, cluster_screen_size.x, cluster_screen_size.y, 1); - RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->compute_list_end(); } - } else { - RD::get_singleton()->barrier(RD::BARRIER_MASK_TRANSFER, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); } RENDER_TIMESTAMP("< Bake 3D Cluster"); RD::get_singleton()->draw_command_end_label(); diff --git a/servers/rendering/renderer_rd/effects/bokeh_dof.cpp b/servers/rendering/renderer_rd/effects/bokeh_dof.cpp index cc5031823e..e6262c83e2 100644 --- a/servers/rendering/renderer_rd/effects/bokeh_dof.cpp +++ b/servers/rendering/renderer_rd/effects/bokeh_dof.cpp @@ -356,7 +356,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr ERR_FAIL_COND(shader.is_null()); RID framebuffer = p_buffers.base_weight_fb; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[BOKEH_GEN_BLUR_SIZE].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_depth_texture), 0); @@ -388,7 +388,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb; // Pass 1 - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_base_texture), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture0), 1); @@ -412,7 +412,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr RD::Uniform texture = bokeh.push_constant.half_size ? u_half_texture0 : u_secondary_texture; RD::Uniform weight = bokeh.push_constant.half_size ? u_weight_texture2 : u_weight_texture1; - draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, texture), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, weight), 1); @@ -430,7 +430,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr framebuffer = p_buffers.base_fb; - draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture1), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture3), 1); @@ -463,7 +463,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_base_texture), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture0), 1); @@ -481,7 +481,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr framebuffer = p_buffers.base_fb; - draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture0), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture2), 1); diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp index 18863d4978..fd6409d6bf 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.cpp +++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp @@ -583,7 +583,7 @@ void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffe RID shader = copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); if (p_secondary.is_valid()) { @@ -650,7 +650,7 @@ void CopyEffects::copy_raster(RID p_source_texture, RID p_dest_framebuffer) { ERR_FAIL_COND(shader.is_null()); // Just copy it back (we use our blur raster shader here).. - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[BLUR_MODE_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0); RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); @@ -724,7 +724,7 @@ void CopyEffects::gaussian_blur_raster(RID p_source_rd_texture, RID p_dest_textu RID shader = blur_raster.shader.version_get_shader(blur_raster.shader_version, blur_mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); @@ -826,7 +826,7 @@ void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, RID p_half_textu ERR_FAIL_COND(shader.is_null()); //HORIZONTAL - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(half_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(half_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(half_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); if (p_auto_exposure.is_valid() && p_first_pass) { @@ -846,7 +846,7 @@ void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, RID p_half_textu ERR_FAIL_COND(shader.is_null()); //VERTICAL - draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture), 0); @@ -916,7 +916,7 @@ void CopyEffects::make_mipmap_raster(RID p_source_rd_texture, RID p_dest_texture RID shader = blur_raster.shader.version_get_shader(blur_raster.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); @@ -982,7 +982,7 @@ void CopyEffects::set_color_raster(RID p_dest_texture, const Color &p_color, con RID shader = copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_region); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer))); RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); RD::get_singleton()->draw_list_set_push_constant(draw_list, ©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); @@ -990,7 +990,7 @@ void CopyEffects::set_color_raster(RID p_dest_texture, const Color &p_color, con RD::get_singleton()->draw_list_end(); } -void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip, BitField<RD::BarrierMask> p_post_barrier) { +void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -1015,14 +1015,14 @@ void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuf RID shader = cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_dp.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CopyToDPPushConstant)); RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(p_post_barrier); + RD::get_singleton()->draw_list_end(); } void CopyEffects::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) { @@ -1050,8 +1050,8 @@ void CopyEffects::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, c RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_cubemap), 1); - int x_groups = (p_size.x - 1) / 8 + 1; - int y_groups = (p_size.y - 1) / 8 + 1; + int x_groups = Math::division_round_up(p_size.x, 8); + int y_groups = Math::division_round_up(p_size.y, 8); RD::get_singleton()->compute_list_set_push_constant(compute_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant)); @@ -1080,7 +1080,7 @@ void CopyEffects::cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_fra RID shader = cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cubemap_downsampler.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0); @@ -1159,7 +1159,7 @@ void CopyEffects::cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebu RID shader = filter.raster_shader.version_get_shader(filter.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, filter.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, filter.uniform_set, 1); @@ -1204,8 +1204,8 @@ void CopyEffects::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); - int x_groups = (p_size - 1) / 8 + 1; - int y_groups = (p_size - 1) / 8 + 1; + int x_groups = Math::division_round_up(p_size, 8); + int y_groups = x_groups; RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, p_face_id > 9 ? 6 : 1); @@ -1237,7 +1237,7 @@ void CopyEffects::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_f RID shader = roughness.raster_shader.version_get_shader(roughness.shader_version, 0); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); @@ -1257,7 +1257,7 @@ void CopyEffects::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_b RD::get_singleton()->draw_command_begin_label("Merge specular"); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, Vector<Color>()); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, Vector<Color>()); int mode; if (p_reflection.is_valid()) { diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h index 60272a2eab..d18971a676 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.h +++ b/servers/rendering/renderer_rd/effects/copy_effects.h @@ -345,7 +345,7 @@ public: void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false); void set_color_raster(RID p_dest_texture, const Color &p_color, const Rect2i &p_region); - void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip, BitField<RD::BarrierMask> p_post_barrier = RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_TRANSFER); + void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip); void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size); void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size); void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array); diff --git a/servers/rendering/renderer_rd/effects/debug_effects.cpp b/servers/rendering/renderer_rd/effects/debug_effects.cpp index 3033d42375..a57a65fd5a 100644 --- a/servers/rendering/renderer_rd/effects/debug_effects.cpp +++ b/servers/rendering/renderer_rd/effects/debug_effects.cpp @@ -282,7 +282,7 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj // And draw our frustum. RD::FramebufferFormatID fb_format_id = RD::get_singleton()->framebuffer_get_format(p_dest_fb); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect); RID pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline); @@ -326,7 +326,7 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj rect.size.x *= atlas_rect_norm.size.x; rect.size.y *= atlas_rect_norm.size.y; - draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect); + draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect); pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline); @@ -351,7 +351,7 @@ void DebugEffects::draw_motion_vectors(RID p_velocity, RID p_depth, RID p_dest_f RD::Uniform u_source_velocity(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_velocity })); RD::Uniform u_source_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, Vector<RID>({ default_sampler, p_depth })); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, motion_vectors.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_fb), false, RD::get_singleton()->draw_list_get_current_pass())); Projection reprojection = p_previous_projection.flipped_y() * p_previous_transform.affine_inverse() * p_current_transform * p_current_projection.flipped_y().inverse(); diff --git a/servers/rendering/renderer_rd/effects/fsr.cpp b/servers/rendering/renderer_rd/effects/fsr.cpp index 0c51adf9ee..5599a5a162 100644 --- a/servers/rendering/renderer_rd/effects/fsr.cpp +++ b/servers/rendering/renderer_rd/effects/fsr.cpp @@ -124,5 +124,5 @@ void FSR::fsr_upscale(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_r RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1); - RD::get_singleton()->compute_list_end(compute_list); + RD::get_singleton()->compute_list_end(); } diff --git a/servers/rendering/renderer_rd/effects/fsr2.cpp b/servers/rendering/renderer_rd/effects/fsr2.cpp index 0c38989304..bebbf51d51 100644 --- a/servers/rendering/renderer_rd/effects/fsr2.cpp +++ b/servers/rendering/renderer_rd/effects/fsr2.cpp @@ -377,10 +377,7 @@ static FfxErrorCode execute_gpu_job_copy_rd(FSR2Context::Scratch &p_scratch, con ERR_FAIL_COND_V(dst_desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT); for (uint32_t mip_level = 0; mip_level < src_desc.mipCount; mip_level++) { - // Only push the barriers on the last copy. - // FIXME: This could be optimized if RenderingDevice was able to copy multiple mip levels in a single command. - BitField<RD::BarrierMask> post_barrier = (mip_level == (src_desc.mipCount - 1)) ? RD::BARRIER_MASK_ALL_BARRIERS : RD::BARRIER_MASK_NO_BARRIER; - RD::get_singleton()->texture_copy(src, dst, Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(src_desc.width, src_desc.height, src_desc.depth), mip_level, mip_level, 0, 0, post_barrier); + RD::get_singleton()->texture_copy(src, dst, Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(src_desc.width, src_desc.height, src_desc.depth), mip_level, mip_level, 0, 0); } return FFX_OK; @@ -435,8 +432,7 @@ static FfxErrorCode execute_gpu_job_compute_rd(FSR2Context::Scratch &p_scratch, RID buffer_rid = p_scratch.ubo_ring_buffer[p_scratch.ubo_ring_buffer_index]; p_scratch.ubo_ring_buffer_index = (p_scratch.ubo_ring_buffer_index + 1) % FSR2_UBO_RING_BUFFER_SIZE; - BitField<RD::BarrierMask> post_barrier = (i == (p_job.pipeline.constCount - 1)) ? RD::BARRIER_MASK_ALL_BARRIERS : RD::BARRIER_MASK_NO_BARRIER; - RD::get_singleton()->buffer_update(buffer_rid, 0, p_job.cbs[i].uint32Size * sizeof(uint32_t), p_job.cbs[i].data, post_barrier); + RD::get_singleton()->buffer_update(buffer_rid, 0, p_job.cbs[i].uint32Size * sizeof(uint32_t), p_job.cbs[i].data); RD::Uniform buffer_uniform(RD::UNIFORM_TYPE_UNIFORM_BUFFER, p_job.pipeline.cbResourceBindings[i].slotIndex, buffer_rid); compute_uniforms.push_back(buffer_uniform); @@ -566,7 +562,6 @@ FSR2Effect::FSR2Effect() { FfxResourceBinding{ 2, 0, L"r_dilatedDepth" }, FfxResourceBinding{ 3, 0, L"r_reactive_mask" }, FfxResourceBinding{ 4, 0, L"r_transparency_and_composition_mask" }, - FfxResourceBinding{ 5, 0, L"r_prepared_input_color" }, FfxResourceBinding{ 6, 0, L"r_previous_dilated_motion_vectors" }, FfxResourceBinding{ 7, 0, L"r_input_motion_vectors" }, FfxResourceBinding{ 8, 0, L"r_input_color_jittered" }, diff --git a/servers/rendering/renderer_rd/effects/luminance.cpp b/servers/rendering/renderer_rd/effects/luminance.cpp index 3aa5f5706e..61b2248b5c 100644 --- a/servers/rendering/renderer_rd/effects/luminance.cpp +++ b/servers/rendering/renderer_rd/effects/luminance.cpp @@ -184,7 +184,7 @@ void Luminance::luminance_reduction(RID p_source_texture, const Size2i p_source_ RD::Uniform u_source_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, i == 0 ? p_source_texture : p_luminance_buffers->reduce[i - 1] })); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, luminance_reduce_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0); if (final) { diff --git a/servers/rendering/renderer_rd/effects/resolve.cpp b/servers/rendering/renderer_rd/effects/resolve.cpp index 18671d06e1..feb0e6ed1e 100644 --- a/servers/rendering/renderer_rd/effects/resolve.cpp +++ b/servers/rendering/renderer_rd/effects/resolve.cpp @@ -54,7 +54,7 @@ Resolve::~Resolve() { resolve.shader.version_free(resolve.shader_version); } -void Resolve::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) { +void Resolve::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -93,10 +93,10 @@ void Resolve::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.x, p_screen_size.y, 1); - RD::get_singleton()->compute_list_end(p_barrier); + RD::get_singleton()->compute_list_end(); } -void Resolve::resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) { +void Resolve::resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -126,5 +126,5 @@ void Resolve::resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_scr RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.x, p_screen_size.y, 1); - RD::get_singleton()->compute_list_end(p_barrier); + RD::get_singleton()->compute_list_end(); } diff --git a/servers/rendering/renderer_rd/effects/resolve.h b/servers/rendering/renderer_rd/effects/resolve.h index fcc1021904..14477f90e4 100644 --- a/servers/rendering/renderer_rd/effects/resolve.h +++ b/servers/rendering/renderer_rd/effects/resolve.h @@ -65,8 +65,8 @@ public: Resolve(); ~Resolve(); - void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); - void resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); + void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples); + void resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples); }; } // namespace RendererRD diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp index 628edc0127..46fb0a75d6 100644 --- a/servers/rendering/renderer_rd/effects/ss_effects.cpp +++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp @@ -525,7 +525,7 @@ void SSEffects::downsample_depth(Ref<RenderSceneBuffersRD> p_render_buffers, uin RD::get_singleton()->compute_list_add_barrier(compute_list); RD::get_singleton()->draw_command_end_label(); - RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->compute_list_end(); ss_effects.used_full_mips_last_frame = use_full_mips; ss_effects.used_half_size_last_frame = use_half_size; @@ -950,10 +950,10 @@ void SSEffects::screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_rende RD::get_singleton()->draw_command_end_label(); // SSIL - RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_TRANSFER); // Zeroing importance_map_load_counter depends on us. + RD::get_singleton()->compute_list_end(); int zero[1] = { 0 }; - RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier + RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero); } /* SSAO */ @@ -1332,10 +1332,10 @@ void SSEffects::generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORe RD::get_singleton()->draw_command_end_label(); // Interleave } RD::get_singleton()->draw_command_end_label(); //SSAO - RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_TRANSFER); // Zeroing importance_map_load_counter depends on us. + RD::get_singleton()->compute_list_end(); int zero[1] = { 0 }; - RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier + RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero); } /* Screen Space Reflection */ @@ -1394,7 +1394,7 @@ void SSEffects::screen_space_reflection(Ref<RenderSceneBuffersRD> p_render_buffe scene_data.eye_offset[v][3] = 0.0; } - RD::get_singleton()->buffer_update(ssr.ubo, 0, sizeof(ScreenSpaceReflectionSceneData), &scene_data, RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(ssr.ubo, 0, sizeof(ScreenSpaceReflectionSceneData), &scene_data); } uint32_t pipeline_specialization = 0; diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.cpp b/servers/rendering/renderer_rd/effects/tone_mapper.cpp index 48c6511408..ee0b6adb4d 100644 --- a/servers/rendering/renderer_rd/effects/tone_mapper.cpp +++ b/servers/rendering/renderer_rd/effects/tone_mapper.cpp @@ -166,7 +166,7 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton RID shader = tonemap.shader.version_get_shader(tonemap.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass())); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_exposure_texture), 1); diff --git a/servers/rendering/renderer_rd/effects/vrs.cpp b/servers/rendering/renderer_rd/effects/vrs.cpp index 63c99facdd..41a6b2d622 100644 --- a/servers/rendering/renderer_rd/effects/vrs.cpp +++ b/servers/rendering/renderer_rd/effects/vrs.cpp @@ -82,7 +82,7 @@ void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multi RID shader = vrs_shader.shader.version_get_shader(vrs_shader.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>()); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>()); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, vrs_shader.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); // RD::get_singleton()->draw_list_set_push_constant(draw_list, &vrs_shader.push_constant, sizeof(VRSPushConstant)); diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index 7d4eb0e038..78ab6f3650 100644 --- a/servers/rendering/renderer_rd/environment/fog.cpp +++ b/servers/rendering/renderer_rd/environment/fog.cpp @@ -570,7 +570,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P RendererRD::MaterialStorage::store_transform(to_prev_cam_view, params.to_prev_view); RendererRD::MaterialStorage::store_transform(p_cam_transform, params.transform); - RD::get_singleton()->buffer_update(volumetric_fog.volume_ubo, 0, sizeof(VolumetricFogShader::VolumeUBO), ¶ms, RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(volumetric_fog.volume_ubo, 0, sizeof(VolumetricFogShader::VolumeUBO), ¶ms); if (fog->fog_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(fog->fog_uniform_set)) { Vector<RD::Uniform> uniforms; @@ -1069,8 +1069,8 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P uint32_t cluster_size = p_settings.cluster_builder->get_cluster_size(); params.cluster_shift = get_shift_from_power_of_2(cluster_size); - uint32_t cluster_screen_width = (p_settings.rb_size.x - 1) / cluster_size + 1; - uint32_t cluster_screen_height = (p_settings.rb_size.y - 1) / cluster_size + 1; + uint32_t cluster_screen_width = Math::division_round_up((uint32_t)p_settings.rb_size.x, cluster_size); + uint32_t cluster_screen_height = Math::division_round_up((uint32_t)p_settings.rb_size.y, cluster_size); params.max_cluster_element_count_div_32 = p_settings.max_cluster_elements / 32; params.cluster_type_size = cluster_screen_width * cluster_screen_height * (params.max_cluster_element_count_div_32 + 32); params.cluster_width = cluster_screen_width; @@ -1086,7 +1086,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog"); RENDER_TIMESTAMP("Render Fog"); - RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), ¶ms, RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), ¶ms); RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); @@ -1140,7 +1140,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->gi_dependent_sets.process_uniform_set, 0); RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, 1); - RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER); + RD::get_singleton()->compute_list_end(); RENDER_TIMESTAMP("< Volumetric Fog"); RD::get_singleton()->draw_command_end_label(); diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index dce8fadb63..6da828df45 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -583,7 +583,8 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re /* Buffers */ cascade.solid_cell_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDFGI::Cascade::SolidCell) * solid_cell_count); - cascade.solid_cell_dispatch_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, Vector<uint8_t>(), RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT); + cascade.solid_cell_dispatch_buffer_storage = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, Vector<uint8_t>()); + cascade.solid_cell_dispatch_buffer_call = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, Vector<uint8_t>(), RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT); cascade.lights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDFGIShader::Light) * MAX(SDFGI::MAX_STATIC_LIGHTS, SDFGI::MAX_DYNAMIC_LIGHTS)); { Vector<RD::Uniform> uniforms; @@ -650,7 +651,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 10; - u.append_id(cascade.solid_cell_dispatch_buffer); + u.append_id(cascade.solid_cell_dispatch_buffer_storage); uniforms.push_back(u); } { @@ -698,7 +699,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 5; - u.append_id(cascade.solid_cell_dispatch_buffer); + u.append_id(cascade.solid_cell_dispatch_buffer_storage); uniforms.push_back(u); } { @@ -761,7 +762,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re RD::Uniform u; u.binding = 3; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.append_id(cascade.solid_cell_dispatch_buffer); + u.append_id(cascade.solid_cell_dispatch_buffer_storage); uniforms.push_back(u); } { @@ -1129,7 +1130,8 @@ GI::SDFGI::~SDFGI() { RD::get_singleton()->free(c.light_aniso_0_tex); RD::get_singleton()->free(c.light_aniso_1_tex); RD::get_singleton()->free(c.sdf_tex); - RD::get_singleton()->free(c.solid_cell_dispatch_buffer); + RD::get_singleton()->free(c.solid_cell_dispatch_buffer_storage); + RD::get_singleton()->free(c.solid_cell_dispatch_buffer_call); RD::get_singleton()->free(c.solid_cell_buffer); RD::get_singleton()->free(c.lightprobe_history_tex); RD::get_singleton()->free(c.lightprobe_average_tex); @@ -1238,6 +1240,10 @@ void GI::SDFGI::update(RID p_env, const Vector3 &p_world_position) { void GI::SDFGI::update_light() { RD::get_singleton()->draw_command_begin_label("SDFGI Update dynamic Light"); + for (uint32_t i = 0; i < cascades.size(); i++) { + RD::get_singleton()->buffer_copy(cascades[i].solid_cell_dispatch_buffer_storage, cascades[i].solid_cell_dispatch_buffer_call, 0, 0, sizeof(uint32_t) * 4); + } + /* Update dynamic light */ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); @@ -1276,9 +1282,9 @@ void GI::SDFGI::update_light() { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_dynamic_uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::DirectLightPushConstant)); - RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer, 0); + RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer_call, 0); } - RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->compute_list_end(); RD::get_singleton()->draw_command_end_label(); } @@ -1351,7 +1357,7 @@ void GI::SDFGI::update_probes(RID p_env, SkyRD::Sky *p_sky) { render_pass++; - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_PROCESS]); int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR; @@ -1368,14 +1374,11 @@ void GI::SDFGI::update_probes(RID p_env, SkyRD::Sky *p_sky) { RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count, probe_axis_count, 1); } - //end later after raster to avoid barriering on layout changes - //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); - + RD::get_singleton()->compute_list_end(); RD::get_singleton()->draw_command_end_label(); } void GI::SDFGI::store_probes() { - RD::get_singleton()->barrier(RD::BARRIER_MASK_COMPUTE, RD::BARRIER_MASK_COMPUTE); RD::get_singleton()->draw_command_begin_label("SDFGI Store Probes"); SDFGIShader::IntegratePushConstant push_constant; @@ -1414,7 +1417,7 @@ void GI::SDFGI::store_probes() { RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1); } - RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->compute_list_end(); RD::get_singleton()->draw_command_end_label(); } @@ -1493,7 +1496,7 @@ void GI::SDFGI::update_cascades() { cascade_data[i].pad = 0; } - RD::get_singleton()->buffer_update(cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data); } void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture, const Vector<RID> &p_texture_views) { @@ -1636,7 +1639,7 @@ void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projection copy_effects->copy_to_fb_rect(p_texture, texture_storage->render_target_get_rd_framebuffer(p_render_target), Rect2i(Point2i(), rtsize), true, false, false, false, RID(), p_view_count > 1); } -void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth) { +void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms) { RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); // setup scene data @@ -1651,7 +1654,7 @@ void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, con RendererRD::MaterialStorage::store_camera(p_camera_with_transforms[v], scene_data.projection[v]); } - RD::get_singleton()->buffer_update(debug_probes_scene_data_ubo, 0, sizeof(SDFGIShader::DebugProbesSceneData), &scene_data, RD::BARRIER_MASK_RASTER); + RD::get_singleton()->buffer_update(debug_probes_scene_data_ubo, 0, sizeof(SDFGIShader::DebugProbesSceneData), &scene_data); } // setup push constant @@ -1718,7 +1721,7 @@ void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, con SDFGIShader::ProbeDebugMode mode = p_view_count > 1 ? SDFGIShader::PROBE_DEBUG_PROBES_MULTIVIEW : SDFGIShader::PROBE_DEBUG_PROBES; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CONTINUE, p_will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE); RD::get_singleton()->draw_command_begin_label("Debug SDFGI"); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, gi->sdfgi_shader.debug_probes_pipeline[mode].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); @@ -1861,7 +1864,7 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r } } - RD::get_singleton()->buffer_update(gi->sdfgi_ubo, 0, sizeof(SDFGIData), &sdfgi_data, RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(gi->sdfgi_ubo, 0, sizeof(SDFGIData), &sdfgi_data); /* Update dynamic lights in SDFGI cascades */ @@ -1983,7 +1986,7 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r } if (idx > 0) { - RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDFGIShader::Light), lights, RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDFGIShader::Light), lights); } cascade_dynamic_light_count[i] = idx; @@ -2046,6 +2049,8 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_ push_constant.cascade = cascade; if (cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) { + RD::get_singleton()->buffer_copy(cascades[cascade].solid_cell_dispatch_buffer_storage, cascades[cascade].solid_cell_dispatch_buffer_call, 0, 0, sizeof(uint32_t) * 4); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); //must pre scroll existing data because not all is dirty @@ -2053,7 +2058,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].scroll_uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant)); - RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascades[cascade].solid_cell_dispatch_buffer, 0); + RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascades[cascade].solid_cell_dispatch_buffer_call, 0); // no barrier do all together RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_SCROLL_OCCLUSION]); @@ -2142,7 +2147,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_ //clear dispatch indirect data uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 }; - RD::get_singleton()->buffer_update(cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data); + RD::get_singleton()->buffer_update(cascades[cascade].solid_cell_dispatch_buffer_storage, 0, sizeof(uint32_t) * 4, dispatch_indirct_data); RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); @@ -2451,6 +2456,15 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen } } + for (uint32_t i = 0; i < p_cascade_count; i++) { + ERR_CONTINUE(p_cascade_indices[i] >= cascades.size()); + + SDFGI::Cascade &cc = cascades[p_cascade_indices[i]]; + if (light_count[i] > 0) { + RD::get_singleton()->buffer_copy(cc.solid_cell_dispatch_buffer_storage, cc.solid_cell_dispatch_buffer_call, 0, 0, sizeof(uint32_t) * 4); + } + } + /* Static Lights */ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); @@ -2482,7 +2496,7 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen if (dl_push_constant.light_count > 0) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cc.sdf_direct_light_static_uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &dl_push_constant, sizeof(SDFGIShader::DirectLightPushConstant)); - RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cc.solid_cell_dispatch_buffer, 0); + RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cc.solid_cell_dispatch_buffer_call, 0); } } @@ -3143,7 +3157,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[0].uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIDynamicPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1); + RD::get_singleton()->compute_list_dispatch(compute_list, Math::division_round_up(rect.size.x, 8), Math::division_round_up(rect.size.y, 8), 1); //print_line("rect: " + itos(i) + ": " + rect); for (int k = 1; k < dynamic_maps.size(); k++) { @@ -3205,7 +3219,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID } RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[k].uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIDynamicPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1); + RD::get_singleton()->compute_list_dispatch(compute_list, Math::division_round_up(rect.size.x, 8), Math::division_round_up(rect.size.y, 8), 1); } RD::get_singleton()->compute_list_end(); @@ -3716,7 +3730,7 @@ void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBu if (p_voxel_gi_instances.size() > 0) { RD::get_singleton()->draw_command_begin_label("VoxelGIs Setup"); - RD::get_singleton()->buffer_update(voxel_gi_buffer, 0, sizeof(VoxelGIData) * MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size()), voxel_gi_data, RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(voxel_gi_buffer, 0, sizeof(VoxelGIData) * MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size()), voxel_gi_data); RD::get_singleton()->draw_command_end_label(); } @@ -3804,11 +3818,11 @@ void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_nor scene_data.screen_size[0] = internal_size.x; scene_data.screen_size[1] = internal_size.y; - RD::get_singleton()->buffer_update(rbgi->scene_data_ubo, 0, sizeof(SceneData), &scene_data, RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(rbgi->scene_data_ubo, 0, sizeof(SceneData), &scene_data); } // Now compute the contents of our buffers. - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); // Render each eye separately. // We need to look into whether we can make our compute shader use Multiview but not sure that works or makes a difference.. @@ -4038,8 +4052,7 @@ void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_nor } } - //do barrier later to allow oeverlap - //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time + RD::get_singleton()->compute_list_end(); RD::get_singleton()->draw_command_end_label(); } diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h index c46d4cbd25..011493f1f6 100644 --- a/servers/rendering/renderer_rd/environment/gi.h +++ b/servers/rendering/renderer_rd/environment/gi.h @@ -584,7 +584,9 @@ public: uint32_t static_light_aniso; }; - RID solid_cell_dispatch_buffer; //buffer for indirect compute dispatch + // Buffers for indirect compute dispatch. + RID solid_cell_dispatch_buffer_storage; + RID solid_cell_dispatch_buffer_call; RID solid_cell_buffer; RID lightprobe_history_tex; @@ -686,7 +688,7 @@ public: void update_cascades(); void debug_draw(uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture, const Vector<RID> &p_texture_views); - void debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth); + void debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms); void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data); void render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, float p_exposure_normalization); diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index ba72ab3b08..41609dc74d 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -1307,7 +1307,7 @@ void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd, p_render_buffers); - cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier); RD::get_singleton()->draw_list_end(); } @@ -1328,7 +1328,7 @@ void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd, p_render_buffers); - cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier); RD::get_singleton()->draw_list_end(); } @@ -1345,7 +1345,7 @@ void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd, p_render_buffers); - cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier); RD::get_singleton()->draw_list_end(); } @@ -1469,7 +1469,7 @@ void SkyRD::update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p Vector<Color> clear_colors; clear_colors.push_back(Color(0.0, 0.0, 0.0)); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); _render_sky(draw_list, p_time, framebuffer, pipeline, material->uniform_set, texture_uniform_set, projection, sky_transform, sky_scene_state.cam_transform.origin, p_luminance_multiplier); RD::get_singleton()->draw_list_end(); } @@ -1488,7 +1488,7 @@ void SkyRD::update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p Vector<Color> clear_colors; clear_colors.push_back(Color(0.0, 0.0, 0.0)); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); _render_sky(draw_list, p_time, framebuffer, pipeline, material->uniform_set, texture_uniform_set, projection, sky_transform, sky_scene_state.cam_transform.origin, p_luminance_multiplier); RD::get_singleton()->draw_list_end(); } 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 f3cde94149..0c0062662a 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -576,31 +576,13 @@ void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_lis } } -void RenderForwardClustered::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) { - uint32_t render_total = p_params->element_count; - uint32_t total_threads = WorkerThreadPool::get_singleton()->get_thread_count(); - uint32_t render_from = p_thread * render_total / total_threads; - uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads); - _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to); -} - -void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) { +void RenderForwardClustered::_render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) { RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer); p_params->framebuffer_format = fb_format; - if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time - //multi threaded - thread_draw_lists.resize(WorkerThreadPool::get_singleton()->get_thread_count()); - RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); - WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &RenderForwardClustered::_render_list_thread_function, p_params, thread_draw_lists.size(), -1, true, SNAME("ForwardClusteredRenderList")); - WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); - RD::get_singleton()->draw_list_end(p_params->barrier); - } else { - //single threaded - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); - _render_list(draw_list, fb_format, p_params, 0, p_params->element_count); - RD::get_singleton()->draw_list_end(p_params->barrier); - } + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region); + _render_list(draw_list, fb_format, p_params, 0, p_params->element_count); + RD::get_singleton()->draw_list_end(); } 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_apply_alpha_multiplier, bool p_pancake_shadows, int p_index) { @@ -626,8 +608,8 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat 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; { - uint32_t cluster_screen_width = (p_screen_size.width - 1) / p_render_data->cluster_size + 1; - uint32_t cluster_screen_height = (p_screen_size.height - 1) / p_render_data->cluster_size + 1; + uint32_t cluster_screen_width = Math::division_round_up((uint32_t)p_screen_size.width, p_render_data->cluster_size); + uint32_t cluster_screen_height = Math::division_round_up((uint32_t)p_screen_size.height, p_render_data->cluster_size); scene_state.ubo.cluster_type_size = cluster_screen_width * cluster_screen_height * (scene_state.ubo.max_cluster_element_count_div_32 + 32); scene_state.ubo.cluster_width = cluster_screen_width; } @@ -683,7 +665,7 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat } } - RD::get_singleton()->buffer_update(scene_state.implementation_uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER); + RD::get_singleton()->buffer_update(scene_state.implementation_uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo); } void RenderForwardClustered::_update_instance_data_buffer(RenderListType p_render_list) { @@ -696,7 +678,7 @@ void RenderForwardClustered::_update_instance_data_buffer(RenderListType p_rende scene_state.instance_buffer[p_render_list] = RD::get_singleton()->storage_buffer_create(new_size * sizeof(SceneState::InstanceData)); scene_state.instance_buffer_size[p_render_list] = new_size; } - RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER); + RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr()); } } void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, int *p_render_info, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) { @@ -1097,7 +1079,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con } if (p_render_list == RENDER_LIST_OPAQUE && lightmap_captures_used) { - RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures, RD::BARRIER_MASK_RASTER); + RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures); } } @@ -1135,7 +1117,7 @@ void RenderForwardClustered::_setup_lightmaps(const RenderDataRD *p_render_data, scene_state.lightmaps_used++; } if (scene_state.lightmaps_used > 0) { - RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps, RD::BARRIER_MASK_RASTER); + RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps); } } @@ -1427,7 +1409,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo if (p_render_data->directional_shadows.size()) { //open the pass for directional shadows light_storage->update_directional_shadow_atlas(); - RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE); + RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE); RD::get_singleton()->draw_list_end(); } } @@ -1461,18 +1443,12 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo _render_shadow_process(); } - //start GI if (render_gi) { gi.process_gi(rb, 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) if (render_shadows) { - _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER); - } - - if (render_gi) { - RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //use a later barrier + _render_shadow_end(); } if (rb_data.is_valid() && ss_effects) { @@ -1496,9 +1472,6 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo } } - //full barrier here, we need raster, transfer and compute and it depends from the previous work - RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL_BARRIERS, RD::BARRIER_MASK_ALL_BARRIERS); - if (current_cluster_builder) { // Note: when rendering stereoscopic (multiview) we are using our combined frustum projection to create // our cluster data. We use reprojection in the shader to adjust for our left/right eye. @@ -1814,7 +1787,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co float sky_energy_multiplier = 1.0 / _render_buffers_get_luminance_multiplier(); Color clear_color; - bool keep_color = false; + bool load_color = false; if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black @@ -1857,10 +1830,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co bool convert_to_linear = !RendererRD::TextureStorage::get_singleton()->render_target_is_using_hdr(rb->get_render_target()); copy_effects->copy_to_fb_rect(texture, color_only_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, convert_to_linear); } - keep_color = true; + load_color = true; } break; case RS::ENV_BG_KEEP: { - keep_color = true; + load_color = true; } break; case RS::ENV_BG_CAMERA_FEED: { } break; @@ -1912,7 +1885,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co bool depth_pre_pass = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable")) && depth_framebuffer.is_valid(); bool using_ssao = depth_pre_pass && !is_reflection_probe && p_render_data->environment.is_valid() && environment_get_ssao_enabled(p_render_data->environment); - bool continue_depth = false; if (depth_pre_pass) { //depth pre pass bool needs_pre_resolve = _needs_post_prepass_render(p_render_data, using_sdfgi || using_voxelgi); @@ -1923,7 +1895,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } if (needs_pre_resolve) { //pre clear the depth framebuffer, as AMD (and maybe others?) use compute for it, and barrier other compute shaders. - RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, depth_pass_clear); + RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pass_clear); RD::get_singleton()->draw_list_end(); //start compute processes here, so they run at the same time as depth pre-pass _post_prepass_render(p_render_data, using_sdfgi || using_voxelgi); @@ -1935,21 +1907,14 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co bool finish_depth = using_ssao || using_ssil || 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->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); + _render_list_with_draw_list(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, needs_pre_resolve ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear); RD::get_singleton()->draw_command_end_label(); - if (needs_pre_resolve) { - _pre_resolve_render(p_render_data, using_sdfgi || using_voxelgi); - } - if (rb->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) { RENDER_TIMESTAMP("Resolve Depth Pre-Pass (MSAA)"); RD::get_singleton()->draw_command_begin_label("Resolve Depth Pre-Pass (MSAA)"); if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI) { - if (needs_pre_resolve) { - RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, RD::BARRIER_MASK_COMPUTE); - } for (uint32_t v = 0; v < rb->get_view_count(); v++) { resolve_effects->resolve_gi(rb->get_depth_msaa(v), rb_data->get_normal_roughness_msaa(v), using_voxelgi ? rb_data->get_voxelgi_msaa(v) : RID(), rb->get_depth_texture(v), rb_data->get_normal_roughness(v), using_voxelgi ? rb_data->get_voxelgi(v) : RID(), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]); } @@ -1960,8 +1925,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } RD::get_singleton()->draw_command_end_label(); } - - continue_depth = !finish_depth; } RID normal_roughness_views[RendererSceneRender::MAX_RENDER_VIEWS]; @@ -1990,10 +1953,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co { bool render_motion_pass = !render_list[RENDER_LIST_MOTION].elements.is_empty(); - bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes); - bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes); - RD::FinalAction final_color_action = will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ; - RD::FinalAction final_depth_action = will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ; { Vector<Color> c; @@ -2014,7 +1973,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co uint32_t opaque_color_pass_flags = using_motion_pass ? (color_pass_flags & ~COLOR_PASS_FLAG_MOTION_VECTORS) : color_pass_flags; RID opaque_framebuffer = using_motion_pass ? rb_data->get_color_pass_fb(opaque_color_pass_flags) : color_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, opaque_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_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, opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, render_motion_pass ? RD::FINAL_ACTION_CONTINUE : final_color_action, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, render_motion_pass ? RD::FINAL_ACTION_CONTINUE : final_depth_action, c, 1.0, 0); + _render_list_with_draw_list(&render_list_params, opaque_framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pre_pass ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 1.0, 0); } RD::get_singleton()->draw_command_end_label(); @@ -2022,7 +1981,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co if (using_motion_pass) { Vector<Color> motion_vector_clear_colors; motion_vector_clear_colors.push_back(Color(-1, -1, 0, 0)); - RD::get_singleton()->draw_list_begin(rb_data->get_velocity_only_fb(), RD::INITIAL_ACTION_CLEAR, render_motion_pass ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE, motion_vector_clear_colors); + RD::get_singleton()->draw_list_begin(rb_data->get_velocity_only_fb(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, motion_vector_clear_colors); RD::get_singleton()->draw_list_end(); } @@ -2034,33 +1993,17 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_MOTION, p_render_data, radiance_texture, samplers, true); RenderListParameters render_list_params(render_list[RENDER_LIST_MOTION].elements.ptr(), render_list[RENDER_LIST_MOTION].element_info.ptr(), render_list[RENDER_LIST_MOTION].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_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, RD::INITIAL_ACTION_CONTINUE, final_color_action, RD::INITIAL_ACTION_CONTINUE, final_depth_action); + _render_list_with_draw_list(&render_list_params, color_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE); RD::get_singleton()->draw_command_end_label(); - - if (will_continue_color) { - // Close the motion vectors framebuffer as it'll no longer be used. - RD::get_singleton()->draw_list_begin(rb_data->get_velocity_only_fb(), RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE); - RD::get_singleton()->draw_list_end(); - } - } - - if (will_continue_color && using_separate_specular) { - // Close the specular framebuffer as it'll no longer be used. - RD::get_singleton()->draw_list_begin(rb_data->get_specular_only_fb(), RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE); - RD::get_singleton()->draw_list_end(); } } if (debug_voxelgis) { - //debug voxelgis - bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); - bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only); - Projection dc; dc.set_depth_correction(true); 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::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE); RD::get_singleton()->draw_command_begin_label("Debug VoxelGIs"); for (int i = 0; i < (int)p_render_data->voxel_gi_instances->size(); i++) { gi.debug_voxel_gi((*p_render_data->voxel_gi_instances)[i], draw_list, color_only_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION, 1.0); @@ -2070,24 +2013,20 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } if (debug_sdfgi_probes) { - //debug sdfgi - bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); - bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only); - Projection dc; dc.set_depth_correction(true); Projection cms[RendererSceneRender::MAX_RENDER_VIEWS]; 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->scene_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); } if (draw_sky || draw_sky_fog_only) { RENDER_TIMESTAMP("Render Sky"); RD::get_singleton()->draw_command_begin_label("Draw Sky"); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer, RD::INITIAL_ACTION_CONTINUE, can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE); sky.draw_sky(draw_list, rb, p_render_data->environment, color_only_framebuffer, time, sky_energy_multiplier); @@ -2146,7 +2085,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RENDER_TIMESTAMP("Clear Separate Specular (Canvas Background Mode)"); Vector<Color> blank_clear_color; blank_clear_color.push_back(Color(0.0, 0.0, 0.0)); - RD::get_singleton()->draw_list_begin(rb_data->get_specular_only_fb(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, blank_clear_color); + RD::get_singleton()->draw_list_begin(rb_data->get_specular_only_fb(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, blank_clear_color); RD::get_singleton()->draw_list_end(); } @@ -2187,7 +2126,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co 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->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); + _render_list_with_draw_list(&render_list_params, alpha_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE); } RD::get_singleton()->draw_command_end_label(); @@ -2226,7 +2165,9 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co exposure = luminance->get_current_luminance_buffer(rb); } + RD::get_singleton()->draw_command_begin_label("FSR2"); RENDER_TIMESTAMP("FSR2"); + for (uint32_t v = 0; v < rb->get_view_count(); v++) { real_t fov = p_render_data->scene_data->cam_projection.get_fov(); real_t aspect = p_render_data->scene_data->cam_projection.get_aspect(); @@ -2257,9 +2198,13 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co fsr2_effect->upscale(params); } + + RD::get_singleton()->draw_command_end_label(); } else if (using_taa) { + RD::get_singleton()->draw_command_begin_label("TAA"); RENDER_TIMESTAMP("TAA"); taa->process(rb, _render_buffers_get_color_format(), p_render_data->scene_data->z_near, p_render_data->scene_data->z_far); + RD::get_singleton()->draw_command_end_label(); } } @@ -2571,8 +2516,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page 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); - shadow_pass.final_depth_action = p_end ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE; + shadow_pass.initial_depth_action = p_begin ? RD::INITIAL_ACTION_CLEAR : (p_clear_region ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD); shadow_pass.rect = p_rect; scene_state.shadow_passes.push_back(shadow_pass); @@ -2591,17 +2535,14 @@ void RenderForwardClustered::_render_shadow_process() { RD::get_singleton()->draw_command_end_label(); } -void RenderForwardClustered::_render_shadow_end(uint32_t p_barrier) { +void RenderForwardClustered::_render_shadow_end() { RD::get_singleton()->draw_command_begin_label("Shadow Render"); for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) { - RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, 0, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER); - _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect); + RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, 0, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from); + _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0, 0, shadow_pass.rect); } - if (p_barrier != RD::BARRIER_MASK_NO_BARRIER) { - RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, p_barrier); - } RD::get_singleton()->draw_command_end_label(); } @@ -2644,7 +2585,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con { //regular forward for now RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, 0, true, false, rp_uniform_set); - _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); + _render_list_with_draw_list(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE); } RD::get_singleton()->draw_command_end_label(); } @@ -2697,7 +2638,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); } @@ -2747,7 +2688,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance Color(0, 0, 0, 0), Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); const int uv_offset_count = 9; static const Vector2 uv_offsets[uv_offset_count] = { @@ -2803,13 +2744,6 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu Vector3 half_size = p_bounds.size * 0.5; Vector3 center = p_bounds.position + half_size; - Vector<RID> sbs = { - p_albedo_texture, - p_emission_texture, - p_emission_aniso_texture, - p_geom_facing_texture - }; - //print_line("re-render " + p_from + " - " + p_size + " bounds " + p_bounds); for (int i = 0; i < 3; i++) { scene_state.ubo.sdf_offset[i] = p_from[i]; @@ -2860,7 +2794,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu } RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, 0, true, false, rp_uniform_set, false); - _render_list_with_threads(&render_list_params, E->value, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2(), sbs); + _render_list_with_draw_list(&render_list_params, E->value, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2()); } RD::get_singleton()->draw_command_end_label(); @@ -4280,8 +4214,6 @@ RenderForwardClustered::RenderForwardClustered() { best_fit_normal.shader.version_free(best_fit_normal.shader_version); } - render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances"); - _update_shader_quality_settings(); resolve_effects = memnew(RendererRD::Resolve()); 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 5ff3d9f52a..5af213bc02 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -209,10 +209,9 @@ class RenderForwardClustered : public RendererSceneRenderRD { float screen_mesh_lod_threshold = 0.0; RD::FramebufferFormatID framebuffer_format = 0; uint32_t element_offset = 0; - uint32_t barrier = RD::BARRIER_MASK_ALL_BARRIERS; bool use_directional_soft_shadow = false; - RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_no_gi, bool p_use_directional_soft_shadows, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS) { + RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_no_gi, bool p_use_directional_soft_shadows, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0) { elements = p_elements; element_info = p_element_info; element_count = p_element_count; @@ -227,7 +226,6 @@ class RenderForwardClustered : public RendererSceneRenderRD { lod_distance_multiplier = p_lod_distance_multiplier; screen_mesh_lod_threshold = p_screen_mesh_lod_threshold; element_offset = p_element_offset; - barrier = p_barrier; use_directional_soft_shadow = p_use_directional_soft_shadows; } }; @@ -352,7 +350,6 @@ class RenderForwardClustered : public RendererSceneRenderRD { RID framebuffer; RD::InitialAction initial_depth_action; - RD::FinalAction final_depth_action; Rect2i rect; }; @@ -378,14 +375,8 @@ class RenderForwardClustered : public RendererSceneRenderRD { template <PassMode p_pass_mode, uint32_t p_color_pass_flags = 0> _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); - void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); - - LocalVector<RD::DrawListID> thread_draw_lists; - void _render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params); - void _render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>()); - - uint32_t render_list_thread_threshold = 500; + void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); void _update_instance_data_buffer(RenderListType p_render_list); void _fill_instance_data(RenderListType p_render_list, int *p_render_info = nullptr, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); @@ -604,7 +595,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { void _render_shadow_begin(); 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_reverse_cull_face, 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, const Size2i &p_viewport_size = Size2i(1, 1)); void _render_shadow_process(); - void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); + void _render_shadow_end(); /* Render Scene */ void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const RID *p_normal_buffers, const Projection *p_projections); diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index bba1f62023..86852ce020 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -446,7 +446,7 @@ void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) { bool SceneShaderForwardClustered::MaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, true, RD::BARRIER_MASK_RASTER); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, true); } SceneShaderForwardClustered::MaterialData::~MaterialData() { 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 b7d7105daa..da04e6f938 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -596,7 +596,7 @@ void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, co scene_state.lightmaps_used++; } if (scene_state.lightmaps_used > 0) { - RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps, RD::BARRIER_MASK_RASTER); + RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps); } } @@ -631,7 +631,7 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { if (p_render_data->directional_shadows.size()) { //open the pass for directional shadows light_storage->update_directional_shadow_atlas(); - RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE); + RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE); RD::get_singleton()->draw_list_end(); } } @@ -655,11 +655,8 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { _render_shadow_process(); - _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER); + _render_shadow_end(); } - - //full barrier here, we need raster, transfer and compute and it depends from the previous work - RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL_BARRIERS, RD::BARRIER_MASK_ALL_BARRIERS); } void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) { @@ -811,7 +808,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color float sky_energy_multiplier = inverse_luminance_multiplier; Color clear_color = p_default_bg_color; - bool keep_color = false; + bool load_color = false; bool copy_canvas = false; if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { @@ -855,7 +852,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } } break; case RS::ENV_BG_KEEP: { - keep_color = true; + load_color = true; } break; case RS::ENV_BG_CAMERA_FEED: { } break; @@ -955,6 +952,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (rb_data.is_valid()) { cc.a = 0; // For transparent viewport backgrounds. } + c.push_back(cc); // Our render buffer. if (rb_data.is_valid()) { if (p_render_data->render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) { @@ -966,7 +964,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } } - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, merge_transparent_pass ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, merge_transparent_pass ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, c, 1.0, 0); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 1.0, 0); RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); if (copy_canvas) { @@ -1026,12 +1024,12 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass - RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS); + RD::get_singleton()->draw_list_end(); } else { // We're done with our subpasses so end our container pass // note, if MSAA is used we should get an automatic resolve here - RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS); + RD::get_singleton()->draw_list_end(); RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass @@ -1062,9 +1060,9 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color render_list_params.framebuffer_format = fb_format; render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass(); // Should now always be 0. - draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); + draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE); _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count); - RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS); + RD::get_singleton()->draw_list_end(); RD::get_singleton()->draw_command_end_label(); // Render Transparent Pass } @@ -1248,15 +1246,15 @@ void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, i _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info); if (finalize_cubemap) { _render_shadow_process(); - _render_shadow_end(RD::BARRIER_MASK_FRAGMENT); + _render_shadow_end(); // reblit Rect2 atlas_rect_norm = atlas_rect; atlas_rect_norm.position /= float(atlas_size); atlas_rect_norm.size /= float(atlas_size); - copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false, RD::BARRIER_MASK_NO_BARRIER); + copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false); atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size; - copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true, RD::BARRIER_MASK_NO_BARRIER); + copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true); //restore transform so it can be properly used light_storage->light_instance_set_shadow_transform(p_light, Projection(), light_storage->light_instance_get_base_transform(p_light), zfar, 0, 0, 0); @@ -1337,8 +1335,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr 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); - shadow_pass.final_depth_action = p_end ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE; + shadow_pass.initial_depth_action = p_begin ? RD::INITIAL_ACTION_CLEAR : (p_clear_region ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD); shadow_pass.rect = p_rect; scene_state.shadow_passes.push_back(shadow_pass); @@ -1357,17 +1354,14 @@ void RenderForwardMobile::_render_shadow_process() { RD::get_singleton()->draw_command_end_label(); } -void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) { +void RenderForwardMobile::_render_shadow_end() { RD::get_singleton()->draw_command_begin_label("Shadow Render"); for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) { - RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER); - _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect); + RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from); + _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0, 0, shadow_pass.rect); } - if (p_barrier != RD::BARRIER_MASK_NO_BARRIER) { - RD::get_singleton()->barrier(RD::BARRIER_MASK_FRAGMENT, p_barrier); - } RD::get_singleton()->draw_command_end_label(); } @@ -1416,7 +1410,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c Color(0, 0, 0, 0), Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); } @@ -1462,7 +1456,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *> Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); const int uv_offset_count = 9; static const Vector2 uv_offsets[uv_offset_count] = { @@ -1535,7 +1529,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const { //regular forward for now RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, rp_uniform_set, 0); - _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); + _render_list_with_draw_list(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE); } RD::get_singleton()->draw_command_end_label(); } @@ -1672,7 +1666,7 @@ void RenderForwardMobile::_update_instance_data_buffer(RenderListType p_render_l scene_state.instance_buffer[p_render_list] = RD::get_singleton()->storage_buffer_create(new_size * sizeof(SceneState::InstanceData)); scene_state.instance_buffer_size[p_render_list] = new_size; } - RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER); + RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr()); } } @@ -1991,32 +1985,13 @@ void RenderForwardMobile::_render_list(RenderingDevice::DrawListID p_draw_list, } } -void RenderForwardMobile::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) { - uint32_t render_total = p_params->element_count; - uint32_t total_threads = WorkerThreadPool::get_singleton()->get_thread_count(); - uint32_t render_from = p_thread * render_total / total_threads; - uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads); - _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to); -} - -void RenderForwardMobile::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) { +void RenderForwardMobile::_render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) { RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer); p_params->framebuffer_format = fb_format; - if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time - //multi threaded - thread_draw_lists.resize(WorkerThreadPool::get_singleton()->get_thread_count()); - RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); - WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &RenderForwardMobile::_render_list_thread_function, p_params, thread_draw_lists.size(), -1, true, SNAME("ForwardMobileRenderSubpass")); - WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); - - RD::get_singleton()->draw_list_end(p_params->barrier); - } else { - //single threaded - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); - _render_list(draw_list, fb_format, p_params, 0, p_params->element_count); - RD::get_singleton()->draw_list_end(p_params->barrier); - } + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region); + _render_list(draw_list, fb_format, p_params, 0, p_params->element_count); + RD::get_singleton()->draw_list_end(); } template <RenderForwardMobile::PassMode p_pass_mode> @@ -2813,9 +2788,6 @@ RenderForwardMobile::RenderForwardMobile() { scene_shader.init(defines); - // !BAS! maybe we need a mobile version of this setting? - render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances"); - _update_shader_quality_settings(); } 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 da96ca2124..f1f6bb3db4 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -155,10 +155,9 @@ private: float screen_mesh_lod_threshold = 0.0; RD::FramebufferFormatID framebuffer_format = 0; uint32_t element_offset = 0; - uint32_t barrier = RD::BARRIER_MASK_ALL_BARRIERS; uint32_t subpass = 0; - RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, uint32_t p_spec_constant_base_flags = 0, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS) { + RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, uint32_t p_spec_constant_base_flags = 0, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0) { elements = p_elements; element_info = p_element_info; element_count = p_element_count; @@ -172,7 +171,6 @@ private: lod_distance_multiplier = p_lod_distance_multiplier; screen_mesh_lod_threshold = p_screen_mesh_lod_threshold; element_offset = p_element_offset; - barrier = p_barrier; spec_constant_base_flags = p_spec_constant_base_flags; } }; @@ -183,7 +181,7 @@ private: void _render_shadow_begin(); 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); void _render_shadow_process(); - void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); + void _render_shadow_end(); /* Render Scene */ @@ -277,7 +275,6 @@ private: RID framebuffer; RD::InitialAction initial_depth_action; - RD::FinalAction final_depth_action; Rect2i rect; }; @@ -351,14 +348,8 @@ private: template <PassMode p_pass_mode> _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); - void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); - - LocalVector<RD::DrawListID> thread_draw_lists; - void _render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params); - void _render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>()); - - uint32_t render_list_thread_threshold = 500; + void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); RenderList render_list[RENDER_LIST_MAX]; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index f1cec0e07c..043cdbc8e5 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -398,7 +398,7 @@ void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) { bool SceneShaderForwardMobile::MaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, true, RD::BARRIER_MASK_RASTER); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, true); } SceneShaderForwardMobile::MaterialData::~MaterialData() { diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 657628111a..283b3ee09a 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1177,7 +1177,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, fb_uniform_set, BASE_UNIFORM_SET); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.default_transforms_uniform_set, TRANSFORMS_UNIFORM_SET); @@ -1721,8 +1721,7 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); Rect2i rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); - RD::InitialAction initial_action = i == 0 ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, initial_action, i != 3 ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, initial_action, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); Projection projection; { @@ -1811,7 +1810,7 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh cc.push_back(Color(1, 1, 1, 1)); Rect2i rect(0, p_shadow_index * 2, state.shadow_texture_size, 2); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR_REGION, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR_REGION, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); Projection projection; projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance); @@ -1881,7 +1880,7 @@ void RendererCanvasRenderRD::render_sdf(RID p_render_target, LightOccluderInstan Vector<Color> cc; cc.push_back(Color(0, 0, 0, 0)); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc); Projection projection; @@ -2371,8 +2370,8 @@ RendererRD::MaterialStorage::ShaderData *RendererCanvasRenderRD::_create_shader_ bool RendererCanvasRenderRD::CanvasMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton); - bool uniform_set_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, true, false, RD::BARRIER_MASK_ALL_BARRIERS); - bool uniform_set_srgb_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set_srgb, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, false, false, RD::BARRIER_MASK_ALL_BARRIERS); + bool uniform_set_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, true, false); + bool uniform_set_srgb_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set_srgb, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, false, false); return uniform_set_changed || uniform_set_srgb_changed; } diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 705fb9e8e5..9b073821c2 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -123,6 +123,7 @@ public: void prepare_for_blitting_render_targets(); void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount); + void end_viewport(bool p_swap_buffers) {} void end_frame(bool p_swap_buffers); void finalize(); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 30c9b97aa4..3b05431f4a 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -220,7 +220,7 @@ void RendererSceneRenderRD::voxel_gi_update(RID p_probe, bool p_update_light_ins gi.voxel_gi_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects); } -void RendererSceneRenderRD::_debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth) { +void RendererSceneRenderRD::_debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms) { ERR_FAIL_COND(p_render_buffers.is_null()); if (!p_render_buffers->has_custom_data(RB_SCOPE_SDFGI)) { @@ -229,7 +229,7 @@ void RendererSceneRenderRD::_debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_rend Ref<RendererRD::GI::SDFGI> sdfgi = p_render_buffers->get_custom_data(RB_SCOPE_SDFGI); - sdfgi->debug_probes(p_framebuffer, p_view_count, p_camera_with_transforms, p_will_continue_color, p_will_continue_depth); + sdfgi->debug_probes(p_framebuffer, p_view_count, p_camera_with_transforms); } //////////////////////////////// @@ -987,14 +987,6 @@ void RendererSceneRenderRD::_post_prepass_render(RenderDataRD *p_render_data, bo } } -void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi) { - if (p_render_data->render_buffers.is_valid()) { - if (p_use_gi) { - RD::get_singleton()->compute_list_end(); - } - } -} - 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::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 211d191039..4811ae3b44 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -137,14 +137,13 @@ protected: virtual void _render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) = 0; virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) = 0; - void _debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth); + void _debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, uint32_t p_view_count, const Projection *p_camera_with_transforms); virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0; virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0; bool _needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi); void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi); - void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi); void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data); void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data); diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 2873269586..db2ca29474 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -45,7 +45,7 @@ void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) { String text; for (int i = 0; i < lines.size(); i++) { - String l = lines[i]; + const String &l = lines[i]; bool push_chunk = false; StageTemplate::Chunk chunk; diff --git a/servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub b/servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub index f06a2d86e2..5b8bbc343b 100644 --- a/servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub +++ b/servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub @@ -6,6 +6,11 @@ if "RD_GLSL" in env["BUILDERS"]: # find all include files gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")] + # Add all FSR2 shader and header files. + fsr2_dir = "#thirdparty/amd-fsr2/shaders" + gl_include_files += [str(f) for f in Glob(fsr2_dir + "/*.h")] + gl_include_files += [str(f) for f in Glob(fsr2_dir + "/*.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] diff --git a/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl b/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl index db710b7cdd..e87f644bb0 100644 --- a/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl @@ -30,7 +30,7 @@ void main() { vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0)); gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0); uv_interp.xy = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0 -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW uv_interp.z = ViewIndex; #endif } diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 5f4bf6c8ed..21c6425a87 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -996,15 +996,15 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged //update without barriers if (omni_light_count) { - RD::get_singleton()->buffer_update(omni_light_buffer, 0, sizeof(LightData) * omni_light_count, omni_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(omni_light_buffer, 0, sizeof(LightData) * omni_light_count, omni_lights); } if (spot_light_count) { - RD::get_singleton()->buffer_update(spot_light_buffer, 0, sizeof(LightData) * spot_light_count, spot_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(spot_light_buffer, 0, sizeof(LightData) * spot_light_count, spot_lights); } if (r_directional_light_count) { - RD::get_singleton()->buffer_update(directional_light_buffer, 0, sizeof(DirectionalLightData) * r_directional_light_count, directional_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(directional_light_buffer, 0, sizeof(DirectionalLightData) * r_directional_light_count, directional_lights); } } @@ -1722,7 +1722,7 @@ void LightStorage::update_reflection_probe_buffer(RenderDataRD *p_render_data, c } if (reflection_count) { - RD::get_singleton()->buffer_update(reflection_buffer, 0, reflection_count * sizeof(ReflectionData), reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(reflection_buffer, 0, reflection_count * sizeof(ReflectionData), reflections); } } diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index 2e8c9d7f8e..1c3076b128 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -986,7 +986,7 @@ void MaterialStorage::MaterialData::free_parameters_uniform_set(RID p_uniform_se } } -bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material, uint32_t p_barrier) { +bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material) { if ((uint32_t)ubo_data.size() != p_ubo_size) { p_uniform_dirty = true; if (uniform_buffer.is_valid()) { @@ -1011,7 +1011,7 @@ bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap< //check whether buffer changed if (p_uniform_dirty && ubo_data.size()) { update_uniform_buffer(p_uniforms, p_uniform_offsets, p_parameters, ubo_data.ptrw(), ubo_data.size(), p_use_linear_color); - RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), p_barrier); + RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw()); } uint32_t tex_uniform_count = 0U; diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h index 403fd286b4..fe769a778d 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h @@ -87,7 +87,7 @@ public: virtual ~MaterialData(); //to be used internally by update_parameters, in the most common configuration of material parameters - bool update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &r_uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); + bool update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &r_uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material); void free_parameters_uniform_set(RID p_uniform_set); private: diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index 3bc1b476cb..b97ce2d006 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -657,7 +657,8 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) { Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton); - if (!skeleton || skeleton->size == 0 || mesh->skeleton_aabb_version == skeleton->version) { + // A mesh can be shared by multiple skeletons and we need to avoid using the AABB from a different skeleton. + if (!skeleton || skeleton->size == 0 || (mesh->skeleton_aabb_version == skeleton->version && mesh->skeleton_aabb_rid == p_skeleton)) { return mesh->aabb; } @@ -763,6 +764,7 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) { mesh->aabb = aabb; mesh->skeleton_aabb_version = skeleton->version; + mesh->skeleton_aabb_rid = p_skeleton; return aabb; } @@ -1456,8 +1458,7 @@ void MeshStorage::_multimesh_enable_motion_vectors(MultiMesh *multimesh) { if (multimesh->buffer_set && multimesh->data_cache.is_empty()) { // If the buffer was set but there's no data cached in the CPU, we copy the buffer directly on the GPU. - RD::get_singleton()->barrier(); - RD::get_singleton()->buffer_copy(multimesh->buffer, new_buffer, 0, 0, buffer_size, RD::BARRIER_MASK_NO_BARRIER); + RD::get_singleton()->buffer_copy(multimesh->buffer, new_buffer, 0, 0, buffer_size); RD::get_singleton()->buffer_copy(multimesh->buffer, new_buffer, 0, buffer_size, buffer_size); } else if (!multimesh->data_cache.is_empty()) { // Simply upload the data cached in the CPU, which should already be doubled in size. @@ -1553,7 +1554,7 @@ void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const { memset(w, 0, buffer_size * sizeof(float)); } } - uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, MULTIMESH_DIRTY_REGION_SIZE); multimesh->data_cache_dirty_regions = memnew_arr(bool, data_cache_dirty_region_count); memset(multimesh->data_cache_dirty_regions, 0, data_cache_dirty_region_count * sizeof(bool)); multimesh->data_cache_dirty_region_count = 0; @@ -1581,7 +1582,7 @@ void MeshStorage::_multimesh_update_motion_vectors_data_cache(MultiMesh *multime uint32_t current_ofs = multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float); uint32_t previous_ofs = multimesh->motion_vectors_previous_offset * multimesh->stride_cache * sizeof(float); uint32_t visible_instances = multimesh->visible_instances >= 0 ? multimesh->visible_instances : multimesh->instances; - uint32_t visible_region_count = visible_instances == 0 ? 0 : (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + uint32_t visible_region_count = visible_instances == 0 ? 0 : Math::division_round_up(visible_instances, (uint32_t)MULTIMESH_DIRTY_REGION_SIZE); uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float); uint32_t size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float); for (uint32_t i = 0; i < visible_region_count; i++) { @@ -1601,7 +1602,7 @@ bool MeshStorage::_multimesh_uses_motion_vectors(MultiMesh *multimesh) { void MeshStorage::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) { uint32_t region_index = p_index / MULTIMESH_DIRTY_REGION_SIZE; #ifdef DEBUG_ENABLED - uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, MULTIMESH_DIRTY_REGION_SIZE); ERR_FAIL_UNSIGNED_INDEX(region_index, data_cache_dirty_region_count); //bug #endif if (!multimesh->data_cache_dirty_regions[region_index]) { @@ -1622,7 +1623,7 @@ void MeshStorage::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool void MeshStorage::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb) { if (p_data) { - uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, MULTIMESH_DIRTY_REGION_SIZE); for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) { if (!multimesh->data_cache_dirty_regions[i]) { @@ -2021,8 +2022,8 @@ void MeshStorage::_update_dirty_multimeshes() { uint32_t total_dirty_regions = multimesh->data_cache_dirty_region_count + multimesh->previous_data_cache_dirty_region_count; if (total_dirty_regions != 0) { - uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; - uint32_t visible_region_count = visible_instances == 0 ? 0 : (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, (int)MULTIMESH_DIRTY_REGION_SIZE); + uint32_t visible_region_count = visible_instances == 0 ? 0 : Math::division_round_up(visible_instances, (uint32_t)MULTIMESH_DIRTY_REGION_SIZE); uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float); if (total_dirty_regions > 32 || total_dirty_regions > visible_region_count / 2) { @@ -2035,10 +2036,9 @@ void MeshStorage::_update_dirty_multimeshes() { uint32_t offset = i * region_size; uint32_t size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float); uint32_t region_start_index = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * i; - RD::get_singleton()->buffer_update(multimesh->buffer, buffer_offset * sizeof(float) + offset, MIN(region_size, size - offset), &data[region_start_index], RD::BARRIER_MASK_NO_BARRIER); + RD::get_singleton()->buffer_update(multimesh->buffer, buffer_offset * sizeof(float) + offset, MIN(region_size, size - offset), &data[region_start_index]); } } - RD::get_singleton()->barrier(RD::BARRIER_MASK_NO_BARRIER, RD::BARRIER_MASK_ALL_BARRIERS); } memcpy(multimesh->previous_data_cache_dirty_regions, multimesh->data_cache_dirty_regions, data_cache_dirty_region_count * sizeof(bool)); diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h index 0fc1a6f320..a1e2ffcf7e 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h @@ -153,6 +153,7 @@ private: AABB aabb; AABB custom_aabb; uint64_t skeleton_aabb_version = 0; + RID skeleton_aabb_rid; Vector<RID> material_cache; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index 3d3cb585ac..a854e78f53 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -307,6 +307,11 @@ void ParticlesStorage::_particles_free_data(Particles *particles) { particles->emission_storage_buffer = RID(); } + if (particles->unused_storage_buffer.is_valid()) { + RD::get_singleton()->free(particles->unused_storage_buffer); + particles->unused_storage_buffer = RID(); + } + if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) { //will need to be re-created RD::get_singleton()->free(particles->particles_material_uniform_set); @@ -530,6 +535,12 @@ void ParticlesStorage::_particles_allocate_emission_buffer(Particles *particles) } } +void ParticlesStorage::_particles_ensure_unused_buffer(Particles *particles) { + if (particles->unused_storage_buffer.is_null()) { + particles->unused_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4); + } +} + void ParticlesStorage::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) { Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL(particles); @@ -757,7 +768,8 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta if (p_particles->emission_storage_buffer.is_valid()) { u.append_id(p_particles->emission_storage_buffer); } else { - u.append_id(MeshStorage::get_singleton()->get_default_rd_storage_buffer()); + _particles_ensure_unused_buffer(p_particles); + u.append_id(p_particles->unused_storage_buffer); } uniforms.push_back(u); } @@ -772,7 +784,8 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta } u.append_id(sub_emitter->emission_storage_buffer); } else { - u.append_id(MeshStorage::get_singleton()->get_default_rd_storage_buffer()); + _particles_ensure_unused_buffer(p_particles); + u.append_id(p_particles->unused_storage_buffer); } uniforms.push_back(u); } @@ -1463,7 +1476,8 @@ void ParticlesStorage::update_particles() { if (particles->trail_bind_pose_buffer.is_valid()) { u.append_id(particles->trail_bind_pose_buffer); } else { - u.append_id(MeshStorage::get_singleton()->get_default_rd_storage_buffer()); + _particles_ensure_unused_buffer(particles); + u.append_id(particles->unused_storage_buffer); } uniforms.push_back(u); } diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h index a28d7b4154..33f44f3045 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h @@ -247,6 +247,8 @@ private: ParticleEmissionBuffer *emission_buffer = nullptr; RID emission_storage_buffer; + RID unused_storage_buffer; + HashSet<RID> collisions; Dependency dependency; @@ -263,6 +265,7 @@ private: void _particles_process(Particles *p_particles, double p_delta); void _particles_allocate_emission_buffer(Particles *particles); + void _particles_ensure_unused_buffer(Particles *particles); void _particles_free_data(Particles *particles); void _particles_update_buffers(Particles *particles); diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp index 6a99eb4108..c338dd0377 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp @@ -151,6 +151,14 @@ void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_co // cleanout any old buffers we had. cleanup(); + // At least one of these is required to be supported. + RenderingDeviceCommons::DataFormat preferred_format[2] = { RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::DATA_FORMAT_D32_SFLOAT_S8_UINT }; + if (can_be_storage) { + // Prefer higher precision on desktop. + preferred_format[0] = RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; + preferred_format[1] = RD::DATA_FORMAT_D24_UNORM_S8_UINT; + } + // create our 3D render buffers { // Create our color buffer(s) @@ -174,7 +182,7 @@ void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_co if (msaa_3d == RS::VIEWPORT_MSAA_DISABLED) { usage_bits |= RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, usage_bits) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; + format = RD::get_singleton()->texture_is_format_supported_for_usage(preferred_format[0], usage_bits) ? preferred_format[0] : preferred_format[1]; } else { format = RD::DATA_FORMAT_R32_SFLOAT; usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | (can_be_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0); @@ -202,7 +210,7 @@ void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_co create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA, format, usage_bits, texture_samples); usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, usage_bits) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; + format = RD::get_singleton()->texture_is_format_supported_for_usage(preferred_format[0], usage_bits) ? preferred_format[0] : preferred_format[1]; create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples); } @@ -330,7 +338,7 @@ RID RenderSceneBuffersRD::create_texture_from_format(const StringName &p_context return named_texture.texture; } -RID RenderSceneBuffersRD::_create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, const Ref<RDTextureView> p_view) { +RID RenderSceneBuffersRD::_create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName &p_view_name, const Ref<RDTextureView> p_view) { RD::TextureView texture_view; if (p_view.is_valid()) { // only use when supplied, else default. texture_view = p_view->base; @@ -339,7 +347,7 @@ RID RenderSceneBuffersRD::_create_texture_view(const StringName &p_context, cons return create_texture_view(p_context, p_texture_name, p_view_name, texture_view); } -RID RenderSceneBuffersRD::create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, RD::TextureView p_view) { +RID RenderSceneBuffersRD::create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName &p_view_name, RD::TextureView p_view) { NTKey view_key(p_context, p_view_name); // check if this is a known texture 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 b2946e6bbc..5b8a74de83 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 @@ -106,7 +106,7 @@ private: } NTKey() {} - NTKey(const StringName p_context, const StringName p_texture_name) { + NTKey(const StringName &p_context, const StringName &p_texture_name) { context = p_context; buffer_name = p_texture_name; } @@ -196,7 +196,7 @@ public: bool has_texture(const StringName &p_context, const StringName &p_texture_name) const; RID create_texture(const StringName &p_context, const StringName &p_texture_name, const RD::DataFormat p_data_format, const uint32_t p_usage_bits, const RD::TextureSamples p_texture_samples = RD::TEXTURE_SAMPLES_1, const Size2i p_size = Size2i(0, 0), const uint32_t p_layers = 0, const uint32_t p_mipmaps = 1, bool p_unique = true); RID create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const RD::TextureFormat &p_texture_format, RD::TextureView p_view = RD::TextureView(), bool p_unique = true); - RID create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, RD::TextureView p_view = RD::TextureView()); + RID create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName &p_view_name, RD::TextureView p_view = RD::TextureView()); RID get_texture(const StringName &p_context, const StringName &p_texture_name) const; const RD::TextureFormat get_texture_format(const StringName &p_context, const StringName &p_texture_name) const; RID get_texture_slice(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers = 1, const uint32_t p_mipmaps = 1); @@ -310,7 +310,7 @@ public: private: RID _create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const Ref<RDTextureFormat> &p_texture_format, const Ref<RDTextureView> &p_view = Ref<RDTextureView>(), bool p_unique = true); - RID _create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, const Ref<RDTextureView> p_view = Ref<RDTextureView>()); + RID _create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName &p_view_name, const Ref<RDTextureView> p_view = Ref<RDTextureView>()); Ref<RDTextureFormat> _get_texture_format(const StringName &p_context, const StringName &p_texture_name) const; RID _get_texture_slice_view(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers = 1, const uint32_t p_mipmaps = 1, const Ref<RDTextureView> p_view = Ref<RDTextureView>()); 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 index 40891f9a63..f2231664fa 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp @@ -252,7 +252,7 @@ void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p } uniform_buffer = p_uniform_buffer; - RD::get_singleton()->buffer_update(uniform_buffer, 0, sizeof(UBODATA), &ubo, RD::BARRIER_MASK_RASTER); + RD::get_singleton()->buffer_update(uniform_buffer, 0, sizeof(UBODATA), &ubo); } RID RenderSceneDataRD::get_uniform_buffer() { diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 380e325ffa..d8baf260f9 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -2703,7 +2703,7 @@ void TextureStorage::update_decal_atlas() { Vector<Color> cc; cc.push_back(clear_color); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(mm.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, cc); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(mm.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, cc); for (const KeyValue<RID, DecalAtlas::Texture> &E : decal_atlas.textures) { DecalAtlas::Texture *t = decal_atlas.textures.getptr(E.key); @@ -2981,7 +2981,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const } if (decal_count > 0) { - RD::get_singleton()->buffer_update(decal_buffer, 0, sizeof(DecalData) * decal_count, decals, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(decal_buffer, 0, sizeof(DecalData) * decal_count, decals); } } @@ -3384,7 +3384,7 @@ void TextureStorage::render_target_do_msaa_resolve(RID p_render_target) { if (!rt->msaa_needs_resolve) { return; } - RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_end(); rt->msaa_needs_resolve = false; } @@ -3501,7 +3501,7 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) { } Vector<Color> clear_colors; clear_colors.push_back(rt->use_hdr ? rt->clear_color.srgb_to_linear() : rt->clear_color); - RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors); RD::get_singleton()->draw_list_end(); rt->clear_requested = false; rt->msaa_needs_resolve = false; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 97e9694fe1..7a2415442d 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -754,7 +754,6 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) { if (blits.size() > 0) { RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blits.ptr(), blits.size()); } - RSG::rasterizer->end_frame(true); } else if (blits.size() > 0) { if (!blit_to_screen_list.has(vp->viewport_to_screen)) { blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>(); @@ -764,6 +763,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) { blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]); } } + RSG::rasterizer->end_viewport(p_swap_buffers && blits.size() > 0); } } } else { @@ -793,10 +793,10 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) { Vector<BlitToScreen> blit_to_screen_vec; blit_to_screen_vec.push_back(blit); RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blit_to_screen_vec.ptr(), 1); - RSG::rasterizer->end_frame(true); } else { blit_to_screen_list[vp->viewport_to_screen].push_back(blit); } + RSG::rasterizer->end_viewport(p_swap_buffers); } } @@ -823,8 +823,8 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) { RENDER_TIMESTAMP("< Render Viewports"); - if (p_swap_buffers) { - //this needs to be called to make screen swapping more efficient + if (p_swap_buffers && !blit_to_screen_list.is_empty()) { + // This needs to be called to make screen swapping more efficient. RSG::rasterizer->prepare_for_blitting_render_targets(); for (const KeyValue<int, Vector<BlitToScreen>> &E : blit_to_screen_list) { diff --git a/servers/rendering/rendering_device.compat.inc b/servers/rendering/rendering_device.compat.inc index 8e7beda6f3..edc08e972d 100644 --- a/servers/rendering/rendering_device.compat.inc +++ b/servers/rendering/rendering_device.compat.inc @@ -34,39 +34,87 @@ RID RenderingDevice::_shader_create_from_bytecode_bind_compat_79606(const Vector return shader_create_from_bytecode(p_shader_binary, RID()); } -BitField<RenderingDevice::BarrierMask> RenderingDevice::_convert_barrier_mask_81356(BitField<BarrierMask> p_old_barrier) { - if (p_old_barrier == 7) { - return BARRIER_MASK_ALL_BARRIERS; - } else if (p_old_barrier == 16) { - return BARRIER_MASK_NO_BARRIER; - } +void RenderingDevice::_draw_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier) { + draw_list_end(); +} - BitField<BarrierMask> new_barrier; - if (p_old_barrier & 1) { - new_barrier.set_flag(BARRIER_MASK_VERTEX); - } - if (p_old_barrier & 2) { - new_barrier.set_flag(BARRIER_MASK_FRAGMENT); - } - if (p_old_barrier & 4) { - new_barrier.set_flag(BARRIER_MASK_COMPUTE); +void RenderingDevice::_compute_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier) { + compute_list_end(); +} + +void RenderingDevice::_barrier_bind_compat_81356(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) { + // Does nothing. +} + +void RenderingDevice::_draw_list_end_bind_compat_84976(BitField<BarrierMask> p_post_barrier) { + draw_list_end(); +} + +void RenderingDevice::_compute_list_end_bind_compat_84976(BitField<BarrierMask> p_post_barrier) { + compute_list_end(); +} + +RenderingDevice::InitialAction RenderingDevice::_convert_initial_action_84976(InitialAction p_old_initial_action) { + switch (uint32_t(p_old_initial_action)) { + case 0: // INITIAL_ACTION_CLEAR + return INITIAL_ACTION_CLEAR; + case 1: // INITIAL_ACTION_CLEAR_REGION + case 2: // INITIAL_ACTION_CLEAR_REGION_CONTINUE + return INITIAL_ACTION_CLEAR; + case 3: // INITIAL_ACTION_KEEP + return INITIAL_ACTION_LOAD; + case 4: // INITIAL_ACTION_DROP + return INITIAL_ACTION_DISCARD; + case 5: // INITIAL_ACTION_CONTINUE + return INITIAL_ACTION_LOAD; + default: + return INITIAL_ACTION_LOAD; } - if (p_old_barrier & 8) { - new_barrier.set_flag(BARRIER_MASK_TRANSFER); +} + +RenderingDevice::FinalAction RenderingDevice::_convert_final_action_84976(FinalAction p_old_final_action) { + switch (uint32_t(p_old_final_action)) { + case 0: // FINAL_ACTION_READ + return FINAL_ACTION_STORE; + case 1: // FINAL_ACTION_DISCARD + return FINAL_ACTION_DISCARD; + case 2: // FINAL_ACTION_CONTINUE + return FINAL_ACTION_STORE; + default: + return FINAL_ACTION_STORE; } - return new_barrier; } -void RenderingDevice::_draw_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier) { - draw_list_end(_convert_barrier_mask_81356(p_post_barrier)); +RenderingDevice::DrawListID RenderingDevice::_draw_list_begin_bind_compat_84976(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) { + return draw_list_begin(p_framebuffer, _convert_initial_action_84976(p_initial_color_action), _convert_final_action_84976(p_final_color_action), _convert_initial_action_84976(p_initial_depth_action), _convert_final_action_84976(p_final_depth_action), p_clear_color_values, p_clear_depth, p_clear_stencil, p_region); } -void RenderingDevice::_compute_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier) { - compute_list_end(_convert_barrier_mask_81356(p_post_barrier)); +RenderingDevice::ComputeListID RenderingDevice::_compute_list_begin_bind_compat_84976(bool p_allow_draw_overlap) { + return compute_list_begin(); } -void RenderingDevice::_barrier_bind_compat_81356(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) { - barrier(_convert_barrier_mask_81356(p_from), _convert_barrier_mask_81356(p_to)); +Error RenderingDevice::_buffer_update_bind_compat_84976(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) { + return _buffer_update_bind(p_buffer, p_offset, p_size, p_data); +} + +Error RenderingDevice::_buffer_clear_bind_compat_84976(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) { + return buffer_clear(p_buffer, p_offset, p_size); +} + +Error RenderingDevice::_texture_update_bind_compat_84976(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) { + return texture_update(p_texture, p_layer, p_data); +} + +Error RenderingDevice::_texture_copy_bind_compat_84976(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier) { + return texture_copy(p_from_texture, p_to_texture, p_from, p_to, p_size, p_src_mipmap, p_dst_mipmap, p_src_layer, p_dst_layer); +} + +Error RenderingDevice::_texture_clear_bind_compat_84976(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier) { + return texture_clear(p_texture, p_color, p_base_mipmap, p_mipmaps, p_base_layer, p_layers); +} + +Error RenderingDevice::_texture_resolve_multisample_bind_compat_84976(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier) { + return texture_resolve_multisample(p_from_texture, p_to_texture); } void RenderingDevice::_bind_compatibility_methods() { @@ -74,6 +122,16 @@ void RenderingDevice::_bind_compatibility_methods() { ClassDB::bind_compatibility_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::_draw_list_end_bind_compat_81356, DEFVAL(7)); ClassDB::bind_compatibility_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::_compute_list_end_bind_compat_81356, DEFVAL(7)); ClassDB::bind_compatibility_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::_barrier_bind_compat_81356, DEFVAL(7), DEFVAL(7)); + ClassDB::bind_compatibility_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::_draw_list_end_bind_compat_84976, DEFVAL(0x7FFF)); + ClassDB::bind_compatibility_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::_compute_list_end_bind_compat_84976, DEFVAL(0x7FFF)); + ClassDB::bind_compatibility_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_bind_compat_84976, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>())); + ClassDB::bind_compatibility_method(D_METHOD("compute_list_begin", "allow_draw_overlap"), &RenderingDevice::_compute_list_begin_bind_compat_84976, DEFVAL(false)); + ClassDB::bind_compatibility_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "post_barrier"), &RenderingDevice::_buffer_update_bind_compat_84976, DEFVAL(0x7FFF)); + ClassDB::bind_compatibility_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::_buffer_clear_bind_compat_84976, DEFVAL(0x7FFF)); + ClassDB::bind_compatibility_method(D_METHOD("texture_update", "texture", "layer", "data", "post_barrier"), &RenderingDevice::_texture_update_bind_compat_84976, DEFVAL(0x7FFF)); + ClassDB::bind_compatibility_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "post_barrier"), &RenderingDevice::_texture_copy_bind_compat_84976, DEFVAL(0x7FFF)); + ClassDB::bind_compatibility_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::_texture_clear_bind_compat_84976, DEFVAL(0x7FFF)); + ClassDB::bind_compatibility_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::_texture_resolve_multisample_bind_compat_84976, DEFVAL(0x7FFF)); } #endif diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index a7f124c23c..8e03796d33 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -37,7 +37,26 @@ #include "core/io/dir_access.h" #include "servers/rendering/renderer_rd/api_context_rd.h" -//#define FORCE_FULL_BARRIER +// When true, the command graph will attempt to reorder the rendering commands submitted by the user based on the dependencies detected from +// the commands automatically. This should improve rendering performance in most scenarios at the cost of some extra CPU overhead. +// +// This behavior can be disabled if it's suspected that the graph is not detecting dependencies correctly and more control over the order of +// the commands is desired (e.g. debugging). + +#define RENDER_GRAPH_REORDER 1 + +// Synchronization barriers are issued between the graph's levels only with the necessary amount of detail to achieve the correct result. If +// it's suspected that the graph is not doing this correctly, full barriers can be issued instead that will block all types of operations +// between the synchronization levels. This setting will have a very negative impact on performance when enabled, so it's only intended for +// debugging purposes. + +#define RENDER_GRAPH_FULL_BARRIERS 0 + +// The command graph can automatically issue secondary command buffers and record them on background threads when they reach an arbitrary +// size threshold. This can be very beneficial towards reducing the time the main thread takes to record all the rendering commands. However, +// this setting is not enabled by default as it's been shown to cause some strange issues with certain IHVs that have yet to be understood. + +#define SECONDARY_COMMAND_BUFFERS_PER_FRAME 0 RenderingDevice *RenderingDevice::singleton = nullptr; @@ -131,127 +150,23 @@ RID RenderingDevice::shader_create_from_spirv(const Vector<ShaderStageSPIRVData> return shader_create_from_bytecode(bytecode); } -/******************/ -/**** BARRIERS ****/ -/******************/ - -void RenderingDevice::_full_barrier(bool p_sync_with_draw) { - // Used for debug. - - RDD::MemoryBarrier mb; - mb.src_access = (RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT | - RDD::BARRIER_ACCESS_INDEX_READ_BIT | - RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | - RDD::BARRIER_ACCESS_UNIFORM_READ_BIT | - RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT | - RDD::BARRIER_ACCESS_SHADER_READ_BIT | - RDD::BARRIER_ACCESS_SHADER_WRITE_BIT | - RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT | - RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - RDD::BARRIER_ACCESS_TRANSFER_READ_BIT | - RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT | - RDD::BARRIER_ACCESS_HOST_READ_BIT | - RDD::BARRIER_ACCESS_HOST_WRITE_BIT); - mb.dst_access = (RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT | - RDD::BARRIER_ACCESS_INDEX_READ_BIT | - RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | - RDD::BARRIER_ACCESS_UNIFORM_READ_BIT | - RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT | - RDD::BARRIER_ACCESS_SHADER_READ_BIT | - RDD::BARRIER_ACCESS_SHADER_WRITE_BIT | - RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT | - RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - RDD::BARRIER_ACCESS_TRANSFER_READ_BIT | - RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT | - RDD::BARRIER_ACCESS_HOST_READ_BIT | - RDD::BARRIER_ACCESS_HOST_WRITE_BIT); - - RDD::CommandBufferID cmd_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; - driver->command_pipeline_barrier(cmd_buffer, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, mb, {}, {}); -} - /***************************/ /**** BUFFER MANAGEMENT ****/ /***************************/ -RenderingDevice::Buffer *RenderingDevice::_get_buffer_from_owner(RID p_buffer, BitField<RDD::PipelineStageBits> &r_stages, BitField<RDD::BarrierAccessBits> &r_access, BitField<BarrierMask> p_post_barrier) { +RenderingDevice::Buffer *RenderingDevice::_get_buffer_from_owner(RID p_buffer) { Buffer *buffer = nullptr; - r_stages.clear(); - r_access.clear(); if (vertex_buffer_owner.owns(p_buffer)) { buffer = vertex_buffer_owner.get_or_null(p_buffer); - - r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT); - r_access.set_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT); - if (buffer->usage & RDD::BUFFER_USAGE_STORAGE_BIT) { - if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { - r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { - r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - r_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { - r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - r_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - } - } } else if (index_buffer_owner.owns(p_buffer)) { - r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT); - r_access.set_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT); buffer = index_buffer_owner.get_or_null(p_buffer); } else if (uniform_buffer_owner.owns(p_buffer)) { - if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { - r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { - r_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { - r_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - } - r_access.set_flag(RDD::BARRIER_ACCESS_UNIFORM_READ_BIT); buffer = uniform_buffer_owner.get_or_null(p_buffer); } else if (texture_buffer_owner.owns(p_buffer)) { - if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { - r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); - r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { - r_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { - r_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT); - } - - // FIXME: Broken. + DEV_ASSERT(false && "FIXME: Broken."); //buffer = texture_buffer_owner.get_or_null(p_buffer)->buffer; } else if (storage_buffer_owner.owns(p_buffer)) { buffer = storage_buffer_owner.get_or_null(p_buffer); - if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { - r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); - r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { - r_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { - r_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - - if (buffer->usage.has_flag(RDD::BUFFER_USAGE_INDIRECT_BIT)) { - r_stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT); - r_access.set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT); - } } return buffer; } @@ -269,10 +184,11 @@ Error RenderingDevice::_insert_staging_block() { return OK; } -Error RenderingDevice::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment) { +Error RenderingDevice::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, StagingRequiredAction &r_required_action, bool p_can_segment) { // Determine a block to use. r_alloc_size = p_amount; + r_required_action = STAGING_REQUIRED_ACTION_NONE; while (true) { r_alloc_offset = 0; @@ -324,23 +240,7 @@ Error RenderingDevice::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_re // and this frame is not even done. // If this is the main thread, it means the user is likely loading a lot of resources at once,. // Otherwise, the thread should just be blocked until the next frame (currently unimplemented). - - if (false) { // Separate thread from render. - - //block_until_next_frame() - continue; - } else { - // Flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands. - _flush(true); - - // Clear the whole staging buffer. - for (int i = 0; i < staging_buffer_blocks.size(); i++) { - staging_buffer_blocks.write[i].frame_used = 0; - staging_buffer_blocks.write[i].fill_amount = 0; - } - // Claim current. - staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; - } + r_required_action = STAGING_REQUIRED_ACTION_FLUSH_CURRENT; } } else { @@ -368,28 +268,7 @@ Error RenderingDevice::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_re // Let's flush older frames. // The logic here is that if a game is loading a lot of data from the main thread, it will need to be stalled anyway. // If loading from a separate thread, we can block that thread until next frame when more room is made (not currently implemented, though). - - if (false) { - // Separate thread from render. - //block_until_next_frame() - continue; // And try again. - } else { - _flush(false); - - for (int i = 0; i < staging_buffer_blocks.size(); i++) { - // Clear all blocks but the ones from this frame. - int block_idx = (i + staging_buffer_current) % staging_buffer_blocks.size(); - if (staging_buffer_blocks[block_idx].frame_used == frames_drawn) { - break; // Ok, we reached something from this frame, abort. - } - - staging_buffer_blocks.write[block_idx].frame_used = 0; - staging_buffer_blocks.write[block_idx].fill_amount = 0; - } - - // Claim for current frame. - staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; - } + r_required_action = STAGING_REQUIRED_ACTION_FLUSH_OLDER; } } @@ -402,20 +281,78 @@ Error RenderingDevice::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_re return OK; } -Error RenderingDevice::_buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer, uint32_t p_required_align) { +void RenderingDevice::_staging_buffer_execute_required_action(StagingRequiredAction p_required_action) { + switch (p_required_action) { + case STAGING_REQUIRED_ACTION_NONE: { + // Do nothing. + } break; + case STAGING_REQUIRED_ACTION_FLUSH_CURRENT: { + // Flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands. + _flush(true); + + // Clear the whole staging buffer. + for (int i = 0; i < staging_buffer_blocks.size(); i++) { + staging_buffer_blocks.write[i].frame_used = 0; + staging_buffer_blocks.write[i].fill_amount = 0; + } + + // Claim for current frame. + staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; + } break; + case STAGING_REQUIRED_ACTION_FLUSH_OLDER: { + _flush(false); + + for (int i = 0; i < staging_buffer_blocks.size(); i++) { + // Clear all blocks but the ones from this frame. + int block_idx = (i + staging_buffer_current) % staging_buffer_blocks.size(); + if (staging_buffer_blocks[block_idx].frame_used == frames_drawn) { + break; // Ok, we reached something from this frame, abort. + } + + staging_buffer_blocks.write[block_idx].frame_used = 0; + staging_buffer_blocks.write[block_idx].fill_amount = 0; + } + + // Claim for current frame. + staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; + } break; + default: { + DEV_ASSERT(false && "Unknown required action."); + } break; + } +} + +Error RenderingDevice::_buffer_update(Buffer *p_buffer, RID p_buffer_id, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_queue, uint32_t p_required_align) { // Submitting may get chunked for various reasons, so convert this to a task. size_t to_submit = p_data_size; size_t submit_from = 0; + thread_local LocalVector<RDG::RecordedBufferCopy> command_buffer_copies_vector; + command_buffer_copies_vector.clear(); + while (to_submit > 0) { uint32_t block_write_offset; uint32_t block_write_amount; + StagingRequiredAction required_action; - Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount); + Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount, required_action); if (err) { return err; } + if (p_use_draw_queue && !command_buffer_copies_vector.is_empty() && required_action == STAGING_REQUIRED_ACTION_FLUSH_CURRENT) { + if (_buffer_make_mutable(p_buffer, p_buffer_id)) { + // The buffer must be mutable to be used as a copy destination. + draw_graph.add_synchronization(); + } + + // If we're using the draw queue and the staging buffer requires flushing everything, we submit the command early and clear the current vector. + draw_graph.add_buffer_update(p_buffer->driver_id, p_buffer->draw_tracker, command_buffer_copies_vector); + command_buffer_copies_vector.clear(); + } + + _staging_buffer_execute_required_action(required_action); + // Map staging buffer (It's CPU and coherent). uint8_t *data_ptr = driver->buffer_map(staging_buffer_blocks[staging_buffer_current].driver_id); ERR_FAIL_NULL_V(data_ptr, ERR_CANT_CREATE); @@ -427,12 +364,19 @@ Error RenderingDevice::_buffer_update(Buffer *p_buffer, size_t p_offset, const u driver->buffer_unmap(staging_buffer_blocks[staging_buffer_current].driver_id); // Insert a command to copy this. - RDD::BufferCopyRegion region; region.src_offset = block_write_offset; region.dst_offset = submit_from + p_offset; region.size = block_write_amount; - driver->command_copy_buffer(p_use_draw_command_buffer ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, p_buffer->driver_id, region); + + if (p_use_draw_queue) { + RDG::RecordedBufferCopy buffer_copy; + buffer_copy.source = staging_buffer_blocks[staging_buffer_current].driver_id; + buffer_copy.region = region; + command_buffer_copies_vector.push_back(buffer_copy); + } else { + driver->command_copy_buffer(frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, p_buffer->driver_id, region); + } staging_buffer_blocks.write[staging_buffer_current].fill_amount = block_write_offset + block_write_amount; @@ -440,10 +384,19 @@ Error RenderingDevice::_buffer_update(Buffer *p_buffer, size_t p_offset, const u submit_from += block_write_amount; } + if (p_use_draw_queue && !command_buffer_copies_vector.is_empty()) { + if (_buffer_make_mutable(p_buffer, p_buffer_id)) { + // The buffer must be mutable to be used as a copy destination. + draw_graph.add_synchronization(); + } + + draw_graph.add_buffer_update(p_buffer->driver_id, p_buffer->draw_tracker, command_buffer_copies_vector); + } + return OK; } -Error RenderingDevice::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) { +Error RenderingDevice::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER, @@ -451,25 +404,12 @@ Error RenderingDevice::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER, "Copying buffers is forbidden during creation of a compute list"); - // This method assumes the barriers have been pushed prior to being called, therefore no barriers are pushed - // for the source or destination buffers before performing the copy. These masks are effectively ignored. - BitField<RDD::PipelineStageBits> src_stages; - BitField<RDD::BarrierAccessBits> src_access; - Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer, src_stages, src_access, BARRIER_MASK_NO_BARRIER); + Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer); if (!src_buffer) { ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Source buffer argument is not a valid buffer of any type."); } - BitField<RDD::PipelineStageBits> dst_stages; - BitField<RDD::BarrierAccessBits> dst_access; - if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { - // If the post barrier mask defines it, we indicate the destination buffer will require a barrier with these flags set - // after the copy command is queued. - dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT); - dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT); - } - - Buffer *dst_buffer = _get_buffer_from_owner(p_dst_buffer, dst_stages, dst_access, p_post_barrier); + Buffer *dst_buffer = _get_buffer_from_owner(p_dst_buffer); if (!dst_buffer) { ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Destination buffer argument is not a valid buffer of any type."); } @@ -483,31 +423,18 @@ Error RenderingDevice::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t region.src_offset = p_src_offset; region.dst_offset = p_dst_offset; region.size = p_size; - driver->command_copy_buffer(frames[frame].draw_command_buffer, src_buffer->driver_id, dst_buffer->driver_id, region); -#ifdef FORCE_FULL_BARRIER - _full_barrier(true); -#else - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS) && p_post_barrier != RD::BARRIER_MASK_NO_BARRIER) { - if (dst_stages.is_empty()) { - dst_stages = RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - } - - // As indicated by the post barrier mask, push a new barrier. - RDD::BufferBarrier bb; - bb.buffer = dst_buffer->driver_id; - bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - bb.dst_access = dst_access; - bb.offset = p_dst_offset; - bb.size = p_size; - driver->command_pipeline_barrier(frames[frame].draw_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, dst_stages, {}, bb, {}); + if (_buffer_make_mutable(dst_buffer, p_dst_buffer)) { + // The destination buffer must be mutable to be used as a copy destination. + draw_graph.add_synchronization(); } -#endif + + draw_graph.add_buffer_copy(src_buffer->driver_id, src_buffer->draw_tracker, dst_buffer->driver_id, dst_buffer->draw_tracker, region); return OK; } -Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier) { +Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER, @@ -515,14 +442,7 @@ Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER, "Updating buffers is forbidden during creation of a compute list"); - BitField<RDD::PipelineStageBits> dst_stages; - BitField<RDD::BarrierAccessBits> dst_access; - if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { - // Protect subsequent updates. - dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT); - dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT); - } - Buffer *buffer = _get_buffer_from_owner(p_buffer, dst_stages, dst_access, p_post_barrier); + Buffer *buffer = _get_buffer_from_owner(p_buffer); if (!buffer) { ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type."); } @@ -530,33 +450,10 @@ Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER, "Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end."); - Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, true); - if (err) { - return err; - } - -#ifdef FORCE_FULL_BARRIER - _full_barrier(true); -#else - if (dst_stages.is_empty()) { - dst_stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); - } - - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS) && p_post_barrier != RD::BARRIER_MASK_NO_BARRIER) { - RDD::BufferBarrier bb; - bb.buffer = buffer->driver_id; - bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - bb.dst_access = dst_access; - bb.offset = p_offset; - bb.size = p_size; - driver->command_pipeline_barrier(frames[frame].draw_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, dst_stages, {}, bb, {}); - } - -#endif - return err; + return _buffer_update(buffer, p_buffer, p_offset, (uint8_t *)p_data, p_size, true); } -Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) { +Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG((p_size % 4) != 0, ERR_INVALID_PARAMETER, @@ -566,15 +463,7 @@ Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_ ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER, "Updating buffers is forbidden during creation of a compute list"); - BitField<RDD::PipelineStageBits> dst_stages; - BitField<RDD::BarrierAccessBits> dst_access; - if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { - // Protect subsequent updates. - dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT); - dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT); - } - - Buffer *buffer = _get_buffer_from_owner(p_buffer, dst_stages, dst_access, p_post_barrier); + Buffer *buffer = _get_buffer_from_owner(p_buffer); if (!buffer) { ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type."); } @@ -582,51 +471,24 @@ Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_ ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER, "Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end."); - driver->command_clear_buffer(frames[frame].draw_command_buffer, buffer->driver_id, p_offset, p_size); - -#ifdef FORCE_FULL_BARRIER - _full_barrier(true); -#else - if (dst_stages.is_empty()) { - dst_stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); + if (_buffer_make_mutable(buffer, p_buffer)) { + // The destination buffer must be mutable to be used as a clear destination. + draw_graph.add_synchronization(); } - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::BufferBarrier bb; - bb.buffer = buffer->driver_id; - bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - bb.dst_access = dst_access; - bb.offset = p_offset; - bb.size = p_size; - driver->command_pipeline_barrier(frames[frame].draw_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, dst_stages, {}, bb, {}); - } + draw_graph.add_buffer_clear(buffer->driver_id, buffer->draw_tracker, p_offset, p_size); -#endif return OK; } Vector<uint8_t> RenderingDevice::buffer_get_data(RID p_buffer, uint32_t p_offset, uint32_t p_size) { _THREAD_SAFE_METHOD_ - // It could be this buffer was just created. - BitField<RDD::PipelineStageBits> src_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; - BitField<RDD::BarrierAccessBits> src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - // Get the vulkan buffer and the potential stage/access possible. - Buffer *buffer = _get_buffer_from_owner(p_buffer, src_stages, src_access, BARRIER_MASK_ALL_BARRIERS); + Buffer *buffer = _get_buffer_from_owner(p_buffer); if (!buffer) { ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving."); } - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - // Make sure no one is using the buffer -- the "true" gets us to the same command buffer as below. - RDD::BufferBarrier bb; - bb.buffer = buffer->driver_id; - bb.src_access = src_access; - bb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT; - bb.size = buffer->size; - driver->command_pipeline_barrier(frames[frame].draw_command_buffer, src_stages, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, bb, {}); - } - // Size of buffer to retrieve. if (!p_size) { p_size = buffer->size; @@ -641,7 +503,9 @@ Vector<uint8_t> RenderingDevice::buffer_get_data(RID p_buffer, uint32_t p_offset RDD::BufferCopyRegion region; region.src_offset = p_offset; region.size = p_size; - driver->command_copy_buffer(frames[frame].draw_command_buffer, buffer->driver_id, tmp_buffer, region); + + draw_graph.add_buffer_get_data(buffer->driver_id, buffer->draw_tracker, tmp_buffer, region); + // Flush everything so memory can be safely mapped. _flush(true); @@ -676,23 +540,21 @@ RID RenderingDevice::storage_buffer_create(uint32_t p_size_bytes, const Vector<u buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU); ERR_FAIL_COND_V(!buffer.driver_id, RID()); + // Storage buffers are assumed to be mutable. + buffer.draw_tracker = RDG::resource_tracker_create(); + buffer.draw_tracker->buffer_driver_id = buffer.driver_id; + if (p_data.size()) { - uint64_t data_size = p_data.size(); - const uint8_t *r = p_data.ptr(); - _buffer_update(&buffer, 0, r, data_size); - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::BufferBarrier bb; - bb.buffer = buffer.driver_id; - bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - bb.dst_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - bb.size = data_size; - driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, bb, {}); - } + _buffer_update(&buffer, RID(), 0, p_data.ptr(), p_data.size()); } buffer_memory += buffer.size; - return storage_buffer_owner.make_rid(buffer); + RID id = storage_buffer_owner.make_rid(buffer); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif + return id; } RID RenderingDevice::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data) { @@ -710,6 +572,12 @@ RID RenderingDevice::texture_buffer_create(uint32_t p_size_elements, DataFormat texture_buffer.driver_id = driver->buffer_create(size_bytes, usage, RDD::MEMORY_ALLOCATION_TYPE_GPU); ERR_FAIL_COND_V(!texture_buffer.driver_id, RID()); + // Texture buffers are assumed to be immutable unless they don't have initial data. + if (p_data.is_empty()) { + texture_buffer.draw_tracker = RDG::resource_tracker_create(); + texture_buffer.draw_tracker->buffer_driver_id = texture_buffer.driver_id; + } + bool ok = driver->buffer_set_texel_format(texture_buffer.driver_id, p_format); if (!ok) { driver->buffer_free(texture_buffer.driver_id); @@ -717,15 +585,7 @@ RID RenderingDevice::texture_buffer_create(uint32_t p_size_elements, DataFormat } if (p_data.size()) { - _buffer_update(&texture_buffer, 0, p_data.ptr(), p_data.size()); - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::BufferBarrier bb; - bb.buffer = texture_buffer.driver_id; - bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - bb.dst_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT; - bb.size = size_bytes; - driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, (RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT), {}, bb, {}); - } + _buffer_update(&texture_buffer, RID(), 0, p_data.ptr(), p_data.size()); } buffer_memory += size_bytes; @@ -787,10 +647,8 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture ERR_FAIL_COND_V_MSG(required_mipmaps < format.mipmaps, RID(), "Too many mipmaps requested for texture format and dimensions (" + itos(format.mipmaps) + "), maximum allowed: (" + itos(required_mipmaps) + ")."); + uint32_t forced_usage_bits = 0; if (p_data.size()) { - ERR_FAIL_COND_V_MSG(!(format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT), RID(), - "Texture needs the TEXTURE_USAGE_CAN_UPDATE_BIT usage flag in order to be updated at initialization or later"); - ERR_FAIL_COND_V_MSG(p_data.size() != (int)format.array_layers, RID(), "Default supplied data for image format is of invalid length (" + itos(p_data.size()) + "), should be (" + itos(format.array_layers) + ")."); @@ -799,6 +657,10 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture ERR_FAIL_COND_V_MSG((uint32_t)p_data[i].size() != required_size, RID(), "Data for slice index " + itos(i) + " (mapped to layer " + itos(i) + ") differs in size (supplied: " + itos(p_data[i].size()) + ") than what is required by the format (" + itos(required_size) + ")."); } + + if (!(format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT)) { + forced_usage_bits = TEXTURE_USAGE_CAN_UPDATE_BIT; + } } { @@ -849,7 +711,7 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture // Create. Texture texture; - + format.usage_bits |= forced_usage_bits; texture.driver_id = driver->texture_create(format, tv); ERR_FAIL_COND_V(!texture.driver_id, RID()); texture.type = format.texture_type; @@ -862,26 +724,10 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture texture.base_mipmap = 0; texture.base_layer = 0; texture.is_resolve_buffer = format.is_resolve_buffer; - texture.usage_flags = format.usage_bits; + texture.usage_flags = format.usage_bits & ~forced_usage_bits; texture.samples = format.samples; texture.allowed_shared_formats = format.shareable_formats; - - // Set base layout based on usage priority. - - if ((format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT)) { - // First priority, readable. - texture.layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } else if ((format.usage_bits & TEXTURE_USAGE_STORAGE_BIT)) { - // Second priority, storage. - texture.layout = RDD::TEXTURE_LAYOUT_GENERAL; - } else if ((format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { - // Third priority, color or depth. - texture.layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } else if ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - texture.layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } else { - texture.layout = RDD::TEXTURE_LAYOUT_GENERAL; - } + texture.has_initial_data = !p_data.is_empty(); if ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT); @@ -896,18 +742,10 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture texture.bound = false; - // Barrier to set layout. - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::TextureBarrier tb; - tb.texture = texture.driver_id; - tb.dst_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT; - tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; - tb.next_layout = texture.layout; - tb.subresources.aspect = texture.barrier_aspect_flags; - tb.subresources.mipmap_count = format.mipmaps; - tb.subresources.layer_count = format.array_layers; - - driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, {}, tb); + // Textures are only assumed to be immutable if they have initial data and none of the other bits that indicate write usage are enabled. + bool texture_mutable_by_default = texture.usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_STORAGE_BIT | TEXTURE_USAGE_STORAGE_ATOMIC_BIT | TEXTURE_USAGE_VRS_ATTACHMENT_BIT); + if (p_data.is_empty() || texture_mutable_by_default) { + _texture_make_mutable(&texture, RID()); } texture_memory += driver->texture_get_allocation_size(texture.driver_id); @@ -919,9 +757,15 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture if (p_data.size()) { for (uint32_t i = 0; i < p_format.array_layers; i++) { - _texture_update(id, i, p_data[i], BARRIER_MASK_ALL_BARRIERS, true); + _texture_update(id, i, p_data[i], true, false); + } + + if (texture.draw_tracker != nullptr) { + // Draw tracker can assume the texture will be in transfer destination. + texture.draw_tracker->usage = RDG::RESOURCE_USAGE_TRANSFER_TO; } } + return id; } @@ -959,6 +803,12 @@ RID RenderingDevice::texture_create_shared(const TextureView &p_view, RID p_with texture.driver_id = driver->texture_create_shared(texture.driver_id, tv); ERR_FAIL_COND_V(!texture.driver_id, RID()); + texture.slice_trackers.clear(); + + if (texture.draw_tracker != nullptr) { + texture.draw_tracker->reference_count++; + } + texture.owner = p_with_texture; RID id = texture_owner.make_rid(texture); #ifdef DEV_ENABLED @@ -988,23 +838,6 @@ RID RenderingDevice::texture_create_from_extension(TextureType p_type, DataForma texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM); texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB); - // Set base layout based on usage priority. - - if (p_usage.has_flag(TEXTURE_USAGE_SAMPLING_BIT)) { - // First priority, readable. - texture.layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } else if (p_usage.has_flag(TEXTURE_USAGE_STORAGE_BIT)) { - // Second priority, storage. - texture.layout = RDD::TEXTURE_LAYOUT_GENERAL; - } else if (p_usage.has_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { - // Third priority, color or depth. - texture.layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } else if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - texture.layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } else { - texture.layout = RDD::TEXTURE_LAYOUT_GENERAL; - } - if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT); texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT); @@ -1019,19 +852,7 @@ RID RenderingDevice::texture_create_from_extension(TextureType p_type, DataForma texture.driver_id = driver->texture_create_from_extension(p_image, p_type, p_format, p_layers, (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)); ERR_FAIL_COND_V(!texture.driver_id, RID()); - // Barrier to set layout. - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::TextureBarrier tb; - tb.texture = texture.driver_id; - tb.dst_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT; - tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; - tb.next_layout = texture.layout; - tb.subresources.aspect = texture.barrier_aspect_flags; - tb.subresources.mipmap_count = texture.mipmaps; - tb.subresources.layer_count = texture.layers; - - driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT, {}, {}, tb); - } + _texture_make_mutable(&texture, RID()); RID id = texture_owner.make_rid(texture); #ifdef DEV_ENABLED @@ -1081,6 +902,7 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view, } Texture texture = *src_texture; + get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height); texture.mipmaps = p_mipmaps; texture.layers = slice_layers; @@ -1118,7 +940,17 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view, texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, tv, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps); ERR_FAIL_COND_V(!texture.driver_id, RID()); + const Rect2i slice_rect(p_mipmap, p_layer, p_mipmaps, slice_layers); texture.owner = p_with_texture; + texture.slice_type = p_slice_type; + texture.slice_rect = slice_rect; + + // If parent is mutable, make slice mutable by default. + if (src_texture->draw_tracker != nullptr) { + texture.draw_tracker = nullptr; + _texture_make_mutable(&texture, RID()); + } + RID id = texture_owner.make_rid(texture); #ifdef DEV_ENABLED set_resource_name(id, "RID:" + itos(id.get_id())); @@ -1128,8 +960,8 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view, return id; } -Error RenderingDevice::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) { - return _texture_update(p_texture, p_layer, p_data, p_post_barrier, false); +Error RenderingDevice::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data) { + return _texture_update(p_texture, p_layer, p_data, false, true); } static _ALWAYS_INLINE_ void _copy_region(uint8_t const *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_x, uint32_t p_src_y, uint32_t p_src_w, uint32_t p_src_h, uint32_t p_src_full_w, uint32_t p_dst_pitch, uint32_t p_unit_size) { @@ -1148,7 +980,7 @@ static _ALWAYS_INLINE_ void _copy_region(uint8_t const *__restrict p_src, uint8_ } } -Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, bool p_use_setup_queue) { +Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, bool p_use_setup_queue, bool p_validate_can_update) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG((draw_list || compute_list) && !p_use_setup_queue, ERR_INVALID_PARAMETER, @@ -1166,7 +998,7 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve ERR_FAIL_COND_V_MSG(texture->bound, ERR_CANT_ACQUIRE_RESOURCE, "Texture can't be updated while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to update this texture."); - ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER, + ERR_FAIL_COND_V_MSG(p_validate_can_update && !(texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER, "Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_UPDATE_BIT` to be set to be updatable."); uint32_t layer_count = texture->layers; @@ -1191,21 +1023,22 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve const uint8_t *r = p_data.ptr(); - RDD::CommandBufferID command_buffer = p_use_setup_queue ? frames[frame].setup_command_buffer : frames[frame].draw_command_buffer; + thread_local LocalVector<RDG::RecordedBufferToTextureCopy> command_buffer_to_texture_copies_vector; + command_buffer_to_texture_copies_vector.clear(); - // Barrier to transfer. - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { + if (p_use_setup_queue && driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { + // When using the setup queue directly, we transition the texture to the optimal layout. RDD::TextureBarrier tb; tb.texture = texture->driver_id; tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - tb.prev_layout = texture->layout; + tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL; tb.subresources.aspect = texture->barrier_aspect_flags; tb.subresources.mipmap_count = texture->mipmaps; tb.subresources.base_layer = p_layer; tb.subresources.layer_count = 1; - driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb); + driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb); } uint32_t mipmap_offset = 0; @@ -1240,12 +1073,26 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP); region_pitch = STEPIFY(region_pitch, pitch_step); uint32_t to_allocate = region_pitch * region_h; - uint32_t alloc_offset = 0, alloc_size = 0; - Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false); + StagingRequiredAction required_action; + Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, required_action, false); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - uint8_t *write_ptr = nullptr; + if (!p_use_setup_queue && !command_buffer_to_texture_copies_vector.is_empty() && required_action == STAGING_REQUIRED_ACTION_FLUSH_CURRENT) { + if (_texture_make_mutable(texture, p_texture)) { + // The texture must be mutable to be used as a copy destination. + draw_graph.add_synchronization(); + } + + // If we're using the draw queue and the staging buffer requires flushing everything, we submit the command early and clear the current vector. + draw_graph.add_texture_update(texture->driver_id, texture->draw_tracker, command_buffer_to_texture_copies_vector); + command_buffer_to_texture_copies_vector.clear(); + } + + _staging_buffer_execute_required_action(required_action); + + uint8_t *write_ptr; + { // Map. uint8_t *data_ptr = driver->buffer_map(staging_buffer_blocks[staging_buffer_current].driver_id); ERR_FAIL_NULL_V(data_ptr, ERR_CANT_CREATE); @@ -1288,7 +1135,14 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve copy_region.texture_offset = Vector3i(x, y, z); copy_region.texture_region_size = Vector3i(region_logic_w, region_logic_h, 1); - driver->command_copy_buffer_to_texture(command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, texture->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, copy_region); + if (p_use_setup_queue) { + driver->command_copy_buffer_to_texture(frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, texture->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, copy_region); + } else { + RDG::RecordedBufferToTextureCopy buffer_to_texture_copy; + buffer_to_texture_copy.from_buffer = staging_buffer_blocks[staging_buffer_current].driver_id; + buffer_to_texture_copy.region = copy_region; + command_buffer_to_texture_copies_vector.push_back(buffer_to_texture_copy); + } staging_buffer_blocks.write[staging_buffer_current].fill_amount = alloc_offset + alloc_size; } @@ -1300,50 +1154,25 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve logic_height = MAX(1u, logic_height >> 1); } - // Barrier to restore layout. - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - BitField<RDD::PipelineStageBits> stages; - BitField<RDD::BarrierAccessBits> access; - if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { - stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { - stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { - stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { - stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT); - } - - if (stages.is_empty()) { - stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); - } - + if (p_use_setup_queue && (texture->draw_tracker == nullptr) && driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { + // If the texture does not have a tracker, it means it must be transitioned to the sampling state. RDD::TextureBarrier tb; tb.texture = texture->driver_id; tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - tb.dst_access = access; tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL; - tb.next_layout = texture->layout; + tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; tb.subresources.aspect = texture->barrier_aspect_flags; tb.subresources.mipmap_count = texture->mipmaps; tb.subresources.base_layer = p_layer; tb.subresources.layer_count = 1; - - driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb); - - if (texture->used_in_frame != frames_drawn) { - texture->used_in_raster = false; - texture->used_in_compute = false; - texture->used_in_frame = frames_drawn; + driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, {}, {}, tb); + } else if (!p_use_setup_queue && !command_buffer_to_texture_copies_vector.is_empty()) { + if (_texture_make_mutable(texture, p_texture)) { + // The texture must be mutable to be used as a copy destination. + draw_graph.add_synchronization(); } - texture->used_in_transfer = true; + + draw_graph.add_texture_update(texture->driver_id, texture->draw_tracker, command_buffer_to_texture_copies_vector); } return OK; @@ -1455,103 +1284,71 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye RDD::BufferID tmp_buffer = driver->buffer_create(work_buffer_size, RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU); ERR_FAIL_COND_V(!tmp_buffer, Vector<uint8_t>()); - RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer; // Makes more sense to retrieve. - - // Pre-copy barrier. - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::TextureBarrier tb; - tb.texture = tex->driver_id; - tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT; - tb.prev_layout = tex->layout; - tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL; - tb.subresources.aspect = tex->barrier_aspect_flags; - tb.subresources.mipmap_count = tex->mipmaps; - tb.subresources.base_layer = p_layer; - tb.subresources.layer_count = 1; - - driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb); - } + thread_local LocalVector<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_vector; + command_buffer_texture_copy_regions_vector.clear(); - { - uint32_t w = tex->width; - uint32_t h = tex->height; - uint32_t d = tex->depth; - for (uint32_t i = 0; i < tex->mipmaps; i++) { - RDD::BufferTextureCopyRegion copy_region; - copy_region.buffer_offset = mip_layouts[i].offset; - copy_region.texture_subresources.aspect = tex->read_aspect_flags; - copy_region.texture_subresources.mipmap = i; - copy_region.texture_subresources.base_layer = p_layer; - copy_region.texture_subresources.layer_count = 1; - copy_region.texture_region_size.x = w; - copy_region.texture_region_size.y = h; - copy_region.texture_region_size.z = d; - driver->command_copy_texture_to_buffer(command_buffer, tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, tmp_buffer, copy_region); - - w = MAX(1u, w >> 1); - h = MAX(1u, h >> 1); - d = MAX(1u, d >> 1); - } + uint32_t w = tex->width; + uint32_t h = tex->height; + uint32_t d = tex->depth; + for (uint32_t i = 0; i < tex->mipmaps; i++) { + RDD::BufferTextureCopyRegion copy_region; + copy_region.buffer_offset = mip_layouts[i].offset; + copy_region.texture_subresources.aspect = tex->read_aspect_flags; + copy_region.texture_subresources.mipmap = i; + copy_region.texture_subresources.base_layer = p_layer; + copy_region.texture_subresources.layer_count = 1; + copy_region.texture_region_size.x = w; + copy_region.texture_region_size.y = h; + copy_region.texture_region_size.z = d; + command_buffer_texture_copy_regions_vector.push_back(copy_region); + + w = MAX(1u, w >> 1); + h = MAX(1u, h >> 1); + d = MAX(1u, d >> 1); } - // Post-copy barrier. - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::TextureBarrier tb; - tb.texture = tex->driver_id; - tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT; - tb.dst_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT; - if ((tex->usage_flags & TEXTURE_USAGE_STORAGE_BIT)) { - tb.dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL; - tb.next_layout = tex->layout; - tb.subresources.aspect = tex->barrier_aspect_flags; - tb.subresources.mipmap_count = tex->mipmaps; - tb.subresources.base_layer = p_layer; - tb.subresources.layer_count = 1; - - driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, {}, tb); + if (_texture_make_mutable(tex, p_texture)) { + // The texture must be mutable to be used as a copy source due to layout transitions. + draw_graph.add_synchronization(); } + draw_graph.add_texture_get_data(tex->driver_id, tex->draw_tracker, tmp_buffer, command_buffer_texture_copy_regions_vector); + _flush(true); const uint8_t *read_ptr = driver->buffer_map(tmp_buffer); ERR_FAIL_NULL_V(read_ptr, Vector<uint8_t>()); Vector<uint8_t> buffer_data; - { - uint32_t tight_buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps); - buffer_data.resize(tight_buffer_size); - - uint8_t *write_ptr = buffer_data.ptrw(); - - uint32_t w = tex->width; - uint32_t h = tex->height; - uint32_t d = tex->depth; - for (uint32_t i = 0; i < tex->mipmaps; i++) { - uint32_t width = 0, height = 0, depth = 0; - uint32_t tight_mip_size = get_image_format_required_size(tex->format, w, h, d, 1, &width, &height, &depth); - uint32_t block_w = 0, block_h = 0; - get_compressed_image_format_block_dimensions(tex->format, block_w, block_h); - uint32_t tight_row_pitch = tight_mip_size / ((height / block_h) * depth); - - { - // Copy row-by-row to erase padding due to alignments. - const uint8_t *rp = read_ptr; - uint8_t *wp = write_ptr; - for (uint32_t row = h * d / block_h; row != 0; row--) { - memcpy(wp, rp, tight_row_pitch); - rp += mip_layouts[i].row_pitch; - wp += tight_row_pitch; - } - } + uint32_t tight_buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps); + buffer_data.resize(tight_buffer_size); + + uint8_t *write_ptr = buffer_data.ptrw(); - w = MAX(1u, w >> 1); - h = MAX(1u, h >> 1); - d = MAX(1u, d >> 1); - read_ptr += mip_layouts[i].size; - write_ptr += tight_mip_size; + w = tex->width; + h = tex->height; + d = tex->depth; + for (uint32_t i = 0; i < tex->mipmaps; i++) { + uint32_t width = 0, height = 0, depth = 0; + uint32_t tight_mip_size = get_image_format_required_size(tex->format, w, h, d, 1, &width, &height, &depth); + uint32_t block_w = 0, block_h = 0; + get_compressed_image_format_block_dimensions(tex->format, block_w, block_h); + uint32_t tight_row_pitch = tight_mip_size / ((height / block_h) * depth); + + // Copy row-by-row to erase padding due to alignments. + const uint8_t *rp = read_ptr; + uint8_t *wp = write_ptr; + for (uint32_t row = h * d / block_h; row != 0; row--) { + memcpy(wp, rp, tight_row_pitch); + rp += mip_layouts[i].row_pitch; + wp += tight_row_pitch; } + + w = MAX(1u, w >> 1); + h = MAX(1u, h >> 1); + d = MAX(1u, d >> 1); + read_ptr += mip_layouts[i].size; + write_ptr += tight_mip_size; } driver->buffer_unmap(tmp_buffer); @@ -1610,7 +1407,7 @@ uint64_t RenderingDevice::texture_get_native_handle(RID p_texture) { } #endif -Error RenderingDevice::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier) { +Error RenderingDevice::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer) { _THREAD_SAFE_METHOD_ Texture *src_tex = texture_owner.get_or_null(p_from_texture); @@ -1658,133 +1455,34 @@ Error RenderingDevice::texture_copy(RID p_from_texture, RID p_to_texture, const ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER, "Source and destination texture must be of the same type (color or depth)."); - RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer; - - // PRE Copy the image. - - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - { // Source. - RDD::TextureBarrier tb; - tb.texture = src_tex->driver_id; - tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT; - tb.prev_layout = src_tex->layout; - tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL; - tb.subresources.aspect = src_tex->barrier_aspect_flags; - tb.subresources.base_mipmap = p_src_mipmap; - tb.subresources.mipmap_count = 1; - tb.subresources.base_layer = p_src_layer; - tb.subresources.layer_count = 1; - - driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb); - } - { // Dest. - RDD::TextureBarrier tb; - tb.texture = dst_tex->driver_id; - tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - tb.prev_layout = dst_tex->layout; - tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL; - tb.subresources.aspect = dst_tex->read_aspect_flags; - tb.subresources.base_mipmap = p_dst_mipmap; - tb.subresources.mipmap_count = 1; - tb.subresources.base_layer = p_dst_layer; - tb.subresources.layer_count = 1; - - driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb); - } - } - - // COPY. - - { - RDD::TextureCopyRegion copy_region; - copy_region.src_subresources.aspect = src_tex->read_aspect_flags; - copy_region.src_subresources.mipmap = p_src_mipmap; - copy_region.src_subresources.base_layer = p_src_layer; - copy_region.src_subresources.layer_count = 1; - copy_region.src_offset = p_from; + RDD::TextureCopyRegion copy_region; + copy_region.src_subresources.aspect = src_tex->read_aspect_flags; + copy_region.src_subresources.mipmap = p_src_mipmap; + copy_region.src_subresources.base_layer = p_src_layer; + copy_region.src_subresources.layer_count = 1; + copy_region.src_offset = p_from; - copy_region.dst_subresources.aspect = dst_tex->read_aspect_flags; - copy_region.dst_subresources.mipmap = p_dst_mipmap; - copy_region.dst_subresources.base_layer = p_dst_layer; - copy_region.dst_subresources.layer_count = 1; - copy_region.dst_offset = p_to; + copy_region.dst_subresources.aspect = dst_tex->read_aspect_flags; + copy_region.dst_subresources.mipmap = p_dst_mipmap; + copy_region.dst_subresources.base_layer = p_dst_layer; + copy_region.dst_subresources.layer_count = 1; + copy_region.dst_offset = p_to; - copy_region.size = p_size; + copy_region.size = p_size; - driver->command_copy_texture(command_buffer, src_tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, copy_region); + // The textures must be mutable to be used in the copy operation. + bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture); + bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture); + if (src_made_mutable || dst_made_mutable) { + draw_graph.add_synchronization(); } - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - // RESTORE LAYOUT for SRC and DST. - - BitField<RDD::PipelineStageBits> stages; - BitField<RDD::BarrierAccessBits> access; - if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { - stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { - stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { - stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { - stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT); - } - - if (stages.is_empty()) { - stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); - } - - { // Restore src. - RDD::TextureBarrier tb; - tb.texture = src_tex->driver_id; - tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT; - tb.dst_access = access; - tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL; - tb.next_layout = src_tex->layout; - tb.subresources.aspect = src_tex->barrier_aspect_flags; - tb.subresources.base_mipmap = p_src_mipmap; - tb.subresources.mipmap_count = 1; - tb.subresources.base_layer = p_src_layer; - tb.subresources.layer_count = 1; - - driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb); - } - - { // Make dst readable. - - RDD::TextureBarrier tb; - tb.texture = dst_tex->driver_id; - tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - tb.dst_access = access; - tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL; - tb.next_layout = dst_tex->layout; - tb.subresources.aspect = dst_tex->read_aspect_flags; - tb.subresources.base_mipmap = p_dst_mipmap; - tb.subresources.mipmap_count = 1; - tb.subresources.base_layer = p_dst_layer; - tb.subresources.layer_count = 1; - - driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb); - } - - if (dst_tex->used_in_frame != frames_drawn) { - dst_tex->used_in_raster = false; - dst_tex->used_in_compute = false; - dst_tex->used_in_frame = frames_drawn; - } - dst_tex->used_in_transfer = true; - } + draw_graph.add_texture_copy(src_tex->driver_id, src_tex->draw_tracker, dst_tex->driver_id, dst_tex->draw_tracker, copy_region); return OK; } -Error RenderingDevice::texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier) { +Error RenderingDevice::texture_resolve_multisample(RID p_from_texture, RID p_to_texture) { _THREAD_SAFE_METHOD_ Texture *src_tex = texture_owner.get_or_null(p_from_texture); @@ -1815,108 +1513,19 @@ Error RenderingDevice::texture_resolve_multisample(RID p_from_texture, RID p_to_ ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER, "Source and destination texture must be of the same type (color or depth)."); - RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer; - - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - // PRE Copy the image. - - { // Source. - RDD::TextureBarrier tb; - tb.texture = src_tex->driver_id; - tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT; - tb.prev_layout = src_tex->layout; - tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL; - tb.subresources.aspect = src_tex->barrier_aspect_flags; - tb.subresources.base_mipmap = src_tex->base_mipmap; - tb.subresources.mipmap_count = 1; - tb.subresources.base_layer = src_tex->base_layer; - tb.subresources.layer_count = 1; - - driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb); - } - { // Dest. - RDD::TextureBarrier tb; - tb.texture = dst_tex->driver_id; - tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - tb.prev_layout = dst_tex->layout; - tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL; - tb.subresources.aspect = dst_tex->barrier_aspect_flags; - tb.subresources.base_mipmap = dst_tex->base_mipmap; - tb.subresources.mipmap_count = 1; - tb.subresources.base_layer = dst_tex->base_layer; - tb.subresources.layer_count = 1; - - driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb); - } + // The textures must be mutable to be used in the resolve operation. + bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture); + bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture); + if (src_made_mutable || dst_made_mutable) { + draw_graph.add_synchronization(); } - // RESOLVE. - driver->command_resolve_texture(command_buffer, src_tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, src_tex->base_layer, src_tex->base_mipmap, dst_tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_tex->base_layer, dst_tex->base_mipmap); - - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - // RESTORE LAYOUT for SRC and DST. - - BitField<RDD::PipelineStageBits> stages; - BitField<RDD::BarrierAccessBits> access; - if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { - stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { - stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { - stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { - stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT); - } - - if (stages.is_empty()) { - stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); - } - - { // Restore src. - RDD::TextureBarrier tb; - tb.texture = src_tex->driver_id; - tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT; - tb.dst_access = access; - tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL; - tb.next_layout = src_tex->layout; - tb.subresources.aspect = src_tex->barrier_aspect_flags; - tb.subresources.base_mipmap = src_tex->base_mipmap; - tb.subresources.mipmap_count = 1; - tb.subresources.base_layer = src_tex->base_layer; - tb.subresources.layer_count = 1; - - driver->command_pipeline_barrier(command_buffer, RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT, stages, {}, {}, tb); - } - - { // Make dst readable. - - RDD::TextureBarrier tb; - tb.texture = dst_tex->driver_id; - tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - tb.dst_access = access; - tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL; - tb.next_layout = dst_tex->layout; - tb.subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT; - tb.subresources.base_mipmap = dst_tex->base_mipmap; - tb.subresources.mipmap_count = 1; - tb.subresources.base_layer = dst_tex->base_layer; - tb.subresources.layer_count = 1; - - driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb); - } - } + draw_graph.add_texture_resolve(src_tex->driver_id, src_tex->draw_tracker, dst_tex->driver_id, dst_tex->draw_tracker, src_tex->base_layer, src_tex->base_mipmap, dst_tex->base_layer, dst_tex->base_mipmap); return OK; } -Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier) { +Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers) { _THREAD_SAFE_METHOD_ Texture *src_tex = texture_owner.get_or_null(p_texture); @@ -1939,33 +1548,6 @@ Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32 ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_base_layer + p_layers > src_layer_count, ERR_INVALID_PARAMETER); - RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer; - - RDD::TextureLayout clear_layout = (src_tex->layout == RDD::TEXTURE_LAYOUT_GENERAL) ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL; - - // NOTE: Perhaps the valid stages/accesses for a given owner should be a property of the owner. (Here and places like _get_buffer_from_owner.) - const BitField<RDD::PipelineStageBits> valid_texture_stages = RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT; - constexpr BitField<RDD::BarrierAccessBits> read_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT; - constexpr BitField<RDD::BarrierAccessBits> read_write_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT; - const BitField<RDD::BarrierAccessBits> valid_texture_access = (src_tex->usage_flags & TEXTURE_USAGE_STORAGE_BIT) ? read_write_access : read_access; - - // Barrier from previous access with optional layout change (see clear_layout logic above). - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::TextureBarrier tb; - tb.texture = src_tex->driver_id; - tb.src_access = valid_texture_access; - tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - tb.prev_layout = src_tex->layout; - tb.next_layout = clear_layout; - tb.subresources.aspect = src_tex->read_aspect_flags; - tb.subresources.base_mipmap = src_tex->base_mipmap + p_base_mipmap; - tb.subresources.mipmap_count = p_mipmaps; - tb.subresources.base_layer = src_tex->base_layer + p_base_layer; - tb.subresources.layer_count = p_layers; - - driver->command_pipeline_barrier(command_buffer, valid_texture_stages, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb); - } - RDD::TextureSubresourceRange range; range.aspect = src_tex->read_aspect_flags; range.base_mipmap = src_tex->base_mipmap + p_base_mipmap; @@ -1973,55 +1555,13 @@ Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32 range.base_layer = src_tex->base_layer + p_base_layer; range.layer_count = p_layers; - driver->command_clear_color_texture(command_buffer, src_tex->driver_id, clear_layout, p_color, range); - - // Barrier to post clear accesses (changing back the layout if needed). - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - BitField<RDD::PipelineStageBits> stages; - BitField<RDD::BarrierAccessBits> access; - if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { - stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { - stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { - stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { - stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT); - } - - if (stages.is_empty()) { - stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); - } - - RDD::TextureBarrier tb; - tb.texture = src_tex->driver_id; - tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - tb.dst_access = access; - tb.prev_layout = clear_layout; - tb.next_layout = src_tex->layout; - tb.subresources.aspect = src_tex->read_aspect_flags; - tb.subresources.base_mipmap = src_tex->base_mipmap + p_base_mipmap; - tb.subresources.mipmap_count = p_mipmaps; - tb.subresources.base_layer = src_tex->base_layer + p_base_layer; - tb.subresources.layer_count = p_layers; - - driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb); - - if (src_tex->used_in_frame != frames_drawn) { - src_tex->used_in_raster = false; - src_tex->used_in_compute = false; - src_tex->used_in_frame = frames_drawn; - } - src_tex->used_in_transfer = true; + if (_texture_make_mutable(src_tex, p_texture)) { + // The texture must be mutable to be used as a clear destination. + draw_graph.add_synchronization(); } + draw_graph.add_texture_clear(src_tex->driver_id, src_tex->draw_tracker, p_color, range); + return OK; } @@ -2040,6 +1580,30 @@ bool RenderingDevice::texture_is_format_supported_for_usage(DataFormat p_format, /**** FRAMEBUFFER ****/ /*********************/ +static RDD::AttachmentLoadOp initial_action_to_load_op(RenderingDevice::InitialAction p_action) { + switch (p_action) { + case RenderingDevice::INITIAL_ACTION_LOAD: + return RDD::ATTACHMENT_LOAD_OP_LOAD; + case RenderingDevice::INITIAL_ACTION_CLEAR: + return RDD::ATTACHMENT_LOAD_OP_CLEAR; + case RenderingDevice::INITIAL_ACTION_DISCARD: + return RDD::ATTACHMENT_LOAD_OP_DONT_CARE; + default: + ERR_FAIL_V_MSG(RDD::ATTACHMENT_LOAD_OP_DONT_CARE, "Invalid initial action value (" + itos(p_action) + ")"); + } +} + +static RDD::AttachmentStoreOp final_action_to_store_op(RenderingDevice::FinalAction p_action) { + switch (p_action) { + case RenderingDevice::FINAL_ACTION_STORE: + return RDD::ATTACHMENT_STORE_OP_STORE; + case RenderingDevice::FINAL_ACTION_DISCARD: + return RDD::ATTACHMENT_STORE_OP_DONT_CARE; + default: + ERR_FAIL_V_MSG(RDD::ATTACHMENT_STORE_OP_DONT_CARE, "Invalid final action value (" + itos(p_action) + ")"); + } +} + RDD::RenderPassID RenderingDevice::_render_pass_create(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, uint32_t p_view_count, Vector<TextureSamples> *r_samples) { // NOTE: // Before the refactor to RenderingDevice-RenderingDeviceDriver, there was commented out code to @@ -2077,209 +1641,40 @@ RDD::RenderPassID RenderingDevice::_render_pass_create(const Vector<AttachmentFo description.format = p_attachments[i].format; description.samples = p_attachments[i].samples; - bool is_sampled = (p_attachments[i].usage_flags & TEXTURE_USAGE_SAMPLING_BIT); - bool is_storage = (p_attachments[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT); - bool is_depth = (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - // We can setup a framebuffer where we write to our VRS texture to set it up. // We make the assumption here that if our texture is actually used as our VRS attachment. // It is used as such for each subpass. This is fairly certain seeing the restrictions on subpasses. bool is_vrs = (p_attachments[i].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && i == p_passes[0].vrs_attachment; if (is_vrs) { - // For VRS we only read, there is no writing to this texture. description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD; - description.initial_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_LOAD; - } else { - // For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write. - // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs - // the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that - // stage. - - switch (is_depth ? p_initial_depth_action : p_initial_action) { - case INITIAL_ACTION_CLEAR_REGION: - case INITIAL_ACTION_CLEAR: { - if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { - description.load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR; - description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - description.load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR; - description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR; - } else { - description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there. - } - } break; - case INITIAL_ACTION_KEEP: { - if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { - description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD; - description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD; - description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_LOAD; - } else { - description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there. - } - } break; - case INITIAL_ACTION_DROP: { - if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { - description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there. - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - } else { - description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there. - } - } break; - case INITIAL_ACTION_CLEAR_REGION_CONTINUE: - case INITIAL_ACTION_CONTINUE: { - if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { - description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD; - description.initial_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD; - description.initial_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_LOAD; - } else { - description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there. - } - } break; - default: { - ERR_FAIL_V(RDD::RenderPassID()); // Should never reach here. - } - } - } - - bool used_last = false; - - { - int last_pass = p_passes.size() - 1; - - if (is_depth) { - // Likely missing depth resolve? - if (p_passes[last_pass].depth_attachment == i) { - used_last = true; - } - } else if (is_vrs) { - if (p_passes[last_pass].vrs_attachment == i) { - used_last = true; - } - } else { - if (p_passes[last_pass].resolve_attachments.size()) { - // If using resolve attachments, check resolve attachments. - for (int j = 0; j < p_passes[last_pass].resolve_attachments.size(); j++) { - if (p_passes[last_pass].resolve_attachments[j] == i) { - used_last = true; - break; - } - } - } - if (!used_last) { - for (int j = 0; j < p_passes[last_pass].color_attachments.size(); j++) { - if (p_passes[last_pass].color_attachments[j] == i) { - used_last = true; - break; - } - } - } - } - - if (!used_last) { - for (int j = 0; j < p_passes[last_pass].preserve_attachments.size(); j++) { - if (p_passes[last_pass].preserve_attachments[j] == i) { - used_last = true; - break; - } - } - } - } - - FinalAction final_action = p_final_action; - FinalAction final_depth_action = p_final_depth_action; - - if (!used_last) { - if (is_depth) { - final_depth_action = FINAL_ACTION_DISCARD; - - } else { - final_action = FINAL_ACTION_DISCARD; - } - } - - if (is_vrs) { - // We don't change our VRS texture during this process. - description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; + description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_LOAD; description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; + description.initial_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; description.final_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } else { - switch (is_depth ? final_depth_action : final_action) { - case FINAL_ACTION_READ: { - if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { - description.store_op = RDD::ATTACHMENT_STORE_OP_STORE; - description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; - description.final_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - description.store_op = RDD::ATTACHMENT_STORE_OP_STORE; - description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_STORE; - description.final_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - } else { - description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; - description.final_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there. - // TODO: What does this mean about the next usage (and thus appropriate dependency masks. - } - } break; - case FINAL_ACTION_DISCARD: { - if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { - description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; - description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; - description.final_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; - description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; - description.final_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - } else { - description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; - description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; - description.final_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there. - } - } break; - case FINAL_ACTION_CONTINUE: { - if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { - description.store_op = RDD::ATTACHMENT_STORE_OP_STORE; - description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; - description.final_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - description.store_op = RDD::ATTACHMENT_STORE_OP_STORE; - description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_STORE; - description.final_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } else { - description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; - description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; - description.final_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there. - } - - } break; - default: { - ERR_FAIL_V(RDD::RenderPassID()); // Should never reach here. - } + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.load_op = initial_action_to_load_op(p_initial_action); + description.store_op = final_action_to_store_op(p_final_action); + description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; + description.initial_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + description.final_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.load_op = initial_action_to_load_op(p_initial_depth_action); + description.store_op = final_action_to_store_op(p_final_depth_action); + description.stencil_load_op = initial_action_to_load_op(p_initial_depth_action); + description.stencil_store_op = final_action_to_store_op(p_final_depth_action); + description.initial_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + description.final_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } else { + description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; + description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; + description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; + description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; + description.final_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; } } @@ -2465,7 +1860,7 @@ RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_format_create_ } Vector<TextureSamples> samples; - RDD::RenderPassID render_pass = _render_pass_create(p_attachments, p_passes, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, p_view_count, &samples); // Actions don't matter for this use case. + RDD::RenderPassID render_pass = _render_pass_create(p_attachments, p_passes, INITIAL_ACTION_CLEAR, FINAL_ACTION_STORE, INITIAL_ACTION_CLEAR, FINAL_ACTION_STORE, p_view_count, &samples); // Actions don't matter for this use case. if (!render_pass) { // Was likely invalid. return INVALID_ID; @@ -2701,18 +2096,14 @@ RID RenderingDevice::vertex_buffer_create(uint32_t p_size_bytes, const Vector<ui buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU); ERR_FAIL_COND_V(!buffer.driver_id, RID()); + // Vertex buffers are assumed to be immutable unless they don't have initial data or they've been marked for storage explicitly. + if (p_data.is_empty() || p_use_as_storage) { + buffer.draw_tracker = RDG::resource_tracker_create(); + buffer.draw_tracker->buffer_driver_id = buffer.driver_id; + } + if (p_data.size()) { - uint64_t data_size = p_data.size(); - const uint8_t *r = p_data.ptr(); - _buffer_update(&buffer, 0, r, data_size); - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::BufferBarrier bb; - bb.buffer = buffer.driver_id; - bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - bb.dst_access = RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; - bb.size = data_size; - driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT, {}, bb, {}); - } + _buffer_update(&buffer, RID(), 0, p_data.ptr(), p_data.size()); } buffer_memory += buffer.size; @@ -2809,6 +2200,12 @@ RID RenderingDevice::vertex_array_create(uint32_t p_vertex_count, VertexFormatID } vertex_array.buffers.push_back(buffer->driver_id); + + if (buffer->draw_tracker != nullptr) { + vertex_array.draw_trackers.push_back(buffer->draw_tracker); + } else { + vertex_array.untracked_buffers.insert(p_src_buffers[i]); + } } RID id = vertex_array_owner.make_rid(vertex_array); @@ -2863,18 +2260,14 @@ RID RenderingDevice::index_buffer_create(uint32_t p_index_count, IndexBufferForm index_buffer.driver_id = driver->buffer_create(index_buffer.size, index_buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU); ERR_FAIL_COND_V(!index_buffer.driver_id, RID()); + // Index buffers are assumed to be immutable unless they don't have initial data. + if (p_data.is_empty()) { + index_buffer.draw_tracker = RDG::resource_tracker_create(); + index_buffer.draw_tracker->buffer_driver_id = index_buffer.driver_id; + } + if (p_data.size()) { - uint64_t data_size = p_data.size(); - const uint8_t *r = p_data.ptr(); - _buffer_update(&index_buffer, 0, r, data_size); - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::BufferBarrier bb; - bb.buffer = index_buffer.driver_id; - bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - bb.dst_access = RDD::BARRIER_ACCESS_INDEX_READ_BIT; - bb.size = data_size; - driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT, {}, bb, {}); - } + _buffer_update(&index_buffer, RID(), 0, p_data.ptr(), p_data.size()); } buffer_memory += index_buffer.size; @@ -2899,6 +2292,7 @@ RID RenderingDevice::index_array_create(RID p_index_buffer, uint32_t p_index_off IndexArray index_array; index_array.max_index = index_buffer->max_index; index_array.driver_id = index_buffer->driver_id; + index_array.draw_tracker = index_buffer->draw_tracker; index_array.offset = p_index_offset; index_array.indices = p_index_count; index_array.format = index_buffer->format; @@ -2991,6 +2385,29 @@ RID RenderingDevice::shader_create_from_bytecode(const Vector<uint8_t> &p_shader shader->set_formats.push_back(format); } + for (ShaderStage stage : shader_desc.stages) { + switch (stage) { + case SHADER_STAGE_VERTEX: + shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); + break; + case SHADER_STAGE_FRAGMENT: + shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + break; + case SHADER_STAGE_TESSELATION_CONTROL: + shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT); + break; + case SHADER_STAGE_TESSELATION_EVALUATION: + shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT); + break; + case SHADER_STAGE_COMPUTE: + shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); + break; + default: + DEV_ASSERT(false && "Unknown shader stage."); + break; + } + } + #ifdef DEV_ENABLED set_resource_name(id, "RID:" + itos(id.get_id())); #endif @@ -3025,18 +2442,14 @@ RID RenderingDevice::uniform_buffer_create(uint32_t p_size_bytes, const Vector<u buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU); ERR_FAIL_COND_V(!buffer.driver_id, RID()); + // Uniform buffers are assumed to be immutable unless they don't have initial data. + if (p_data.is_empty()) { + buffer.draw_tracker = RDG::resource_tracker_create(); + buffer.draw_tracker->buffer_driver_id = buffer.driver_id; + } + if (p_data.size()) { - uint64_t data_size = p_data.size(); - const uint8_t *r = p_data.ptr(); - _buffer_update(&buffer, 0, r, data_size); - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::BufferBarrier bb; - bb.buffer = buffer.driver_id; - bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; - bb.dst_access = RDD::BARRIER_ACCESS_UNIFORM_READ_BIT; - bb.size = data_size; - driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, bb, {}); - } + _buffer_update(&buffer, RID(), 0, p_data.ptr(), p_data.size()); } buffer_memory += buffer.size; @@ -3073,8 +2486,9 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p // Used for verification to make sure a uniform set does not use a framebuffer bound texture. LocalVector<UniformSet::AttachableTexture> attachable_textures; - Vector<Texture *> mutable_sampled_textures; - Vector<Texture *> mutable_storage_textures; + Vector<RDG::ResourceTracker *> draw_trackers; + Vector<RDG::ResourceUsage> draw_trackers_usage; + HashMap<RID, RDG::ResourceUsage> untracked_usage; for (uint32_t i = 0; i < set_uniform_count; i++) { const ShaderUniform &set_uniform = set_uniforms[i]; @@ -3126,7 +2540,8 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j + 0)); ERR_FAIL_COND_V_MSG(!sampler_driver_id, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler."); - Texture *texture = texture_owner.get_or_null(uniform.get_id(j + 1)); + RID texture_id = uniform.get_id(j + 1); + Texture *texture = texture_owner.get_or_null(texture_id); ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture."); ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(), @@ -3139,8 +2554,11 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p attachable_textures.push_back(attachable_texture); } - if ((texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT)) { - mutable_sampled_textures.push_back(texture); + if (texture->draw_tracker != nullptr) { + draw_trackers.push_back(texture->draw_tracker); + draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE); + } else { + untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE; } DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner)); @@ -3159,7 +2577,8 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p } for (uint32_t j = 0; j < uniform.get_id_count(); j++) { - Texture *texture = texture_owner.get_or_null(uniform.get_id(j)); + RID texture_id = uniform.get_id(j); + Texture *texture = texture_owner.get_or_null(texture_id); ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture."); ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(), @@ -3172,8 +2591,11 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p attachable_textures.push_back(attachable_texture); } - if ((texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT)) { - mutable_sampled_textures.push_back(texture); + if (texture->draw_tracker != nullptr) { + draw_trackers.push_back(texture->draw_tracker); + draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE); + } else { + untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE; } DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner)); @@ -3191,7 +2613,8 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p } for (uint32_t j = 0; j < uniform.get_id_count(); j++) { - Texture *texture = texture_owner.get_or_null(uniform.get_id(j)); + RID texture_id = uniform.get_id(j); + Texture *texture = texture_owner.get_or_null(texture_id); ERR_FAIL_NULL_V_MSG(texture, RID(), "Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture."); @@ -3199,8 +2622,19 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(), "Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform."); - if ((texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT)) { - mutable_storage_textures.push_back(texture); + if (_texture_make_mutable(texture, texture_id)) { + // The texture must be mutable as a layout transition will be required. + draw_graph.add_synchronization(); + } + + if (texture->draw_tracker != nullptr) { + draw_trackers.push_back(texture->draw_tracker); + + if (set_uniform.writable) { + draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE); + } else { + draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_IMAGE_READ); + } } DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner)); @@ -3218,9 +2652,27 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p } for (uint32_t j = 0; j < uniform.get_id_count(); j++) { - Buffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j)); + RID buffer_id = uniform.get_id(j); + Buffer *buffer = texture_buffer_owner.get_or_null(buffer_id); ERR_FAIL_NULL_V_MSG(buffer, RID(), "Texture Buffer (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture buffer."); + if (set_uniform.writable && _buffer_make_mutable(buffer, buffer_id)) { + // The buffer must be mutable if it's used for writing. + draw_graph.add_synchronization(); + } + + if (buffer->draw_tracker != nullptr) { + draw_trackers.push_back(buffer->draw_tracker); + + if (set_uniform.writable) { + draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE); + } else { + draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ); + } + } else { + untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ; + } + driver_uniform.ids.push_back(buffer->driver_id); } } break; @@ -3237,9 +2689,17 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j + 0)); ERR_FAIL_COND_V_MSG(!sampler_driver_id, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler."); - Buffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j + 1)); + RID buffer_id = uniform.get_id(j + 1); + Buffer *buffer = texture_buffer_owner.get_or_null(buffer_id); ERR_FAIL_NULL_V_MSG(buffer, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid texture buffer."); + if (buffer->draw_tracker != nullptr) { + draw_trackers.push_back(buffer->draw_tracker); + draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ); + } else { + untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_TEXTURE_BUFFER_READ; + } + driver_uniform.ids.push_back(*sampler_driver_id); driver_uniform.ids.push_back(buffer->driver_id); } @@ -3251,12 +2711,20 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided)."); - Buffer *buffer = uniform_buffer_owner.get_or_null(uniform.get_id(0)); + RID buffer_id = uniform.get_id(0); + Buffer *buffer = uniform_buffer_owner.get_or_null(buffer_id); ERR_FAIL_NULL_V_MSG(buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid."); ERR_FAIL_COND_V_MSG(buffer->size < (uint32_t)set_uniform.length, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " is smaller than size of shader uniform: (" + itos(set_uniform.length) + ")."); + if (buffer->draw_tracker != nullptr) { + draw_trackers.push_back(buffer->draw_tracker); + draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_UNIFORM_BUFFER_READ); + } else { + untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_UNIFORM_BUFFER_READ; + } + driver_uniform.ids.push_back(buffer->driver_id); } break; case UNIFORM_TYPE_STORAGE_BUFFER: { @@ -3265,10 +2733,11 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p Buffer *buffer = nullptr; - if (storage_buffer_owner.owns(uniform.get_id(0))) { - buffer = storage_buffer_owner.get_or_null(uniform.get_id(0)); - } else if (vertex_buffer_owner.owns(uniform.get_id(0))) { - buffer = vertex_buffer_owner.get_or_null(uniform.get_id(0)); + RID buffer_id = uniform.get_id(0); + if (storage_buffer_owner.owns(buffer_id)) { + buffer = storage_buffer_owner.get_or_null(buffer_id); + } else if (vertex_buffer_owner.owns(buffer_id)) { + buffer = vertex_buffer_owner.get_or_null(buffer_id); ERR_FAIL_COND_V_MSG(!(buffer->usage.has_flag(RDD::BUFFER_USAGE_STORAGE_BIT)), RID(), "Vertex buffer supplied (binding: " + itos(uniform.binding) + ") was not created with storage flag."); } @@ -3278,6 +2747,23 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); + if (set_uniform.writable && _buffer_make_mutable(buffer, buffer_id)) { + // The buffer must be mutable if it's used for writing. + draw_graph.add_synchronization(); + } + + if (buffer->draw_tracker != nullptr) { + draw_trackers.push_back(buffer->draw_tracker); + + if (set_uniform.writable) { + draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE); + } else { + draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ); + } + } else { + untracked_usage[buffer_id] = RDG::RESOURCE_USAGE_STORAGE_BUFFER_READ; + } + driver_uniform.ids.push_back(buffer->driver_id); } break; case UNIFORM_TYPE_INPUT_ATTACHMENT: { @@ -3292,7 +2778,8 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p } for (uint32_t j = 0; j < uniform.get_id_count(); j++) { - Texture *texture = texture_owner.get_or_null(uniform.get_id(j)); + RID texture_id = uniform.get_id(j); + Texture *texture = texture_owner.get_or_null(texture_id); ERR_FAIL_NULL_V_MSG(texture, RID(), "InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture."); @@ -3302,6 +2789,17 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner)); + if (_texture_make_mutable(texture, texture_id)) { + // The texture must be mutable as a layout transition will be required. + draw_graph.add_synchronization(); + } + + if (texture->draw_tracker != nullptr) { + bool depth_stencil_read = (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); + draw_trackers.push_back(texture->draw_tracker); + draw_trackers_usage.push_back(depth_stencil_read ? RDG::RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ : RDG::RESOURCE_USAGE_ATTACHMENT_COLOR_READ); + } + driver_uniform.ids.push_back(texture->driver_id); } } break; @@ -3317,8 +2815,9 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p uniform_set.driver_id = driver_uniform_set; uniform_set.format = shader->set_formats[p_shader_set]; uniform_set.attachable_textures = attachable_textures; - uniform_set.mutable_sampled_textures = mutable_sampled_textures; - uniform_set.mutable_storage_textures = mutable_storage_textures; + uniform_set.draw_trackers = draw_trackers; + uniform_set.draw_trackers_usage = draw_trackers_usage; + uniform_set.untracked_usage = untracked_usage; uniform_set.shader_set = p_shader_set; uniform_set.shader_id = p_shader; @@ -3486,6 +2985,7 @@ RID RenderingDevice::render_pipeline_create(RID p_shader, FramebufferFormatID p_ pipeline.shader_layout_hash = shader->layout_hash; pipeline.set_formats = shader->set_formats; pipeline.push_constant_size = shader->push_constant_size; + pipeline.stage_bits = shader->stage_bits; #ifdef DEBUG_ENABLED pipeline.validation.dynamic_state = p_dynamic_state_flags; @@ -3623,15 +3123,13 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin_for_screen(DisplayS ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time."); ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time."); - RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer; - if (!context->window_is_valid_swapchain(p_screen)) { return INVALID_ID; } - Size2i size = Size2i(context->window_get_width(p_screen), context->window_get_height(p_screen)); + Rect2i viewport = Rect2i(0, 0, context->window_get_width(p_screen), context->window_get_height(p_screen)); - _draw_list_allocate(Rect2i(Vector2i(), size), 0, 0); + _draw_list_allocate(viewport, 0); #ifdef DEBUG_ENABLED draw_list_framebuffer_format = screen_get_framebuffer_format(); #endif @@ -3639,16 +3137,11 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin_for_screen(DisplayS RDD::RenderPassClearValue clear_value; clear_value.color = p_clear_color; - driver->command_begin_render_pass( - command_buffer, - context->window_get_render_pass(p_screen), - context->window_get_framebuffer(p_screen), - RDD::COMMAND_BUFFER_TYPE_PRIMARY, - Rect2i(0, 0, size.width, size.height), - VectorView(&clear_value, 1)); - driver->command_render_set_viewport(command_buffer, Rect2i(Point2i(), size)); - driver->command_render_set_scissor(command_buffer, Rect2i(Point2i(), size)); + draw_graph.add_draw_list_begin(context->window_get_render_pass(p_screen), context->window_get_framebuffer(p_screen), viewport, clear_value, true, false); + + _draw_list_set_viewport(viewport); + _draw_list_set_scissor(viewport); return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; } @@ -3694,8 +3187,12 @@ Error RenderingDevice::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer, return OK; } -Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass, RDD::CommandBufferID p_command_buffer, RDD::CommandBufferType p_cmd_buffer_mode, const Vector<RID> &p_storage_textures, bool p_constrained_to_region) { +Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass) { LocalVector<RDD::RenderPassClearValue> clear_values; + LocalVector<RDG::ResourceTracker *> resource_trackers; + LocalVector<RDG::ResourceUsage> resource_usages; + bool uses_color = false; + bool uses_depth = false; clear_values.resize(p_framebuffer->texture_ids.size()); int clear_values_count = 0; { @@ -3709,69 +3206,33 @@ Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer, continue; } - if (color_index < p_clear_colors.size() && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { - ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); // A bug. - clear_value.color = p_clear_colors[color_index]; - color_index++; + if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + if (color_index < p_clear_colors.size()) { + ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); // A bug. + clear_value.color = p_clear_colors[color_index]; + color_index++; + } + + resource_trackers.push_back(texture->draw_tracker); + resource_usages.push_back(RDG::RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE); + uses_color = true; } else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { clear_value.depth = p_clear_depth; clear_value.stencil = p_clear_stencil; + resource_trackers.push_back(texture->draw_tracker); + resource_usages.push_back(RDG::RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE); + uses_depth = true; } clear_values[clear_values_count++] = clear_value; } } - for (int i = 0; i < p_storage_textures.size(); i++) { - Texture *texture = texture_owner.get_or_null(p_storage_textures[i]); - if (!texture) { - continue; - } - ERR_CONTINUE_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), "Supplied storage texture " + itos(i) + " for draw list is not set to be used for storage."); - - if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) { - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - // Must change layout to general. - RDD::TextureBarrier tb; - tb.texture = texture->driver_id; - tb.src_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - tb.dst_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - tb.prev_layout = texture->layout; - tb.next_layout = RDD::TEXTURE_LAYOUT_GENERAL; - tb.subresources.aspect = texture->read_aspect_flags; - tb.subresources.base_mipmap = texture->base_mipmap; - tb.subresources.mipmap_count = texture->mipmaps; - tb.subresources.base_layer = texture->base_layer; - tb.subresources.layer_count = texture->layers; - - driver->command_pipeline_barrier(p_command_buffer, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT, RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT, {}, {}, tb); - - texture->layout = RDD::TEXTURE_LAYOUT_GENERAL; - } - - draw_list_storage_textures.push_back(p_storage_textures[i]); - } - } - - Rect2i region; - if (p_constrained_to_region) { - region = Rect2i(p_viewport_offset, p_viewport_size); - } else { - region = Rect2i(Point2i(), p_framebuffer->size); - } - - driver->command_begin_render_pass( - p_command_buffer, - p_render_pass, - p_framebuffer_driver_id, - p_cmd_buffer_mode, - region, - clear_values); + draw_graph.add_draw_list_begin(p_render_pass, p_framebuffer_driver_id, Rect2i(p_viewport_offset, p_viewport_size), clear_values, uses_color, uses_depth); + draw_graph.add_draw_list_usages(resource_trackers, resource_usages); // Mark textures as bound. draw_list_bound_textures.clear(); - draw_list_unbind_color_textures = p_final_color_action != FINAL_ACTION_CONTINUE; - draw_list_unbind_depth_textures = p_final_depth_action != FINAL_ACTION_CONTINUE; for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) { Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]); @@ -3785,6 +3246,14 @@ Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer, return OK; } +void RenderingDevice::_draw_list_set_viewport(Rect2i p_rect) { + draw_graph.add_draw_list_set_viewport(p_rect); +} + +void RenderingDevice::_draw_list_set_scissor(Rect2i p_rect) { + draw_graph.add_draw_list_set_scissor(p_rect); +} + void RenderingDevice::_draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) { LocalVector<RDD::AttachmentClear> clear_attachments; int color_index = 0; @@ -3818,24 +3287,19 @@ void RenderingDevice::_draw_list_insert_clear_region(DrawList *p_draw_list, Fram } Rect2i rect = Rect2i(p_viewport_offset, p_viewport_size); - - driver->command_render_clear_attachments(p_draw_list->command_buffer, clear_attachments, rect); + draw_graph.add_draw_list_clear_attachments(clear_attachments, rect); } -RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) { +RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time."); - ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, INVALID_ID, "Only one draw/compute list can be active at the same time."); Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer); ERR_FAIL_NULL_V(framebuffer, INVALID_ID); Point2i viewport_offset; Point2i viewport_size = framebuffer->size; - bool constrained_to_region = false; - bool needs_clear_color = false; - bool needs_clear_depth = false; if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region. Rect2i viewport(viewport_offset, viewport_size); @@ -3848,34 +3312,9 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, viewport_offset = regioni.position; viewport_size = regioni.size; - - // If clearing regions both in color and depth, we can switch to a fast path where we let Vulkan to the clears - // and we constrain the render area to the region. - if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION && p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) { - constrained_to_region = true; - p_initial_color_action = INITIAL_ACTION_CLEAR; - p_initial_depth_action = INITIAL_ACTION_CLEAR; - } else { - if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) { - needs_clear_color = true; - p_initial_color_action = INITIAL_ACTION_CONTINUE; - } - if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) { - needs_clear_depth = true; - p_initial_depth_action = INITIAL_ACTION_CONTINUE; - } - if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION) { - needs_clear_color = true; - p_initial_color_action = INITIAL_ACTION_KEEP; - } - if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) { - needs_clear_depth = true; - p_initial_depth_action = INITIAL_ACTION_KEEP; - } - } } - if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { // Check clear values. + if (p_initial_color_action == INITIAL_ACTION_CLEAR) { // Check clear values. int color_count = 0; for (int i = 0; i < framebuffer->texture_ids.size(); i++) { Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]); @@ -3897,8 +3336,7 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &fb_driver_id, &render_pass, &draw_list_subpass_count); ERR_FAIL_COND_V(err != OK, INVALID_ID); - RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer; - err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, fb_driver_id, render_pass, command_buffer, RDD::COMMAND_BUFFER_TYPE_PRIMARY, p_storage_textures, constrained_to_region); + err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, fb_driver_id, render_pass); if (err != OK) { return INVALID_ID; @@ -3907,135 +3345,23 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, draw_list_render_pass = render_pass; draw_list_vkframebuffer = fb_driver_id; - _draw_list_allocate(Rect2i(viewport_offset, viewport_size), 0, 0); + _draw_list_allocate(Rect2i(viewport_offset, viewport_size), 0); #ifdef DEBUG_ENABLED draw_list_framebuffer_format = framebuffer->format_id; #endif draw_list_current_subpass = 0; - if (needs_clear_color || needs_clear_depth) { - DEV_ASSERT(!constrained_to_region); - _draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil); - } - - driver->command_render_set_viewport(command_buffer, Rect2i(viewport_offset, viewport_size)); - driver->command_render_set_scissor(command_buffer, Rect2i(viewport_offset, viewport_size)); + _draw_list_set_viewport(Rect2i(viewport_offset, viewport_size)); + _draw_list_set_scissor(Rect2i(viewport_offset, viewport_size)); return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; } +#ifndef DISABLE_DEPRECATED Error RenderingDevice::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) { - _THREAD_SAFE_METHOD_ - - ERR_FAIL_COND_V_MSG(draw_list != nullptr, ERR_BUSY, "Only one draw list can be active at the same time."); - ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, ERR_BUSY, "Only one draw/compute list can be active at the same time."); - - ERR_FAIL_COND_V(p_splits < 1, ERR_INVALID_DECLARATION); - - Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer); - ERR_FAIL_NULL_V(framebuffer, ERR_INVALID_DECLARATION); - - Point2i viewport_offset; - Point2i viewport_size = framebuffer->size; - bool constrained_to_region = false; - bool needs_clear_color = false; - bool needs_clear_depth = false; - - if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region. - Rect2i viewport(viewport_offset, viewport_size); - Rect2i regioni = p_region; - if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) && - ((regioni.position.x + regioni.size.x) <= (viewport.position.x + viewport.size.x)) && - ((regioni.position.y + regioni.size.y) <= (viewport.position.y + viewport.size.y))) { - ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "When supplying a custom region, it must be contained within the framebuffer rectangle"); - } - - viewport_offset = regioni.position; - viewport_size = regioni.size; - - // If clearing regions both in color and depth, we can switch to a fast path where we let Vulkan to the clears - // and we constrain the render area to the region. - if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION && p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) { - constrained_to_region = true; - p_initial_color_action = INITIAL_ACTION_CLEAR; - p_initial_depth_action = INITIAL_ACTION_CLEAR; - } else { - if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) { - needs_clear_color = true; - p_initial_color_action = INITIAL_ACTION_CONTINUE; - } - if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) { - needs_clear_depth = true; - p_initial_depth_action = INITIAL_ACTION_CONTINUE; - } - if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION) { - needs_clear_color = true; - p_initial_color_action = INITIAL_ACTION_KEEP; - } - if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) { - needs_clear_depth = true; - p_initial_depth_action = INITIAL_ACTION_KEEP; - } - } - } - - if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { // Check clear values. - - int color_count = 0; - for (int i = 0; i < framebuffer->texture_ids.size(); i++) { - Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]); - - if (!texture || !(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - color_count++; - } - } - - ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, ERR_INVALID_PARAMETER, - "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_count) + ")."); - } - - RDD::FramebufferID fb_driver_id; - RDD::RenderPassID render_pass; - - Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &fb_driver_id, &render_pass, &draw_list_subpass_count); - ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); - - RDD::CommandBufferID frame_command_buffer = frames[frame].draw_command_buffer; - err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, fb_driver_id, render_pass, frame_command_buffer, RDD::COMMAND_BUFFER_TYPE_SECONDARY, p_storage_textures, constrained_to_region); - - if (err != OK) { - return ERR_CANT_CREATE; - } - - draw_list_current_subpass = 0; - -#ifdef DEBUG_ENABLED - draw_list_framebuffer_format = framebuffer->format_id; -#endif - draw_list_render_pass = render_pass; - draw_list_vkframebuffer = fb_driver_id; - - err = _draw_list_allocate(Rect2i(viewport_offset, viewport_size), p_splits, 0); - if (err != OK) { - return err; - } - - if (needs_clear_color || needs_clear_depth) { - DEV_ASSERT(!constrained_to_region); - _draw_list_insert_clear_region(&draw_list[0], framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil); - } - - bool secondary_viewport_scissor = driver->api_trait_get(RDD::API_TRAIT_SECONDARY_VIEWPORT_SCISSOR); - for (uint32_t i = 0; i < p_splits; i++) { - if (secondary_viewport_scissor) { - driver->command_render_set_viewport(draw_list[i].command_buffer, Rect2i(viewport_offset, viewport_size)); - driver->command_render_set_scissor(draw_list[i].command_buffer, Rect2i(viewport_offset, viewport_size)); - } - r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i; - } - - return OK; + ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Deprecated. Split draw lists are used automatically by RenderingDevice."); } +#endif RenderingDevice::DrawList *RenderingDevice::_get_draw_list_ptr(DrawListID p_id) { if (p_id < 0) { @@ -4045,22 +3371,7 @@ RenderingDevice::DrawList *RenderingDevice::_get_draw_list_ptr(DrawListID p_id) if (!draw_list) { return nullptr; } else if (p_id == (int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT)) { - if (draw_list_split) { - return nullptr; - } return draw_list; - } else if (p_id >> DrawListID(ID_BASE_SHIFT) == ID_TYPE_SPLIT_DRAW_LIST) { - if (!draw_list_split) { - return nullptr; - } - - uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); // Mask. - - if (index >= draw_list_count) { - return nullptr; - } - - return &draw_list[index]; } else { return nullptr; } @@ -4073,7 +3384,7 @@ void RenderingDevice::draw_list_set_blend_constants(DrawListID p_list, const Col ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); #endif - driver->command_render_set_blend_constants(dl->command_buffer, p_color); + draw_graph.add_draw_list_set_blend_constants(p_color); } void RenderingDevice::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) { @@ -4095,7 +3406,7 @@ void RenderingDevice::draw_list_bind_render_pipeline(DrawListID p_list, RID p_re dl->state.pipeline = p_render_pipeline; - driver->command_bind_render_pipeline(dl->command_buffer, pipeline->driver_id); + draw_graph.add_draw_list_bind_pipeline(pipeline->driver_id, pipeline->stage_bits); if (dl->state.pipeline_shader != pipeline->shader) { // Shader changed, so descriptor sets may become incompatible. @@ -4125,7 +3436,7 @@ void RenderingDevice::draw_list_bind_render_pipeline(DrawListID p_list, RID p_re } for (uint32_t i = 0; i < pcount; i++) { - dl->state.sets[i].bound = i < first_invalid_set; + dl->state.sets[i].bound = dl->state.sets[i].bound && i < first_invalid_set; dl->state.sets[i].pipeline_expected_format = pformats[i]; } @@ -4183,21 +3494,6 @@ void RenderingDevice::draw_list_bind_uniform_set(DrawListID p_list, RID p_unifor dl->state.sets[p_index].uniform_set_format = uniform_set->format; dl->state.sets[p_index].uniform_set = p_uniform_set; - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - uint32_t mst_count = uniform_set->mutable_storage_textures.size(); - if (mst_count) { - Texture **mst_textures = const_cast<UniformSet *>(uniform_set)->mutable_storage_textures.ptrw(); - for (uint32_t i = 0; i < mst_count; i++) { - if (mst_textures[i]->used_in_frame != frames_drawn) { - mst_textures[i]->used_in_frame = frames_drawn; - mst_textures[i]->used_in_transfer = false; - mst_textures[i]->used_in_compute = false; - } - mst_textures[i]->used_in_raster = true; - } - } - } - #ifdef DEBUG_ENABLED { // Validate that textures bound are not attached as framebuffer bindings. uint32_t attachable_count = uniform_set->attachable_textures.size(); @@ -4235,7 +3531,12 @@ void RenderingDevice::draw_list_bind_vertex_array(DrawListID p_list, RID p_verte dl->validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed; #endif dl->validation.vertex_array_size = vertex_array->vertex_count; - driver->command_render_bind_vertex_buffers(dl->command_buffer, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr()); + + draw_graph.add_draw_list_bind_vertex_buffers(vertex_array->buffers, vertex_array->offsets); + + for (int i = 0; i < vertex_array->draw_trackers.size(); i++) { + draw_graph.add_draw_list_usage(vertex_array->draw_trackers[i], RDG::RESOURCE_USAGE_VERTEX_BUFFER_READ); + } } void RenderingDevice::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) { @@ -4256,10 +3557,14 @@ void RenderingDevice::draw_list_bind_index_array(DrawListID p_list, RID p_index_ #ifdef DEBUG_ENABLED dl->validation.index_array_max_index = index_array->max_index; #endif - dl->validation.index_array_size = index_array->indices; - dl->validation.index_array_offset = index_array->offset; + dl->validation.index_array_count = index_array->indices; + + const uint64_t offset_bytes = index_array->offset * (index_array->format == INDEX_BUFFER_FORMAT_UINT16 ? sizeof(uint16_t) : sizeof(uint32_t)); + draw_graph.add_draw_list_bind_index_buffer(index_array->driver_id, index_array->format, offset_bytes); - driver->command_render_bind_index_buffer(dl->command_buffer, index_array->driver_id, index_array->format, index_array->offset); + if (index_array->draw_tracker != nullptr) { + draw_graph.add_draw_list_usage(index_array->draw_tracker, RDG::RESOURCE_USAGE_INDEX_BUFFER_READ); + } } void RenderingDevice::draw_list_set_line_width(DrawListID p_list, float p_width) { @@ -4269,7 +3574,7 @@ void RenderingDevice::draw_list_set_line_width(DrawListID p_list, float p_width) ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); #endif - driver->command_render_set_line_width(dl->command_buffer, p_width); + draw_graph.add_draw_list_set_line_width(p_width); } void RenderingDevice::draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size) { @@ -4284,7 +3589,9 @@ void RenderingDevice::draw_list_set_push_constant(DrawListID p_list, const void ERR_FAIL_COND_MSG(p_data_size != dl->validation.pipeline_push_constant_size, "This render pipeline requires (" + itos(dl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")"); #endif - driver->command_bind_push_constants(dl->command_buffer, dl->state.pipeline_shader_driver_id, 0, VectorView((const uint32_t *)p_data, p_data_size / sizeof(uint32_t))); + + draw_graph.add_draw_list_set_push_constant(dl->state.pipeline_shader_driver_id, p_data, p_data_size); + #ifdef DEBUG_ENABLED dl->validation.pipeline_push_constant_supplied = true; #endif @@ -4338,14 +3645,19 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint } } #endif - driver->command_uniform_set_prepare_for_use(dl->command_buffer, dl->state.sets[i].uniform_set_driver_id, dl->state.pipeline_shader_driver_id, i); + draw_graph.add_draw_list_uniform_set_prepare_for_use(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i); } for (uint32_t i = 0; i < dl->state.set_count; i++) { if (dl->state.sets[i].pipeline_expected_format == 0) { continue; // Nothing expected by this pipeline. } if (!dl->state.sets[i].bound) { - driver->command_bind_render_uniform_set(dl->command_buffer, dl->state.sets[i].uniform_set_driver_id, dl->state.pipeline_shader_driver_id, i); + // All good, see if this requires re-binding. + draw_graph.add_draw_list_bind_uniform_set(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i); + + UniformSet *uniform_set = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set); + draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); + dl->state.sets[i].bound = true; } } @@ -4355,13 +3667,13 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint ERR_FAIL_COND_MSG(p_procedural_vertices > 0, "Procedural vertices can't be used together with indices."); - ERR_FAIL_COND_MSG(!dl->validation.index_array_size, + ERR_FAIL_COND_MSG(!dl->validation.index_array_count, "Draw command requested indices, but no index buffer was set."); ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices, "The usage of restart indices in index buffer does not match the render primitive in the pipeline."); #endif - uint32_t to_draw = dl->validation.index_array_size; + uint32_t to_draw = dl->validation.index_array_count; #ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, @@ -4370,7 +3682,8 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, "Index amount (" + itos(to_draw) + ") must be a multiple of the amount of indices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); #endif - driver->command_render_draw_indexed(dl->command_buffer, to_draw, p_instances, dl->validation.index_array_offset, 0, 0); + + draw_graph.add_draw_list_draw_indexed(to_draw, p_instances, 0); } else { uint32_t to_draw; @@ -4396,7 +3709,7 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint "Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); #endif - driver->command_render_draw(dl->command_buffer, to_draw, p_instances, 0, 0); + draw_graph.add_draw_list_draw(to_draw, p_instances); } } @@ -4416,7 +3729,7 @@ void RenderingDevice::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p return; } - driver->command_render_set_scissor(dl->command_buffer, rect); + _draw_list_set_scissor(rect); } void RenderingDevice::draw_list_disable_scissor(DrawListID p_list) { @@ -4426,7 +3739,7 @@ void RenderingDevice::draw_list_disable_scissor(DrawListID p_list) { ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); #endif - driver->command_render_set_scissor(dl->command_buffer, dl->viewport); + _draw_list_set_scissor(dl->viewport); } uint32_t RenderingDevice::draw_list_get_current_pass() { @@ -4443,230 +3756,80 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_switch_to_next_pass() { Rect2i viewport; _draw_list_free(&viewport); - driver->command_next_render_subpass(frames[frame].draw_command_buffer, RDD::COMMAND_BUFFER_TYPE_PRIMARY); + draw_graph.add_draw_list_next_subpass(RDD::COMMAND_BUFFER_TYPE_PRIMARY); - _draw_list_allocate(viewport, 0, draw_list_current_subpass); + _draw_list_allocate(viewport, draw_list_current_subpass); return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; } -Error RenderingDevice::draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) { - _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V(draw_list == nullptr, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, ERR_INVALID_PARAMETER); - draw_list_current_subpass++; - - Rect2i viewport; - _draw_list_free(&viewport); - - driver->command_next_render_subpass(frames[frame].draw_command_buffer, RDD::COMMAND_BUFFER_TYPE_PRIMARY); - - _draw_list_allocate(viewport, p_splits, draw_list_current_subpass); - - for (uint32_t i = 0; i < p_splits; i++) { - r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i; - } - - return OK; +#ifndef DISABLE_DEPRECATED +Error RenderingDevice::draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) { + ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Deprecated. Split draw lists are used automatically by RenderingDevice."); } +#endif -Error RenderingDevice::_draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass) { +Error RenderingDevice::_draw_list_allocate(const Rect2i &p_viewport, uint32_t p_subpass) { // Lock while draw_list is active. _THREAD_SAFE_LOCK_ - if (p_splits == 0) { - draw_list = memnew(DrawList); - draw_list->command_buffer = frames[frame].draw_command_buffer; - draw_list->viewport = p_viewport; - draw_list_count = 0; - draw_list_split = false; - } else { - if (p_splits > (uint32_t)split_draw_list_allocators.size()) { - uint32_t from = split_draw_list_allocators.size(); - split_draw_list_allocators.resize(p_splits); - for (uint32_t i = from; i < p_splits; i++) { - RDD::CommandPoolID cmd_pool = driver->command_pool_create(RDD::COMMAND_BUFFER_TYPE_SECONDARY); - ERR_FAIL_COND_V(!cmd_pool, ERR_CANT_CREATE); - split_draw_list_allocators.write[i].command_pool = cmd_pool; - - for (int j = 0; j < frame_count; j++) { - RDD::CommandBufferID cmd_buffer = driver->command_buffer_create(RDD::COMMAND_BUFFER_TYPE_SECONDARY, cmd_pool); - ERR_FAIL_COND_V(!cmd_buffer, ERR_CANT_CREATE); - split_draw_list_allocators.write[i].command_buffers.push_back(cmd_buffer); - } - } - } - draw_list = memnew_arr(DrawList, p_splits); - draw_list_count = p_splits; - draw_list_split = true; - - for (uint32_t i = 0; i < p_splits; i++) { - // Take a command buffer and initialize it. - RDD::CommandBufferID cmd_buffer = split_draw_list_allocators[i].command_buffers[frame]; - - bool ok = driver->command_buffer_begin_secondary(cmd_buffer, draw_list_render_pass, p_subpass, draw_list_vkframebuffer); - if (!ok) { - memdelete_arr(draw_list); - draw_list = nullptr; - ERR_FAIL_V(ERR_CANT_CREATE); - } - - draw_list[i].command_buffer = cmd_buffer; - draw_list[i].viewport = p_viewport; - } - } + draw_list = memnew(DrawList); + draw_list->viewport = p_viewport; + draw_list_count = 0; return OK; } void RenderingDevice::_draw_list_free(Rect2i *r_last_viewport) { - if (draw_list_split) { - // Send all command buffers. - RDD::CommandBufferID *command_buffers = (RDD::CommandBufferID *)alloca(sizeof(RDD::CommandBufferID) * draw_list_count); - for (uint32_t i = 0; i < draw_list_count; i++) { - driver->command_buffer_end(draw_list[i].command_buffer); - command_buffers[i] = draw_list[i].command_buffer; - if (r_last_viewport) { - if (i == 0 || draw_list[i].viewport_set) { - *r_last_viewport = draw_list[i].viewport; - } - } - } - - driver->command_buffer_execute_secondary(frames[frame].draw_command_buffer, VectorView(command_buffers, draw_list_count)); - memdelete_arr(draw_list); - draw_list = nullptr; - - } else { - if (r_last_viewport) { - *r_last_viewport = draw_list->viewport; - } - // Just end the list. - memdelete(draw_list); - draw_list = nullptr; + if (r_last_viewport) { + *r_last_viewport = draw_list->viewport; } + // Just end the list. + memdelete(draw_list); + draw_list = nullptr; // Draw_list is no longer active. _THREAD_SAFE_UNLOCK_ } -void RenderingDevice::draw_list_end(BitField<BarrierMask> p_post_barrier) { +void RenderingDevice::draw_list_end() { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_MSG(!draw_list, "Immediate draw list is already inactive."); - _draw_list_free(); + draw_graph.add_draw_list_end(); - driver->command_end_render_pass(frames[frame].draw_command_buffer); + _draw_list_free(); for (int i = 0; i < draw_list_bound_textures.size(); i++) { Texture *texture = texture_owner.get_or_null(draw_list_bound_textures[i]); ERR_CONTINUE(!texture); // Wtf. - if (draw_list_unbind_color_textures && (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { + if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { texture->bound = false; } - if (draw_list_unbind_depth_textures && (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { texture->bound = false; } } - draw_list_bound_textures.clear(); - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - BitField<RDD::PipelineStageBits> dst_stages; - BitField<RDD::BarrierAccessBits> dst_access; - if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { - dst_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { - dst_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT).set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); // RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT - dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT).set_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT); // RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT - } - if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { - dst_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); // RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT - dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); // RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT - } - if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { - dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT); - dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT); - } - - if (dst_stages.is_empty()) { - dst_stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); - } - - RDD::TextureBarrier *texture_barriers = nullptr; - - uint32_t texture_barrier_count = draw_list_storage_textures.size(); - - if (texture_barrier_count) { - texture_barriers = (RDD::TextureBarrier *)alloca(sizeof(RDD::TextureBarrier) * draw_list_storage_textures.size()); - } - - BitField<RDD::PipelineStageBits> src_stage(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | - RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); - BitField<RDD::BarrierAccessBits> src_access( - RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); - - if (texture_barrier_count) { - src_stage.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - src_access.set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - - for (uint32_t i = 0; i < texture_barrier_count; i++) { - Texture *texture = texture_owner.get_or_null(draw_list_storage_textures[i]); - - RDD::TextureBarrier &tb = texture_barriers[i]; - tb.texture = texture->driver_id; - tb.src_access = src_access; - tb.dst_access = dst_access; - tb.prev_layout = texture->layout; - tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - tb.subresources.aspect = texture->read_aspect_flags; - tb.subresources.base_mipmap = texture->base_mipmap; - tb.subresources.mipmap_count = texture->mipmaps; - tb.subresources.base_layer = texture->base_layer; - tb.subresources.layer_count = texture->layers; - - texture->layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - - // To ensure proper synchronization, we must make sure rendering is done before: - // * Some buffer is copied. - // * Another render pass happens (since we may be done). - - RDD::MemoryBarrier mb; - mb.src_access = src_access; - mb.dst_access = dst_access; - - if (texture_barrier_count > 0 || p_post_barrier != BARRIER_MASK_NO_BARRIER) { - driver->command_pipeline_barrier(frames[frame].draw_command_buffer, src_stage, dst_stages, mb, {}, VectorView(texture_barriers, texture_barrier_count)); - } - } - - draw_list_storage_textures.clear(); - -#ifdef FORCE_FULL_BARRIER - _full_barrier(true); -#endif + draw_list_bound_textures.clear(); } /***********************/ /**** COMPUTE LISTS ****/ /***********************/ -RenderingDevice::ComputeListID RenderingDevice::compute_list_begin(bool p_allow_draw_overlap) { +RenderingDevice::ComputeListID RenderingDevice::compute_list_begin() { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V_MSG(!p_allow_draw_overlap && draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time."); ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time."); // Lock while compute_list is active. _THREAD_SAFE_LOCK_ compute_list = memnew(ComputeList); - compute_list->command_buffer = frames[frame].draw_command_buffer; - compute_list->state.allow_draw_overlap = p_allow_draw_overlap; + + draw_graph.add_compute_list_begin(); return ID_TYPE_COMPUTE_LIST; } @@ -4688,7 +3851,7 @@ void RenderingDevice::compute_list_bind_compute_pipeline(ComputeListID p_list, R cl->state.pipeline = p_compute_pipeline; - driver->command_bind_compute_pipeline(cl->command_buffer, pipeline->driver_id); + draw_graph.add_compute_list_bind_pipeline(pipeline->driver_id); if (cl->state.pipeline_shader != pipeline->shader) { // Shader changed, so descriptor sets may become incompatible. @@ -4718,7 +3881,7 @@ void RenderingDevice::compute_list_bind_compute_pipeline(ComputeListID p_list, R } for (uint32_t i = 0; i < pcount; i++) { - cl->state.sets[i].bound = i >= first_invalid_set; + cl->state.sets[i].bound = cl->state.sets[i].bound && i < first_invalid_set; cl->state.sets[i].pipeline_expected_format = pformats[i]; } @@ -4779,109 +3942,6 @@ void RenderingDevice::compute_list_bind_uniform_set(ComputeListID p_list, RID p_ cl->state.sets[p_index].uniform_set_format = uniform_set->format; cl->state.sets[p_index].uniform_set = p_uniform_set; - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - uint32_t textures_to_sampled_count = uniform_set->mutable_sampled_textures.size(); - uint32_t textures_to_storage_count = uniform_set->mutable_storage_textures.size(); - - Texture **textures_to_sampled = uniform_set->mutable_sampled_textures.ptrw(); - - RDD::TextureBarrier *texture_barriers = nullptr; - - if (textures_to_sampled_count + textures_to_storage_count) { - texture_barriers = (RDD::TextureBarrier *)alloca(sizeof(RDD::TextureBarrier) * (textures_to_sampled_count + textures_to_storage_count)); - } - uint32_t texture_barrier_count = 0; - - BitField<RDD::PipelineStageBits> src_stages; - - for (uint32_t i = 0; i < textures_to_sampled_count; i++) { - if (textures_to_sampled[i]->layout != RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { - src_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - - RDD::TextureBarrier &tb = texture_barriers[texture_barrier_count++]; - tb.texture = textures_to_sampled[i]->driver_id; - tb.src_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - tb.dst_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - tb.prev_layout = textures_to_sampled[i]->layout; - tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - tb.subresources.aspect = textures_to_sampled[i]->read_aspect_flags; - tb.subresources.base_mipmap = textures_to_sampled[i]->base_mipmap; - tb.subresources.mipmap_count = textures_to_sampled[i]->mipmaps; - tb.subresources.base_layer = textures_to_sampled[i]->base_layer; - tb.subresources.layer_count = textures_to_sampled[i]->layers; - - textures_to_sampled[i]->layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - cl->state.textures_to_sampled_layout.erase(textures_to_sampled[i]); - } - - if (textures_to_sampled[i]->used_in_frame != frames_drawn) { - textures_to_sampled[i]->used_in_frame = frames_drawn; - textures_to_sampled[i]->used_in_transfer = false; - textures_to_sampled[i]->used_in_raster = false; - } - textures_to_sampled[i]->used_in_compute = true; - } - - Texture **textures_to_storage = uniform_set->mutable_storage_textures.ptrw(); - - for (uint32_t i = 0; i < textures_to_storage_count; i++) { - if (textures_to_storage[i]->layout != RDD::TEXTURE_LAYOUT_GENERAL) { - BitField<RDD::BarrierAccessBits> src_access; - - if (textures_to_storage[i]->used_in_frame == frames_drawn) { - if (textures_to_storage[i]->used_in_compute) { - src_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - src_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (textures_to_storage[i]->used_in_raster) { - src_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); - src_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (textures_to_storage[i]->used_in_transfer) { - src_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT); - src_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT); - } - - textures_to_storage[i]->used_in_compute = false; - textures_to_storage[i]->used_in_raster = false; - textures_to_storage[i]->used_in_transfer = false; - - } else { - src_access.clear(); - textures_to_storage[i]->used_in_compute = false; - textures_to_storage[i]->used_in_raster = false; - textures_to_storage[i]->used_in_transfer = false; - textures_to_storage[i]->used_in_frame = frames_drawn; - } - - RDD::TextureBarrier &tb = texture_barriers[texture_barrier_count++]; - tb.texture = textures_to_storage[i]->driver_id; - tb.src_access = src_access; - tb.dst_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - tb.prev_layout = textures_to_storage[i]->layout; - tb.next_layout = RDD::TEXTURE_LAYOUT_GENERAL; - tb.subresources.aspect = textures_to_storage[i]->read_aspect_flags; - tb.subresources.base_mipmap = textures_to_storage[i]->base_mipmap; - tb.subresources.mipmap_count = textures_to_storage[i]->mipmaps; - tb.subresources.base_layer = textures_to_storage[i]->base_layer; - tb.subresources.layer_count = textures_to_storage[i]->layers; - - textures_to_storage[i]->layout = RDD::TEXTURE_LAYOUT_GENERAL; - - cl->state.textures_to_sampled_layout.insert(textures_to_storage[i]); // Needs to go back to sampled layout afterwards. - } - } - - if (texture_barrier_count) { - if (src_stages.is_empty()) { - src_stages.set_flag(RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT); - } - - driver->command_pipeline_barrier(cl->command_buffer, src_stages, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, {}, VectorView(texture_barriers, texture_barrier_count)); - } - } - #if 0 { // Validate that textures bound are not attached as framebuffer bindings. uint32_t attachable_count = uniform_set->attachable_textures.size(); @@ -4901,6 +3961,7 @@ void RenderingDevice::compute_list_bind_uniform_set(ComputeListID p_list, RID p_ void RenderingDevice::compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size) { ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); ERR_FAIL_NULL(compute_list); + ERR_FAIL_COND_MSG(p_data_size > MAX_PUSH_CONSTANT_SIZE, "Push constants can't be bigger than 128 bytes to maintain compatibility."); ComputeList *cl = compute_list; @@ -4912,7 +3973,13 @@ void RenderingDevice::compute_list_set_push_constant(ComputeListID p_list, const ERR_FAIL_COND_MSG(p_data_size != cl->validation.pipeline_push_constant_size, "This compute pipeline requires (" + itos(cl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")"); #endif - driver->command_bind_push_constants(cl->command_buffer, cl->state.pipeline_shader_driver_id, 0, VectorView((const uint32_t *)p_data, p_data_size / sizeof(uint32_t))); + + draw_graph.add_compute_list_set_push_constant(cl->state.pipeline_shader_driver_id, p_data, p_data_size); + + // Store it in the state in case we need to restart the compute list. + memcpy(cl->state.push_constant_data, p_data, p_data_size); + cl->state.push_constant_size = p_data_size; + #ifdef DEBUG_ENABLED cl->validation.pipeline_push_constant_supplied = true; #endif @@ -4970,19 +4037,24 @@ void RenderingDevice::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_g } } #endif - driver->command_uniform_set_prepare_for_use(cl->command_buffer, cl->state.sets[i].uniform_set_driver_id, cl->state.pipeline_shader_driver_id, i); + draw_graph.add_compute_list_uniform_set_prepare_for_use(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i); } for (uint32_t i = 0; i < cl->state.set_count; i++) { if (cl->state.sets[i].pipeline_expected_format == 0) { continue; // Nothing expected by this pipeline. } if (!cl->state.sets[i].bound) { - driver->command_bind_compute_uniform_set(cl->command_buffer, cl->state.sets[i].uniform_set_driver_id, cl->state.pipeline_shader_driver_id, i); + // All good, see if this requires re-binding. + draw_graph.add_compute_list_bind_uniform_set(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i); + + UniformSet *uniform_set = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set); + draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); + cl->state.sets[i].bound = true; } } - driver->command_compute_dispatch(cl->command_buffer, p_x_groups, p_y_groups, p_z_groups); + draw_graph.add_compute_list_dispatch(p_x_groups, p_y_groups, p_z_groups); } void RenderingDevice::compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads) { @@ -5009,7 +4081,7 @@ void RenderingDevice::compute_list_dispatch_threads(ComputeListID p_list, uint32 #endif - compute_list_dispatch(p_list, (p_x_threads - 1) / cl->state.local_group_size[0] + 1, (p_y_threads - 1) / cl->state.local_group_size[1] + 1, (p_z_threads - 1) / cl->state.local_group_size[2] + 1); + compute_list_dispatch(p_list, Math::division_round_up(p_x_threads, cl->state.local_group_size[0]), Math::division_round_up(p_y_threads, cl->state.local_group_size[1]), Math::division_round_up(p_z_threads, cl->state.local_group_size[2])); } void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset) { @@ -5058,106 +4130,56 @@ void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p } } #endif - driver->command_uniform_set_prepare_for_use(cl->command_buffer, cl->state.sets[i].uniform_set_driver_id, cl->state.pipeline_shader_driver_id, i); + draw_graph.add_compute_list_uniform_set_prepare_for_use(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i); } for (uint32_t i = 0; i < cl->state.set_count; i++) { if (cl->state.sets[i].pipeline_expected_format == 0) { continue; // Nothing expected by this pipeline. } if (!cl->state.sets[i].bound) { - driver->command_bind_compute_uniform_set(cl->command_buffer, cl->state.sets[i].uniform_set_driver_id, cl->state.pipeline_shader_driver_id, i); + // All good, see if this requires re-binding. + draw_graph.add_compute_list_bind_uniform_set(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i); + + UniformSet *uniform_set = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set); + draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); + cl->state.sets[i].bound = true; } } - driver->command_compute_dispatch_indirect(cl->command_buffer, buffer->driver_id, p_offset); + draw_graph.add_compute_list_dispatch_indirect(buffer->driver_id, p_offset); + + if (buffer->draw_tracker != nullptr) { + draw_graph.add_compute_list_usage(buffer->draw_tracker, RDG::RESOURCE_USAGE_INDIRECT_BUFFER_READ); + } } void RenderingDevice::compute_list_add_barrier(ComputeListID p_list) { // Must be called within a compute list, the class mutex is locked during that time - BitField<RDD::PipelineStageBits> stages(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - BitField<RDD::BarrierAccessBits> access(RDD::BARRIER_ACCESS_SHADER_READ_BIT); - _compute_list_add_barrier(BARRIER_MASK_COMPUTE, stages, access); -} - -void RenderingDevice::_compute_list_add_barrier(BitField<BarrierMask> p_post_barrier, BitField<RDD::PipelineStageBits> p_stages, BitField<RDD::BarrierAccessBits> p_access) { - ERR_FAIL_NULL(compute_list); - - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::TextureBarrier *texture_barriers = nullptr; - - uint32_t texture_barrier_count = compute_list->state.textures_to_sampled_layout.size(); - - if (texture_barrier_count) { - texture_barriers = (RDD::TextureBarrier *)alloca(sizeof(RDD::TextureBarrier) * texture_barrier_count); - } - - texture_barrier_count = 0; // We'll count how many we end up issuing. - - for (Texture *E : compute_list->state.textures_to_sampled_layout) { - if (E->layout != RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { - RDD::TextureBarrier &tb = texture_barriers[texture_barrier_count++]; - tb.texture = E->driver_id; - tb.src_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT; - tb.dst_access = p_access; - tb.prev_layout = E->layout; - tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - tb.subresources.aspect = E->read_aspect_flags; - tb.subresources.base_mipmap = E->base_mipmap; - tb.subresources.mipmap_count = E->mipmaps; - tb.subresources.base_layer = E->base_layer; - tb.subresources.layer_count = E->layers; - - E->layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - - if (E->used_in_frame != frames_drawn) { - E->used_in_transfer = false; - E->used_in_raster = false; - E->used_in_compute = false; - E->used_in_frame = frames_drawn; - } - } + compute_list_barrier_state = compute_list->state; + compute_list_end(); + compute_list_begin(); - if (p_stages) { - RDD::MemoryBarrier mb; - mb.src_access = RDD::BARRIER_ACCESS_SHADER_WRITE_BIT; - mb.dst_access = p_access; - driver->command_pipeline_barrier(compute_list->command_buffer, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, p_stages, mb, {}, VectorView(texture_barriers, texture_barrier_count)); + if (compute_list_barrier_state.pipeline.is_valid()) { + compute_list_bind_compute_pipeline(p_list, compute_list_barrier_state.pipeline); + } - } else if (texture_barrier_count) { - driver->command_pipeline_barrier(compute_list->command_buffer, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, {}, {}, VectorView(texture_barriers, texture_barrier_count)); + for (uint32_t i = 0; i < compute_list_barrier_state.set_count; i++) { + if (compute_list_barrier_state.sets[i].uniform_set.is_valid()) { + compute_list_bind_uniform_set(p_list, compute_list_barrier_state.sets[i].uniform_set, i); } } -#ifdef FORCE_FULL_BARRIER - _full_barrier(true); -#endif + if (compute_list_barrier_state.push_constant_size > 0) { + compute_list_set_push_constant(p_list, compute_list_barrier_state.push_constant_data, compute_list_barrier_state.push_constant_size); + } } -void RenderingDevice::compute_list_end(BitField<BarrierMask> p_post_barrier) { +void RenderingDevice::compute_list_end() { ERR_FAIL_NULL(compute_list); - BitField<RDD::PipelineStageBits> stages; - BitField<RDD::BarrierAccessBits> access; - if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { - stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { - stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT).set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT).set_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT).set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { - stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT); - access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT); - } - if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { - stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT); - access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT); - } - _compute_list_add_barrier(p_post_barrier, stages, access); + draw_graph.add_compute_list_end(); memdelete(compute_list); compute_list = nullptr; @@ -5166,66 +4188,168 @@ void RenderingDevice::compute_list_end(BitField<BarrierMask> p_post_barrier) { _THREAD_SAFE_UNLOCK_ } +#ifndef DISABLE_DEPRECATED void RenderingDevice::barrier(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) { - if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - return; - } + WARN_PRINT("Deprecated. Barriers are automatically inserted by RenderingDevice."); +} - BitField<RDD::PipelineStageBits> src_stages; - BitField<RDD::BarrierAccessBits> src_access; +void RenderingDevice::full_barrier() { + WARN_PRINT("Deprecated. Barriers are automatically inserted by RenderingDevice."); +} +#endif - if (p_from == 0) { - src_stages.set_flag(RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT); +/***********************/ +/**** COMMAND GRAPH ****/ +/***********************/ + +bool RenderingDevice::_texture_make_mutable(Texture *p_texture, RID p_texture_id) { + if (p_texture->draw_tracker != nullptr) { + // Texture already has a tracker. + return false; } else { - if (p_from.has_flag(BARRIER_MASK_COMPUTE)) { - src_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - src_access.set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_from.has_flag(BARRIER_MASK_FRAGMENT)) { - src_stages.set_flag(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT).set_flag(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT).set_flag(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); - src_access.set_flag(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); + if (p_texture->owner.is_valid()) { + // Texture has an owner. + Texture *owner_texture = texture_owner.get_or_null(p_texture->owner); + ERR_FAIL_COND_V(!owner_texture, false); + + if (owner_texture->draw_tracker != nullptr) { + // Create a tracker for this dependency in particular. + if (p_texture->slice_type == TEXTURE_SLICE_MAX) { + // Shared texture. + p_texture->draw_tracker = owner_texture->draw_tracker; + p_texture->draw_tracker->reference_count++; + } else { + // Slice texture. + HashMap<Rect2i, RDG::ResourceTracker *>::ConstIterator draw_tracker_iterator = owner_texture->slice_trackers.find(p_texture->slice_rect); + RDG::ResourceTracker *draw_tracker = nullptr; + if (draw_tracker_iterator != owner_texture->slice_trackers.end()) { + // Reuse the tracker at the matching rectangle. + draw_tracker = draw_tracker_iterator->value; + } else { + // Create a new tracker and store it on the map. + draw_tracker = RDG::resource_tracker_create(); + draw_tracker->parent = owner_texture->draw_tracker; + draw_tracker->texture_driver_id = p_texture->driver_id; + draw_tracker->texture_subresources = p_texture->barrier_range(); + draw_tracker->texture_slice_or_dirty_rect = p_texture->slice_rect; + owner_texture->slice_trackers[p_texture->slice_rect] = draw_tracker; + } + + p_texture->slice_trackers.clear(); + p_texture->draw_tracker = draw_tracker; + p_texture->draw_tracker->reference_count++; + } + + if (p_texture_id.is_valid()) { + _dependencies_make_mutable(p_texture_id, p_texture->draw_tracker); + } + } else { + // Delegate this to the owner instead, as it'll make all its dependencies mutable. + _texture_make_mutable(owner_texture, p_texture->owner); + } + } else { + // Regular texture. + p_texture->draw_tracker = RDG::resource_tracker_create(); + p_texture->draw_tracker->texture_driver_id = p_texture->driver_id; + p_texture->draw_tracker->texture_subresources = p_texture->barrier_range(); + p_texture->draw_tracker->reference_count = 1; + + if (p_texture_id.is_valid()) { + if (p_texture->has_initial_data) { + // If the texture was initialized with initial data but wasn't made mutable from the start, assume the texture sampling usage. + p_texture->draw_tracker->usage = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE; + } + + _dependencies_make_mutable(p_texture_id, p_texture->draw_tracker); + } } - if (p_from.has_flag(BARRIER_MASK_TRANSFER)) { - src_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT); - src_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT); + + return true; + } +} + +bool RenderingDevice::_buffer_make_mutable(Buffer *p_buffer, RID p_buffer_id) { + if (p_buffer->draw_tracker != nullptr) { + // Buffer already has a tracker. + return false; + } else { + // Create a tracker for the buffer and make all its dependencies mutable. + p_buffer->draw_tracker = RDG::resource_tracker_create(); + p_buffer->draw_tracker->buffer_driver_id = p_buffer->driver_id; + if (p_buffer_id.is_valid()) { + _dependencies_make_mutable(p_buffer_id, p_buffer->draw_tracker); } + + return true; } +} - BitField<RDD::PipelineStageBits> dst_stages; - BitField<RDD::BarrierAccessBits> dst_access; +bool RenderingDevice::_vertex_array_make_mutable(VertexArray *p_vertex_array, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker) { + if (!p_vertex_array->untracked_buffers.has(p_resource_id)) { + // Vertex array thinks the buffer is already tracked or does not use it. + return false; + } else { + // Vertex array is aware of the buffer but it isn't being tracked. + p_vertex_array->draw_trackers.push_back(p_resource_tracker); + p_vertex_array->untracked_buffers.erase(p_resource_id); + return true; + } +} - if (p_to == 0) { - dst_stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); +bool RenderingDevice::_index_array_make_mutable(IndexArray *p_index_array, RDG::ResourceTracker *p_resource_tracker) { + if (p_index_array->draw_tracker != nullptr) { + // Index array already has a tracker. + return false; } else { - if (p_to.has_flag(BARRIER_MASK_COMPUTE)) { - dst_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); - dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); - } - if (p_to.has_flag(BARRIER_MASK_VERTEX)) { - dst_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT).set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT); - dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT).set_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT).set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT); - } - if (p_to.has_flag(BARRIER_MASK_FRAGMENT)) { - dst_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT); - dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT); - } - if (p_to.has_flag(BARRIER_MASK_TRANSFER)) { - dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT); - dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT); - } + // Index array should assign the tracker from the buffer. + p_index_array->draw_tracker = p_resource_tracker; + return true; } +} - RDD::MemoryBarrier mb; - mb.src_access = src_access; - mb.dst_access = dst_access; - driver->command_pipeline_barrier(frames[frame].draw_command_buffer, src_stages, dst_stages, mb, {}, {}); +bool RenderingDevice::_uniform_set_make_mutable(UniformSet *p_uniform_set, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker) { + HashMap<RID, RDG::ResourceUsage>::Iterator E = p_uniform_set->untracked_usage.find(p_resource_id); + if (!E) { + // Uniform set thinks the resource is already tracked or does not use it. + return false; + } else { + // Uniform set has seen the resource but hasn't added its tracker yet. + p_uniform_set->draw_trackers.push_back(p_resource_tracker); + p_uniform_set->draw_trackers_usage.push_back(E->value); + p_uniform_set->untracked_usage.remove(E); + return true; + } } -void RenderingDevice::full_barrier() { -#ifndef DEBUG_ENABLED - ERR_PRINT("Full barrier is debug-only, should not be used in production"); -#endif - _full_barrier(true); +bool RenderingDevice::_dependency_make_mutable(RID p_id, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker) { + if (texture_owner.owns(p_id)) { + Texture *texture = texture_owner.get_or_null(p_id); + return _texture_make_mutable(texture, p_id); + } else if (vertex_array_owner.owns(p_id)) { + VertexArray *vertex_array = vertex_array_owner.get_or_null(p_id); + return _vertex_array_make_mutable(vertex_array, p_resource_id, p_resource_tracker); + } else if (index_array_owner.owns(p_id)) { + IndexArray *index_array = index_array_owner.get_or_null(p_id); + return _index_array_make_mutable(index_array, p_resource_tracker); + } else if (uniform_set_owner.owns(p_id)) { + UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id); + return _uniform_set_make_mutable(uniform_set, p_resource_id, p_resource_tracker); + } else { + DEV_ASSERT(false && "Unknown resource type to make mutable."); + return false; + } +} + +bool RenderingDevice::_dependencies_make_mutable(RID p_id, RDG::ResourceTracker *p_resource_tracker) { + bool made_mutable = false; + HashMap<RID, HashSet<RID>>::Iterator E = dependency_map.find(p_id); + if (E) { + for (RID rid : E->value) { + made_mutable = _dependency_make_mutable(rid, p_id, p_resource_tracker) || made_mutable; + } + } + + return made_mutable; } /**************************/ @@ -5251,6 +4375,22 @@ void RenderingDevice::_free_internal(RID p_id) { // Push everything so it's disposed of next time this frame index is processed (means, it's safe to do it). if (texture_owner.owns(p_id)) { Texture *texture = texture_owner.get_or_null(p_id); + RDG::ResourceTracker *draw_tracker = texture->draw_tracker; + if (draw_tracker != nullptr) { + draw_tracker->reference_count--; + if (draw_tracker->reference_count == 0) { + RDG::resource_tracker_free(draw_tracker); + + if (texture->owner.is_valid() && (texture->slice_type != TEXTURE_SLICE_MAX)) { + // If this was a texture slice, erase the tracker from the map. + Texture *owner_texture = texture_owner.get_or_null(texture->owner); + if (owner_texture != nullptr) { + owner_texture->slice_trackers.erase(texture->slice_rect); + } + } + } + } + frames[frame].textures_to_dispose_of.push_back(*texture); texture_owner.free(p_id); } else if (framebuffer_owner.owns(p_id)) { @@ -5268,12 +4408,14 @@ void RenderingDevice::_free_internal(RID p_id) { sampler_owner.free(p_id); } else if (vertex_buffer_owner.owns(p_id)) { Buffer *vertex_buffer = vertex_buffer_owner.get_or_null(p_id); + RDG::resource_tracker_free(vertex_buffer->draw_tracker); frames[frame].buffers_to_dispose_of.push_back(*vertex_buffer); vertex_buffer_owner.free(p_id); } else if (vertex_array_owner.owns(p_id)) { vertex_array_owner.free(p_id); } else if (index_buffer_owner.owns(p_id)) { IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_id); + RDG::resource_tracker_free(index_buffer->draw_tracker); frames[frame].buffers_to_dispose_of.push_back(*index_buffer); index_buffer_owner.free(p_id); } else if (index_array_owner.owns(p_id)) { @@ -5286,14 +4428,17 @@ void RenderingDevice::_free_internal(RID p_id) { shader_owner.free(p_id); } else if (uniform_buffer_owner.owns(p_id)) { Buffer *uniform_buffer = uniform_buffer_owner.get_or_null(p_id); + RDG::resource_tracker_free(uniform_buffer->draw_tracker); frames[frame].buffers_to_dispose_of.push_back(*uniform_buffer); uniform_buffer_owner.free(p_id); } else if (texture_buffer_owner.owns(p_id)) { Buffer *texture_buffer = texture_buffer_owner.get_or_null(p_id); + RDG::resource_tracker_free(texture_buffer->draw_tracker); frames[frame].buffers_to_dispose_of.push_back(*texture_buffer); texture_buffer_owner.free(p_id); } else if (storage_buffer_owner.owns(p_id)) { Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id); + RDG::resource_tracker_free(storage_buffer->draw_tracker); frames[frame].buffers_to_dispose_of.push_back(*storage_buffer); storage_buffer_owner.free(p_id); } else if (uniform_set_owner.owns(p_id)) { @@ -5370,18 +4515,21 @@ void RenderingDevice::set_resource_name(RID p_id, const String &p_name) { } void RenderingDevice::draw_command_begin_label(String p_label_name, const Color &p_color) { - _THREAD_SAFE_METHOD_ - context->command_begin_label(frames[frame].draw_command_buffer, p_label_name, p_color); + if (!context->is_debug_utils_enabled()) { + return; + } + + draw_graph.begin_label(p_label_name, p_color); } +#ifndef DISABLE_DEPRECATED void RenderingDevice::draw_command_insert_label(String p_label_name, const Color &p_color) { - _THREAD_SAFE_METHOD_ - context->command_insert_label(frames[frame].draw_command_buffer, p_label_name, p_color); + WARN_PRINT("Deprecated. Inserting labels no longer applies due to command reordering."); } +#endif void RenderingDevice::draw_command_end_label() { - _THREAD_SAFE_METHOD_ - context->command_end_label(frames[frame].draw_command_buffer); + draw_graph.end_label(); } String RenderingDevice::get_device_vendor_name() const { @@ -5404,7 +4552,7 @@ String RenderingDevice::get_device_pipeline_cache_uuid() const { return context->get_device_pipeline_cache_uuid(); } -void RenderingDevice::_finalize_command_bufers() { +void RenderingDevice::_finalize_command_buffers(bool p_postpare) { if (draw_list) { ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work)."); } @@ -5413,7 +4561,13 @@ void RenderingDevice::_finalize_command_bufers() { ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work)."); } - { + { // Complete the setup buffer (that needs to be processed before anything else). + draw_graph.end(frames[frame].draw_command_buffer, RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS); + + if (p_postpare) { + context->postpare_buffers(frames[frame].draw_command_buffer); + } + driver->end_segment(); driver->command_buffer_end(frames[frame].setup_command_buffer); driver->command_buffer_end(frames[frame].draw_command_buffer); @@ -5421,6 +4575,8 @@ void RenderingDevice::_finalize_command_bufers() { } void RenderingDevice::_begin_frame() { + draw_graph.begin(); + // Erase pending resources. _free_pending_resources(frame); @@ -5464,12 +4620,15 @@ void RenderingDevice::swap_buffers() { ERR_FAIL_COND_MSG(local_device.is_valid(), "Local devices can't swap buffers."); _THREAD_SAFE_METHOD_ - context->postpare_buffers(frames[frame].draw_command_buffer); - _finalize_command_bufers(); + _finalize_command_buffers(true); - screen_prepared = false; // Swap buffers. - context->swap_buffers(); + if (!screen_prepared) { + context->flush(true, true, false); + } else { + screen_prepared = false; + context->swap_buffers(); + } frame = (frame + 1) % frame_count; @@ -5482,7 +4641,7 @@ void RenderingDevice::submit() { ERR_FAIL_COND_MSG(local_device.is_null(), "Only local devices can submit and sync."); ERR_FAIL_COND_MSG(local_device_processing, "device already submitted, call sync to wait until done."); - _finalize_command_bufers(); + _finalize_command_buffers(false); RDD::CommandBufferID command_buffers[2] = { frames[frame].setup_command_buffer, frames[frame].draw_command_buffer }; context->local_device_push_command_buffers(local_device, command_buffers, 2); @@ -5614,11 +4773,14 @@ void RenderingDevice::_flush(bool p_current_frame) { if (local_device.is_valid() && !p_current_frame) { return; // Flushing previous frames has no effect with local device. } + // Not doing this crashes RADV (undefined behavior). if (p_current_frame) { + draw_graph.end(frames[frame].draw_command_buffer, RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS); driver->end_segment(); driver->command_buffer_end(frames[frame].setup_command_buffer); driver->command_buffer_end(frames[frame].draw_command_buffer); + draw_graph.begin(); } if (local_device.is_valid()) { @@ -5739,7 +4901,6 @@ void RenderingDevice::initialize(ApiContextRD *p_context, bool p_local_device) { draw_list = nullptr; draw_list_count = 0; - draw_list_split = false; compute_list = nullptr; @@ -5756,6 +4917,8 @@ void RenderingDevice::initialize(ApiContextRD *p_context, bool p_local_device) { pipelines_cache_size = driver->pipeline_cache_query_size(); print_verbose(vformat("Startup PSO cache (%.1f MiB)", pipelines_cache_size / (1024.0f * 1024.0f))); } + + draw_graph.initialize(driver, frame_count, SECONDARY_COMMAND_BUFFERS_PER_FRAME); } Vector<uint8_t> RenderingDevice::_load_pipeline_cache() { @@ -5853,46 +5016,11 @@ void RenderingDevice::_free_rids(T &p_owner, const char *p_type) { void RenderingDevice::capture_timestamp(const String &p_name) { ERR_FAIL_COND_MSG(draw_list != nullptr, "Capturing timestamps during draw list creation is not allowed. Offending timestamp was: " + p_name); + ERR_FAIL_COND_MSG(compute_list != nullptr, "Capturing timestamps during compute list creation is not allowed. Offending timestamp was: " + p_name); ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements); - // This should be optional for profiling, else it will slow things down. - if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { - RDD::MemoryBarrier mb; - mb.src_access = (RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT | - RDD::BARRIER_ACCESS_INDEX_READ_BIT | - RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | - RDD::BARRIER_ACCESS_UNIFORM_READ_BIT | - RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT | - RDD::BARRIER_ACCESS_SHADER_READ_BIT | - RDD::BARRIER_ACCESS_SHADER_WRITE_BIT | - RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT | - RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - RDD::BARRIER_ACCESS_TRANSFER_READ_BIT | - RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT | - RDD::BARRIER_ACCESS_HOST_READ_BIT | - RDD::BARRIER_ACCESS_HOST_WRITE_BIT); - mb.dst_access = (RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT | - RDD::BARRIER_ACCESS_INDEX_READ_BIT | - RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | - RDD::BARRIER_ACCESS_UNIFORM_READ_BIT | - RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT | - RDD::BARRIER_ACCESS_SHADER_READ_BIT | - RDD::BARRIER_ACCESS_SHADER_WRITE_BIT | - RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT | - RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - RDD::BARRIER_ACCESS_TRANSFER_READ_BIT | - RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT | - RDD::BARRIER_ACCESS_HOST_READ_BIT | - RDD::BARRIER_ACCESS_HOST_WRITE_BIT); - - driver->command_pipeline_barrier(frames[frame].draw_command_buffer, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, mb, {}, {}); - } - - driver->command_timestamp_write(frames[frame].draw_command_buffer, frames[frame].timestamp_pool, frames[frame].timestamp_count); + draw_graph.add_capture_timestamp(frames[frame].timestamp_pool, frames[frame].timestamp_count); + frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name; frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec(); frames[frame].timestamp_count++; @@ -6060,10 +5188,6 @@ void RenderingDevice::finalize() { driver->pipeline_cache_free(); } - for (int i = 0; i < split_draw_list_allocators.size(); i++) { - driver->command_pool_free(split_draw_list_allocators[i].command_pool); - } - frames.clear(); for (int i = 0; i < staging_buffer_blocks.size(); i++) { @@ -6102,7 +5226,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_create_shared_from_slice", "view", "with_texture", "layer", "mipmap", "mipmaps", "slice_type"), &RenderingDevice::_texture_create_shared_from_slice, DEFVAL(1), DEFVAL(TEXTURE_SLICE_2D)); ClassDB::bind_method(D_METHOD("texture_create_from_extension", "type", "format", "samples", "usage_flags", "image", "width", "height", "depth", "layers"), &RenderingDevice::texture_create_from_extension); - ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data", "post_barrier"), &RenderingDevice::texture_update, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); + ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data"), &RenderingDevice::texture_update); ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "layer"), &RenderingDevice::texture_get_data); ClassDB::bind_method(D_METHOD("texture_is_format_supported_for_usage", "format", "usage_flags"), &RenderingDevice::texture_is_format_supported_for_usage); @@ -6110,9 +5234,9 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_is_shared", "texture"), &RenderingDevice::texture_is_shared); ClassDB::bind_method(D_METHOD("texture_is_valid", "texture"), &RenderingDevice::texture_is_valid); - ClassDB::bind_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "post_barrier"), &RenderingDevice::texture_copy, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); - ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::texture_clear, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); - ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::texture_resolve_multisample, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); + ClassDB::bind_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer"), &RenderingDevice::texture_copy); + ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count"), &RenderingDevice::texture_clear); + ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture"), &RenderingDevice::texture_resolve_multisample); ClassDB::bind_method(D_METHOD("texture_get_format", "texture"), &RenderingDevice::_texture_get_format); #ifndef DISABLE_DEPRECATED @@ -6154,8 +5278,9 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("uniform_set_create", "uniforms", "shader", "shader_set"), &RenderingDevice::_uniform_set_create); ClassDB::bind_method(D_METHOD("uniform_set_is_valid", "uniform_set"), &RenderingDevice::uniform_set_is_valid); - ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "post_barrier"), &RenderingDevice::_buffer_update_bind, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); - ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); + ClassDB::bind_method(D_METHOD("buffer_copy", "src_buffer", "dst_buffer", "src_offset", "dst_offset", "size"), &RenderingDevice::buffer_copy); + ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data"), &RenderingDevice::_buffer_update_bind); + ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes"), &RenderingDevice::buffer_clear); ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer", "offset_bytes", "size_bytes"), &RenderingDevice::buffer_get_data, DEFVAL(0), DEFVAL(0)); ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass", "specialization_constants"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0), DEFVAL(TypedArray<RDPipelineSpecializationConstant>())); @@ -6170,8 +5295,10 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_list_begin_for_screen", "screen", "clear_color"), &RenderingDevice::draw_list_begin_for_screen, DEFVAL(DisplayServer::MAIN_WINDOW_ID), DEFVAL(Color())); - ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>())); + ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region"), &RenderingDevice::draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2())); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("draw_list_begin_split", "framebuffer", "splits", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_split, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>())); +#endif ClassDB::bind_method(D_METHOD("draw_list_set_blend_constants", "draw_list", "color"), &RenderingDevice::draw_list_set_blend_constants); ClassDB::bind_method(D_METHOD("draw_list_bind_render_pipeline", "draw_list", "render_pipeline"), &RenderingDevice::draw_list_bind_render_pipeline); @@ -6186,17 +5313,19 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor); ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass"), &RenderingDevice::draw_list_switch_to_next_pass); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass_split", "splits"), &RenderingDevice::_draw_list_switch_to_next_pass_split); +#endif - ClassDB::bind_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::draw_list_end, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); + ClassDB::bind_method(D_METHOD("draw_list_end"), &RenderingDevice::draw_list_end); - ClassDB::bind_method(D_METHOD("compute_list_begin", "allow_draw_overlap"), &RenderingDevice::compute_list_begin, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("compute_list_begin"), &RenderingDevice::compute_list_begin); ClassDB::bind_method(D_METHOD("compute_list_bind_compute_pipeline", "compute_list", "compute_pipeline"), &RenderingDevice::compute_list_bind_compute_pipeline); ClassDB::bind_method(D_METHOD("compute_list_set_push_constant", "compute_list", "buffer", "size_bytes"), &RenderingDevice::_compute_list_set_push_constant); ClassDB::bind_method(D_METHOD("compute_list_bind_uniform_set", "compute_list", "uniform_set", "set_index"), &RenderingDevice::compute_list_bind_uniform_set); ClassDB::bind_method(D_METHOD("compute_list_dispatch", "compute_list", "x_groups", "y_groups", "z_groups"), &RenderingDevice::compute_list_dispatch); ClassDB::bind_method(D_METHOD("compute_list_add_barrier", "compute_list"), &RenderingDevice::compute_list_add_barrier); - ClassDB::bind_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::compute_list_end, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); + ClassDB::bind_method(D_METHOD("compute_list_end"), &RenderingDevice::compute_list_end); ClassDB::bind_method(D_METHOD("free_rid", "rid"), &RenderingDevice::free); @@ -6212,15 +5341,19 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("submit"), &RenderingDevice::submit); ClassDB::bind_method(D_METHOD("sync"), &RenderingDevice::sync); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::barrier, DEFVAL(BARRIER_MASK_ALL_BARRIERS), DEFVAL(BARRIER_MASK_ALL_BARRIERS)); ClassDB::bind_method(D_METHOD("full_barrier"), &RenderingDevice::full_barrier); +#endif ClassDB::bind_method(D_METHOD("create_local_device"), &RenderingDevice::create_local_device); ClassDB::bind_method(D_METHOD("set_resource_name", "id", "name"), &RenderingDevice::set_resource_name); ClassDB::bind_method(D_METHOD("draw_command_begin_label", "name", "color"), &RenderingDevice::draw_command_begin_label); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("draw_command_insert_label", "name", "color"), &RenderingDevice::draw_command_insert_label); +#endif ClassDB::bind_method(D_METHOD("draw_command_end_label"), &RenderingDevice::draw_command_end_label); ClassDB::bind_method(D_METHOD("get_device_vendor_name"), &RenderingDevice::get_device_vendor_name); @@ -6487,6 +5620,7 @@ void RenderingDevice::_bind_methods() { BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM); BIND_ENUM_CONSTANT(DATA_FORMAT_MAX); +#ifndef DISABLE_DEPRECATED BIND_BITFIELD_FLAG(BARRIER_MASK_VERTEX); BIND_BITFIELD_FLAG(BARRIER_MASK_FRAGMENT); BIND_BITFIELD_FLAG(BARRIER_MASK_COMPUTE); @@ -6494,6 +5628,7 @@ void RenderingDevice::_bind_methods() { BIND_BITFIELD_FLAG(BARRIER_MASK_RASTER); BIND_BITFIELD_FLAG(BARRIER_MASK_ALL_BARRIERS); BIND_BITFIELD_FLAG(BARRIER_MASK_NO_BARRIER); +#endif BIND_ENUM_CONSTANT(TEXTURE_TYPE_1D); BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D); @@ -6668,18 +5803,25 @@ void RenderingDevice::_bind_methods() { BIND_BITFIELD_FLAG(DYNAMIC_STATE_STENCIL_WRITE_MASK); BIND_BITFIELD_FLAG(DYNAMIC_STATE_STENCIL_REFERENCE); - BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR); //start rendering and clear the framebuffer (supply params) - BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION); //start rendering and clear the framebuffer (supply params) - BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION_CONTINUE); //continue rendering and clear the framebuffer (supply params) - BIND_ENUM_CONSTANT(INITIAL_ACTION_KEEP); //start rendering); but keep attached color texture contents (depth will be cleared) - BIND_ENUM_CONSTANT(INITIAL_ACTION_DROP); //start rendering); ignore what is there); just write above it - BIND_ENUM_CONSTANT(INITIAL_ACTION_CONTINUE); //continue rendering (framebuffer must have been left in "continue" state as final action previously) + BIND_ENUM_CONSTANT(INITIAL_ACTION_LOAD); + BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR); + BIND_ENUM_CONSTANT(INITIAL_ACTION_DISCARD); BIND_ENUM_CONSTANT(INITIAL_ACTION_MAX); +#ifndef DISABLE_DEPRECATED + BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION); + BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION_CONTINUE); + BIND_ENUM_CONSTANT(INITIAL_ACTION_KEEP); + BIND_ENUM_CONSTANT(INITIAL_ACTION_DROP); + BIND_ENUM_CONSTANT(INITIAL_ACTION_CONTINUE); +#endif - BIND_ENUM_CONSTANT(FINAL_ACTION_READ); //will no longer render to it); allows attached textures to be read again); but depth buffer contents will be dropped (Can't be read from) - BIND_ENUM_CONSTANT(FINAL_ACTION_DISCARD); // discard contents after rendering - BIND_ENUM_CONSTANT(FINAL_ACTION_CONTINUE); //will continue rendering later); attached textures can't be read until re-bound with "finish" + BIND_ENUM_CONSTANT(FINAL_ACTION_STORE); + BIND_ENUM_CONSTANT(FINAL_ACTION_DISCARD); BIND_ENUM_CONSTANT(FINAL_ACTION_MAX); +#ifndef DISABLE_DEPRECATED + BIND_ENUM_CONSTANT(FINAL_ACTION_READ); + BIND_ENUM_CONSTANT(FINAL_ACTION_CONTINUE); +#endif BIND_ENUM_CONSTANT(SHADER_STAGE_VERTEX); BIND_ENUM_CONSTANT(SHADER_STAGE_FRAGMENT); @@ -6946,8 +6088,8 @@ RID RenderingDevice::_uniform_set_create(const TypedArray<RDUniform> &p_uniforms return uniform_set_create(uniforms, p_shader, p_shader_set); } -Error RenderingDevice::_buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) { - return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier); +Error RenderingDevice::_buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data) { + return buffer_update(p_buffer, p_offset, p_size, p_data.ptr()); } static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constants(const TypedArray<RDPipelineSpecializationConstant> &p_constants) { @@ -7018,47 +6160,15 @@ RID RenderingDevice::_compute_pipeline_create(RID p_shader, const TypedArray<RDP return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants)); } -RenderingDevice::DrawListID RenderingDevice::_draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) { - Vector<RID> stextures; - for (int i = 0; i < p_storage_textures.size(); i++) { - stextures.push_back(p_storage_textures[i]); - } - return draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, stextures); -} - +#ifndef DISABLE_DEPRECATED Vector<int64_t> RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) { - Vector<DrawListID> splits; - splits.resize(p_splits); - Vector<RID> stextures; - for (int i = 0; i < p_storage_textures.size(); i++) { - stextures.push_back(p_storage_textures[i]); - } - draw_list_begin_split(p_framebuffer, p_splits, splits.ptrw(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, stextures); - - Vector<int64_t> split_ids; - split_ids.resize(splits.size()); - for (int i = 0; i < splits.size(); i++) { - split_ids.write[i] = splits[i]; - } - - return split_ids; + ERR_FAIL_V_MSG(Vector<int64_t>(), "Deprecated. Split draw lists are used automatically by RenderingDevice."); } Vector<int64_t> RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p_splits) { - Vector<DrawListID> splits; - splits.resize(p_splits); - - Error err = draw_list_switch_to_next_pass_split(p_splits, splits.ptrw()); - ERR_FAIL_COND_V(err != OK, Vector<int64_t>()); - - Vector<int64_t> split_ids; - split_ids.resize(splits.size()); - for (int i = 0; i < splits.size(); i++) { - split_ids.write[i] = splits[i]; - } - - return split_ids; + ERR_FAIL_V_MSG(Vector<int64_t>(), "Deprecated. Split draw lists are used automatically by RenderingDevice."); } +#endif void RenderingDevice::_draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) { ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 90ed2828c0..2ccef66308 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -42,6 +42,7 @@ #include "servers/rendering/rendering_device.h" #include "servers/rendering/rendering_device_commons.h" #include "servers/rendering/rendering_device_driver.h" +#include "servers/rendering/rendering_device_graph.h" class RDTextureFormat; class RDTextureView; @@ -93,6 +94,9 @@ public: uint32_t version_minor = 0; }; + typedef int64_t DrawListID; + typedef int64_t ComputeListID; + typedef String (*ShaderSPIRVGetCacheKeyFunction)(const RenderingDevice *p_render_device); typedef Vector<uint8_t> (*ShaderCompileToSPIRVFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const RenderingDevice *p_render_device); typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language); @@ -131,8 +135,7 @@ public: ID_TYPE_FRAMEBUFFER_FORMAT, ID_TYPE_VERTEX_FORMAT, ID_TYPE_DRAW_LIST, - ID_TYPE_SPLIT_DRAW_LIST, - ID_TYPE_COMPUTE_LIST, + ID_TYPE_COMPUTE_LIST = 4, ID_TYPE_MAX, ID_BASE_SHIFT = 58, // 5 bits for ID types. ID_MASK = (ID_BASE_SHIFT - 1), @@ -145,25 +148,7 @@ private: void _add_dependency(RID p_id, RID p_depends_on); void _free_dependencies(RID p_id); - /*****************/ - /**** BARRIER ****/ - /*****************/ - -public: - enum BarrierMask { - BARRIER_MASK_VERTEX = 1, - BARRIER_MASK_FRAGMENT = 8, - BARRIER_MASK_COMPUTE = 2, - BARRIER_MASK_TRANSFER = 4, - - BARRIER_MASK_RASTER = BARRIER_MASK_VERTEX | BARRIER_MASK_FRAGMENT, // 9, - BARRIER_MASK_ALL_BARRIERS = 0x7FFF, // all flags set - BARRIER_MASK_NO_BARRIER = 0x8000, - }; - private: - void _full_barrier(bool p_sync_with_draw); - /***************************/ /**** BUFFER MANAGEMENT ****/ /***************************/ @@ -201,26 +186,34 @@ private: uint64_t staging_buffer_max_size = 0; bool staging_buffer_used = false; - Error _staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment = true); + enum StagingRequiredAction { + STAGING_REQUIRED_ACTION_NONE, + STAGING_REQUIRED_ACTION_FLUSH_CURRENT, + STAGING_REQUIRED_ACTION_FLUSH_OLDER + }; + + Error _staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, StagingRequiredAction &r_required_action, bool p_can_segment = true); + void _staging_buffer_execute_required_action(StagingRequiredAction p_required_action); Error _insert_staging_block(); struct Buffer { RDD::BufferID driver_id; uint32_t size = 0; BitField<RDD::BufferUsageBits> usage; + RDG::ResourceTracker *draw_tracker = nullptr; }; - Buffer *_get_buffer_from_owner(RID p_buffer, BitField<RDD::PipelineStageBits> &r_stages, BitField<RDD::BarrierAccessBits> &r_access, BitField<BarrierMask> p_post_barrier); - Error _buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer = false, uint32_t p_required_align = 32); + Buffer *_get_buffer_from_owner(RID p_buffer); + Error _buffer_update(Buffer *p_buffer, RID p_buffer_id, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_queue = false, uint32_t p_required_align = 32); RID_Owner<Buffer> uniform_buffer_owner; RID_Owner<Buffer> storage_buffer_owner; RID_Owner<Buffer> texture_buffer_owner; public: - Error buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + Error buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size); + Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data); + Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size); Vector<uint8_t> buffer_get_data(RID p_buffer, uint32_t p_offset = 0, uint32_t p_size = 0); // This causes stall, only use to retrieve large buffers for saving. /*****************/ @@ -245,6 +238,8 @@ public: TextureType type = TEXTURE_TYPE_MAX; DataFormat format = DATA_FORMAT_MAX; TextureSamples samples = TEXTURE_SAMPLES_MAX; + TextureSliceType slice_type = TEXTURE_SLICE_MAX; + Rect2i slice_rect; uint32_t width = 0; uint32_t height = 0; uint32_t depth = 0; @@ -256,26 +251,33 @@ public: Vector<DataFormat> allowed_shared_formats; - RDD::TextureLayout layout = RDD::TEXTURE_LAYOUT_UNDEFINED; - - uint64_t used_in_frame = 0; - bool used_in_transfer = false; - bool used_in_raster = false; - bool used_in_compute = false; - bool is_resolve_buffer = false; + bool has_initial_data = false; BitField<RDD::TextureAspectBits> read_aspect_flags; BitField<RDD::TextureAspectBits> barrier_aspect_flags; - bool bound = false; // Bound to framebffer. + bool bound = false; // Bound to framebuffer. RID owner; + + RDG::ResourceTracker *draw_tracker = nullptr; + HashMap<Rect2i, RDG::ResourceTracker *> slice_trackers; + + RDD::TextureSubresourceRange barrier_range() const { + RDD::TextureSubresourceRange r; + r.aspect = barrier_aspect_flags; + r.base_mipmap = base_mipmap; + r.mipmap_count = mipmaps; + r.base_layer = base_layer; + r.layer_count = layers; + return r; + } }; RID_Owner<Texture> texture_owner; uint32_t texture_upload_region_size_px = 0; Vector<uint8_t> _texture_get_data(Texture *tex, uint32_t p_layer, bool p_2d = false); - Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, bool p_use_setup_queue); + Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, bool p_use_setup_queue, bool p_validate_can_update); public: struct TextureView { @@ -306,7 +308,7 @@ public: RID texture_create_shared(const TextureView &p_view, RID p_with_texture); RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, BitField<RenderingDevice::TextureUsageBits> p_usage, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers); RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D, uint32_t p_layers = 0); - Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data); Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer); // CPU textures will return immediately, while GPU textures will most likely force a flush bool texture_is_format_supported_for_usage(DataFormat p_format, BitField<TextureUsageBits> p_usage) const; @@ -318,29 +320,36 @@ public: uint64_t texture_get_native_handle(RID p_texture); #endif - Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer); + Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers); + Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture); /************************/ /**** DRAW LISTS (I) ****/ /************************/ enum InitialAction { - INITIAL_ACTION_CLEAR, // Start rendering and clear the whole framebuffer. - INITIAL_ACTION_CLEAR_REGION, // Start rendering and clear the framebuffer in the specified region. - INITIAL_ACTION_CLEAR_REGION_CONTINUE, // Continue rendering and clear the framebuffer in the specified region. Framebuffer must have been left in `FINAL_ACTION_CONTINUE` state as the final action previously. - INITIAL_ACTION_KEEP, // Start rendering, but keep attached color texture contents. If the framebuffer was previously used to read in a shader, this will automatically insert a layout transition. - INITIAL_ACTION_DROP, // Start rendering, ignore what is there; write above it. In general, this is the fastest option when you will be writing every single pixel and you don't need a clear color. - INITIAL_ACTION_CONTINUE, // Continue rendering. Framebuffer must have been left in `FINAL_ACTION_CONTINUE` state as the final action previously. - INITIAL_ACTION_MAX + INITIAL_ACTION_LOAD, + INITIAL_ACTION_CLEAR, + INITIAL_ACTION_DISCARD, + INITIAL_ACTION_MAX, +#ifndef DISABLE_DEPRECATED + INITIAL_ACTION_CLEAR_REGION = INITIAL_ACTION_CLEAR, + INITIAL_ACTION_CLEAR_REGION_CONTINUE = INITIAL_ACTION_CLEAR, + INITIAL_ACTION_KEEP = INITIAL_ACTION_LOAD, + INITIAL_ACTION_DROP = INITIAL_ACTION_DISCARD, + INITIAL_ACTION_CONTINUE = INITIAL_ACTION_LOAD, +#endif }; enum FinalAction { - FINAL_ACTION_READ, // Store the texture for reading and make it read-only if it has the `TEXTURE_USAGE_SAMPLING_BIT` bit (only applies to color, depth and stencil attachments). - FINAL_ACTION_DISCARD, // Discard the texture data and make it read-only if it has the `TEXTURE_USAGE_SAMPLING_BIT` bit (only applies to color, depth and stencil attachments). - FINAL_ACTION_CONTINUE, // Store the texture and continue for further processing. Similar to `FINAL_ACTION_READ`, but does not make the texture read-only if it has the `TEXTURE_USAGE_SAMPLING_BIT` bit. - FINAL_ACTION_MAX + FINAL_ACTION_STORE, + FINAL_ACTION_DISCARD, + FINAL_ACTION_MAX, +#ifndef DISABLE_DEPRECATED + FINAL_ACTION_READ = FINAL_ACTION_STORE, + FINAL_ACTION_CONTINUE = FINAL_ACTION_STORE, +#endif }; /*********************/ @@ -668,7 +677,9 @@ private: uint32_t max_instances_allowed = 0; Vector<RDD::BufferID> buffers; // Not owned, just referenced. + Vector<RDG::ResourceTracker *> draw_trackers; // Not owned, just referenced. Vector<uint64_t> offsets; + HashSet<RID> untracked_buffers; }; RID_Owner<VertexArray> vertex_array_owner; @@ -685,6 +696,7 @@ private: struct IndexArray { uint32_t max_index = 0; // Remember the maximum index here too, for validation. RDD::BufferID driver_id; // Not owned, inherited from index buffer. + RDG::ResourceTracker *draw_tracker = nullptr; // Not owned, inherited from index buffer. uint32_t offset = 0; uint32_t indices = 0; IndexBufferFormat format = INDEX_BUFFER_FORMAT_UINT16; @@ -762,6 +774,7 @@ private: String name; // Used for debug. RDD::ShaderID driver_id; uint32_t layout_hash = 0; + BitField<RDD::PipelineStageBits> stage_bits; Vector<uint32_t> set_formats; }; @@ -770,10 +783,42 @@ private: RID_Owner<Shader> shader_owner; #ifndef DISABLE_DEPRECATED - BitField<BarrierMask> _convert_barrier_mask_81356(BitField<BarrierMask> p_old_barrier); +public: + enum BarrierMask{ + BARRIER_MASK_VERTEX = 1, + BARRIER_MASK_FRAGMENT = 8, + BARRIER_MASK_COMPUTE = 2, + BARRIER_MASK_TRANSFER = 4, + + BARRIER_MASK_RASTER = BARRIER_MASK_VERTEX | BARRIER_MASK_FRAGMENT, // 9, + BARRIER_MASK_ALL_BARRIERS = 0x7FFF, // all flags set + BARRIER_MASK_NO_BARRIER = 0x8000, + }; + + void barrier(BitField<BarrierMask> p_from = BARRIER_MASK_ALL_BARRIERS, BitField<BarrierMask> p_to = BARRIER_MASK_ALL_BARRIERS); + void full_barrier(); + void draw_command_insert_label(String p_label_name, const Color &p_color = Color(1, 1, 1, 1)); + Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>()); + Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids); + Vector<int64_t> _draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray<RID> &p_storage_textures = TypedArray<RID>()); + Vector<int64_t> _draw_list_switch_to_next_pass_split(uint32_t p_splits); + +private: void _draw_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier); void _compute_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier); void _barrier_bind_compat_81356(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to); + void _draw_list_end_bind_compat_84976(BitField<BarrierMask> p_post_barrier); + void _compute_list_end_bind_compat_84976(BitField<BarrierMask> p_post_barrier); + InitialAction _convert_initial_action_84976(InitialAction p_old_initial_action); + FinalAction _convert_final_action_84976(FinalAction p_old_final_action); + DrawListID _draw_list_begin_bind_compat_84976(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures); + ComputeListID _compute_list_begin_bind_compat_84976(bool p_allow_draw_overlap); + Error _buffer_update_bind_compat_84976(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier); + Error _buffer_clear_bind_compat_84976(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier); + Error _texture_update_bind_compat_84976(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier); + Error _texture_copy_bind_compat_84976(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier); + Error _texture_clear_bind_compat_84976(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier); + Error _texture_resolve_multisample_bind_compat_84976(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier); #endif public: @@ -875,6 +920,9 @@ public: }; private: + static const uint32_t MAX_UNIFORM_SETS = 16; + static const uint32_t MAX_PUSH_CONSTANT_SIZE = 128; + // This structure contains the descriptor set. They _need_ to be allocated // for a shader (and will be erased when this shader is erased), but should // work for other shaders as long as the hash matches. This covers using @@ -894,8 +942,9 @@ private: }; LocalVector<AttachableTexture> attachable_textures; // Used for validation. - Vector<Texture *> mutable_sampled_textures; // Used for layout change. - Vector<Texture *> mutable_storage_textures; // Used for layout change. + Vector<RDG::ResourceTracker *> draw_trackers; + Vector<RDG::ResourceUsage> draw_trackers_usage; + HashMap<RID, RDG::ResourceUsage> untracked_usage; InvalidationCallback invalidated_callback = nullptr; void *invalidated_callback_userdata = nullptr; }; @@ -941,6 +990,7 @@ private: uint32_t shader_layout_hash = 0; Vector<uint32_t> set_formats; RDD::PipelineID driver_id; + BitField<RDD::PipelineStageBits> stage_bits; uint32_t push_constant_size = 0; }; @@ -986,8 +1036,6 @@ public: /**** DRAW LISTS (II) ****/ /*************************/ - typedef int64_t DrawListID; - private: // Draw list contains both the command buffer // used for drawing as well as a LOT of @@ -995,20 +1043,7 @@ private: // validation is cheap so most of it can // also run in release builds. - // When using split command lists, this is - // implemented internally using secondary command - // buffers. As they can be created in threads, - // each needs its own command pool. - - struct SplitDrawListAllocator { - RDD::CommandPoolID command_pool; - Vector<RDD::CommandBufferID> command_buffers; // One for each frame. - }; - - Vector<SplitDrawListAllocator> split_draw_list_allocators; - struct DrawList { - RDD::CommandBufferID command_buffer; // If persistent, this is owned, otherwise it's shared with the ringbuffer. Rect2i viewport; bool viewport_set = false; @@ -1040,9 +1075,8 @@ private: uint32_t vertex_array_size = 0; uint32_t vertex_max_instances_allowed = 0xFFFFFFFF; bool index_buffer_uses_restart_indices = false; - uint32_t index_array_size = 0; + uint32_t index_array_count = 0; uint32_t index_array_max_index = 0; - uint32_t index_array_offset = 0; Vector<uint32_t> set_formats; Vector<bool> set_bound; Vector<RID> set_rids; @@ -1060,13 +1094,12 @@ private: #else struct Validation { uint32_t vertex_array_size = 0; - uint32_t index_array_size = 0; - uint32_t index_array_offset; + uint32_t index_array_count = 0; } validation; #endif }; - DrawList *draw_list = nullptr; // One for regular draw lists, multiple for split. + DrawList *draw_list = nullptr; uint32_t draw_list_subpass_count = 0; uint32_t draw_list_count = 0; RDD::RenderPassID draw_list_render_pass; @@ -1076,23 +1109,20 @@ private: #endif uint32_t draw_list_current_subpass = 0; - bool draw_list_split = false; Vector<RID> draw_list_bound_textures; - Vector<RID> draw_list_storage_textures; - bool draw_list_unbind_color_textures = false; - bool draw_list_unbind_depth_textures = false; void _draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil); Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, RDD::FramebufferID *r_framebuffer, RDD::RenderPassID *r_render_pass, uint32_t *r_subpass_count); - Error _draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass, RDD::CommandBufferID p_command_buffer, RDD::CommandBufferType p_cmd_buffer_mode, const Vector<RID> &p_storage_textures, bool p_constrained_to_region); + Error _draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass); + void _draw_list_set_viewport(Rect2i p_rect); + void _draw_list_set_scissor(Rect2i p_rect); _FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id); - Error _draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass); + Error _draw_list_allocate(const Rect2i &p_viewport, uint32_t p_subpass); void _draw_list_free(Rect2i *r_last_viewport = nullptr); public: DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color()); - DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>()); - Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>()); + DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color); void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline); @@ -1109,20 +1139,15 @@ public: uint32_t draw_list_get_current_pass(); DrawListID draw_list_switch_to_next_pass(); - Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids); - void draw_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + void draw_list_end(); +private: /***********************/ /**** COMPUTE LISTS ****/ /***********************/ - typedef int64_t ComputeListID; - -private: struct ComputeList { - RDD::CommandBufferID command_buffer; // If persistent, this is owned, otherwise it's shared with the ringbuffer. - struct SetState { uint32_t pipeline_expected_format = 0; uint32_t uniform_set_format = 0; @@ -1132,7 +1157,6 @@ private: }; struct State { - HashSet<Texture *> textures_to_sampled_layout; SetState sets[MAX_UNIFORM_SETS]; uint32_t set_count = 0; RID pipeline; @@ -1140,7 +1164,8 @@ private: RDD::ShaderID pipeline_shader_driver_id; uint32_t pipeline_shader_layout_hash = 0; uint32_t local_group_size[3] = { 0, 0, 0 }; - bool allow_draw_overlap; + uint8_t push_constant_data[MAX_PUSH_CONSTANT_SIZE] = {}; + uint32_t push_constant_size = 0; } state; #ifdef DEBUG_ENABLED @@ -1160,11 +1185,10 @@ private: }; ComputeList *compute_list = nullptr; - - void _compute_list_add_barrier(BitField<BarrierMask> p_post_barrier, BitField<RDD::PipelineStageBits> p_stages, BitField<RDD::BarrierAccessBits> p_access); + ComputeList::State compute_list_barrier_state; public: - ComputeListID compute_list_begin(bool p_allow_draw_overlap = false); + ComputeListID compute_list_begin(); void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline); void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index); void compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size); @@ -1173,10 +1197,22 @@ public: void compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset); void compute_list_add_barrier(ComputeListID p_list); - void compute_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + void compute_list_end(); - void barrier(BitField<BarrierMask> p_from = BARRIER_MASK_ALL_BARRIERS, BitField<BarrierMask> p_to = BARRIER_MASK_ALL_BARRIERS); - void full_barrier(); +private: + /***********************/ + /**** COMMAND GRAPH ****/ + /***********************/ + + bool _texture_make_mutable(Texture *p_texture, RID p_texture_id); + bool _buffer_make_mutable(Buffer *p_buffer, RID p_buffer_id); + bool _vertex_array_make_mutable(VertexArray *p_vertex_array, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker); + bool _index_array_make_mutable(IndexArray *p_index_array, RDG::ResourceTracker *p_resource_tracker); + bool _uniform_set_make_mutable(UniformSet *p_uniform_set, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker); + bool _dependency_make_mutable(RID p_id, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker); + bool _dependencies_make_mutable(RID p_id, RDG::ResourceTracker *p_resource_tracker); + + RenderingDeviceGraph draw_graph; /**************************/ /**** FRAME MANAGEMENT ****/ @@ -1258,7 +1294,7 @@ private: template <class T> void _free_rids(T &p_owner, const char *p_type); - void _finalize_command_bufers(); + void _finalize_command_buffers(bool p_postpare); void _begin_frame(); #ifdef DEV_ENABLED @@ -1311,7 +1347,6 @@ public: void set_resource_name(RID p_id, const String &p_name); void draw_command_begin_label(String p_label_name, const Color &p_color = Color(1, 1, 1, 1)); - void draw_command_insert_label(String p_label_name, const Color &p_color = Color(1, 1, 1, 1)); void draw_command_end_label(); String get_device_vendor_name() const; @@ -1353,16 +1388,13 @@ private: RID _uniform_set_create(const TypedArray<RDUniform> &p_uniforms, RID p_shader, uint32_t p_shader_set); - Error _buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + Error _buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data); RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants); RID _compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants); - DrawListID _draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray<RID> &p_storage_textures = TypedArray<RID>()); - Vector<int64_t> _draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray<RID> &p_storage_textures = TypedArray<RID>()); void _draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size); void _compute_list_set_push_constant(ComputeListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size); - Vector<int64_t> _draw_list_switch_to_next_pass_split(uint32_t p_splits); }; VARIANT_ENUM_CAST(RenderingDevice::DeviceType) @@ -1371,7 +1403,6 @@ VARIANT_ENUM_CAST(RenderingDevice::ShaderStage) VARIANT_ENUM_CAST(RenderingDevice::ShaderLanguage) VARIANT_ENUM_CAST(RenderingDevice::CompareOperator) VARIANT_ENUM_CAST(RenderingDevice::DataFormat) -VARIANT_BITFIELD_CAST(RenderingDevice::BarrierMask); VARIANT_ENUM_CAST(RenderingDevice::TextureType) VARIANT_ENUM_CAST(RenderingDevice::TextureSamples) VARIANT_BITFIELD_CAST(RenderingDevice::TextureUsageBits) @@ -1399,6 +1430,10 @@ VARIANT_ENUM_CAST(RenderingDevice::Limit) VARIANT_ENUM_CAST(RenderingDevice::MemoryType) VARIANT_ENUM_CAST(RenderingDevice::Features) +#ifndef DISABLE_DEPRECATED +VARIANT_BITFIELD_CAST(RenderingDevice::BarrierMask); +#endif + typedef RenderingDevice RD; #endif // RENDERING_DEVICE_H diff --git a/servers/rendering/rendering_device_commons.h b/servers/rendering/rendering_device_commons.h index dabd0c0867..a8936f8cca 100644 --- a/servers/rendering/rendering_device_commons.h +++ b/servers/rendering/rendering_device_commons.h @@ -379,6 +379,7 @@ public: TEXTURE_SLICE_CUBEMAP, TEXTURE_SLICE_3D, TEXTURE_SLICE_2D_ARRAY, + TEXTURE_SLICE_MAX }; /*****************/ @@ -910,6 +911,7 @@ protected: Vector<Vector<ShaderUniform>> uniform_sets; Vector<ShaderSpecializationConstant> specialization_constants; + Vector<ShaderStage> stages; }; struct ShaderReflection : public ShaderDescription { diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index bb71a29bbc..663222e69d 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -181,6 +181,10 @@ public: BUFFER_USAGE_INDIRECT_BIT = (1 << 8), }; + enum { + BUFFER_WHOLE_SIZE = ~0ULL + }; + virtual BufferID buffer_create(uint64_t p_size, BitField<BufferUsageBits> p_usage, MemoryAllocationType p_allocation_type) = 0; // Only for a buffer with BUFFER_USAGE_TEXEL_BIT. virtual bool buffer_set_texel_format(BufferID p_buffer, DataFormat p_format) = 0; @@ -535,6 +539,8 @@ public: float depth; uint32_t stencil; }; + + RenderPassClearValue() {} }; struct AttachmentClear { @@ -621,6 +627,13 @@ public: virtual void command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) = 0; /****************/ + /**** LABELS ****/ + /****************/ + + virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) = 0; + virtual void command_end_label(CommandBufferID p_cmd_buffer) = 0; + + /****************/ /**** SCREEN ****/ /****************/ diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp new file mode 100644 index 0000000000..bfacd38065 --- /dev/null +++ b/servers/rendering/rendering_device_graph.cpp @@ -0,0 +1,1930 @@ +/**************************************************************************/ +/* rendering_device_graph.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "rendering_device_graph.h" + +#define PRINT_RENDER_GRAPH 0 +#define FORCE_FULL_ACCESS_BITS 0 +#define PRINT_RESOURCE_TRACKER_TOTAL 0 + +RenderingDeviceGraph::RenderingDeviceGraph() { + // Default initialization. +} + +RenderingDeviceGraph::~RenderingDeviceGraph() { + _wait_for_secondary_command_buffer_tasks(); + + for (Frame &f : frames) { + for (SecondaryCommandBuffer &secondary : f.secondary_command_buffers) { + if (secondary.command_pool.id != 0) { + driver->command_pool_free(secondary.command_pool); + } + } + } +} + +bool RenderingDeviceGraph::_is_write_usage(ResourceUsage p_usage) { + switch (p_usage) { + case RESOURCE_USAGE_TRANSFER_FROM: + case RESOURCE_USAGE_UNIFORM_BUFFER_READ: + case RESOURCE_USAGE_INDIRECT_BUFFER_READ: + case RESOURCE_USAGE_TEXTURE_BUFFER_READ: + case RESOURCE_USAGE_STORAGE_BUFFER_READ: + case RESOURCE_USAGE_VERTEX_BUFFER_READ: + case RESOURCE_USAGE_INDEX_BUFFER_READ: + case RESOURCE_USAGE_TEXTURE_SAMPLE: + case RESOURCE_USAGE_STORAGE_IMAGE_READ: + case RESOURCE_USAGE_ATTACHMENT_COLOR_READ: + case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ: + return false; + case RESOURCE_USAGE_TRANSFER_TO: + case RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE: + case RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE: + case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE: + case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE: + case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE: + return true; + default: + DEV_ASSERT(false && "Invalid resource tracker usage."); + return false; + } +} + +RDD::TextureLayout RenderingDeviceGraph::_usage_to_image_layout(ResourceUsage p_usage) { + switch (p_usage) { + case RESOURCE_USAGE_TRANSFER_FROM: + return RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL; + case RESOURCE_USAGE_TRANSFER_TO: + return RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL; + case RESOURCE_USAGE_TEXTURE_SAMPLE: + return RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + case RESOURCE_USAGE_STORAGE_IMAGE_READ: + case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE: + return RDD::TEXTURE_LAYOUT_GENERAL; + case RESOURCE_USAGE_ATTACHMENT_COLOR_READ: + case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE: + return RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ: + return RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE: + return RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + case RESOURCE_USAGE_NONE: + return RDD::TEXTURE_LAYOUT_UNDEFINED; + default: + DEV_ASSERT(false && "Invalid resource tracker usage or not an image usage."); + return RDD::TEXTURE_LAYOUT_UNDEFINED; + } +} + +RDD::BarrierAccessBits RenderingDeviceGraph::_usage_to_access_bits(ResourceUsage p_usage) { +#if FORCE_FULL_ACCESS_BITS + return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT); +#else + switch (p_usage) { + case RESOURCE_USAGE_NONE: + return RDD::BarrierAccessBits(0); + case RESOURCE_USAGE_TRANSFER_FROM: + return RDD::BARRIER_ACCESS_TRANSFER_READ_BIT; + case RESOURCE_USAGE_TRANSFER_TO: + return RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT; + case RESOURCE_USAGE_UNIFORM_BUFFER_READ: + return RDD::BARRIER_ACCESS_UNIFORM_READ_BIT; + case RESOURCE_USAGE_INDIRECT_BUFFER_READ: + return RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT; + case RESOURCE_USAGE_STORAGE_BUFFER_READ: + case RESOURCE_USAGE_STORAGE_IMAGE_READ: + case RESOURCE_USAGE_TEXTURE_BUFFER_READ: + case RESOURCE_USAGE_TEXTURE_SAMPLE: + return RDD::BARRIER_ACCESS_SHADER_READ_BIT; + case RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE: + case RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE: + case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE: + return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); + case RESOURCE_USAGE_VERTEX_BUFFER_READ: + return RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + case RESOURCE_USAGE_INDEX_BUFFER_READ: + return RDD::BARRIER_ACCESS_INDEX_READ_BIT; + case RESOURCE_USAGE_ATTACHMENT_COLOR_READ: + return RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT; + case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE: + return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT | RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); + case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ: + return RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE: + return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT); + default: + DEV_ASSERT(false && "Invalid usage."); + return RDD::BarrierAccessBits(0); + } +#endif +} + +int32_t RenderingDeviceGraph::_add_to_command_list(int32_t p_command_index, int32_t p_list_index) { + DEV_ASSERT(p_command_index < int32_t(command_count)); + DEV_ASSERT(p_list_index < int32_t(command_list_nodes.size())); + + int32_t next_index = int32_t(command_list_nodes.size()); + command_list_nodes.resize(next_index + 1); + + RecordedCommandListNode &new_node = command_list_nodes[next_index]; + new_node.command_index = p_command_index; + new_node.next_list_index = p_list_index; + return next_index; +} + +void RenderingDeviceGraph::_add_adjacent_command(int32_t p_previous_command_index, int32_t p_command_index, RecordedCommand *r_command) { + const uint32_t previous_command_data_offset = command_data_offsets[p_previous_command_index]; + RecordedCommand &previous_command = *reinterpret_cast<RecordedCommand *>(&command_data[previous_command_data_offset]); + previous_command.adjacent_command_list_index = _add_to_command_list(p_command_index, previous_command.adjacent_command_list_index); + r_command->src_stages = r_command->src_stages | previous_command.dst_stages; +} + +int32_t RenderingDeviceGraph::_add_to_write_list(int32_t p_command_index, Rect2i suberesources, int32_t p_list_index) { + DEV_ASSERT(p_command_index < int32_t(command_count)); + DEV_ASSERT(p_list_index < int32_t(write_list_nodes.size())); + + int32_t next_index = int32_t(write_list_nodes.size()); + write_list_nodes.resize(next_index + 1); + + RecordedWriteListNode &new_node = write_list_nodes[next_index]; + new_node.command_index = p_command_index; + new_node.next_list_index = p_list_index; + new_node.subresources = suberesources; + return next_index; +} + +RenderingDeviceGraph::RecordedCommand *RenderingDeviceGraph::_allocate_command(uint32_t p_command_size, int32_t &r_command_index) { + uint32_t command_data_offset = command_data.size(); + command_data_offsets.push_back(command_data_offset); + command_data.resize(command_data_offset + p_command_size); + r_command_index = command_count++; + RecordedCommand *new_command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]); + *new_command = RecordedCommand(); + return new_command; +} + +RenderingDeviceGraph::DrawListInstruction *RenderingDeviceGraph::_allocate_draw_list_instruction(uint32_t p_instruction_size) { + uint32_t draw_list_data_offset = draw_instruction_list.data.size(); + draw_instruction_list.data.resize(draw_list_data_offset + p_instruction_size); + return reinterpret_cast<DrawListInstruction *>(&draw_instruction_list.data[draw_list_data_offset]); +} + +RenderingDeviceGraph::ComputeListInstruction *RenderingDeviceGraph::_allocate_compute_list_instruction(uint32_t p_instruction_size) { + uint32_t compute_list_data_offset = compute_instruction_list.data.size(); + compute_instruction_list.data.resize(compute_list_data_offset + p_instruction_size); + return reinterpret_cast<ComputeListInstruction *>(&compute_instruction_list.data[compute_list_data_offset]); +} + +void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_trackers, ResourceUsage *p_resource_usages, uint32_t p_resource_count, int32_t p_command_index, RecordedCommand *r_command) { + if (command_label_index >= 0) { + // If a label is active, tag the command with the label. + r_command->label_index = command_label_index; + } + + if (r_command->type == RecordedCommand::TYPE_CAPTURE_TIMESTAMP) { + // All previous commands starting from the previous timestamp should be adjacent to this command. + int32_t start_command_index = uint32_t(MAX(command_timestamp_index, 0)); + for (int32_t i = start_command_index; i < p_command_index; i++) { + _add_adjacent_command(i, p_command_index, r_command); + } + + // Make this command the new active timestamp command. + command_timestamp_index = p_command_index; + } else if (command_timestamp_index >= 0) { + // Timestamp command should be adjacent to this command. + _add_adjacent_command(command_timestamp_index, p_command_index, r_command); + } + + if (command_synchronization_pending) { + // All previous commands should be adjacent to this command. + int32_t start_command_index = uint32_t(MAX(command_synchronization_index, 0)); + for (int32_t i = start_command_index; i < p_command_index; i++) { + _add_adjacent_command(i, p_command_index, r_command); + } + + command_synchronization_index = p_command_index; + command_synchronization_pending = false; + } else if (command_synchronization_index >= 0) { + // Synchronization command should be adjacent to this command. + _add_adjacent_command(command_synchronization_index, p_command_index, r_command); + } + + for (uint32_t i = 0; i < p_resource_count; i++) { + ResourceTracker *resource_tracker = p_resource_trackers[i]; + DEV_ASSERT(resource_tracker != nullptr); + + resource_tracker->reset_if_outdated(tracking_frame); + + ResourceUsage new_resource_usage = p_resource_usages[i]; + bool write_usage = _is_write_usage(new_resource_usage); + BitField<RDD::BarrierAccessBits> new_usage_access = _usage_to_access_bits(new_resource_usage); + bool is_resource_a_slice = resource_tracker->parent != nullptr; + if (is_resource_a_slice) { + // This resource depends on a parent resource. + resource_tracker->parent->reset_if_outdated(tracking_frame); + + if (resource_tracker->texture_slice_command_index != p_command_index) { + // Indicate this slice has been used by this command. + resource_tracker->texture_slice_command_index = p_command_index; + } + + if (resource_tracker->parent->usage == RESOURCE_USAGE_NONE) { + if (resource_tracker->parent->texture_driver_id != 0) { + // If the resource is a texture, we transition it entirely to the layout determined by the first slice that uses it. + _add_texture_barrier_to_command(resource_tracker->parent->texture_driver_id, RDD::BarrierAccessBits(0), new_usage_access, RDG::RESOURCE_USAGE_NONE, new_resource_usage, resource_tracker->parent->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count); + } + + // If the parent hasn't been used yet, we assign the usage of the slice to the entire resource. + resource_tracker->parent->usage = new_resource_usage; + + // Also assign the usage to the slice and consider it a write operation. + resource_tracker->usage = new_resource_usage; + write_usage = true; + } else if (resource_tracker->in_parent_dirty_list) { + if (resource_tracker->parent->usage == new_resource_usage) { + // The slice will be transitioned to the resource of the parent and can be deleted from the dirty list. + ResourceTracker *previous_tracker = nullptr; + ResourceTracker *current_tracker = resource_tracker->parent->dirty_shared_list; + bool initialized_dirty_rect = false; + while (current_tracker != nullptr) { + if (current_tracker == resource_tracker) { + current_tracker->in_parent_dirty_list = false; + + if (previous_tracker != nullptr) { + previous_tracker->next_shared = current_tracker->next_shared; + } else { + resource_tracker->parent->dirty_shared_list = current_tracker->next_shared; + } + + current_tracker = current_tracker->next_shared; + } else { + if (initialized_dirty_rect) { + resource_tracker->parent->texture_slice_or_dirty_rect = resource_tracker->parent->texture_slice_or_dirty_rect.merge(current_tracker->texture_slice_or_dirty_rect); + } else { + resource_tracker->parent->texture_slice_or_dirty_rect = current_tracker->texture_slice_or_dirty_rect; + initialized_dirty_rect = true; + } + + previous_tracker = current_tracker; + current_tracker = current_tracker->next_shared; + } + } + } + } else { + if (resource_tracker->parent->dirty_shared_list != nullptr && resource_tracker->parent->texture_slice_or_dirty_rect.intersects(resource_tracker->texture_slice_or_dirty_rect)) { + // There's an intersection with the current dirty area of the parent and the slice. We must verify if the intersection is against a slice + // that was used in this command or not. Any slice we can find that wasn't used by this command must be reverted to the layout of the parent. + ResourceTracker *previous_tracker = nullptr; + ResourceTracker *current_tracker = resource_tracker->parent->dirty_shared_list; + bool initialized_dirty_rect = false; + while (current_tracker != nullptr) { + if (current_tracker->texture_slice_or_dirty_rect.intersects(resource_tracker->texture_slice_or_dirty_rect)) { + if (current_tracker->command_frame == tracking_frame && current_tracker->texture_slice_command_index == p_command_index) { + ERR_FAIL_MSG("Texture slices that overlap can't be used in the same command."); + } else { + // Delete the slice from the dirty list and revert it to the usage of the parent. + if (current_tracker->texture_driver_id != 0) { + _add_texture_barrier_to_command(current_tracker->texture_driver_id, current_tracker->usage_access, new_usage_access, current_tracker->usage, resource_tracker->parent->usage, current_tracker->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count); + } + + current_tracker->in_parent_dirty_list = false; + + if (previous_tracker != nullptr) { + previous_tracker->next_shared = current_tracker->next_shared; + } else { + resource_tracker->parent->dirty_shared_list = current_tracker->next_shared; + } + + current_tracker = current_tracker->next_shared; + } + } else { + // Recalculate the dirty rect of the parent so the deleted slices are excluded. + if (initialized_dirty_rect) { + resource_tracker->parent->texture_slice_or_dirty_rect = resource_tracker->parent->texture_slice_or_dirty_rect.merge(current_tracker->texture_slice_or_dirty_rect); + } else { + resource_tracker->parent->texture_slice_or_dirty_rect = current_tracker->texture_slice_or_dirty_rect; + initialized_dirty_rect = true; + } + + previous_tracker = current_tracker; + current_tracker = current_tracker->next_shared; + } + } + } + + // If it wasn't in the list, assume the usage is the same as the parent. + resource_tracker->usage = resource_tracker->parent->usage; + + if (resource_tracker->usage != new_resource_usage) { + // Insert to the dirty list if the requested usage is different. + resource_tracker->next_shared = resource_tracker->parent->dirty_shared_list; + resource_tracker->parent->dirty_shared_list = resource_tracker; + resource_tracker->in_parent_dirty_list = true; + if (resource_tracker->parent->dirty_shared_list != nullptr) { + resource_tracker->parent->texture_slice_or_dirty_rect = resource_tracker->parent->texture_slice_or_dirty_rect.merge(resource_tracker->texture_slice_or_dirty_rect); + } else { + resource_tracker->parent->texture_slice_or_dirty_rect = resource_tracker->texture_slice_or_dirty_rect; + } + } + } + } else { + if (resource_tracker->dirty_shared_list != nullptr) { + // Consider the usage as write if we must transition any of the slices. + write_usage = true; + } + + while (resource_tracker->dirty_shared_list != nullptr) { + if (resource_tracker->dirty_shared_list->texture_driver_id != 0) { + // Transition all slices to the layout of the parent resource. + _add_texture_barrier_to_command(resource_tracker->dirty_shared_list->texture_driver_id, resource_tracker->dirty_shared_list->usage_access, new_usage_access, resource_tracker->dirty_shared_list->usage, resource_tracker->usage, resource_tracker->dirty_shared_list->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count); + } + + resource_tracker->dirty_shared_list->in_parent_dirty_list = false; + resource_tracker->dirty_shared_list = resource_tracker->dirty_shared_list->next_shared; + } + } + + // Use the resource's parent tracker directly for all search operations. + bool resource_has_parent = resource_tracker->parent != nullptr; + ResourceTracker *search_tracker = resource_has_parent ? resource_tracker->parent : resource_tracker; + const RDD::TextureSubresourceRange &subresources = resource_tracker->texture_subresources; + Rect2i resource_tracker_rect(subresources.base_mipmap, subresources.base_layer, subresources.mipmap_count, subresources.layer_count); + bool different_usage = resource_tracker->usage != new_resource_usage; + bool write_usage_after_write = (write_usage && search_tracker->write_command_or_list_index >= 0); + if (different_usage || write_usage_after_write) { + // A barrier must be pushed if the usage is different of it's a write usage and there was already a command that wrote to this resource previously. + if (resource_tracker->texture_driver_id.id != 0) { + if (resource_tracker->usage_access.is_empty()) { + // FIXME: If the tracker does not know the previous type of usage, assume the generic memory write one. + // Tracking access bits across texture slices can be tricky, so this failsafe can be removed once that's improved. + resource_tracker->usage_access = RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT; + } + + _add_texture_barrier_to_command(resource_tracker->texture_driver_id, resource_tracker->usage_access, new_usage_access, resource_tracker->usage, new_resource_usage, resource_tracker->texture_subresources, command_transition_barriers, r_command->transition_barrier_index, r_command->transition_barrier_count); + } else if (resource_tracker->buffer_driver_id.id != 0) { +#if USE_BUFFER_BARRIERS + _add_buffer_barrier_to_command(resource_tracker->buffer_driver_id, resource_tracker->usage_access, new_usage_access, r_command->buffer_barrier_index, r_command->buffer_barrier_count); +#endif + // FIXME: Memory barriers are currently pushed regardless of whether buffer barriers are being used or not. Refer to the comment on the + // definition of USE_BUFFER_BARRIERS for the reason behind this. This can be fixed to be one case or the other once it's been confirmed + // the buffer and memory barrier behavior discrepancy has been solved. + r_command->memory_barrier.src_access = resource_tracker->usage_access; + r_command->memory_barrier.dst_access = new_usage_access; + } else { + DEV_ASSERT(false && "Resource tracker does not contain a valid buffer or texture ID."); + } + } + + // Always update the access of the tracker according to the latest usage. + resource_tracker->usage_access = new_usage_access; + + if (different_usage) { + // Even if the usage of the resource isn't a write usage explicitly, a different usage implies a transition and it should therefore be considered a write. + write_usage = true; + resource_tracker->usage = new_resource_usage; + } + + if (search_tracker->write_command_or_list_index >= 0) { + if (search_tracker->write_command_list_enabled) { + // Make this command adjacent to any commands that wrote to this resource and intersect with the slice if it applies. + // For buffers or textures that never use slices, this list will only be one element long at most. + int32_t previous_write_list_index = -1; + int32_t write_list_index = search_tracker->write_command_or_list_index; + while (write_list_index >= 0) { + const RecordedWriteListNode &write_list_node = write_list_nodes[write_list_index]; + if (!resource_has_parent || resource_tracker_rect.intersects(write_list_node.subresources)) { + if (write_list_node.command_index == p_command_index) { + ERR_FAIL_COND_MSG(!resource_has_parent, "Command can't have itself as a dependency."); + } else { + // Command is dependent on this command. Add this command to the adjacency list of the write command. + _add_adjacent_command(write_list_node.command_index, p_command_index, r_command); + + if (resource_has_parent && write_usage && resource_tracker_rect.encloses(write_list_node.subresources)) { + // Eliminate redundant writes from the list. + if (previous_write_list_index >= 0) { + RecordedWriteListNode &previous_list_node = write_list_nodes[previous_write_list_index]; + previous_list_node.next_list_index = write_list_node.next_list_index; + } else { + search_tracker->write_command_or_list_index = write_list_node.next_list_index; + } + + write_list_index = write_list_node.next_list_index; + continue; + } + } + } + + previous_write_list_index = write_list_index; + write_list_index = write_list_node.next_list_index; + } + } else { + // The index is just the latest command index that wrote to the resource. + if (search_tracker->write_command_or_list_index == p_command_index) { + ERR_FAIL_MSG("Command can't have itself as a dependency."); + } else { + _add_adjacent_command(search_tracker->write_command_or_list_index, p_command_index, r_command); + } + } + } + + if (write_usage) { + if (resource_has_parent) { + if (!search_tracker->write_command_list_enabled && search_tracker->write_command_or_list_index >= 0) { + // Write command list was not being used but there was a write command recorded. Add a new node with the entire parent resource's subresources and the recorded command index to the list. + const RDD::TextureSubresourceRange &tracker_subresources = search_tracker->texture_subresources; + Rect2i tracker_rect(tracker_subresources.base_mipmap, tracker_subresources.base_layer, tracker_subresources.mipmap_count, tracker_subresources.layer_count); + search_tracker->write_command_or_list_index = _add_to_write_list(search_tracker->write_command_or_list_index, tracker_rect, -1); + } + + search_tracker->write_command_or_list_index = _add_to_write_list(p_command_index, resource_tracker_rect, search_tracker->write_command_or_list_index); + search_tracker->write_command_list_enabled = true; + } else { + search_tracker->write_command_or_list_index = p_command_index; + search_tracker->write_command_list_enabled = false; + } + + // We add this command to the adjacency list of all commands that were reading from this resource. We clear the list in the process. + int32_t previous_command_list_index = -1; + int32_t read_command_list_index = search_tracker->read_command_list_index; + while (read_command_list_index >= 0) { + const RecordedCommandListNode &command_list_node = command_list_nodes[read_command_list_index]; + if (command_list_node.command_index == p_command_index) { + if (!resource_has_parent) { + // Slices are allowed to be in different usages in the same command as they are guaranteed to have no overlap in the same command. + ERR_FAIL_MSG("Command can't have itself as a dependency."); + } else { + // Advance to the next element. + read_command_list_index = command_list_node.next_list_index; + previous_command_list_index = read_command_list_index; + } + } else { + if (previous_command_list_index >= 0) { + // Erase this element and connect the previous one to the next element. + command_list_nodes[previous_command_list_index].next_list_index = command_list_node.next_list_index; + read_command_list_index = command_list_node.next_list_index; + previous_command_list_index = read_command_list_index; + } else { + // Erase this element from the head of the list. + DEV_ASSERT(search_tracker->read_command_list_index == read_command_list_index); + read_command_list_index = command_list_node.next_list_index; + search_tracker->read_command_list_index = read_command_list_index; + } + + // Add this command to the adjacency list of each command that was reading this resource. + _add_adjacent_command(command_list_node.command_index, p_command_index, r_command); + } + } + } else { + // We add a read dependency to the tracker to indicate this command reads from the resource. + search_tracker->read_command_list_index = _add_to_command_list(p_command_index, search_tracker->read_command_list_index); + } + } +} + +void RenderingDeviceGraph::_add_texture_barrier_to_command(RDD::TextureID p_texture_id, BitField<RDD::BarrierAccessBits> p_src_access, BitField<RDD::BarrierAccessBits> p_dst_access, ResourceUsage p_prev_usage, ResourceUsage p_next_usage, RDD::TextureSubresourceRange p_subresources, LocalVector<RDD::TextureBarrier> &r_barrier_vector, int32_t &r_barrier_index, int32_t &r_barrier_count) { + if (!driver_honors_barriers) { + return; + } + + if (r_barrier_index < 0) { + r_barrier_index = r_barrier_vector.size(); + } + + RDD::TextureBarrier texture_barrier; + texture_barrier.texture = p_texture_id; + texture_barrier.src_access = p_src_access; + texture_barrier.dst_access = p_dst_access; + texture_barrier.prev_layout = _usage_to_image_layout(p_prev_usage); + texture_barrier.next_layout = _usage_to_image_layout(p_next_usage); + texture_barrier.subresources = p_subresources; + r_barrier_vector.push_back(texture_barrier); + r_barrier_count++; +} + +#if USE_BUFFER_BARRIERS +void RenderingDeviceGraph::_add_buffer_barrier_to_command(RDD::BufferID p_buffer_id, BitField<RDD::BarrierAccessBits> p_src_access, BitField<RDD::BarrierAccessBits> p_dst_access, int32_t &r_barrier_index, int32_t &r_barrier_count) { + if (!driver_honors_barriers) { + return; + } + + if (r_barrier_index < 0) { + r_barrier_index = command_buffer_barriers.size(); + } + + RDD::BufferBarrier buffer_barrier; + buffer_barrier.buffer = p_buffer_id; + buffer_barrier.src_access = p_src_access; + buffer_barrier.dst_access = p_dst_access; + buffer_barrier.offset = 0; + buffer_barrier.size = RDD::BUFFER_WHOLE_SIZE; + command_buffer_barriers.push_back(buffer_barrier); + r_barrier_count++; +} +#endif + +void RenderingDeviceGraph::_run_compute_list_command(RDD::CommandBufferID p_command_buffer, const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) { + uint32_t instruction_data_cursor = 0; + while (instruction_data_cursor < p_instruction_data_size) { + DEV_ASSERT((instruction_data_cursor + sizeof(ComputeListInstruction)) <= p_instruction_data_size); + + const ComputeListInstruction *instruction = reinterpret_cast<const ComputeListInstruction *>(&p_instruction_data[instruction_data_cursor]); + switch (instruction->type) { + case ComputeListInstruction::TYPE_BIND_PIPELINE: { + const ComputeListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const ComputeListBindPipelineInstruction *>(instruction); + driver->command_bind_compute_pipeline(p_command_buffer, bind_pipeline_instruction->pipeline); + instruction_data_cursor += sizeof(ComputeListBindPipelineInstruction); + } break; + case ComputeListInstruction::TYPE_BIND_UNIFORM_SET: { + const ComputeListBindUniformSetInstruction *bind_uniform_set_instruction = reinterpret_cast<const ComputeListBindUniformSetInstruction *>(instruction); + driver->command_bind_compute_uniform_set(p_command_buffer, bind_uniform_set_instruction->uniform_set, bind_uniform_set_instruction->shader, bind_uniform_set_instruction->set_index); + instruction_data_cursor += sizeof(ComputeListBindUniformSetInstruction); + } break; + case ComputeListInstruction::TYPE_DISPATCH: { + const ComputeListDispatchInstruction *dispatch_instruction = reinterpret_cast<const ComputeListDispatchInstruction *>(instruction); + driver->command_compute_dispatch(p_command_buffer, dispatch_instruction->x_groups, dispatch_instruction->y_groups, dispatch_instruction->z_groups); + instruction_data_cursor += sizeof(ComputeListDispatchInstruction); + } break; + case ComputeListInstruction::TYPE_DISPATCH_INDIRECT: { + const ComputeListDispatchIndirectInstruction *dispatch_indirect_instruction = reinterpret_cast<const ComputeListDispatchIndirectInstruction *>(instruction); + driver->command_compute_dispatch_indirect(p_command_buffer, dispatch_indirect_instruction->buffer, dispatch_indirect_instruction->offset); + instruction_data_cursor += sizeof(ComputeListDispatchIndirectInstruction); + } break; + case ComputeListInstruction::TYPE_SET_PUSH_CONSTANT: { + const ComputeListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const ComputeListSetPushConstantInstruction *>(instruction); + const VectorView push_constant_data_view(reinterpret_cast<const uint32_t *>(set_push_constant_instruction->data()), set_push_constant_instruction->size / sizeof(uint32_t)); + driver->command_bind_push_constants(p_command_buffer, set_push_constant_instruction->shader, 0, push_constant_data_view); + instruction_data_cursor += sizeof(ComputeListSetPushConstantInstruction); + instruction_data_cursor += set_push_constant_instruction->size; + } break; + case ComputeListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: { + const ComputeListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const ComputeListUniformSetPrepareForUseInstruction *>(instruction); + driver->command_uniform_set_prepare_for_use(p_command_buffer, uniform_set_prepare_for_use_instruction->uniform_set, uniform_set_prepare_for_use_instruction->shader, uniform_set_prepare_for_use_instruction->set_index); + instruction_data_cursor += sizeof(ComputeListUniformSetPrepareForUseInstruction); + } break; + default: + DEV_ASSERT(false && "Unknown compute list instruction type."); + return; + } + } +} + +void RenderingDeviceGraph::_run_draw_list_command(RDD::CommandBufferID p_command_buffer, const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) { + uint32_t instruction_data_cursor = 0; + while (instruction_data_cursor < p_instruction_data_size) { + DEV_ASSERT((instruction_data_cursor + sizeof(DrawListInstruction)) <= p_instruction_data_size); + + const DrawListInstruction *instruction = reinterpret_cast<const DrawListInstruction *>(&p_instruction_data[instruction_data_cursor]); + switch (instruction->type) { + case DrawListInstruction::TYPE_BIND_INDEX_BUFFER: { + const DrawListBindIndexBufferInstruction *bind_index_buffer_instruction = reinterpret_cast<const DrawListBindIndexBufferInstruction *>(instruction); + driver->command_render_bind_index_buffer(p_command_buffer, bind_index_buffer_instruction->buffer, bind_index_buffer_instruction->format, bind_index_buffer_instruction->offset); + instruction_data_cursor += sizeof(DrawListBindIndexBufferInstruction); + } break; + case DrawListInstruction::TYPE_BIND_PIPELINE: { + const DrawListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const DrawListBindPipelineInstruction *>(instruction); + driver->command_bind_render_pipeline(p_command_buffer, bind_pipeline_instruction->pipeline); + instruction_data_cursor += sizeof(DrawListBindPipelineInstruction); + } break; + case DrawListInstruction::TYPE_BIND_UNIFORM_SET: { + const DrawListBindUniformSetInstruction *bind_uniform_set_instruction = reinterpret_cast<const DrawListBindUniformSetInstruction *>(instruction); + driver->command_bind_render_uniform_set(p_command_buffer, bind_uniform_set_instruction->uniform_set, bind_uniform_set_instruction->shader, bind_uniform_set_instruction->set_index); + instruction_data_cursor += sizeof(DrawListBindUniformSetInstruction); + } break; + case DrawListInstruction::TYPE_BIND_VERTEX_BUFFERS: { + const DrawListBindVertexBuffersInstruction *bind_vertex_buffers_instruction = reinterpret_cast<const DrawListBindVertexBuffersInstruction *>(instruction); + driver->command_render_bind_vertex_buffers(p_command_buffer, bind_vertex_buffers_instruction->vertex_buffers_count, bind_vertex_buffers_instruction->vertex_buffers(), bind_vertex_buffers_instruction->vertex_buffer_offsets()); + instruction_data_cursor += sizeof(DrawListBindVertexBuffersInstruction); + instruction_data_cursor += sizeof(RDD::BufferID) * bind_vertex_buffers_instruction->vertex_buffers_count; + instruction_data_cursor += sizeof(uint64_t) * bind_vertex_buffers_instruction->vertex_buffers_count; + } break; + case DrawListInstruction::TYPE_CLEAR_ATTACHMENTS: { + const DrawListClearAttachmentsInstruction *clear_attachments_instruction = reinterpret_cast<const DrawListClearAttachmentsInstruction *>(instruction); + const VectorView attachments_clear_view(clear_attachments_instruction->attachments_clear(), clear_attachments_instruction->attachments_clear_count); + const VectorView attachments_clear_rect_view(clear_attachments_instruction->attachments_clear_rect(), clear_attachments_instruction->attachments_clear_rect_count); + driver->command_render_clear_attachments(p_command_buffer, attachments_clear_view, attachments_clear_rect_view); + instruction_data_cursor += sizeof(DrawListClearAttachmentsInstruction); + instruction_data_cursor += sizeof(RDD::AttachmentClear) * clear_attachments_instruction->attachments_clear_count; + instruction_data_cursor += sizeof(Rect2i) * clear_attachments_instruction->attachments_clear_rect_count; + } break; + case DrawListInstruction::TYPE_DRAW: { + const DrawListDrawInstruction *draw_instruction = reinterpret_cast<const DrawListDrawInstruction *>(instruction); + driver->command_render_draw(p_command_buffer, draw_instruction->vertex_count, draw_instruction->instance_count, 0, 0); + instruction_data_cursor += sizeof(DrawListDrawInstruction); + } break; + case DrawListInstruction::TYPE_DRAW_INDEXED: { + const DrawListDrawIndexedInstruction *draw_indexed_instruction = reinterpret_cast<const DrawListDrawIndexedInstruction *>(instruction); + driver->command_render_draw_indexed(p_command_buffer, draw_indexed_instruction->index_count, draw_indexed_instruction->instance_count, draw_indexed_instruction->first_index, 0, 0); + instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction); + } break; + case DrawListInstruction::TYPE_EXECUTE_COMMANDS: { + const DrawListExecuteCommandsInstruction *execute_commands_instruction = reinterpret_cast<const DrawListExecuteCommandsInstruction *>(instruction); + driver->command_buffer_execute_secondary(p_command_buffer, execute_commands_instruction->command_buffer); + instruction_data_cursor += sizeof(DrawListExecuteCommandsInstruction); + } break; + case DrawListInstruction::TYPE_NEXT_SUBPASS: { + const DrawListNextSubpassInstruction *next_subpass_instruction = reinterpret_cast<const DrawListNextSubpassInstruction *>(instruction); + driver->command_next_render_subpass(p_command_buffer, next_subpass_instruction->command_buffer_type); + instruction_data_cursor += sizeof(DrawListNextSubpassInstruction); + } break; + case DrawListInstruction::TYPE_SET_BLEND_CONSTANTS: { + const DrawListSetBlendConstantsInstruction *set_blend_constants_instruction = reinterpret_cast<const DrawListSetBlendConstantsInstruction *>(instruction); + driver->command_render_set_blend_constants(p_command_buffer, set_blend_constants_instruction->color); + instruction_data_cursor += sizeof(DrawListSetBlendConstantsInstruction); + } break; + case DrawListInstruction::TYPE_SET_LINE_WIDTH: { + const DrawListSetLineWidthInstruction *set_line_width_instruction = reinterpret_cast<const DrawListSetLineWidthInstruction *>(instruction); + driver->command_render_set_line_width(p_command_buffer, set_line_width_instruction->width); + instruction_data_cursor += sizeof(DrawListSetLineWidthInstruction); + } break; + case DrawListInstruction::TYPE_SET_PUSH_CONSTANT: { + const DrawListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const DrawListSetPushConstantInstruction *>(instruction); + const VectorView push_constant_data_view(reinterpret_cast<const uint32_t *>(set_push_constant_instruction->data()), set_push_constant_instruction->size / sizeof(uint32_t)); + driver->command_bind_push_constants(p_command_buffer, set_push_constant_instruction->shader, 0, push_constant_data_view); + instruction_data_cursor += sizeof(DrawListSetPushConstantInstruction); + instruction_data_cursor += set_push_constant_instruction->size; + } break; + case DrawListInstruction::TYPE_SET_SCISSOR: { + const DrawListSetScissorInstruction *set_scissor_instruction = reinterpret_cast<const DrawListSetScissorInstruction *>(instruction); + driver->command_render_set_scissor(p_command_buffer, set_scissor_instruction->rect); + instruction_data_cursor += sizeof(DrawListSetScissorInstruction); + } break; + case DrawListInstruction::TYPE_SET_VIEWPORT: { + const DrawListSetViewportInstruction *set_viewport_instruction = reinterpret_cast<const DrawListSetViewportInstruction *>(instruction); + driver->command_render_set_viewport(p_command_buffer, set_viewport_instruction->rect); + instruction_data_cursor += sizeof(DrawListSetViewportInstruction); + } break; + case DrawListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: { + const DrawListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const DrawListUniformSetPrepareForUseInstruction *>(instruction); + driver->command_uniform_set_prepare_for_use(p_command_buffer, uniform_set_prepare_for_use_instruction->uniform_set, uniform_set_prepare_for_use_instruction->shader, uniform_set_prepare_for_use_instruction->set_index); + instruction_data_cursor += sizeof(DrawListUniformSetPrepareForUseInstruction); + } break; + default: + DEV_ASSERT(false && "Unknown draw list instruction type."); + return; + } + } +} + +void RenderingDeviceGraph::_run_secondary_command_buffer_task(const SecondaryCommandBuffer *p_secondary) { + driver->command_buffer_begin_secondary(p_secondary->command_buffer, p_secondary->render_pass, 0, p_secondary->framebuffer); + _run_draw_list_command(p_secondary->command_buffer, p_secondary->instruction_data.ptr(), p_secondary->instruction_data.size()); + driver->command_buffer_end(p_secondary->command_buffer); +} + +void RenderingDeviceGraph::_wait_for_secondary_command_buffer_tasks() { + for (uint32_t i = 0; i < frames[frame].secondary_command_buffers_used; i++) { + WorkerThreadPool::TaskID &task = frames[frame].secondary_command_buffers[i].task; + if (task != WorkerThreadPool::INVALID_TASK_ID) { + WorkerThreadPool::get_singleton()->wait_for_task_completion(task); + task = WorkerThreadPool::INVALID_TASK_ID; + } + } +} + +void RenderingDeviceGraph::_run_render_commands(RDD::CommandBufferID p_command_buffer, int32_t p_level, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, int32_t &r_current_label_index, int32_t &r_current_label_level) { + for (uint32_t i = 0; i < p_sorted_commands_count; i++) { + const uint32_t command_index = p_sorted_commands[i].index; + const uint32_t command_data_offset = command_data_offsets[command_index]; + const RecordedCommand *command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]); + _run_label_command_change(p_command_buffer, command->label_index, p_level, false, true, &p_sorted_commands[i], p_sorted_commands_count - i, r_current_label_index, r_current_label_level); + + switch (command->type) { + case RecordedCommand::TYPE_BUFFER_CLEAR: { + const RecordedBufferClearCommand *buffer_clear_command = reinterpret_cast<const RecordedBufferClearCommand *>(command); + driver->command_clear_buffer(p_command_buffer, buffer_clear_command->buffer, buffer_clear_command->offset, buffer_clear_command->size); + } break; + case RecordedCommand::TYPE_BUFFER_COPY: { + const RecordedBufferCopyCommand *buffer_copy_command = reinterpret_cast<const RecordedBufferCopyCommand *>(command); + driver->command_copy_buffer(p_command_buffer, buffer_copy_command->source, buffer_copy_command->destination, buffer_copy_command->region); + } break; + case RecordedCommand::TYPE_BUFFER_GET_DATA: { + const RecordedBufferGetDataCommand *buffer_get_data_command = reinterpret_cast<const RecordedBufferGetDataCommand *>(command); + driver->command_copy_buffer(p_command_buffer, buffer_get_data_command->source, buffer_get_data_command->destination, buffer_get_data_command->region); + } break; + case RecordedCommand::TYPE_BUFFER_UPDATE: { + const RecordedBufferUpdateCommand *buffer_update_command = reinterpret_cast<const RecordedBufferUpdateCommand *>(command); + const RecordedBufferCopy *command_buffer_copies = buffer_update_command->buffer_copies(); + for (uint32_t j = 0; j < buffer_update_command->buffer_copies_count; j++) { + driver->command_copy_buffer(p_command_buffer, command_buffer_copies[j].source, buffer_update_command->destination, command_buffer_copies[j].region); + } + } break; + case RecordedCommand::TYPE_COMPUTE_LIST: { + const RecordedComputeListCommand *compute_list_command = reinterpret_cast<const RecordedComputeListCommand *>(command); + _run_compute_list_command(p_command_buffer, compute_list_command->instruction_data(), compute_list_command->instruction_data_size); + } break; + case RecordedCommand::TYPE_DRAW_LIST: { + const RecordedDrawListCommand *draw_list_command = reinterpret_cast<const RecordedDrawListCommand *>(command); + const VectorView clear_values(draw_list_command->clear_values(), draw_list_command->clear_values_count); + driver->command_begin_render_pass(p_command_buffer, draw_list_command->render_pass, draw_list_command->framebuffer, draw_list_command->command_buffer_type, draw_list_command->region, clear_values); + _run_draw_list_command(p_command_buffer, draw_list_command->instruction_data(), draw_list_command->instruction_data_size); + driver->command_end_render_pass(p_command_buffer); + } break; + case RecordedCommand::TYPE_TEXTURE_CLEAR: { + const RecordedTextureClearCommand *texture_clear_command = reinterpret_cast<const RecordedTextureClearCommand *>(command); + driver->command_clear_color_texture(p_command_buffer, texture_clear_command->texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_clear_command->color, texture_clear_command->range); + } break; + case RecordedCommand::TYPE_TEXTURE_COPY: { + const RecordedTextureCopyCommand *texture_copy_command = reinterpret_cast<const RecordedTextureCopyCommand *>(command); + driver->command_copy_texture(p_command_buffer, texture_copy_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_copy_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_copy_command->region); + } break; + case RecordedCommand::TYPE_TEXTURE_GET_DATA: { + const RecordedTextureGetDataCommand *texture_get_data_command = reinterpret_cast<const RecordedTextureGetDataCommand *>(command); + const VectorView<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_view(texture_get_data_command->buffer_texture_copy_regions(), texture_get_data_command->buffer_texture_copy_regions_count); + driver->command_copy_texture_to_buffer(p_command_buffer, texture_get_data_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_get_data_command->to_buffer, command_buffer_texture_copy_regions_view); + } break; + case RecordedCommand::TYPE_TEXTURE_RESOLVE: { + const RecordedTextureResolveCommand *texture_resolve_command = reinterpret_cast<const RecordedTextureResolveCommand *>(command); + driver->command_resolve_texture(p_command_buffer, texture_resolve_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_resolve_command->src_layer, texture_resolve_command->src_mipmap, texture_resolve_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_resolve_command->dst_layer, texture_resolve_command->dst_mipmap); + } break; + case RecordedCommand::TYPE_TEXTURE_UPDATE: { + const RecordedTextureUpdateCommand *texture_update_command = reinterpret_cast<const RecordedTextureUpdateCommand *>(command); + const RecordedBufferToTextureCopy *command_buffer_to_texture_copies = texture_update_command->buffer_to_texture_copies(); + for (uint32_t j = 0; j < texture_update_command->buffer_to_texture_copies_count; j++) { + driver->command_copy_buffer_to_texture(p_command_buffer, command_buffer_to_texture_copies[j].from_buffer, texture_update_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, command_buffer_to_texture_copies[j].region); + } + } break; + case RecordedCommand::TYPE_CAPTURE_TIMESTAMP: { + const RecordedCaptureTimestampCommand *texture_capture_timestamp_command = reinterpret_cast<const RecordedCaptureTimestampCommand *>(command); + driver->command_timestamp_write(p_command_buffer, texture_capture_timestamp_command->pool, texture_capture_timestamp_command->index); + } break; + default: { + DEV_ASSERT(false && "Unknown recorded command type."); + return; + } + } + } +} + +void RenderingDeviceGraph::_run_label_command_change(RDD::CommandBufferID p_command_buffer, int32_t p_new_label_index, int32_t p_new_level, bool p_ignore_previous_value, bool p_use_label_for_empty, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, int32_t &r_current_label_index, int32_t &r_current_label_level) { + if (command_label_count == 0) { + // Ignore any label operations if no labels were pushed. + return; + } + + if (p_ignore_previous_value || p_new_label_index != r_current_label_index || p_new_level != r_current_label_level) { + if (!p_ignore_previous_value && (p_use_label_for_empty || r_current_label_index >= 0)) { + // End the current label. + driver->command_end_label(p_command_buffer); + } + + String label_name; + Color label_color; + if (p_new_label_index >= 0) { + const char *label_chars = &command_label_chars[command_label_offsets[p_new_label_index]]; + label_name.parse_utf8(label_chars); + label_color = command_label_colors[p_new_label_index]; + } else if (p_use_label_for_empty) { + label_name = "Command graph"; + label_color = Color(1, 1, 1, 1); + } + + // Add the level to the name. + label_name += " (L" + itos(p_new_level) + ")"; + + if (p_sorted_commands != nullptr && p_sorted_commands_count > 0) { + // Analyze the commands in the level that have the same label to detect what type of operations are performed. + bool copy_commands = false; + bool compute_commands = false; + bool draw_commands = false; + for (uint32_t i = 0; i < p_sorted_commands_count; i++) { + const uint32_t command_index = p_sorted_commands[i].index; + const uint32_t command_data_offset = command_data_offsets[command_index]; + const RecordedCommand *command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]); + if (command->label_index != p_new_label_index) { + break; + } + + switch (command->type) { + case RecordedCommand::TYPE_BUFFER_CLEAR: + case RecordedCommand::TYPE_BUFFER_COPY: + case RecordedCommand::TYPE_BUFFER_GET_DATA: + case RecordedCommand::TYPE_BUFFER_UPDATE: + case RecordedCommand::TYPE_TEXTURE_CLEAR: + case RecordedCommand::TYPE_TEXTURE_COPY: + case RecordedCommand::TYPE_TEXTURE_GET_DATA: + case RecordedCommand::TYPE_TEXTURE_RESOLVE: + case RecordedCommand::TYPE_TEXTURE_UPDATE: { + copy_commands = true; + } break; + case RecordedCommand::TYPE_COMPUTE_LIST: { + compute_commands = true; + } break; + case RecordedCommand::TYPE_DRAW_LIST: { + draw_commands = true; + } break; + default: { + // Ignore command. + } break; + } + + if (copy_commands && compute_commands && draw_commands) { + // There's no more command types to find. + break; + } + } + + if (copy_commands || compute_commands || draw_commands) { + // Add the operations to the name. + bool plus_after_copy = copy_commands && (compute_commands || draw_commands); + bool plus_after_compute = compute_commands && draw_commands; + label_name += " ("; + label_name += copy_commands ? "Copy" : ""; + label_name += plus_after_copy ? "+" : ""; + label_name += compute_commands ? "Compute" : ""; + label_name += plus_after_compute ? "+" : ""; + label_name += draw_commands ? "Draw" : ""; + label_name += ")"; + } + } + + // Start the new label. + CharString label_name_utf8 = label_name.utf8(); + driver->command_begin_label(p_command_buffer, label_name_utf8.get_data(), label_color); + + r_current_label_index = p_new_label_index; + r_current_label_level = p_new_level; + } +} + +void RenderingDeviceGraph::_boost_priority_for_render_commands(RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, uint32_t &r_boosted_priority) { + if (p_sorted_commands_count == 0) { + return; + } + + const uint32_t boosted_priority_value = 0; + if (r_boosted_priority > 0) { + bool perform_sort = false; + for (uint32_t j = 0; j < p_sorted_commands_count; j++) { + if (p_sorted_commands[j].priority == r_boosted_priority) { + p_sorted_commands[j].priority = boosted_priority_value; + perform_sort = true; + } + } + + if (perform_sort) { + SortArray<RecordedCommandSort> command_sorter; + command_sorter.sort(p_sorted_commands, p_sorted_commands_count); + } + } + + if (p_sorted_commands[p_sorted_commands_count - 1].priority != boosted_priority_value) { + r_boosted_priority = p_sorted_commands[p_sorted_commands_count - 1].priority; + } +} + +void RenderingDeviceGraph::_group_barriers_for_render_commands(RDD::CommandBufferID p_command_buffer, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, bool p_full_memory_barrier) { + if (!driver_honors_barriers) { + return; + } + + barrier_group.clear(); + barrier_group.src_stages = RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT; + barrier_group.dst_stages = RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + + for (uint32_t i = 0; i < p_sorted_commands_count; i++) { + const uint32_t command_index = p_sorted_commands[i].index; + const uint32_t command_data_offset = command_data_offsets[command_index]; + const RecordedCommand *command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]); + + // Merge command's stage bits with the barrier group. + barrier_group.src_stages = barrier_group.src_stages | command->src_stages; + barrier_group.dst_stages = barrier_group.dst_stages | command->dst_stages; + + // Merge command's memory barrier bits with the barrier group. + barrier_group.memory_barrier.src_access = barrier_group.memory_barrier.src_access | command->memory_barrier.src_access; + barrier_group.memory_barrier.dst_access = barrier_group.memory_barrier.dst_access | command->memory_barrier.dst_access; + + // Gather texture barriers. + for (int32_t j = 0; j < command->normalization_barrier_count; j++) { + const RDD::TextureBarrier &recorded_barrier = command_normalization_barriers[command->normalization_barrier_index + j]; + barrier_group.normalization_barriers.push_back(recorded_barrier); + } + + for (int32_t j = 0; j < command->transition_barrier_count; j++) { + const RDD::TextureBarrier &recorded_barrier = command_transition_barriers[command->transition_barrier_index + j]; + barrier_group.transition_barriers.push_back(recorded_barrier); + } + +#if USE_BUFFER_BARRIERS + // Gather buffer barriers. + for (int32_t j = 0; j < command->buffer_barrier_count; j++) { + const RDD::BufferBarrier &recorded_barrier = command_buffer_barriers[command->buffer_barrier_index + j]; + barrier_group.buffer_barriers.push_back(recorded_barrier); + } +#endif + } + + if (p_full_memory_barrier) { + barrier_group.src_stages = RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT; + barrier_group.dst_stages = RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT; + barrier_group.memory_barrier.src_access = RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT; + barrier_group.memory_barrier.dst_access = RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT; + } + + const bool is_memory_barrier_empty = barrier_group.memory_barrier.src_access.is_empty() && barrier_group.memory_barrier.dst_access.is_empty(); + const bool are_texture_barriers_empty = barrier_group.normalization_barriers.is_empty() && barrier_group.transition_barriers.is_empty(); +#if USE_BUFFER_BARRIERS + const bool are_buffer_barriers_empty = barrier_group.buffer_barriers.is_empty(); +#else + const bool are_buffer_barriers_empty = true; +#endif + if (is_memory_barrier_empty && are_texture_barriers_empty && are_buffer_barriers_empty) { + // Commands don't require synchronization. + return; + } + + const VectorView<RDD::MemoryBarrier> memory_barriers = !is_memory_barrier_empty ? barrier_group.memory_barrier : VectorView<RDD::MemoryBarrier>(); + const VectorView<RDD::TextureBarrier> texture_barriers = barrier_group.normalization_barriers.is_empty() ? barrier_group.transition_barriers : barrier_group.normalization_barriers; +#if USE_BUFFER_BARRIERS + const VectorView<RDD::BufferBarrier> buffer_barriers = !are_buffer_barriers_empty ? barrier_group.buffer_barriers : VectorView<RDD::BufferBarrier>(); +#else + const VectorView<RDD::BufferBarrier> buffer_barriers = VectorView<RDD::BufferBarrier>(); +#endif + + driver->command_pipeline_barrier(p_command_buffer, barrier_group.src_stages, barrier_group.dst_stages, memory_barriers, buffer_barriers, texture_barriers); + + bool separate_texture_barriers = !barrier_group.normalization_barriers.is_empty() && !barrier_group.transition_barriers.is_empty(); + if (separate_texture_barriers) { + driver->command_pipeline_barrier(p_command_buffer, barrier_group.src_stages, barrier_group.dst_stages, VectorView<RDD::MemoryBarrier>(), VectorView<RDD::BufferBarrier>(), barrier_group.transition_barriers); + } +} + +void RenderingDeviceGraph::_print_render_commands(const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count) { + for (uint32_t i = 0; i < p_sorted_commands_count; i++) { + const uint32_t command_index = p_sorted_commands[i].index; + const uint32_t command_level = p_sorted_commands[i].level; + const uint32_t command_data_offset = command_data_offsets[command_index]; + const RecordedCommand *command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]); + switch (command->type) { + case RecordedCommand::TYPE_BUFFER_CLEAR: { + const RecordedBufferClearCommand *buffer_clear_command = reinterpret_cast<const RecordedBufferClearCommand *>(command); + print_line(command_index, "LEVEL", command_level, "BUFFER CLEAR DESTINATION", itos(buffer_clear_command->buffer.id)); + } break; + case RecordedCommand::TYPE_BUFFER_COPY: { + const RecordedBufferCopyCommand *buffer_copy_command = reinterpret_cast<const RecordedBufferCopyCommand *>(command); + print_line(command_index, "LEVEL", command_level, "BUFFER COPY SOURCE", itos(buffer_copy_command->source.id), "DESTINATION", itos(buffer_copy_command->destination.id)); + } break; + case RecordedCommand::TYPE_BUFFER_GET_DATA: { + const RecordedBufferGetDataCommand *buffer_get_data_command = reinterpret_cast<const RecordedBufferGetDataCommand *>(command); + print_line(command_index, "LEVEL", command_level, "BUFFER GET DATA DESTINATION", itos(buffer_get_data_command->destination.id)); + } break; + case RecordedCommand::TYPE_BUFFER_UPDATE: { + const RecordedBufferUpdateCommand *buffer_update_command = reinterpret_cast<const RecordedBufferUpdateCommand *>(command); + print_line(command_index, "LEVEL", command_level, "BUFFER UPDATE DESTINATION", itos(buffer_update_command->destination.id), "COPIES", buffer_update_command->buffer_copies_count); + } break; + case RecordedCommand::TYPE_COMPUTE_LIST: { + const RecordedComputeListCommand *compute_list_command = reinterpret_cast<const RecordedComputeListCommand *>(command); + print_line(command_index, "LEVEL", command_level, "COMPUTE LIST SIZE", compute_list_command->instruction_data_size); + } break; + case RecordedCommand::TYPE_DRAW_LIST: { + const RecordedDrawListCommand *draw_list_command = reinterpret_cast<const RecordedDrawListCommand *>(command); + print_line(command_index, "LEVEL", command_level, "DRAW LIST SIZE", draw_list_command->instruction_data_size); + } break; + case RecordedCommand::TYPE_TEXTURE_CLEAR: { + const RecordedTextureClearCommand *texture_clear_command = reinterpret_cast<const RecordedTextureClearCommand *>(command); + print_line(command_index, "LEVEL", command_level, "TEXTURE CLEAR", itos(texture_clear_command->texture.id), "COLOR", texture_clear_command->color); + } break; + case RecordedCommand::TYPE_TEXTURE_COPY: { + const RecordedTextureCopyCommand *texture_copy_command = reinterpret_cast<const RecordedTextureCopyCommand *>(command); + print_line(command_index, "LEVEL", command_level, "TEXTURE COPY FROM", itos(texture_copy_command->from_texture.id), "TO", itos(texture_copy_command->to_texture.id)); + } break; + case RecordedCommand::TYPE_TEXTURE_GET_DATA: { + print_line(command_index, "LEVEL", command_level, "TEXTURE GET DATA"); + } break; + case RecordedCommand::TYPE_TEXTURE_RESOLVE: { + const RecordedTextureResolveCommand *texture_resolve_command = reinterpret_cast<const RecordedTextureResolveCommand *>(command); + print_line(command_index, "LEVEL", command_level, "TEXTURE RESOLVE FROM", itos(texture_resolve_command->from_texture.id), "TO", itos(texture_resolve_command->to_texture.id)); + } break; + case RecordedCommand::TYPE_TEXTURE_UPDATE: { + const RecordedTextureUpdateCommand *texture_update_command = reinterpret_cast<const RecordedTextureUpdateCommand *>(command); + print_line(command_index, "LEVEL", command_level, "TEXTURE UPDATE TO", itos(texture_update_command->to_texture.id)); + } break; + case RecordedCommand::TYPE_CAPTURE_TIMESTAMP: { + const RecordedCaptureTimestampCommand *texture_capture_timestamp_command = reinterpret_cast<const RecordedCaptureTimestampCommand *>(command); + print_line(command_index, "LEVEL", command_level, "CAPTURE TIMESTAMP POOL", itos(texture_capture_timestamp_command->pool.id), "INDEX", texture_capture_timestamp_command->index); + } break; + default: + DEV_ASSERT(false && "Unknown recorded command type."); + return; + } + } +} + +void RenderingDeviceGraph::_print_draw_list(const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) { + uint32_t instruction_data_cursor = 0; + while (instruction_data_cursor < p_instruction_data_size) { + DEV_ASSERT((instruction_data_cursor + sizeof(DrawListInstruction)) <= p_instruction_data_size); + + const DrawListInstruction *instruction = reinterpret_cast<const DrawListInstruction *>(&p_instruction_data[instruction_data_cursor]); + switch (instruction->type) { + case DrawListInstruction::TYPE_BIND_INDEX_BUFFER: { + const DrawListBindIndexBufferInstruction *bind_index_buffer_instruction = reinterpret_cast<const DrawListBindIndexBufferInstruction *>(instruction); + print_line("\tBIND INDEX BUFFER ID", itos(bind_index_buffer_instruction->buffer.id), "FORMAT", bind_index_buffer_instruction->format, "OFFSET", bind_index_buffer_instruction->offset); + instruction_data_cursor += sizeof(DrawListBindIndexBufferInstruction); + } break; + case DrawListInstruction::TYPE_BIND_PIPELINE: { + const DrawListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const DrawListBindPipelineInstruction *>(instruction); + print_line("\tBIND PIPELINE ID", itos(bind_pipeline_instruction->pipeline.id)); + instruction_data_cursor += sizeof(DrawListBindPipelineInstruction); + } break; + case DrawListInstruction::TYPE_BIND_UNIFORM_SET: { + const DrawListBindUniformSetInstruction *bind_uniform_set_instruction = reinterpret_cast<const DrawListBindUniformSetInstruction *>(instruction); + print_line("\tBIND UNIFORM SET ID", itos(bind_uniform_set_instruction->uniform_set.id), "SET INDEX", bind_uniform_set_instruction->set_index); + instruction_data_cursor += sizeof(DrawListBindUniformSetInstruction); + } break; + case DrawListInstruction::TYPE_BIND_VERTEX_BUFFERS: { + const DrawListBindVertexBuffersInstruction *bind_vertex_buffers_instruction = reinterpret_cast<const DrawListBindVertexBuffersInstruction *>(instruction); + print_line("\tBIND VERTEX BUFFERS COUNT", bind_vertex_buffers_instruction->vertex_buffers_count); + instruction_data_cursor += sizeof(DrawListBindVertexBuffersInstruction); + instruction_data_cursor += sizeof(RDD::BufferID) * bind_vertex_buffers_instruction->vertex_buffers_count; + instruction_data_cursor += sizeof(uint64_t) * bind_vertex_buffers_instruction->vertex_buffers_count; + } break; + case DrawListInstruction::TYPE_CLEAR_ATTACHMENTS: { + const DrawListClearAttachmentsInstruction *clear_attachments_instruction = reinterpret_cast<const DrawListClearAttachmentsInstruction *>(instruction); + print_line("\tATTACHMENTS CLEAR COUNT", clear_attachments_instruction->attachments_clear_count, "RECT COUNT", clear_attachments_instruction->attachments_clear_rect_count); + instruction_data_cursor += sizeof(DrawListClearAttachmentsInstruction); + instruction_data_cursor += sizeof(RDD::AttachmentClear) * clear_attachments_instruction->attachments_clear_count; + instruction_data_cursor += sizeof(Rect2i) * clear_attachments_instruction->attachments_clear_rect_count; + } break; + case DrawListInstruction::TYPE_DRAW: { + const DrawListDrawInstruction *draw_instruction = reinterpret_cast<const DrawListDrawInstruction *>(instruction); + print_line("\tDRAW VERTICES", draw_instruction->vertex_count, "INSTANCES", draw_instruction->instance_count); + instruction_data_cursor += sizeof(DrawListDrawInstruction); + } break; + case DrawListInstruction::TYPE_DRAW_INDEXED: { + const DrawListDrawIndexedInstruction *draw_indexed_instruction = reinterpret_cast<const DrawListDrawIndexedInstruction *>(instruction); + print_line("\tDRAW INDICES", draw_indexed_instruction->index_count, "INSTANCES", draw_indexed_instruction->instance_count, "FIRST INDEX", draw_indexed_instruction->first_index); + instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction); + } break; + case DrawListInstruction::TYPE_EXECUTE_COMMANDS: { + print_line("\tEXECUTE COMMANDS"); + instruction_data_cursor += sizeof(DrawListExecuteCommandsInstruction); + } break; + case DrawListInstruction::TYPE_NEXT_SUBPASS: { + print_line("\tNEXT SUBPASS"); + instruction_data_cursor += sizeof(DrawListNextSubpassInstruction); + } break; + case DrawListInstruction::TYPE_SET_BLEND_CONSTANTS: { + const DrawListSetBlendConstantsInstruction *set_blend_constants_instruction = reinterpret_cast<const DrawListSetBlendConstantsInstruction *>(instruction); + print_line("\tSET BLEND CONSTANTS COLOR", set_blend_constants_instruction->color); + instruction_data_cursor += sizeof(DrawListSetBlendConstantsInstruction); + } break; + case DrawListInstruction::TYPE_SET_LINE_WIDTH: { + const DrawListSetLineWidthInstruction *set_line_width_instruction = reinterpret_cast<const DrawListSetLineWidthInstruction *>(instruction); + print_line("\tSET LINE WIDTH", set_line_width_instruction->width); + instruction_data_cursor += sizeof(DrawListSetLineWidthInstruction); + } break; + case DrawListInstruction::TYPE_SET_PUSH_CONSTANT: { + const DrawListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const DrawListSetPushConstantInstruction *>(instruction); + print_line("\tSET PUSH CONSTANT SIZE", set_push_constant_instruction->size); + instruction_data_cursor += sizeof(DrawListSetPushConstantInstruction); + instruction_data_cursor += set_push_constant_instruction->size; + } break; + case DrawListInstruction::TYPE_SET_SCISSOR: { + const DrawListSetScissorInstruction *set_scissor_instruction = reinterpret_cast<const DrawListSetScissorInstruction *>(instruction); + print_line("\tSET SCISSOR", set_scissor_instruction->rect); + instruction_data_cursor += sizeof(DrawListSetScissorInstruction); + } break; + case DrawListInstruction::TYPE_SET_VIEWPORT: { + const DrawListSetViewportInstruction *set_viewport_instruction = reinterpret_cast<const DrawListSetViewportInstruction *>(instruction); + print_line("\tSET VIEWPORT", set_viewport_instruction->rect); + instruction_data_cursor += sizeof(DrawListSetViewportInstruction); + } break; + case DrawListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: { + const DrawListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const DrawListUniformSetPrepareForUseInstruction *>(instruction); + print_line("\tUNIFORM SET PREPARE FOR USE ID", itos(uniform_set_prepare_for_use_instruction->uniform_set.id), "SHADER ID", itos(uniform_set_prepare_for_use_instruction->shader.id), "INDEX", uniform_set_prepare_for_use_instruction->set_index); + instruction_data_cursor += sizeof(DrawListUniformSetPrepareForUseInstruction); + } break; + default: + DEV_ASSERT(false && "Unknown draw list instruction type."); + return; + } + } +} + +void RenderingDeviceGraph::_print_compute_list(const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) { + uint32_t instruction_data_cursor = 0; + while (instruction_data_cursor < p_instruction_data_size) { + DEV_ASSERT((instruction_data_cursor + sizeof(ComputeListInstruction)) <= p_instruction_data_size); + + const ComputeListInstruction *instruction = reinterpret_cast<const ComputeListInstruction *>(&p_instruction_data[instruction_data_cursor]); + switch (instruction->type) { + case ComputeListInstruction::TYPE_BIND_PIPELINE: { + const ComputeListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const ComputeListBindPipelineInstruction *>(instruction); + print_line("\tBIND PIPELINE ID", itos(bind_pipeline_instruction->pipeline.id)); + instruction_data_cursor += sizeof(ComputeListBindPipelineInstruction); + } break; + case ComputeListInstruction::TYPE_BIND_UNIFORM_SET: { + const ComputeListBindUniformSetInstruction *bind_uniform_set_instruction = reinterpret_cast<const ComputeListBindUniformSetInstruction *>(instruction); + print_line("\tBIND UNIFORM SET ID", itos(bind_uniform_set_instruction->uniform_set.id), "SHADER ID", itos(bind_uniform_set_instruction->shader.id)); + instruction_data_cursor += sizeof(ComputeListBindUniformSetInstruction); + } break; + case ComputeListInstruction::TYPE_DISPATCH: { + const ComputeListDispatchInstruction *dispatch_instruction = reinterpret_cast<const ComputeListDispatchInstruction *>(instruction); + print_line("\tDISPATCH", dispatch_instruction->x_groups, dispatch_instruction->y_groups, dispatch_instruction->z_groups); + instruction_data_cursor += sizeof(ComputeListDispatchInstruction); + } break; + case ComputeListInstruction::TYPE_DISPATCH_INDIRECT: { + const ComputeListDispatchIndirectInstruction *dispatch_indirect_instruction = reinterpret_cast<const ComputeListDispatchIndirectInstruction *>(instruction); + print_line("\tDISPATCH INDIRECT BUFFER ID", itos(dispatch_indirect_instruction->buffer.id), "OFFSET", dispatch_indirect_instruction->offset); + instruction_data_cursor += sizeof(ComputeListDispatchIndirectInstruction); + } break; + case ComputeListInstruction::TYPE_SET_PUSH_CONSTANT: { + const ComputeListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const ComputeListSetPushConstantInstruction *>(instruction); + print_line("\tSET PUSH CONSTANT SIZE", set_push_constant_instruction->size); + instruction_data_cursor += sizeof(ComputeListSetPushConstantInstruction); + instruction_data_cursor += set_push_constant_instruction->size; + } break; + case ComputeListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: { + const ComputeListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const ComputeListUniformSetPrepareForUseInstruction *>(instruction); + print_line("\tUNIFORM SET PREPARE FOR USE ID", itos(uniform_set_prepare_for_use_instruction->uniform_set.id), "SHADER ID", itos(uniform_set_prepare_for_use_instruction->shader.id), "INDEX", itos(uniform_set_prepare_for_use_instruction->set_index)); + instruction_data_cursor += sizeof(ComputeListUniformSetPrepareForUseInstruction); + } break; + default: + DEV_ASSERT(false && "Unknown compute list instruction type."); + return; + } + } +} + +void RenderingDeviceGraph::initialize(RDD *p_driver, uint32_t p_frame_count, uint32_t p_secondary_command_buffers_per_frame) { + driver = p_driver; + frames.resize(p_frame_count); + + for (uint32_t i = 0; i < p_frame_count; i++) { + frames[i].secondary_command_buffers.resize(p_secondary_command_buffers_per_frame); + + for (uint32_t j = 0; j < p_secondary_command_buffers_per_frame; j++) { + SecondaryCommandBuffer &secondary = frames[i].secondary_command_buffers[j]; + secondary.command_pool = driver->command_pool_create(RDD::COMMAND_BUFFER_TYPE_SECONDARY); + secondary.command_buffer = driver->command_buffer_create(RDD::COMMAND_BUFFER_TYPE_SECONDARY, secondary.command_pool); + secondary.task = WorkerThreadPool::INVALID_TASK_ID; + } + } + + driver_honors_barriers = driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS); +} + +void RenderingDeviceGraph::begin() { + command_data.clear(); + command_data_offsets.clear(); + command_normalization_barriers.clear(); + command_transition_barriers.clear(); + command_label_chars.clear(); + command_label_colors.clear(); + command_label_offsets.clear(); + command_list_nodes.clear(); + write_list_nodes.clear(); + command_count = 0; + command_label_count = 0; + command_timestamp_index = -1; + command_synchronization_index = -1; + command_synchronization_pending = false; + command_label_index = -1; + frames[frame].secondary_command_buffers_used = 0; + draw_instruction_list.index = 0; + compute_instruction_list.index = 0; + tracking_frame++; + +#ifdef DEV_ENABLED + write_dependency_counters.clear(); +#endif +} + +void RenderingDeviceGraph::add_buffer_clear(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_offset, uint32_t p_size) { + DEV_ASSERT(p_dst_tracker != nullptr); + + int32_t command_index; + RecordedBufferClearCommand *command = static_cast<RecordedBufferClearCommand *>(_allocate_command(sizeof(RecordedBufferClearCommand), command_index)); + command->type = RecordedCommand::TYPE_BUFFER_CLEAR; + command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->buffer = p_dst; + command->offset = p_offset; + command->size = p_size; + + ResourceUsage usage = RESOURCE_USAGE_TRANSFER_TO; + _add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command); +} + +void RenderingDeviceGraph::add_buffer_copy(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, RDD::BufferCopyRegion p_region) { + // Source tracker is allowed to be null as it could be a read-only buffer. + DEV_ASSERT(p_dst_tracker != nullptr); + + int32_t command_index; + RecordedBufferCopyCommand *command = static_cast<RecordedBufferCopyCommand *>(_allocate_command(sizeof(RecordedBufferCopyCommand), command_index)); + command->type = RecordedCommand::TYPE_BUFFER_COPY; + command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->source = p_src; + command->destination = p_dst; + command->region = p_region; + + ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker }; + ResourceUsage usages[2] = { RESOURCE_USAGE_TRANSFER_TO, RESOURCE_USAGE_TRANSFER_FROM }; + _add_command_to_graph(trackers, usages, p_src_tracker != nullptr ? 2 : 1, command_index, command); +} + +void RenderingDeviceGraph::add_buffer_get_data(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, RDD::BufferCopyRegion p_region) { + // Source tracker is allowed to be null as it could be a read-only buffer. + int32_t command_index; + RecordedBufferGetDataCommand *command = static_cast<RecordedBufferGetDataCommand *>(_allocate_command(sizeof(RecordedBufferGetDataCommand), command_index)); + command->type = RecordedCommand::TYPE_BUFFER_GET_DATA; + command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->source = p_src; + command->destination = p_dst; + command->region = p_region; + + if (p_src_tracker != nullptr) { + ResourceUsage usage = RESOURCE_USAGE_TRANSFER_FROM; + _add_command_to_graph(&p_src_tracker, &usage, 1, command_index, command); + } else { + _add_command_to_graph(nullptr, nullptr, 0, command_index, command); + } +} + +void RenderingDeviceGraph::add_buffer_update(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferCopy> p_buffer_copies) { + DEV_ASSERT(p_dst_tracker != nullptr); + + size_t buffer_copies_size = p_buffer_copies.size() * sizeof(RecordedBufferCopy); + uint64_t command_size = sizeof(RecordedBufferUpdateCommand) + buffer_copies_size; + int32_t command_index; + RecordedBufferUpdateCommand *command = static_cast<RecordedBufferUpdateCommand *>(_allocate_command(command_size, command_index)); + command->type = RecordedCommand::TYPE_BUFFER_UPDATE; + command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->destination = p_dst; + command->buffer_copies_count = p_buffer_copies.size(); + + RecordedBufferCopy *buffer_copies = command->buffer_copies(); + for (uint32_t i = 0; i < command->buffer_copies_count; i++) { + buffer_copies[i] = p_buffer_copies[i]; + } + + ResourceUsage buffer_usage = RESOURCE_USAGE_TRANSFER_TO; + _add_command_to_graph(&p_dst_tracker, &buffer_usage, 1, command_index, command); +} + +void RenderingDeviceGraph::add_compute_list_begin() { + compute_instruction_list.clear(); + compute_instruction_list.index++; +} + +void RenderingDeviceGraph::add_compute_list_bind_pipeline(RDD::PipelineID p_pipeline) { + ComputeListBindPipelineInstruction *instruction = reinterpret_cast<ComputeListBindPipelineInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListBindPipelineInstruction))); + instruction->type = ComputeListInstruction::TYPE_BIND_PIPELINE; + instruction->pipeline = p_pipeline; + compute_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); +} + +void RenderingDeviceGraph::add_compute_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) { + ComputeListBindUniformSetInstruction *instruction = reinterpret_cast<ComputeListBindUniformSetInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListBindUniformSetInstruction))); + instruction->type = ComputeListInstruction::TYPE_BIND_UNIFORM_SET; + instruction->shader = p_shader; + instruction->uniform_set = p_uniform_set; + instruction->set_index = set_index; +} + +void RenderingDeviceGraph::add_compute_list_dispatch(uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) { + ComputeListDispatchInstruction *instruction = reinterpret_cast<ComputeListDispatchInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListDispatchInstruction))); + instruction->type = ComputeListInstruction::TYPE_DISPATCH; + instruction->x_groups = p_x_groups; + instruction->y_groups = p_y_groups; + instruction->z_groups = p_z_groups; +} + +void RenderingDeviceGraph::add_compute_list_dispatch_indirect(RDD::BufferID p_buffer, uint32_t p_offset) { + ComputeListDispatchIndirectInstruction *instruction = reinterpret_cast<ComputeListDispatchIndirectInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListDispatchIndirectInstruction))); + instruction->type = ComputeListInstruction::TYPE_DISPATCH_INDIRECT; + instruction->buffer = p_buffer; + instruction->offset = p_offset; + compute_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT); +} + +void RenderingDeviceGraph::add_compute_list_set_push_constant(RDD::ShaderID p_shader, const void *p_data, uint32_t p_data_size) { + uint32_t instruction_size = sizeof(ComputeListSetPushConstantInstruction) + p_data_size; + ComputeListSetPushConstantInstruction *instruction = reinterpret_cast<ComputeListSetPushConstantInstruction *>(_allocate_compute_list_instruction(instruction_size)); + instruction->type = ComputeListInstruction::TYPE_SET_PUSH_CONSTANT; + instruction->size = p_data_size; + instruction->shader = p_shader; + memcpy(instruction->data(), p_data, p_data_size); +} + +void RenderingDeviceGraph::add_compute_list_uniform_set_prepare_for_use(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) { + ComputeListUniformSetPrepareForUseInstruction *instruction = reinterpret_cast<ComputeListUniformSetPrepareForUseInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListUniformSetPrepareForUseInstruction))); + instruction->type = ComputeListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE; + instruction->shader = p_shader; + instruction->uniform_set = p_uniform_set; + instruction->set_index = set_index; +} + +void RenderingDeviceGraph::add_compute_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage) { + DEV_ASSERT(p_tracker != nullptr); + + p_tracker->reset_if_outdated(tracking_frame); + + if (p_tracker->compute_list_index != compute_instruction_list.index) { + compute_instruction_list.command_trackers.push_back(p_tracker); + compute_instruction_list.command_tracker_usages.push_back(p_usage); + p_tracker->compute_list_index = compute_instruction_list.index; + } +} + +void RenderingDeviceGraph::add_compute_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages) { + DEV_ASSERT(p_trackers.size() == p_usages.size()); + + for (uint32_t i = 0; i < p_trackers.size(); i++) { + add_compute_list_usage(p_trackers[i], p_usages[i]); + } +} + +void RenderingDeviceGraph::add_compute_list_end() { + int32_t command_index; + uint32_t instruction_data_size = compute_instruction_list.data.size(); + uint32_t command_size = sizeof(RecordedComputeListCommand) + instruction_data_size; + RecordedComputeListCommand *command = static_cast<RecordedComputeListCommand *>(_allocate_command(command_size, command_index)); + command->type = RecordedCommand::TYPE_COMPUTE_LIST; + command->dst_stages = compute_instruction_list.stages; + command->instruction_data_size = instruction_data_size; + memcpy(command->instruction_data(), compute_instruction_list.data.ptr(), instruction_data_size); + _add_command_to_graph(compute_instruction_list.command_trackers.ptr(), compute_instruction_list.command_tracker_usages.ptr(), compute_instruction_list.command_trackers.size(), command_index, command); +} + +void RenderingDeviceGraph::add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView<RDD::RenderPassClearValue> p_clear_values, bool p_uses_color, bool p_uses_depth) { + draw_instruction_list.clear(); + draw_instruction_list.index++; + draw_instruction_list.render_pass = p_render_pass; + draw_instruction_list.framebuffer = p_framebuffer; + draw_instruction_list.region = p_region; + draw_instruction_list.clear_values.resize(p_clear_values.size()); + for (uint32_t i = 0; i < p_clear_values.size(); i++) { + draw_instruction_list.clear_values[i] = p_clear_values[i]; + } + + if (p_uses_color) { + draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + } + + if (p_uses_depth) { + draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); + draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); + } +} + +void RenderingDeviceGraph::add_draw_list_bind_index_buffer(RDD::BufferID p_buffer, RDD::IndexBufferFormat p_format, uint32_t p_offset) { + DrawListBindIndexBufferInstruction *instruction = reinterpret_cast<DrawListBindIndexBufferInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListBindIndexBufferInstruction))); + instruction->type = DrawListInstruction::TYPE_BIND_INDEX_BUFFER; + instruction->buffer = p_buffer; + instruction->format = p_format; + instruction->offset = p_offset; + + if (instruction->buffer.id != 0) { + draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT); + } +} + +void RenderingDeviceGraph::add_draw_list_bind_pipeline(RDD::PipelineID p_pipeline, BitField<RDD::PipelineStageBits> p_pipeline_stage_bits) { + DrawListBindPipelineInstruction *instruction = reinterpret_cast<DrawListBindPipelineInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListBindPipelineInstruction))); + instruction->type = DrawListInstruction::TYPE_BIND_PIPELINE; + instruction->pipeline = p_pipeline; + draw_instruction_list.stages = draw_instruction_list.stages | p_pipeline_stage_bits; +} + +void RenderingDeviceGraph::add_draw_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) { + DrawListBindUniformSetInstruction *instruction = reinterpret_cast<DrawListBindUniformSetInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListBindUniformSetInstruction))); + instruction->type = DrawListInstruction::TYPE_BIND_UNIFORM_SET; + instruction->shader = p_shader; + instruction->uniform_set = p_uniform_set; + instruction->set_index = set_index; +} + +void RenderingDeviceGraph::add_draw_list_bind_vertex_buffers(VectorView<RDD::BufferID> p_vertex_buffers, VectorView<uint64_t> p_vertex_buffer_offsets) { + DEV_ASSERT(p_vertex_buffers.size() == p_vertex_buffer_offsets.size()); + + uint32_t instruction_size = sizeof(DrawListBindVertexBuffersInstruction) + sizeof(RDD::BufferID) * p_vertex_buffers.size() + sizeof(uint64_t) * p_vertex_buffer_offsets.size(); + DrawListBindVertexBuffersInstruction *instruction = reinterpret_cast<DrawListBindVertexBuffersInstruction *>(_allocate_draw_list_instruction(instruction_size)); + instruction->type = DrawListInstruction::TYPE_BIND_VERTEX_BUFFERS; + instruction->vertex_buffers_count = p_vertex_buffers.size(); + + RDD::BufferID *vertex_buffers = instruction->vertex_buffers(); + uint64_t *vertex_buffer_offsets = instruction->vertex_buffer_offsets(); + for (uint32_t i = 0; i < instruction->vertex_buffers_count; i++) { + vertex_buffers[i] = p_vertex_buffers[i]; + vertex_buffer_offsets[i] = p_vertex_buffer_offsets[i]; + } + + if (instruction->vertex_buffers_count > 0) { + draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT); + } +} + +void RenderingDeviceGraph::add_draw_list_clear_attachments(VectorView<RDD::AttachmentClear> p_attachments_clear, VectorView<Rect2i> p_attachments_clear_rect) { + uint32_t instruction_size = sizeof(DrawListClearAttachmentsInstruction) + sizeof(RDD::AttachmentClear) * p_attachments_clear.size() + sizeof(Rect2i) * p_attachments_clear_rect.size(); + DrawListClearAttachmentsInstruction *instruction = reinterpret_cast<DrawListClearAttachmentsInstruction *>(_allocate_draw_list_instruction(instruction_size)); + instruction->type = DrawListInstruction::TYPE_CLEAR_ATTACHMENTS; + instruction->attachments_clear_count = p_attachments_clear.size(); + instruction->attachments_clear_rect_count = p_attachments_clear_rect.size(); + + RDD::AttachmentClear *attachments_clear = instruction->attachments_clear(); + Rect2i *attachments_clear_rect = instruction->attachments_clear_rect(); + for (uint32_t i = 0; i < instruction->attachments_clear_count; i++) { + attachments_clear[i] = p_attachments_clear[i]; + } + + for (uint32_t i = 0; i < instruction->attachments_clear_rect_count; i++) { + attachments_clear_rect[i] = p_attachments_clear_rect[i]; + } +} + +void RenderingDeviceGraph::add_draw_list_draw(uint32_t p_vertex_count, uint32_t p_instance_count) { + DrawListDrawInstruction *instruction = reinterpret_cast<DrawListDrawInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawInstruction))); + instruction->type = DrawListInstruction::TYPE_DRAW; + instruction->vertex_count = p_vertex_count; + instruction->instance_count = p_instance_count; +} + +void RenderingDeviceGraph::add_draw_list_draw_indexed(uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index) { + DrawListDrawIndexedInstruction *instruction = reinterpret_cast<DrawListDrawIndexedInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndexedInstruction))); + instruction->type = DrawListInstruction::TYPE_DRAW_INDEXED; + instruction->index_count = p_index_count; + instruction->instance_count = p_instance_count; + instruction->first_index = p_first_index; +} + +void RenderingDeviceGraph::add_draw_list_execute_commands(RDD::CommandBufferID p_command_buffer) { + DrawListExecuteCommandsInstruction *instruction = reinterpret_cast<DrawListExecuteCommandsInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListExecuteCommandsInstruction))); + instruction->type = DrawListInstruction::TYPE_EXECUTE_COMMANDS; + instruction->command_buffer = p_command_buffer; +} + +void RenderingDeviceGraph::add_draw_list_next_subpass(RDD::CommandBufferType p_command_buffer_type) { + DrawListNextSubpassInstruction *instruction = reinterpret_cast<DrawListNextSubpassInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListNextSubpassInstruction))); + instruction->type = DrawListInstruction::TYPE_NEXT_SUBPASS; + instruction->command_buffer_type = p_command_buffer_type; +} + +void RenderingDeviceGraph::add_draw_list_set_blend_constants(const Color &p_color) { + DrawListSetBlendConstantsInstruction *instruction = reinterpret_cast<DrawListSetBlendConstantsInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListSetBlendConstantsInstruction))); + instruction->type = DrawListInstruction::TYPE_SET_BLEND_CONSTANTS; + instruction->color = p_color; +} + +void RenderingDeviceGraph::add_draw_list_set_line_width(float p_width) { + DrawListSetLineWidthInstruction *instruction = reinterpret_cast<DrawListSetLineWidthInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListSetLineWidthInstruction))); + instruction->type = DrawListInstruction::TYPE_SET_LINE_WIDTH; + instruction->width = p_width; +} + +void RenderingDeviceGraph::add_draw_list_set_push_constant(RDD::ShaderID p_shader, const void *p_data, uint32_t p_data_size) { + uint32_t instruction_size = sizeof(DrawListSetPushConstantInstruction) + p_data_size; + DrawListSetPushConstantInstruction *instruction = reinterpret_cast<DrawListSetPushConstantInstruction *>(_allocate_draw_list_instruction(instruction_size)); + instruction->type = DrawListInstruction::TYPE_SET_PUSH_CONSTANT; + instruction->size = p_data_size; + instruction->shader = p_shader; + memcpy(instruction->data(), p_data, p_data_size); +} + +void RenderingDeviceGraph::add_draw_list_set_scissor(Rect2i p_rect) { + DrawListSetScissorInstruction *instruction = reinterpret_cast<DrawListSetScissorInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListSetScissorInstruction))); + instruction->type = DrawListInstruction::TYPE_SET_SCISSOR; + instruction->rect = p_rect; +} + +void RenderingDeviceGraph::add_draw_list_set_viewport(Rect2i p_rect) { + DrawListSetViewportInstruction *instruction = reinterpret_cast<DrawListSetViewportInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListSetViewportInstruction))); + instruction->type = DrawListInstruction::TYPE_SET_VIEWPORT; + instruction->rect = p_rect; +} + +void RenderingDeviceGraph::add_draw_list_uniform_set_prepare_for_use(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) { + DrawListUniformSetPrepareForUseInstruction *instruction = reinterpret_cast<DrawListUniformSetPrepareForUseInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListUniformSetPrepareForUseInstruction))); + instruction->type = DrawListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE; + instruction->shader = p_shader; + instruction->uniform_set = p_uniform_set; + instruction->set_index = set_index; +} + +void RenderingDeviceGraph::add_draw_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage) { + p_tracker->reset_if_outdated(tracking_frame); + + if (p_tracker->draw_list_index != draw_instruction_list.index) { + draw_instruction_list.command_trackers.push_back(p_tracker); + draw_instruction_list.command_tracker_usages.push_back(p_usage); + p_tracker->draw_list_index = draw_instruction_list.index; + } +} + +void RenderingDeviceGraph::add_draw_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages) { + DEV_ASSERT(p_trackers.size() == p_usages.size()); + + for (uint32_t i = 0; i < p_trackers.size(); i++) { + add_draw_list_usage(p_trackers[i], p_usages[i]); + } +} + +void RenderingDeviceGraph::add_draw_list_end() { + // Arbitrary size threshold to evaluate if it'd be best to record the draw list on the background as a secondary buffer. + const uint32_t instruction_data_threshold_for_secondary = 16384; + RDD::CommandBufferType command_buffer_type; + uint32_t &secondary_buffers_used = frames[frame].secondary_command_buffers_used; + if (draw_instruction_list.data.size() > instruction_data_threshold_for_secondary && secondary_buffers_used < frames[frame].secondary_command_buffers.size()) { + // Copy the current instruction list data into another array that will be used by the secondary command buffer worker. + SecondaryCommandBuffer &secondary = frames[frame].secondary_command_buffers[secondary_buffers_used]; + secondary.render_pass = draw_instruction_list.render_pass; + secondary.framebuffer = draw_instruction_list.framebuffer; + secondary.instruction_data.resize(draw_instruction_list.data.size()); + memcpy(secondary.instruction_data.ptr(), draw_instruction_list.data.ptr(), draw_instruction_list.data.size()); + + // Run a background task for recording the secondary command buffer. + secondary.task = WorkerThreadPool::get_singleton()->add_template_task(this, &RenderingDeviceGraph::_run_secondary_command_buffer_task, &secondary, true); + + // Clear the instruction list and add a single command for executing the secondary command buffer instead. + draw_instruction_list.data.clear(); + add_draw_list_execute_commands(secondary.command_buffer); + secondary_buffers_used++; + + command_buffer_type = RDD::COMMAND_BUFFER_TYPE_SECONDARY; + } else { + command_buffer_type = RDD::COMMAND_BUFFER_TYPE_PRIMARY; + } + + int32_t command_index; + uint32_t clear_values_size = sizeof(RDD::RenderPassClearValue) * draw_instruction_list.clear_values.size(); + uint32_t instruction_data_size = draw_instruction_list.data.size(); + uint32_t command_size = sizeof(RecordedDrawListCommand) + clear_values_size + instruction_data_size; + RecordedDrawListCommand *command = static_cast<RecordedDrawListCommand *>(_allocate_command(command_size, command_index)); + command->type = RecordedCommand::TYPE_DRAW_LIST; + command->dst_stages = draw_instruction_list.stages; + command->instruction_data_size = instruction_data_size; + command->render_pass = draw_instruction_list.render_pass; + command->framebuffer = draw_instruction_list.framebuffer; + command->command_buffer_type = command_buffer_type; + command->region = draw_instruction_list.region; + command->clear_values_count = draw_instruction_list.clear_values.size(); + + RDD::RenderPassClearValue *clear_values = command->clear_values(); + for (uint32_t i = 0; i < command->clear_values_count; i++) { + clear_values[i] = draw_instruction_list.clear_values[i]; + } + + memcpy(command->instruction_data(), draw_instruction_list.data.ptr(), instruction_data_size); + _add_command_to_graph(draw_instruction_list.command_trackers.ptr(), draw_instruction_list.command_tracker_usages.ptr(), draw_instruction_list.command_trackers.size(), command_index, command); +} + +void RenderingDeviceGraph::add_texture_clear(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, const Color &p_color, const RDD::TextureSubresourceRange &p_range) { + DEV_ASSERT(p_dst_tracker != nullptr); + + int32_t command_index; + RecordedTextureClearCommand *command = static_cast<RecordedTextureClearCommand *>(_allocate_command(sizeof(RecordedTextureClearCommand), command_index)); + command->type = RecordedCommand::TYPE_TEXTURE_CLEAR; + command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->texture = p_dst; + command->color = p_color; + command->range = p_range; + + ResourceUsage usage = RESOURCE_USAGE_TRANSFER_TO; + _add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command); +} + +void RenderingDeviceGraph::add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, RDD::TextureCopyRegion p_region) { + DEV_ASSERT(p_src_tracker != nullptr); + DEV_ASSERT(p_dst_tracker != nullptr); + + int32_t command_index; + RecordedTextureCopyCommand *command = static_cast<RecordedTextureCopyCommand *>(_allocate_command(sizeof(RecordedTextureCopyCommand), command_index)); + command->type = RecordedCommand::TYPE_TEXTURE_COPY; + command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->from_texture = p_src; + command->to_texture = p_dst; + command->region = p_region; + + ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker }; + ResourceUsage usages[2] = { RESOURCE_USAGE_TRANSFER_TO, RESOURCE_USAGE_TRANSFER_FROM }; + _add_command_to_graph(trackers, usages, 2, command_index, command); +} + +void RenderingDeviceGraph::add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions) { + DEV_ASSERT(p_src_tracker != nullptr); + + int32_t command_index; + uint64_t command_size = sizeof(RecordedTextureGetDataCommand) + p_buffer_texture_copy_regions.size() * sizeof(RDD::BufferTextureCopyRegion); + RecordedTextureGetDataCommand *command = static_cast<RecordedTextureGetDataCommand *>(_allocate_command(command_size, command_index)); + command->type = RecordedCommand::TYPE_TEXTURE_GET_DATA; + command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->from_texture = p_src; + command->to_buffer = p_dst; + command->buffer_texture_copy_regions_count = p_buffer_texture_copy_regions.size(); + + RDD::BufferTextureCopyRegion *buffer_texture_copy_regions = command->buffer_texture_copy_regions(); + for (uint32_t i = 0; i < command->buffer_texture_copy_regions_count; i++) { + buffer_texture_copy_regions[i] = p_buffer_texture_copy_regions[i]; + } + + ResourceUsage usage = RESOURCE_USAGE_TRANSFER_FROM; + _add_command_to_graph(&p_src_tracker, &usage, 1, command_index, command); +} + +void RenderingDeviceGraph::add_texture_resolve(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_src_layer, uint32_t p_src_mipmap, uint32_t p_dst_layer, uint32_t p_dst_mipmap) { + DEV_ASSERT(p_src_tracker != nullptr); + DEV_ASSERT(p_dst_tracker != nullptr); + + int32_t command_index; + RecordedTextureResolveCommand *command = static_cast<RecordedTextureResolveCommand *>(_allocate_command(sizeof(RecordedTextureResolveCommand), command_index)); + command->type = RecordedCommand::TYPE_TEXTURE_RESOLVE; + command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->from_texture = p_src; + command->to_texture = p_dst; + command->src_layer = p_src_layer; + command->src_mipmap = p_src_mipmap; + command->dst_layer = p_dst_layer; + command->dst_mipmap = p_dst_mipmap; + + ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker }; + ResourceUsage usages[2] = { RESOURCE_USAGE_TRANSFER_TO, RESOURCE_USAGE_TRANSFER_FROM }; + _add_command_to_graph(trackers, usages, 2, command_index, command); +} + +void RenderingDeviceGraph::add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies) { + DEV_ASSERT(p_dst_tracker != nullptr); + + int32_t command_index; + uint64_t command_size = sizeof(RecordedTextureUpdateCommand) + p_buffer_copies.size() * sizeof(RecordedBufferToTextureCopy); + RecordedTextureUpdateCommand *command = static_cast<RecordedTextureUpdateCommand *>(_allocate_command(command_size, command_index)); + command->type = RecordedCommand::TYPE_TEXTURE_UPDATE; + command->dst_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + command->to_texture = p_dst; + command->buffer_to_texture_copies_count = p_buffer_copies.size(); + + RecordedBufferToTextureCopy *buffer_to_texture_copies = command->buffer_to_texture_copies(); + for (uint32_t i = 0; i < command->buffer_to_texture_copies_count; i++) { + buffer_to_texture_copies[i] = p_buffer_copies[i]; + } + + ResourceUsage usage = RESOURCE_USAGE_TRANSFER_TO; + _add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command); +} + +void RenderingDeviceGraph::add_capture_timestamp(RDD::QueryPoolID p_query_pool, uint32_t p_index) { + int32_t command_index; + RecordedCaptureTimestampCommand *command = static_cast<RecordedCaptureTimestampCommand *>(_allocate_command(sizeof(RecordedCaptureTimestampCommand), command_index)); + command->type = RecordedCommand::TYPE_CAPTURE_TIMESTAMP; + command->dst_stages = 0; + command->pool = p_query_pool; + command->index = p_index; + _add_command_to_graph(nullptr, nullptr, 0, command_index, command); +} + +void RenderingDeviceGraph::add_synchronization() { + // Synchronization is only acknowledged if commands have been recorded on the graph already. + if (command_count > 0) { + command_synchronization_pending = true; + } +} + +void RenderingDeviceGraph::begin_label(const String &p_label_name, const Color &p_color) { + uint32_t command_label_offset = command_label_chars.size(); + PackedByteArray command_label_utf8 = p_label_name.to_utf8_buffer(); + int command_label_utf8_size = command_label_utf8.size(); + command_label_chars.resize(command_label_offset + command_label_utf8_size + 1); + memcpy(&command_label_chars[command_label_offset], command_label_utf8.ptr(), command_label_utf8.size()); + command_label_chars[command_label_offset + command_label_utf8_size] = '\0'; + command_label_colors.push_back(p_color); + command_label_offsets.push_back(command_label_offset); + command_label_index = command_label_count; + command_label_count++; +} + +void RenderingDeviceGraph::end_label() { + command_label_index = -1; +} + +void RenderingDeviceGraph::end(RDD::CommandBufferID p_command_buffer, bool p_reorder_commands, bool p_full_barriers) { + if (command_count == 0) { + // No commands have been logged, do nothing. + return; + } + + thread_local LocalVector<RecordedCommandSort> commands_sorted; + if (p_reorder_commands) { + thread_local LocalVector<int64_t> command_stack; + thread_local LocalVector<int32_t> sorted_command_indices; + thread_local LocalVector<uint32_t> command_degrees; + int32_t adjacency_list_index = 0; + int32_t command_index; + + // Count all the incoming connections to every node by traversing their adjacency list. + command_degrees.resize(command_count); + memset(command_degrees.ptr(), 0, sizeof(uint32_t) * command_degrees.size()); + for (uint32_t i = 0; i < command_count; i++) { + const RecordedCommand &recorded_command = *reinterpret_cast<const RecordedCommand *>(&command_data[command_data_offsets[i]]); + adjacency_list_index = recorded_command.adjacent_command_list_index; + while (adjacency_list_index >= 0) { + const RecordedCommandListNode &command_list_node = command_list_nodes[adjacency_list_index]; + DEV_ASSERT((command_list_node.command_index != int32_t(i)) && "Command can't have itself as a dependency."); + command_degrees[command_list_node.command_index] += 1; + adjacency_list_index = command_list_node.next_list_index; + } + } + + // Push to the stack all nodes that have no incoming connections. + command_stack.clear(); + for (uint32_t i = 0; i < command_count; i++) { + if (command_degrees[i] == 0) { + command_stack.push_back(i); + } + } + + sorted_command_indices.clear(); + while (!command_stack.is_empty()) { + // Pop command from the stack. + command_index = command_stack[command_stack.size() - 1]; + command_stack.resize(command_stack.size() - 1); + + // Add it to the sorted commands. + sorted_command_indices.push_back(command_index); + + // Search for its adjacents and lower their degree for every visit. If the degree reaches zero, we push the command to the stack. + const uint32_t command_data_offset = command_data_offsets[command_index]; + const RecordedCommand &recorded_command = *reinterpret_cast<const RecordedCommand *>(&command_data[command_data_offset]); + adjacency_list_index = recorded_command.adjacent_command_list_index; + while (adjacency_list_index >= 0) { + const RecordedCommandListNode &command_list_node = command_list_nodes[adjacency_list_index]; + uint32_t &command_degree = command_degrees[command_list_node.command_index]; + DEV_ASSERT(command_degree > 0); + command_degree--; + if (command_degree == 0) { + command_stack.push_back(command_list_node.command_index); + } + + adjacency_list_index = command_list_node.next_list_index; + } + } + + // Batch buffer, texture, draw lists and compute operations together. + const uint32_t PriorityTable[RecordedCommand::TYPE_MAX] = { + 0, // TYPE_NONE + 1, // TYPE_BUFFER_CLEAR + 1, // TYPE_BUFFER_COPY + 1, // TYPE_BUFFER_GET_DATA + 1, // TYPE_BUFFER_UPDATE + 4, // TYPE_COMPUTE_LIST + 3, // TYPE_DRAW_LIST + 2, // TYPE_TEXTURE_CLEAR + 2, // TYPE_TEXTURE_COPY + 2, // TYPE_TEXTURE_GET_DATA + 2, // TYPE_TEXTURE_RESOLVE + 2, // TYPE_TEXTURE_UPDATE + }; + + commands_sorted.clear(); + commands_sorted.resize(command_count); + + for (uint32_t i = 0; i < command_count; i++) { + const int32_t sorted_command_index = sorted_command_indices[i]; + const uint32_t command_data_offset = command_data_offsets[sorted_command_index]; + const RecordedCommand recorded_command = *reinterpret_cast<const RecordedCommand *>(&command_data[command_data_offset]); + const uint32_t next_command_level = commands_sorted[sorted_command_index].level + 1; + adjacency_list_index = recorded_command.adjacent_command_list_index; + while (adjacency_list_index >= 0) { + const RecordedCommandListNode &command_list_node = command_list_nodes[adjacency_list_index]; + uint32_t &adjacent_command_level = commands_sorted[command_list_node.command_index].level; + if (adjacent_command_level < next_command_level) { + adjacent_command_level = next_command_level; + } + + adjacency_list_index = command_list_node.next_list_index; + } + + commands_sorted[sorted_command_index].index = sorted_command_index; + commands_sorted[sorted_command_index].priority = PriorityTable[recorded_command.type]; + } + } else { + commands_sorted.clear(); + commands_sorted.resize(command_count); + + for (uint32_t i = 0; i < command_count; i++) { + commands_sorted[i].index = i; + } + } + + _wait_for_secondary_command_buffer_tasks(); + + if (command_count > 0) { + int32_t current_label_index = -1; + int32_t current_label_level = -1; + _run_label_command_change(p_command_buffer, -1, -1, true, true, nullptr, 0, current_label_index, current_label_level); + + if (p_reorder_commands) { +#if PRINT_RENDER_GRAPH + print_line("BEFORE SORT"); + _print_render_commands(commands_sorted.ptr(), command_count); +#endif + + commands_sorted.sort(); + +#if PRINT_RENDER_GRAPH + print_line("AFTER SORT"); + _print_render_commands(commands_sorted.ptr(), command_count); +#endif + + uint32_t boosted_priority = 0; + uint32_t current_level = commands_sorted[0].level; + uint32_t current_level_start = 0; + for (uint32_t i = 0; i < command_count; i++) { + if (current_level != commands_sorted[i].level) { + RecordedCommandSort *level_command_ptr = &commands_sorted[current_level_start]; + uint32_t level_command_count = i - current_level_start; + _boost_priority_for_render_commands(level_command_ptr, level_command_count, boosted_priority); + _group_barriers_for_render_commands(p_command_buffer, level_command_ptr, level_command_count, p_full_barriers); + _run_render_commands(p_command_buffer, current_level, level_command_ptr, level_command_count, current_label_index, current_label_level); + current_level = commands_sorted[i].level; + current_level_start = i; + } + } + + RecordedCommandSort *level_command_ptr = &commands_sorted[current_level_start]; + uint32_t level_command_count = command_count - current_level_start; + _boost_priority_for_render_commands(level_command_ptr, level_command_count, boosted_priority); + _group_barriers_for_render_commands(p_command_buffer, level_command_ptr, level_command_count, p_full_barriers); + _run_render_commands(p_command_buffer, current_level, level_command_ptr, level_command_count, current_label_index, current_label_level); + +#if PRINT_RENDER_GRAPH + print_line("COMMANDS", command_count, "LEVELS", current_level + 1); +#endif + } else { + for (uint32_t i = 0; i < command_count; i++) { + _group_barriers_for_render_commands(p_command_buffer, &commands_sorted[i], 1, p_full_barriers); + _run_render_commands(p_command_buffer, i, &commands_sorted[i], 1, current_label_index, current_label_level); + } + } + + _run_label_command_change(p_command_buffer, -1, -1, true, false, nullptr, 0, current_label_index, current_label_level); + } + + // Advance the frame counter. It's not necessary to do this if no commands are recorded because that means no secondary command buffers were used. + frame = (frame + 1) % frames.size(); +} + +#if PRINT_RESOURCE_TRACKER_TOTAL +static uint32_t resource_tracker_total = 0; +#endif + +RenderingDeviceGraph::ResourceTracker *RenderingDeviceGraph::resource_tracker_create() { +#if PRINT_RESOURCE_TRACKER_TOTAL + print_line("Resource trackers:", ++resource_tracker_total); +#endif + return memnew(ResourceTracker); +} + +void RenderingDeviceGraph::resource_tracker_free(ResourceTracker *tracker) { + if (tracker == nullptr) { + return; + } + + if (tracker->in_parent_dirty_list) { + // Delete the tracker from the parent's dirty linked list. + if (tracker->parent->dirty_shared_list == tracker) { + tracker->parent->dirty_shared_list = tracker->next_shared; + } else { + ResourceTracker *node = tracker->parent->dirty_shared_list; + while (node != nullptr) { + if (node->next_shared == tracker) { + node->next_shared = tracker->next_shared; + node = nullptr; + } else { + node = node->next_shared; + } + } + } + } + + memdelete(tracker); + +#if PRINT_RESOURCE_TRACKER_TOTAL + print_line("Resource trackers:", --resource_tracker_total); +#endif +} diff --git a/servers/rendering/rendering_device_graph.h b/servers/rendering/rendering_device_graph.h new file mode 100644 index 0000000000..84fbe02095 --- /dev/null +++ b/servers/rendering/rendering_device_graph.h @@ -0,0 +1,668 @@ +/**************************************************************************/ +/* rendering_device_graph.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef RENDERING_DEVICE_GRAPH_H +#define RENDERING_DEVICE_GRAPH_H + +#include "core/object/worker_thread_pool.h" +#include "rendering_device_commons.h" +#include "rendering_device_driver.h" + +// Buffer barriers have not shown any significant improvement or shown to be +// even detrimental to performance. However, there are currently some known +// cases where using them can solve problems that using singular memory +// barriers does not, probably due to driver issues (see comment on PR #84976 +// https://github.com/godotengine/godot/pull/84976#issuecomment-1878566830). + +#define USE_BUFFER_BARRIERS 1 + +class RenderingDeviceGraph { +public: + struct ComputeListInstruction { + enum Type { + TYPE_NONE, + TYPE_BIND_PIPELINE, + TYPE_BIND_UNIFORM_SET, + TYPE_DISPATCH, + TYPE_DISPATCH_INDIRECT, + TYPE_SET_PUSH_CONSTANT, + TYPE_UNIFORM_SET_PREPARE_FOR_USE + }; + + Type type = TYPE_NONE; + }; + + struct DrawListInstruction { + enum Type { + TYPE_NONE, + TYPE_BIND_INDEX_BUFFER, + TYPE_BIND_PIPELINE, + TYPE_BIND_UNIFORM_SET, + TYPE_BIND_VERTEX_BUFFERS, + TYPE_CLEAR_ATTACHMENTS, + TYPE_DRAW, + TYPE_DRAW_INDEXED, + TYPE_EXECUTE_COMMANDS, + TYPE_NEXT_SUBPASS, + TYPE_SET_BLEND_CONSTANTS, + TYPE_SET_LINE_WIDTH, + TYPE_SET_PUSH_CONSTANT, + TYPE_SET_SCISSOR, + TYPE_SET_VIEWPORT, + TYPE_UNIFORM_SET_PREPARE_FOR_USE + }; + + Type type = TYPE_NONE; + }; + + struct RecordedCommand { + enum Type { + TYPE_NONE, + TYPE_BUFFER_CLEAR, + TYPE_BUFFER_COPY, + TYPE_BUFFER_GET_DATA, + TYPE_BUFFER_UPDATE, + TYPE_COMPUTE_LIST, + TYPE_DRAW_LIST, + TYPE_TEXTURE_CLEAR, + TYPE_TEXTURE_COPY, + TYPE_TEXTURE_GET_DATA, + TYPE_TEXTURE_RESOLVE, + TYPE_TEXTURE_UPDATE, + TYPE_CAPTURE_TIMESTAMP, + TYPE_MAX + }; + + Type type = TYPE_NONE; + int32_t adjacent_command_list_index = -1; + RDD::MemoryBarrier memory_barrier; + int32_t normalization_barrier_index = -1; + int normalization_barrier_count = 0; + int32_t transition_barrier_index = -1; + int32_t transition_barrier_count = 0; +#if USE_BUFFER_BARRIERS + int32_t buffer_barrier_index = -1; + int32_t buffer_barrier_count = 0; +#endif + int32_t label_index = -1; + BitField<RDD::PipelineStageBits> src_stages; + BitField<RDD::PipelineStageBits> dst_stages; + }; + + struct RecordedBufferCopy { + RDD::BufferID source; + RDD::BufferCopyRegion region; + }; + + struct RecordedBufferToTextureCopy { + RDD::BufferID from_buffer; + RDD::BufferTextureCopyRegion region; + }; + + enum ResourceUsage { + RESOURCE_USAGE_NONE, + RESOURCE_USAGE_TRANSFER_FROM, + RESOURCE_USAGE_TRANSFER_TO, + RESOURCE_USAGE_UNIFORM_BUFFER_READ, + RESOURCE_USAGE_INDIRECT_BUFFER_READ, + RESOURCE_USAGE_TEXTURE_BUFFER_READ, + RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE, + RESOURCE_USAGE_STORAGE_BUFFER_READ, + RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE, + RESOURCE_USAGE_VERTEX_BUFFER_READ, + RESOURCE_USAGE_INDEX_BUFFER_READ, + RESOURCE_USAGE_TEXTURE_SAMPLE, + RESOURCE_USAGE_STORAGE_IMAGE_READ, + RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE, + RESOURCE_USAGE_ATTACHMENT_COLOR_READ, + RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE, + RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ, + RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE + }; + + struct ResourceTracker { + uint32_t reference_count = 0; + int64_t command_frame = -1; + int32_t read_command_list_index = -1; + int32_t write_command_or_list_index = -1; + int32_t draw_list_index = -1; + int32_t compute_list_index = -1; + ResourceUsage usage = RESOURCE_USAGE_NONE; + BitField<RDD::BarrierAccessBits> usage_access; + RDD::BufferID buffer_driver_id; + RDD::TextureID texture_driver_id; + RDD::TextureSubresourceRange texture_subresources; + int32_t texture_slice_command_index = -1; + ResourceTracker *parent = nullptr; + ResourceTracker *dirty_shared_list = nullptr; + ResourceTracker *next_shared = nullptr; + Rect2i texture_slice_or_dirty_rect; + bool in_parent_dirty_list = false; + bool write_command_list_enabled = false; + + _FORCE_INLINE_ void reset_if_outdated(int64_t new_command_frame) { + if (new_command_frame != command_frame) { + usage_access.clear(); + command_frame = new_command_frame; + read_command_list_index = -1; + write_command_or_list_index = -1; + draw_list_index = -1; + compute_list_index = -1; + texture_slice_command_index = -1; + write_command_list_enabled = false; + } + } + }; + +private: + struct InstructionList { + LocalVector<uint8_t> data; + LocalVector<ResourceTracker *> command_trackers; + LocalVector<ResourceUsage> command_tracker_usages; + BitField<RDD::PipelineStageBits> stages; + int32_t index = 0; + + void clear() { + data.clear(); + command_trackers.clear(); + command_tracker_usages.clear(); + stages.clear(); + } + }; + + struct ComputeInstructionList : InstructionList { + // No extra contents. + }; + + struct DrawInstructionList : InstructionList { + RDD::RenderPassID render_pass; + RDD::FramebufferID framebuffer; + Rect2i region; + LocalVector<RDD::RenderPassClearValue> clear_values; + }; + + struct RecordedCommandSort { + uint32_t level = 0; + uint32_t priority = 0; + int32_t index = -1; + + RecordedCommandSort() = default; + + bool operator<(const RecordedCommandSort &p_other) const { + if (level < p_other.level) { + return true; + } else if (level > p_other.level) { + return false; + } + + if (priority < p_other.priority) { + return true; + } else if (priority > p_other.priority) { + return false; + } + + return index < p_other.index; + } + }; + + struct RecordedCommandListNode { + int32_t command_index = -1; + int32_t next_list_index = -1; + }; + + struct RecordedWriteListNode { + int32_t command_index = -1; + int32_t next_list_index = -1; + Rect2i subresources; + }; + + struct RecordedBufferClearCommand : RecordedCommand { + RDD::BufferID buffer; + uint32_t offset = 0; + uint32_t size = 0; + }; + + struct RecordedBufferCopyCommand : RecordedCommand { + RDD::BufferID source; + RDD::BufferID destination; + RDD::BufferCopyRegion region; + }; + + struct RecordedBufferGetDataCommand : RecordedCommand { + RDD::BufferID source; + RDD::BufferID destination; + RDD::BufferCopyRegion region; + }; + + struct RecordedBufferUpdateCommand : RecordedCommand { + RDD::BufferID destination; + uint32_t buffer_copies_count = 0; + + _FORCE_INLINE_ RecordedBufferCopy *buffer_copies() { + return reinterpret_cast<RecordedBufferCopy *>(&this[1]); + } + + _FORCE_INLINE_ const RecordedBufferCopy *buffer_copies() const { + return reinterpret_cast<const RecordedBufferCopy *>(&this[1]); + } + }; + + struct RecordedComputeListCommand : RecordedCommand { + uint32_t instruction_data_size = 0; + + _FORCE_INLINE_ uint8_t *instruction_data() { + return reinterpret_cast<uint8_t *>(&this[1]); + } + + _FORCE_INLINE_ const uint8_t *instruction_data() const { + return reinterpret_cast<const uint8_t *>(&this[1]); + } + }; + + struct RecordedDrawListCommand : RecordedCommand { + uint32_t instruction_data_size = 0; + RDD::RenderPassID render_pass; + RDD::FramebufferID framebuffer; + RDD::CommandBufferType command_buffer_type; + Rect2i region; + uint32_t clear_values_count = 0; + + _FORCE_INLINE_ RDD::RenderPassClearValue *clear_values() { + return reinterpret_cast<RDD::RenderPassClearValue *>(&this[1]); + } + + _FORCE_INLINE_ const RDD::RenderPassClearValue *clear_values() const { + return reinterpret_cast<const RDD::RenderPassClearValue *>(&this[1]); + } + + _FORCE_INLINE_ uint8_t *instruction_data() { + return reinterpret_cast<uint8_t *>(&clear_values()[clear_values_count]); + } + + _FORCE_INLINE_ const uint8_t *instruction_data() const { + return reinterpret_cast<const uint8_t *>(&clear_values()[clear_values_count]); + } + }; + + struct RecordedTextureClearCommand : RecordedCommand { + RDD::TextureID texture; + RDD::TextureSubresourceRange range; + Color color; + }; + + struct RecordedTextureCopyCommand : RecordedCommand { + RDD::TextureID from_texture; + RDD::TextureID to_texture; + RDD::TextureCopyRegion region; + }; + + struct RecordedTextureGetDataCommand : RecordedCommand { + RDD::TextureID from_texture; + RDD::BufferID to_buffer; + uint32_t buffer_texture_copy_regions_count = 0; + + _FORCE_INLINE_ RDD::BufferTextureCopyRegion *buffer_texture_copy_regions() { + return reinterpret_cast<RDD::BufferTextureCopyRegion *>(&this[1]); + } + + _FORCE_INLINE_ const RDD::BufferTextureCopyRegion *buffer_texture_copy_regions() const { + return reinterpret_cast<const RDD::BufferTextureCopyRegion *>(&this[1]); + } + }; + + struct RecordedTextureResolveCommand : RecordedCommand { + RDD::TextureID from_texture; + RDD::TextureID to_texture; + uint32_t src_layer = 0; + uint32_t src_mipmap = 0; + uint32_t dst_layer = 0; + uint32_t dst_mipmap = 0; + }; + + struct RecordedTextureUpdateCommand : RecordedCommand { + RDD::TextureID to_texture; + uint32_t buffer_to_texture_copies_count = 0; + + _FORCE_INLINE_ RecordedBufferToTextureCopy *buffer_to_texture_copies() { + return reinterpret_cast<RecordedBufferToTextureCopy *>(&this[1]); + } + + _FORCE_INLINE_ const RecordedBufferToTextureCopy *buffer_to_texture_copies() const { + return reinterpret_cast<const RecordedBufferToTextureCopy *>(&this[1]); + } + }; + + struct RecordedCaptureTimestampCommand : RecordedCommand { + RDD::QueryPoolID pool; + uint32_t index = 0; + }; + + struct DrawListBindIndexBufferInstruction : DrawListInstruction { + RDD::BufferID buffer; + RenderingDeviceCommons::IndexBufferFormat format; + uint32_t offset = 0; + }; + + struct DrawListBindPipelineInstruction : DrawListInstruction { + RDD::PipelineID pipeline; + }; + + struct DrawListBindUniformSetInstruction : DrawListInstruction { + RDD::UniformSetID uniform_set; + RDD::ShaderID shader; + uint32_t set_index = 0; + }; + + struct DrawListBindVertexBuffersInstruction : DrawListInstruction { + uint32_t vertex_buffers_count = 0; + + _FORCE_INLINE_ RDD::BufferID *vertex_buffers() { + return reinterpret_cast<RDD::BufferID *>(&this[1]); + } + + _FORCE_INLINE_ const RDD::BufferID *vertex_buffers() const { + return reinterpret_cast<const RDD::BufferID *>(&this[1]); + } + + _FORCE_INLINE_ uint64_t *vertex_buffer_offsets() { + return reinterpret_cast<uint64_t *>(&vertex_buffers()[vertex_buffers_count]); + } + + _FORCE_INLINE_ const uint64_t *vertex_buffer_offsets() const { + return reinterpret_cast<const uint64_t *>(&vertex_buffers()[vertex_buffers_count]); + } + }; + + struct DrawListClearAttachmentsInstruction : DrawListInstruction { + uint32_t attachments_clear_count = 0; + uint32_t attachments_clear_rect_count = 0; + + _FORCE_INLINE_ RDD::AttachmentClear *attachments_clear() { + return reinterpret_cast<RDD::AttachmentClear *>(&this[1]); + } + + _FORCE_INLINE_ const RDD::AttachmentClear *attachments_clear() const { + return reinterpret_cast<const RDD::AttachmentClear *>(&this[1]); + } + + _FORCE_INLINE_ Rect2i *attachments_clear_rect() { + return reinterpret_cast<Rect2i *>(&attachments_clear()[attachments_clear_count]); + } + + _FORCE_INLINE_ const Rect2i *attachments_clear_rect() const { + return reinterpret_cast<const Rect2i *>(&attachments_clear()[attachments_clear_count]); + } + }; + + struct DrawListDrawInstruction : DrawListInstruction { + uint32_t vertex_count = 0; + uint32_t instance_count = 0; + }; + + struct DrawListDrawIndexedInstruction : DrawListInstruction { + uint32_t index_count = 0; + uint32_t instance_count = 0; + uint32_t first_index = 0; + }; + + struct DrawListEndRenderPassInstruction : DrawListInstruction { + // No contents. + }; + + struct DrawListExecuteCommandsInstruction : DrawListInstruction { + RDD::CommandBufferID command_buffer; + }; + + struct DrawListSetPushConstantInstruction : DrawListInstruction { + uint32_t size = 0; + RDD::ShaderID shader; + + _FORCE_INLINE_ uint8_t *data() { + return reinterpret_cast<uint8_t *>(&this[1]); + } + + _FORCE_INLINE_ const uint8_t *data() const { + return reinterpret_cast<const uint8_t *>(&this[1]); + } + }; + + struct DrawListNextSubpassInstruction : DrawListInstruction { + RDD::CommandBufferType command_buffer_type; + }; + + struct DrawListSetBlendConstantsInstruction : DrawListInstruction { + Color color; + }; + + struct DrawListSetLineWidthInstruction : DrawListInstruction { + float width; + }; + + struct DrawListSetScissorInstruction : DrawListInstruction { + Rect2i rect; + }; + + struct DrawListSetViewportInstruction : DrawListInstruction { + Rect2i rect; + }; + + struct DrawListUniformSetPrepareForUseInstruction : DrawListInstruction { + RDD::UniformSetID uniform_set; + RDD::ShaderID shader; + uint32_t set_index = 0; + }; + + struct ComputeListBindPipelineInstruction : ComputeListInstruction { + RDD::PipelineID pipeline; + }; + + struct ComputeListBindUniformSetInstruction : ComputeListInstruction { + RDD::UniformSetID uniform_set; + RDD::ShaderID shader; + uint32_t set_index = 0; + }; + + struct ComputeListDispatchInstruction : ComputeListInstruction { + uint32_t x_groups = 0; + uint32_t y_groups = 0; + uint32_t z_groups = 0; + }; + + struct ComputeListDispatchIndirectInstruction : ComputeListInstruction { + RDD::BufferID buffer; + uint32_t offset = 0; + }; + + struct ComputeListSetPushConstantInstruction : ComputeListInstruction { + uint32_t size = 0; + RDD::ShaderID shader; + + _FORCE_INLINE_ uint8_t *data() { + return reinterpret_cast<uint8_t *>(&this[1]); + } + + _FORCE_INLINE_ const uint8_t *data() const { + return reinterpret_cast<const uint8_t *>(&this[1]); + } + }; + + struct ComputeListUniformSetPrepareForUseInstruction : ComputeListInstruction { + RDD::UniformSetID uniform_set; + RDD::ShaderID shader; + uint32_t set_index = 0; + }; + + struct BarrierGroup { + BitField<RDD::PipelineStageBits> src_stages; + BitField<RDD::PipelineStageBits> dst_stages; + RDD::MemoryBarrier memory_barrier; + LocalVector<RDD::TextureBarrier> normalization_barriers; + LocalVector<RDD::TextureBarrier> transition_barriers; +#if USE_BUFFER_BARRIERS + LocalVector<RDD::BufferBarrier> buffer_barriers; +#endif + + void clear() { + src_stages.clear(); + dst_stages.clear(); + memory_barrier.src_access.clear(); + memory_barrier.dst_access.clear(); + normalization_barriers.clear(); + transition_barriers.clear(); +#if USE_BUFFER_BARRIERS + buffer_barriers.clear(); +#endif + } + }; + + struct SecondaryCommandBuffer { + LocalVector<uint8_t> instruction_data; + RDD::CommandBufferID command_buffer; + RDD::CommandPoolID command_pool; + RDD::RenderPassID render_pass; + RDD::FramebufferID framebuffer; + WorkerThreadPool::TaskID task; + }; + + struct Frame { + TightLocalVector<SecondaryCommandBuffer> secondary_command_buffers; + uint32_t secondary_command_buffers_used = 0; + }; + + RDD *driver = nullptr; + int64_t tracking_frame = 0; + LocalVector<uint8_t> command_data; + LocalVector<uint32_t> command_data_offsets; + LocalVector<RDD::TextureBarrier> command_normalization_barriers; + LocalVector<RDD::TextureBarrier> command_transition_barriers; + LocalVector<RDD::BufferBarrier> command_buffer_barriers; + LocalVector<char> command_label_chars; + LocalVector<Color> command_label_colors; + LocalVector<uint32_t> command_label_offsets; + int32_t command_label_index = -1; + DrawInstructionList draw_instruction_list; + ComputeInstructionList compute_instruction_list; + uint32_t command_count = 0; + uint32_t command_label_count = 0; + LocalVector<RecordedCommandListNode> command_list_nodes; + LocalVector<RecordedWriteListNode> write_list_nodes; + int32_t command_timestamp_index = -1; + int32_t command_synchronization_index = -1; + bool command_synchronization_pending = false; + BarrierGroup barrier_group; + bool driver_honors_barriers = false; + TightLocalVector<Frame> frames; + uint32_t frame = 0; + +#ifdef DEV_ENABLED + RBMap<ResourceTracker *, uint32_t> write_dependency_counters; +#endif + + static bool _is_write_usage(ResourceUsage p_usage); + static RDD::TextureLayout _usage_to_image_layout(ResourceUsage p_usage); + static RDD::BarrierAccessBits _usage_to_access_bits(ResourceUsage p_usage); + int32_t _add_to_command_list(int32_t p_command_index, int32_t p_list_index); + void _add_adjacent_command(int32_t p_previous_command_index, int32_t p_command_index, RecordedCommand *r_command); + int32_t _add_to_write_list(int32_t p_command_index, Rect2i suberesources, int32_t p_list_index); + RecordedCommand *_allocate_command(uint32_t p_command_size, int32_t &r_command_index); + DrawListInstruction *_allocate_draw_list_instruction(uint32_t p_instruction_size); + ComputeListInstruction *_allocate_compute_list_instruction(uint32_t p_instruction_size); + void _add_command_to_graph(ResourceTracker **p_resource_trackers, ResourceUsage *p_resource_usages, uint32_t p_resource_count, int32_t p_command_index, RecordedCommand *r_command); + void _add_texture_barrier_to_command(RDD::TextureID p_texture_id, BitField<RDD::BarrierAccessBits> p_src_access, BitField<RDD::BarrierAccessBits> p_dst_access, ResourceUsage p_prev_usage, ResourceUsage p_next_usage, RDD::TextureSubresourceRange p_subresources, LocalVector<RDD::TextureBarrier> &r_barrier_vector, int32_t &r_barrier_index, int32_t &r_barrier_count); +#if USE_BUFFER_BARRIERS + void _add_buffer_barrier_to_command(RDD::BufferID p_buffer_id, BitField<RDD::BarrierAccessBits> p_src_access, BitField<RDD::BarrierAccessBits> p_dst_access, int32_t &r_barrier_index, int32_t &r_barrier_count); +#endif + void _run_compute_list_command(RDD::CommandBufferID p_command_buffer, const uint8_t *p_instruction_data, uint32_t p_instruction_data_size); + void _run_draw_list_command(RDD::CommandBufferID p_command_buffer, const uint8_t *p_instruction_data, uint32_t p_instruction_data_size); + void _run_secondary_command_buffer_task(const SecondaryCommandBuffer *p_secondary); + void _wait_for_secondary_command_buffer_tasks(); + void _run_render_commands(RDD::CommandBufferID p_command_buffer, int32_t p_level, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, int32_t &r_current_label_index, int32_t &r_current_label_level); + void _run_label_command_change(RDD::CommandBufferID p_command_buffer, int32_t p_new_label_index, int32_t p_new_level, bool p_ignore_previous_value, bool p_use_label_for_empty, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, int32_t &r_current_label_index, int32_t &r_current_label_level); + void _boost_priority_for_render_commands(RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, uint32_t &r_boosted_priority); + void _group_barriers_for_render_commands(RDD::CommandBufferID p_command_buffer, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, bool p_full_memory_barrier); + void _print_render_commands(const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count); + void _print_draw_list(const uint8_t *p_instruction_data, uint32_t p_instruction_data_size); + void _print_compute_list(const uint8_t *p_instruction_data, uint32_t p_instruction_data_size); + +public: + RenderingDeviceGraph(); + ~RenderingDeviceGraph(); + void initialize(RDD *p_driver, uint32_t p_frame_count, uint32_t p_secondary_command_buffers_per_frame); + void begin(); + void add_buffer_clear(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_offset, uint32_t p_size); + void add_buffer_copy(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, RDD::BufferCopyRegion p_region); + void add_buffer_get_data(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, RDD::BufferCopyRegion p_region); + void add_buffer_update(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferCopy> p_buffer_copies); + void add_compute_list_begin(); + void add_compute_list_bind_pipeline(RDD::PipelineID p_pipeline); + void add_compute_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index); + void add_compute_list_dispatch(uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups); + void add_compute_list_dispatch_indirect(RDD::BufferID p_buffer, uint32_t p_offset); + void add_compute_list_set_push_constant(RDD::ShaderID p_shader, const void *p_data, uint32_t p_data_size); + void add_compute_list_uniform_set_prepare_for_use(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index); + void add_compute_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage); + void add_compute_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages); + void add_compute_list_end(); + void add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView<RDD::RenderPassClearValue> p_clear_values, bool p_uses_color, bool p_uses_depth); + void add_draw_list_bind_index_buffer(RDD::BufferID p_buffer, RDD::IndexBufferFormat p_format, uint32_t p_offset); + void add_draw_list_bind_pipeline(RDD::PipelineID p_pipeline, BitField<RDD::PipelineStageBits> p_pipeline_stage_bits); + void add_draw_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index); + void add_draw_list_bind_vertex_buffers(VectorView<RDD::BufferID> p_vertex_buffers, VectorView<uint64_t> p_vertex_buffer_offsets); + void add_draw_list_clear_attachments(VectorView<RDD::AttachmentClear> p_attachments_clear, VectorView<Rect2i> p_attachments_clear_rect); + void add_draw_list_draw(uint32_t p_vertex_count, uint32_t p_instance_count); + void add_draw_list_draw_indexed(uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index); + void add_draw_list_execute_commands(RDD::CommandBufferID p_command_buffer); + void add_draw_list_next_subpass(RDD::CommandBufferType p_command_buffer_type); + void add_draw_list_set_blend_constants(const Color &p_color); + void add_draw_list_set_line_width(float p_width); + void add_draw_list_set_push_constant(RDD::ShaderID p_shader, const void *p_data, uint32_t p_data_size); + void add_draw_list_set_scissor(Rect2i p_rect); + void add_draw_list_set_viewport(Rect2i p_rect); + void add_draw_list_uniform_set_prepare_for_use(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index); + void add_draw_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage); + void add_draw_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages); + void add_draw_list_end(); + void add_texture_clear(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, const Color &p_color, const RDD::TextureSubresourceRange &p_range); + void add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, RDD::TextureCopyRegion p_region); + void add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions); + void add_texture_resolve(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_src_layer, uint32_t p_src_mipmap, uint32_t p_dst_layer, uint32_t p_dst_mipmap); + void add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies); + void add_capture_timestamp(RDD::QueryPoolID p_query_pool, uint32_t p_index); + void add_synchronization(); + void begin_label(const String &p_label_name, const Color &p_color); + void end_label(); + void end(RDD::CommandBufferID p_command_buffer, bool p_reorder_commands, bool p_full_barriers); + static ResourceTracker *resource_tracker_create(); + static void resource_tracker_free(ResourceTracker *tracker); +}; + +using RDG = RenderingDeviceGraph; + +#endif // RENDERING_DEVICE_GRAPH_H diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index 77fe91e4c9..f7620ad5dc 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -91,10 +91,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { RSG::viewport->draw_viewports(p_swap_buffers); RSG::canvas_render->update(); - if (!OS::get_singleton()->get_current_rendering_driver_name().begins_with("opengl3")) { - // Already called for gl_compatibility renderer. - RSG::rasterizer->end_frame(p_swap_buffers); - } + RSG::rasterizer->end_frame(p_swap_buffers); XRServer *xr_server = XRServer::get_singleton(); if (xr_server != nullptr) { @@ -214,6 +211,7 @@ void RenderingServerDefault::_finish() { free(test_cube); } + RSG::canvas->finalize(); RSG::rasterizer->finalize(); } @@ -289,9 +287,11 @@ void RenderingServerDefault::set_default_clear_color(const Color &p_color) { RSG::viewport->set_default_clear_color(p_color); } +#ifndef DISABLE_DEPRECATED bool RenderingServerDefault::has_feature(Features p_feature) const { return false; } +#endif void RenderingServerDefault::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { RSG::scene->sdfgi_set_debug_probe_select(p_position, p_dir); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index dac1275957..11ec670280 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -1021,7 +1021,9 @@ public: virtual Color get_default_clear_color() override; virtual void set_default_clear_color(const Color &p_color) override; +#ifndef DISABLE_DEPRECATED virtual bool has_feature(Features p_feature) const override; +#endif virtual bool has_os_feature(const String &p_feature) const override; virtual void set_debug_generate_wireframes(bool p_generate) override; diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index 880c13096e..6875400d1e 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -543,7 +543,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene uniform_names.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced for (int k = 0; k < uniform_names.size(); k++) { - StringName uniform_name = uniform_names[k]; + const StringName &uniform_name = uniform_names[k]; const SL::ShaderNode::Uniform &uniform = pnode->uniforms[uniform_name]; String ucode; @@ -670,7 +670,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene varying_names.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced for (int k = 0; k < varying_names.size(); k++) { - StringName varying_name = varying_names[k]; + const StringName &varying_name = varying_names[k]; const SL::ShaderNode::Varying &varying = pnode->varyings[varying_name]; if (varying.stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || varying.stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) { diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index a2da26eb65..fef1a205d6 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -4665,7 +4665,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi return false; } -bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) { +bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(const StringName &p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) { for (int i = 0; i < shader->vfunctions.size(); i++) { if (shader->vfunctions[i].name == p_name) { ERR_FAIL_INDEX_V(p_argument, shader->vfunctions[i].function->arguments.size(), false); @@ -4699,7 +4699,7 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringNam ERR_FAIL_V(false); //bug? function not found } -bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin) { +bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(const StringName &p_name, int p_argument, const StringName &p_builtin) { for (int i = 0; i < shader->vfunctions.size(); i++) { if (shader->vfunctions[i].name == p_name) { ERR_FAIL_INDEX_V(p_argument, shader->vfunctions[i].function->arguments.size(), false); diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index c707f6aad7..737545b8ca 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -1092,8 +1092,8 @@ private: bool _validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str, bool *r_is_custom_function = nullptr); bool _parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg = nullptr); - bool _propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat); - bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin); + bool _propagate_function_call_sampler_uniform_settings(const StringName &p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat); + bool _propagate_function_call_sampler_builtin_reference(const StringName &p_name, int p_argument, const StringName &p_builtin); bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message); bool _check_node_constness(const Node *p_node) const; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index b4af27c510..27e677bce0 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -103,7 +103,7 @@ PackedInt64Array RenderingServer::_instances_cull_convex_bind(const TypedArray<P } Vector<Plane> planes; for (int i = 0; i < p_convex.size(); ++i) { - Variant v = p_convex[i]; + const Variant &v = p_convex[i]; ERR_FAIL_COND_V(v.get_type() != Variant::PLANE, PackedInt64Array()); planes.push_back(v); } @@ -2204,6 +2204,25 @@ void RenderingServer::fix_surface_compatibility(SurfaceData &p_surface, const St } #endif +#ifdef TOOLS_ENABLED +void RenderingServer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { + String pf = p_function; + if (p_idx == 0) { + if (pf == "global_shader_parameter_set" || pf == "global_shader_parameter_set_override" || + pf == "global_shader_parameter_get" || pf == "global_shader_parameter_get_type" || pf == "global_shader_parameter_remove") { + for (StringName E : global_shader_parameter_get_list()) { + r_options->push_back(E.operator String().quote()); + } + } else if (pf == "has_os_feature") { + for (String E : { "\"rgtc\"", "\"s3tc\"", "\"bptc\"", "\"etc\"", "\"etc2\"", "\"astc\"" }) { + r_options->push_back(E); + } + } + } + Object::get_argument_options(p_function, p_idx, r_options); +} +#endif + void RenderingServer::_bind_methods() { BIND_CONSTANT(NO_INDEX_ARRAY); BIND_CONSTANT(ARRAY_WEIGHTS_SIZE); @@ -3343,7 +3362,6 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_default_clear_color"), &RenderingServer::get_default_clear_color); ClassDB::bind_method(D_METHOD("set_default_clear_color", "color"), &RenderingServer::set_default_clear_color); - ClassDB::bind_method(D_METHOD("has_feature", "feature"), &RenderingServer::has_feature); ClassDB::bind_method(D_METHOD("has_os_feature", "feature"), &RenderingServer::has_os_feature); ClassDB::bind_method(D_METHOD("set_debug_generate_wireframes", "generate"), &RenderingServer::set_debug_generate_wireframes); @@ -3361,9 +3379,6 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(RENDERING_INFO_BUFFER_MEM_USED); BIND_ENUM_CONSTANT(RENDERING_INFO_VIDEO_MEM_USED); - BIND_ENUM_CONSTANT(FEATURE_SHADERS); - BIND_ENUM_CONSTANT(FEATURE_MULTITHREADED); - ADD_SIGNAL(MethodInfo("frame_pre_draw")); ADD_SIGNAL(MethodInfo("frame_post_draw")); @@ -3373,6 +3388,13 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("create_local_rendering_device"), &RenderingServer::create_local_rendering_device); ClassDB::bind_method(D_METHOD("call_on_render_thread", "callable"), &RenderingServer::call_on_render_thread); + +#ifndef DISABLE_DEPRECATED + ClassDB::bind_method(D_METHOD("has_feature", "feature"), &RenderingServer::has_feature); + + BIND_ENUM_CONSTANT(FEATURE_SHADERS); + BIND_ENUM_CONSTANT(FEATURE_MULTITHREADED); +#endif } void RenderingServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry3D::MeshData &p_mesh_data) { @@ -3471,15 +3493,15 @@ void RenderingServer::init() { GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug", false); GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug.release", true); - GLOBAL_DEF_RST("rendering/reflections/sky_reflections/roughness_layers", 8); // Assumes a 256x256 cubemap + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/reflections/sky_reflections/roughness_layers", PROPERTY_HINT_RANGE, "1,32,1"), 8); // Assumes a 256x256 cubemap GLOBAL_DEF_RST("rendering/reflections/sky_reflections/texture_array_reflections", true); GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections.mobile", false); - GLOBAL_DEF_RST("rendering/reflections/sky_reflections/ggx_samples", 32); - GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples.mobile", 16); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/reflections/sky_reflections/ggx_samples", PROPERTY_HINT_RANGE, "0,256,1"), 32); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/sky_reflections/ggx_samples.mobile", PROPERTY_HINT_RANGE, "0,128,1"), 16); GLOBAL_DEF("rendering/reflections/sky_reflections/fast_filter_high_quality", false); - GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_size", 256); - GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_size.mobile", 128); - GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_count", 64); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_size", PROPERTY_HINT_RANGE, "0,4096,1"), 256); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_size.mobile", PROPERTY_HINT_RANGE, "0,2048,1"), 128); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_count", PROPERTY_HINT_RANGE, "0,256,1"), 64); GLOBAL_DEF("rendering/global_illumination/gi/use_half_resolution", false); @@ -3526,7 +3548,7 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/textures/decals/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Linear (Fast),Nearest Mipmap (Fast),Linear Mipmap (Fast),Nearest Mipmap Anisotropic (Average),Linear Mipmap Anisotropic (Average)"), DECAL_FILTER_LINEAR_MIPMAPS); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/textures/light_projectors/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Linear (Fast),Nearest Mipmap (Fast),Linear Mipmap (Fast),Nearest Mipmap Anisotropic (Average),Linear Mipmap Anisotropic (Average)"), LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS); - GLOBAL_DEF_RST("rendering/occlusion_culling/occlusion_rays_per_thread", 512); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/occlusion_culling/occlusion_rays_per_thread", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), 512); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/glow/upscale_mode", PROPERTY_HINT_ENUM, "Linear (Fast),Bicubic (Slow)"), 1); GLOBAL_DEF("rendering/environment/glow/upscale_mode.mobile", 0); @@ -3537,7 +3559,7 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"), 0.05); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"), 0.01); - GLOBAL_DEF("rendering/limits/global_shader_variables/buffer_size", 65536); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/global_shader_variables/buffer_size", PROPERTY_HINT_RANGE, "1,1048576,1"), 65536); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/lightmapping/probe_capture/update_speed", PROPERTY_HINT_RANGE, "0.001,256,0.001"), 15); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/lightmapping/primitive_meshes/texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.2); @@ -3552,7 +3574,6 @@ void RenderingServer::init() { GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1"), 10); GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 1000); - GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 500); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1"), 512); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 016801fa6e..958c21f893 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1612,13 +1612,14 @@ public: virtual Color get_default_clear_color() = 0; virtual void set_default_clear_color(const Color &p_color) = 0; +#ifndef DISABLE_DEPRECATED + // Never actually used, should be removed when we can break compatibility. enum Features { FEATURE_SHADERS, FEATURE_MULTITHREADED, }; - virtual bool has_feature(Features p_feature) const = 0; - +#endif virtual bool has_os_feature(const String &p_feature) const = 0; virtual void set_debug_generate_wireframes(bool p_generate) = 0; @@ -1639,6 +1640,10 @@ public: virtual void call_on_render_thread(const Callable &p_callable) = 0; +#ifdef TOOLS_ENABLED + virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; +#endif + RenderingServer(); virtual ~RenderingServer(); @@ -1744,10 +1749,13 @@ VARIANT_ENUM_CAST(RenderingServer::CanvasLightShadowFilter); VARIANT_ENUM_CAST(RenderingServer::CanvasOccluderPolygonCullMode); VARIANT_ENUM_CAST(RenderingServer::GlobalShaderParameterType); VARIANT_ENUM_CAST(RenderingServer::RenderingInfo); -VARIANT_ENUM_CAST(RenderingServer::Features); VARIANT_ENUM_CAST(RenderingServer::CanvasTextureChannel); VARIANT_ENUM_CAST(RenderingServer::BakeChannels); +#ifndef DISABLE_DEPRECATED +VARIANT_ENUM_CAST(RenderingServer::Features); +#endif + // Alias to make it easier to use. #define RS RenderingServer diff --git a/tests/core/math/test_math_funcs.h b/tests/core/math/test_math_funcs.h index 5fbea4aece..0a9d9c97d9 100644 --- a/tests/core/math/test_math_funcs.h +++ b/tests/core/math/test_math_funcs.h @@ -110,6 +110,29 @@ TEST_CASE_TEMPLATE("[Math] round/floor/ceil", T, float, double) { CHECK(Math::ceil((T)-1.9) == (T)-1.0); } +TEST_CASE_TEMPLATE("[Math] integer division round up unsigned", T, uint32_t, uint64_t) { + CHECK(Math::division_round_up((T)0, (T)64) == 0); + CHECK(Math::division_round_up((T)1, (T)64) == 1); + CHECK(Math::division_round_up((T)63, (T)64) == 1); + CHECK(Math::division_round_up((T)64, (T)64) == 1); + CHECK(Math::division_round_up((T)65, (T)64) == 2); + CHECK(Math::division_round_up((T)65, (T)1) == 65); +} + +TEST_CASE_TEMPLATE("[Math] integer division round up signed", T, int32_t, int64_t) { + CHECK(Math::division_round_up((T)0, (T)64) == 0); + CHECK(Math::division_round_up((T)1, (T)64) == 1); + CHECK(Math::division_round_up((T)63, (T)64) == 1); + CHECK(Math::division_round_up((T)64, (T)64) == 1); + CHECK(Math::division_round_up((T)65, (T)64) == 2); + CHECK(Math::division_round_up((T)65, (T)1) == 65); + CHECK(Math::division_round_up((T)-1, (T)64) == 0); + CHECK(Math::division_round_up((T)-1, (T)-1) == 1); + CHECK(Math::division_round_up((T)-1, (T)1) == -1); + CHECK(Math::division_round_up((T)-1, (T)-2) == 1); + CHECK(Math::division_round_up((T)-4, (T)-2) == 2); +} + TEST_CASE_TEMPLATE("[Math] sin/cos/tan", T, float, double) { CHECK(Math::sin((T)-0.1) == doctest::Approx((T)-0.0998334166)); CHECK(Math::sin((T)0.1) == doctest::Approx((T)0.0998334166)); diff --git a/tests/core/math/test_vector2i.h b/tests/core/math/test_vector2i.h index 743c87f486..0f33400f7f 100644 --- a/tests/core/math/test_vector2i.h +++ b/tests/core/math/test_vector2i.h @@ -87,6 +87,12 @@ TEST_CASE("[Vector2i] Length methods") { CHECK_MESSAGE( vector2.length() == doctest::Approx(36.05551275463989293119), "Vector2i length should work as expected."); + CHECK_MESSAGE( + vector1.distance_squared_to(vector2) == 500, + "Vector2i distance_squared_to should work as expected and return exact result."); + CHECK_MESSAGE( + vector1.distance_to(vector2) == doctest::Approx(22.36067977499789696409), + "Vector2i distance_to should work as expected."); } TEST_CASE("[Vector2i] Operators") { diff --git a/tests/core/math/test_vector3i.h b/tests/core/math/test_vector3i.h index 485a500715..3914b85a75 100644 --- a/tests/core/math/test_vector3i.h +++ b/tests/core/math/test_vector3i.h @@ -90,6 +90,12 @@ TEST_CASE("[Vector3i] Length methods") { CHECK_MESSAGE( vector2.length() == doctest::Approx(53.8516480713450403125), "Vector3i length should work as expected."); + CHECK_MESSAGE( + vector1.distance_squared_to(vector2) == 1400, + "Vector3i distance_squared_to should work as expected and return exact result."); + CHECK_MESSAGE( + vector1.distance_to(vector2) == doctest::Approx(37.41657386773941385584), + "Vector3i distance_to should work as expected."); } TEST_CASE("[Vector3i] Operators") { diff --git a/tests/core/math/test_vector4i.h b/tests/core/math/test_vector4i.h index 5fda6f1778..31f68696c0 100644 --- a/tests/core/math/test_vector4i.h +++ b/tests/core/math/test_vector4i.h @@ -90,6 +90,12 @@ TEST_CASE("[Vector4i] Length methods") { CHECK_MESSAGE( vector2.length() == doctest::Approx(73.4846922835), "Vector4i length should work as expected."); + CHECK_MESSAGE( + vector1.distance_squared_to(vector2) == 3000, + "Vector4i distance_squared_to should work as expected."); + CHECK_MESSAGE( + vector1.distance_to(vector2) == doctest::Approx(54.772255750517), + "Vector4i distance_to should work as expected."); } TEST_CASE("[Vector4i] Operators") { diff --git a/tests/core/string/test_node_path.h b/tests/core/string/test_node_path.h index b0c810bb54..031a33c570 100644 --- a/tests/core/string/test_node_path.h +++ b/tests/core/string/test_node_path.h @@ -98,44 +98,44 @@ TEST_CASE("[NodePath] Relative path") { } TEST_CASE("[NodePath] Absolute path") { - const NodePath node_path_aboslute = NodePath("/root/Sprite2D"); + const NodePath node_path_absolute = NodePath("/root/Sprite2D"); CHECK_MESSAGE( - node_path_aboslute.get_as_property_path() == NodePath(":root/Sprite2D"), + node_path_absolute.get_as_property_path() == NodePath(":root/Sprite2D"), "The returned property path should match the expected value."); CHECK_MESSAGE( - node_path_aboslute.get_concatenated_subnames() == "", + node_path_absolute.get_concatenated_subnames() == "", "The returned concatenated subnames should match the expected value."); CHECK_MESSAGE( - node_path_aboslute.get_name(0) == "root", + node_path_absolute.get_name(0) == "root", "The returned name at index 0 should match the expected value."); CHECK_MESSAGE( - node_path_aboslute.get_name(1) == "Sprite2D", + node_path_absolute.get_name(1) == "Sprite2D", "The returned name at index 1 should match the expected value."); ERR_PRINT_OFF; CHECK_MESSAGE( - node_path_aboslute.get_name(2) == "", + node_path_absolute.get_name(2) == "", "The returned name at invalid index 2 should match the expected value."); CHECK_MESSAGE( - node_path_aboslute.get_name(-1) == "", + node_path_absolute.get_name(-1) == "", "The returned name at invalid index -1 should match the expected value."); ERR_PRINT_ON; CHECK_MESSAGE( - node_path_aboslute.get_name_count() == 2, + node_path_absolute.get_name_count() == 2, "The returned number of names should match the expected value."); CHECK_MESSAGE( - node_path_aboslute.get_subname_count() == 0, + node_path_absolute.get_subname_count() == 0, "The returned number of subnames should match the expected value."); CHECK_MESSAGE( - node_path_aboslute.is_absolute(), + node_path_absolute.is_absolute(), "The node path should be considered absolute."); CHECK_MESSAGE( - !node_path_aboslute.is_empty(), + !node_path_absolute.is_empty(), "The node path shouldn't be considered empty."); } diff --git a/tests/core/variant/test_array.h b/tests/core/variant/test_array.h index 228d77b3b5..ea61ae2a02 100644 --- a/tests/core/variant/test_array.h +++ b/tests/core/variant/test_array.h @@ -367,7 +367,7 @@ TEST_CASE("[Array] Duplicate recursive array") { Array a_shallow = a.duplicate(false); CHECK_EQ(a, a_shallow); - // Deep copy of recursive array endup with recursion limit and return + // Deep copy of recursive array ends up with recursion limit and return // an invalid result (multiple nested arrays), the point is we should // not end up with a segfault and an error log should be printed ERR_PRINT_OFF; diff --git a/tests/scene/test_curve_2d.h b/tests/scene/test_curve_2d.h index fc141f3d09..099f6fefa9 100644 --- a/tests/scene/test_curve_2d.h +++ b/tests/scene/test_curve_2d.h @@ -155,17 +155,37 @@ TEST_CASE("[Curve2D] Sampling") { SUBCASE("sample_baked_with_rotation") { const real_t pi = 3.14159; - Transform2D t = curve->sample_baked_with_rotation(curve->get_closest_offset(Vector2(0, 0))); - CHECK(t.get_origin() == Vector2(0, 0)); - CHECK(Math::is_equal_approx(t.get_rotation(), pi)); - - t = curve->sample_baked_with_rotation(curve->get_closest_offset(Vector2(0, 25))); + const real_t half_pi = pi * 0.5; + Ref<Curve2D> rot_curve = memnew(Curve2D); + Transform2D t; + + rot_curve->clear_points(); + rot_curve->add_point(Vector2()); + rot_curve->add_point(Vector2(50, 0)); + t = rot_curve->sample_baked_with_rotation(25); + CHECK(t.get_origin() == Vector2(25, 0)); + CHECK(Math::is_equal_approx(t.get_rotation(), 0)); + + rot_curve->clear_points(); + rot_curve->add_point(Vector2()); + rot_curve->add_point(Vector2(0, 50)); + t = rot_curve->sample_baked_with_rotation(25); CHECK(t.get_origin() == Vector2(0, 25)); - CHECK(Math::is_equal_approx(t.get_rotation(), pi)); + CHECK(Math::is_equal_approx(t.get_rotation(), half_pi)); - t = curve->sample_baked_with_rotation(curve->get_closest_offset(Vector2(0, 50))); - CHECK(t.get_origin() == Vector2(0, 50)); + rot_curve->clear_points(); + rot_curve->add_point(Vector2()); + rot_curve->add_point(Vector2(-50, 0)); + t = rot_curve->sample_baked_with_rotation(25); + CHECK(t.get_origin() == Vector2(-25, 0)); CHECK(Math::is_equal_approx(t.get_rotation(), pi)); + + rot_curve->clear_points(); + rot_curve->add_point(Vector2()); + rot_curve->add_point(Vector2(0, -50)); + t = rot_curve->sample_baked_with_rotation(25); + CHECK(t.get_origin() == Vector2(0, -25)); + CHECK(Math::is_equal_approx(t.get_rotation(), -half_pi)); } SUBCASE("get_closest_point") { diff --git a/tests/scene/test_packed_scene.h b/tests/scene/test_packed_scene.h index 3517aba31f..1e784c199d 100644 --- a/tests/scene/test_packed_scene.h +++ b/tests/scene/test_packed_scene.h @@ -150,6 +150,71 @@ TEST_CASE("[PackedScene] Instantiate Packed Scene With Children") { memdelete(instance); } +TEST_CASE("[PackedScene] Set Path") { + // Create a scene to pack. + Node *scene = memnew(Node); + scene->set_name("TestScene"); + + // Pack the scene. + PackedScene packed_scene; + packed_scene.pack(scene); + + // Set a new path for the packed scene. + const String new_path = "NewTestPath"; + packed_scene.set_path(new_path); + + // Check if the path has been set correctly. + Ref<SceneState> state = packed_scene.get_state(); + CHECK(state.is_valid()); + CHECK(state->get_path() == new_path); + + memdelete(scene); +} + +TEST_CASE("[PackedScene] Replace State") { + // Create a scene to pack. + Node *scene = memnew(Node); + scene->set_name("TestScene"); + + // Pack the scene. + PackedScene packed_scene; + packed_scene.pack(scene); + + // Create another scene state to replace with. + Ref<SceneState> new_state = memnew(SceneState); + new_state->set_path("NewPath"); + + // Replace the state. + packed_scene.replace_state(new_state); + + // Check if the state has been replaced. + Ref<SceneState> state = packed_scene.get_state(); + CHECK(state.is_valid()); + CHECK(state == new_state); + + memdelete(scene); +} + +TEST_CASE("[PackedScene] Recreate State") { + // Create a scene to pack. + Node *scene = memnew(Node); + scene->set_name("TestScene"); + + // Pack the scene. + PackedScene packed_scene; + packed_scene.pack(scene); + + // Recreate the state. + packed_scene.recreate_state(); + + // Check if the state has been recreated. + Ref<SceneState> state = packed_scene.get_state(); + CHECK(state.is_valid()); + CHECK(state->get_node_count() == 0); // Since the state was recreated, it should be empty. + + memdelete(scene); +} + } // namespace TestPackedScene #endif // TEST_PACKED_SCENE_H diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 5187ebd00f..7f49805274 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -30,6 +30,8 @@ #include "test_main.h" +#include "editor/editor_paths.h" +#include "editor/editor_settings.h" #include "tests/core/config/test_project_settings.h" #include "tests/core/input/test_input_event.h" #include "tests/core/input/test_input_event_key.h" @@ -94,7 +96,6 @@ #include "tests/scene/test_arraymesh.h" #include "tests/scene/test_audio_stream_wav.h" #include "tests/scene/test_bit_map.h" -#include "tests/scene/test_camera_3d.h" #include "tests/scene/test_code_edit.h" #include "tests/scene/test_color_picker.h" #include "tests/scene/test_control.h" @@ -103,16 +104,12 @@ #include "tests/scene/test_curve_3d.h" #include "tests/scene/test_gradient.h" #include "tests/scene/test_navigation_agent_2d.h" -#include "tests/scene/test_navigation_agent_3d.h" #include "tests/scene/test_navigation_obstacle_2d.h" -#include "tests/scene/test_navigation_obstacle_3d.h" #include "tests/scene/test_navigation_region_2d.h" -#include "tests/scene/test_navigation_region_3d.h" #include "tests/scene/test_node.h" #include "tests/scene/test_node_2d.h" #include "tests/scene/test_packed_scene.h" #include "tests/scene/test_path_2d.h" -#include "tests/scene/test_path_3d.h" #include "tests/scene/test_primitives.h" #include "tests/scene/test_sprite_frames.h" #include "tests/scene/test_text_edit.h" @@ -122,10 +119,18 @@ #include "tests/scene/test_window.h" #include "tests/servers/rendering/test_shader_preprocessor.h" #include "tests/servers/test_navigation_server_2d.h" -#include "tests/servers/test_navigation_server_3d.h" #include "tests/servers/test_text_server.h" #include "tests/test_validate_testing.h" +#ifndef _3D_DISABLED +#include "tests/scene/test_camera_3d.h" +#include "tests/scene/test_navigation_agent_3d.h" +#include "tests/scene/test_navigation_obstacle_3d.h" +#include "tests/scene/test_navigation_region_3d.h" +#include "tests/scene/test_path_3d.h" +#include "tests/servers/test_navigation_server_3d.h" +#endif // _3D_DISABLED + #include "modules/modules_tests.gen.h" #include "tests/display_server_mock.h" @@ -221,7 +226,7 @@ struct GodotTestCaseListener : public doctest::IReporter { String name = String(p_in.m_name); String suite_name = String(p_in.m_test_suite); - if (name.find("[SceneTree]") != -1) { + if (name.find("[SceneTree]") != -1 || name.find("[Editor]") != -1) { memnew(MessageQueue); memnew(Input); @@ -264,6 +269,13 @@ struct GodotTestCaseListener : public doctest::IReporter { if (!DisplayServer::get_singleton()->has_feature(DisplayServer::Feature::FEATURE_SUBWINDOWS)) { SceneTree::get_singleton()->get_root()->set_embedding_subwindows(true); } + + if (name.find("[Editor]") != -1) { + Engine::get_singleton()->set_editor_hint(true); + EditorPaths::create(); + EditorSettings::create(); + } + return; } @@ -286,6 +298,12 @@ struct GodotTestCaseListener : public doctest::IReporter { } void test_case_end(const doctest::CurrentTestCaseStats &) override { + if (EditorSettings::get_singleton()) { + EditorSettings::destroy(); + } + + Engine::get_singleton()->set_editor_hint(false); + if (SceneTree::get_singleton()) { SceneTree::get_singleton()->finalize(); } diff --git a/thirdparty/README.md b/thirdparty/README.md index 00d8820605..51ba9f1df4 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -389,7 +389,7 @@ Files extracted from upstream source: ## icu4c - Upstream: https://github.com/unicode-org/icu -- Version: 73.2 (680f521746a3bd6a86f25f25ee50a62d88b489cf, 2023) +- Version: 74.1 (9edac7b78327a1cb58db29e2714b15f9fa14e4d7, 2023) - License: Unicode Files extracted from upstream source: @@ -401,7 +401,7 @@ Files extracted from upstream source: Files generated from upstream source: -- The `icudt73l.dat` built with the provided `godot_data.json` config file (see +- The `icudt74l.dat` built with the provided `godot_data.json` config file (see https://github.com/unicode-org/icu/blob/master/docs/userguide/icu_data/buildtool.md for instructions). @@ -411,7 +411,7 @@ Files generated from upstream source: 3. Reconfigure ICU with custom data config: `ICU_DATA_FILTER_FILE={GODOT_SOURCE}/thirdparty/icu4c/godot_data.json ./runConfigureICU {PLATFORM} --with-data-packaging=common` 4. Delete `data/out` folder and rebuild data: `cd data && rm -rf ./out && make` -5. Copy `source/data/out/icudt73l.dat` to the `{GODOT_SOURCE}/thirdparty/icu4c/icudt73l.dat` +5. Copy `source/data/out/icudt74l.dat` to the `{GODOT_SOURCE}/thirdparty/icu4c/icudt74l.dat` ## jpeg-compressor @@ -727,7 +727,7 @@ with the provided patch. ## openxr - Upstream: https://github.com/KhronosGroup/OpenXR-SDK -- Version: 1.0.31 (95fe35ffb383710a6e0567e958ead9a3b66e930c, 2023) +- Version: 1.0.33 (dc1e23937fe45eabcce80f6588cf47449edb29d1, 2024) - License: Apache 2.0 Files extracted from upstream source: @@ -861,7 +861,7 @@ instead of `miniz.h` as an external dependency. ## thorvg - Upstream: https://github.com/thorvg/thorvg -- Version: 0.11.2 (b01fe9bf4461146304d3520d6dc699cf580a3744, 2023) +- Version: 0.12.0 (25ea242d3867ed66807714f5a52d080984d3c8cc, 2024) - License: MIT Files extracted from upstream source: diff --git a/thirdparty/amd-fsr2/shaders/ffx_fsr2_depth_clip_pass.glsl b/thirdparty/amd-fsr2/shaders/ffx_fsr2_depth_clip_pass.glsl index 65cc8b67ef..d989416eb3 100644 --- a/thirdparty/amd-fsr2/shaders/ffx_fsr2_depth_clip_pass.glsl +++ b/thirdparty/amd-fsr2/shaders/ffx_fsr2_depth_clip_pass.glsl @@ -29,7 +29,6 @@ #define FSR2_BIND_SRV_DILATED_DEPTH 2 #define FSR2_BIND_SRV_REACTIVE_MASK 3 #define FSR2_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK 4 -#define FSR2_BIND_SRV_PREPARED_INPUT_COLOR 5 #define FSR2_BIND_SRV_PREVIOUS_DILATED_MOTION_VECTORS 6 #define FSR2_BIND_SRV_INPUT_MOTION_VECTORS 7 #define FSR2_BIND_SRV_INPUT_COLOR 8 diff --git a/thirdparty/icu4c/LICENSE b/thirdparty/icu4c/LICENSE index 22472dc2ec..9f54372feb 100644 --- a/thirdparty/icu4c/LICENSE +++ b/thirdparty/icu4c/LICENSE @@ -1,49 +1,42 @@ -UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE - -See Terms of Use <https://www.unicode.org/copyright.html> -for definitions of Unicode Inc.’s Data Files and Software. - -NOTICE TO USER: Carefully read the following legal agreement. -BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S -DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), -YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE -TERMS AND CONDITIONS OF THIS AGREEMENT. -IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE -THE DATA FILES OR SOFTWARE. +UNICODE LICENSE V3 COPYRIGHT AND PERMISSION NOTICE -Copyright © 1991-2023 Unicode, Inc. All rights reserved. -Distributed under the Terms of Use in https://www.unicode.org/copyright.html. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Unicode data files and any associated documentation -(the "Data Files") or Unicode software and any associated documentation -(the "Software") to deal in the Data Files or Software -without restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, and/or sell copies of -the Data Files or Software, and to permit persons to whom the Data Files -or Software are furnished to do so, provided that either -(a) this copyright and permission notice appear with all copies -of the Data Files or Software, or -(b) this copyright and permission notice appear in associated -Documentation. - -THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS -NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL -DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, -DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THE DATA FILES OR SOFTWARE. - -Except as contained in this notice, the name of a copyright holder -shall not be used in advertising or otherwise to promote the sale, -use or other dealings in these Data Files or Software without prior -written authorization of the copyright holder. +Copyright © 2016-2023 Unicode, Inc. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR +SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT +DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of data files and any associated documentation (the "Data Files") or +software and any associated documentation (the "Software") to deal in the +Data Files or Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, and/or sell +copies of the Data Files or Software, and to permit persons to whom the +Data Files or Software are furnished to do so, provided that either (a) +this copyright and permission notice appear with all copies of the Data +Files or Software, or (b) this copyright and permission notice appear in +associated Documentation. + +THE DATA FILES AND SOFTWARE ARE 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 OF +THIRD PARTY RIGHTS. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE +BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA +FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in these Data Files or Software without prior written +authorization of the copyright holder. ---------------------------------------------------------------------- diff --git a/thirdparty/icu4c/common/brkeng.cpp b/thirdparty/icu4c/common/brkeng.cpp index ce3d09cf23..3f58287532 100644 --- a/thirdparty/icu4c/common/brkeng.cpp +++ b/thirdparty/icu4c/common/brkeng.cpp @@ -21,6 +21,7 @@ #include "unicode/uscript.h" #include "unicode/ucharstrie.h" #include "unicode/bytestrie.h" +#include "unicode/rbbi.h" #include "brkeng.h" #include "cmemory.h" @@ -70,19 +71,21 @@ UnhandledEngine::~UnhandledEngine() { } UBool -UnhandledEngine::handles(UChar32 c) const { +UnhandledEngine::handles(UChar32 c, const char* locale) const { + (void)locale; // Unused return fHandled && fHandled->contains(c); } int32_t UnhandledEngine::findBreaks( UText *text, - int32_t /* startPos */, + int32_t startPos, int32_t endPos, UVector32 &/*foundBreaks*/, UBool /* isPhraseBreaking */, UErrorCode &status) const { if (U_FAILURE(status)) return 0; - UChar32 c = utext_current32(text); + utext_setNativeIndex(text, startPos); + UChar32 c = utext_current32(text); while((int32_t)utext_getNativeIndex(text) < endPos && fHandled->contains(c)) { utext_next32(text); // TODO: recast loop to work with post-increment operations. c = utext_current32(text); @@ -120,41 +123,39 @@ ICULanguageBreakFactory::~ICULanguageBreakFactory() { } } -U_NAMESPACE_END -U_CDECL_BEGIN -static void U_CALLCONV _deleteEngine(void *obj) { - delete (const icu::LanguageBreakEngine *) obj; +void ICULanguageBreakFactory::ensureEngines(UErrorCode& status) { + static UMutex gBreakEngineMutex; + Mutex m(&gBreakEngineMutex); + if (fEngines == nullptr) { + LocalPointer<UStack> engines(new UStack(uprv_deleteUObject, nullptr, status), status); + if (U_SUCCESS(status)) { + fEngines = engines.orphan(); + } + } } -U_CDECL_END -U_NAMESPACE_BEGIN const LanguageBreakEngine * -ICULanguageBreakFactory::getEngineFor(UChar32 c) { +ICULanguageBreakFactory::getEngineFor(UChar32 c, const char* locale) { const LanguageBreakEngine *lbe = nullptr; UErrorCode status = U_ZERO_ERROR; + ensureEngines(status); + if (U_FAILURE(status) ) { + // Note: no way to return error code to caller. + return nullptr; + } static UMutex gBreakEngineMutex; Mutex m(&gBreakEngineMutex); - - if (fEngines == nullptr) { - LocalPointer<UStack> engines(new UStack(_deleteEngine, nullptr, status), status); - if (U_FAILURE(status) ) { - // Note: no way to return error code to caller. - return nullptr; - } - fEngines = engines.orphan(); - } else { - int32_t i = fEngines->size(); - while (--i >= 0) { - lbe = (const LanguageBreakEngine *)(fEngines->elementAt(i)); - if (lbe != nullptr && lbe->handles(c)) { - return lbe; - } + int32_t i = fEngines->size(); + while (--i >= 0) { + lbe = (const LanguageBreakEngine *)(fEngines->elementAt(i)); + if (lbe != nullptr && lbe->handles(c, locale)) { + return lbe; } } - + // We didn't find an engine. Create one. - lbe = loadEngineFor(c); + lbe = loadEngineFor(c, locale); if (lbe != nullptr) { fEngines->push((void *)lbe, status); } @@ -162,7 +163,7 @@ ICULanguageBreakFactory::getEngineFor(UChar32 c) { } const LanguageBreakEngine * -ICULanguageBreakFactory::loadEngineFor(UChar32 c) { +ICULanguageBreakFactory::loadEngineFor(UChar32 c, const char*) { UErrorCode status = U_ZERO_ERROR; UScriptCode code = uscript_getScript(c, &status); if (U_SUCCESS(status)) { @@ -299,6 +300,70 @@ ICULanguageBreakFactory::loadDictionaryMatcherFor(UScriptCode script) { return nullptr; } + +void ICULanguageBreakFactory::addExternalEngine( + ExternalBreakEngine* external, UErrorCode& status) { + LocalPointer<ExternalBreakEngine> engine(external, status); + ensureEngines(status); + LocalPointer<BreakEngineWrapper> wrapper( + new BreakEngineWrapper(engine.orphan(), status), status); + static UMutex gBreakEngineMutex; + Mutex m(&gBreakEngineMutex); + fEngines->push(wrapper.getAlias(), status); + wrapper.orphan(); +} + +BreakEngineWrapper::BreakEngineWrapper( + ExternalBreakEngine* engine, UErrorCode &status) : delegate(engine, status) { +} + +BreakEngineWrapper::~BreakEngineWrapper() { +} + +UBool BreakEngineWrapper::handles(UChar32 c, const char* locale) const { + return delegate->isFor(c, locale); +} + +int32_t BreakEngineWrapper::findBreaks( + UText *text, + int32_t startPos, + int32_t endPos, + UVector32 &foundBreaks, + UBool /* isPhraseBreaking */, + UErrorCode &status) const { + if (U_FAILURE(status)) return 0; + int32_t result = 0; + + // Find the span of characters included in the set. + // The span to break begins at the current position in the text, and + // extends towards the start or end of the text, depending on 'reverse'. + + utext_setNativeIndex(text, startPos); + int32_t start = (int32_t)utext_getNativeIndex(text); + int32_t current; + int32_t rangeStart; + int32_t rangeEnd; + UChar32 c = utext_current32(text); + while((current = (int32_t)utext_getNativeIndex(text)) < endPos && delegate->handles(c)) { + utext_next32(text); // TODO: recast loop for postincrement + c = utext_current32(text); + } + rangeStart = start; + rangeEnd = current; + int32_t beforeSize = foundBreaks.size(); + int32_t additionalCapacity = rangeEnd - rangeStart + 1; + // enlarge to contains (rangeEnd-rangeStart+1) more items + foundBreaks.ensureCapacity(beforeSize+additionalCapacity, status); + if (U_FAILURE(status)) return 0; + foundBreaks.setSize(beforeSize + beforeSize+additionalCapacity); + result = delegate->fillBreaks(text, rangeStart, rangeEnd, foundBreaks.getBuffer()+beforeSize, + additionalCapacity, status); + if (U_FAILURE(status)) return 0; + foundBreaks.setSize(beforeSize + result); + utext_setNativeIndex(text, current); + return result; +} + U_NAMESPACE_END #endif /* #if !UCONFIG_NO_BREAK_ITERATION */ diff --git a/thirdparty/icu4c/common/brkeng.h b/thirdparty/icu4c/common/brkeng.h index 240dc8f4d3..42a3d697cf 100644 --- a/thirdparty/icu4c/common/brkeng.h +++ b/thirdparty/icu4c/common/brkeng.h @@ -10,6 +10,7 @@ #ifndef BRKENG_H #define BRKENG_H +#include "unicode/umisc.h" #include "unicode/utypes.h" #include "unicode/uobject.h" #include "unicode/utext.h" @@ -21,6 +22,7 @@ class UnicodeSet; class UStack; class UVector32; class DictionaryMatcher; +class ExternalBreakEngine; /******************************************************************* * LanguageBreakEngine @@ -35,7 +37,7 @@ class DictionaryMatcher; * <p>LanguageBreakEngines should normally be implemented so as to * be shared between threads without locking.</p> */ -class LanguageBreakEngine : public UMemory { +class LanguageBreakEngine : public UObject { public: /** @@ -54,10 +56,11 @@ class LanguageBreakEngine : public UMemory { * a particular kind of break.</p> * * @param c A character which begins a run that the engine might handle + * @param locale The locale. * @return true if this engine handles the particular character and break * type. */ - virtual UBool handles(UChar32 c) const = 0; + virtual UBool handles(UChar32 c, const char* locale) const = 0; /** * <p>Find any breaks within a run in the supplied text.</p> @@ -81,6 +84,35 @@ class LanguageBreakEngine : public UMemory { }; /******************************************************************* + * BreakEngineWrapper + */ + +/** + * <p>BreakEngineWrapper implement LanguageBreakEngine by + * a thin wrapper that delegate the task to ExternalBreakEngine + * </p> + */ +class BreakEngineWrapper : public LanguageBreakEngine { + public: + + BreakEngineWrapper(ExternalBreakEngine* engine, UErrorCode &status); + + virtual ~BreakEngineWrapper(); + + virtual UBool handles(UChar32 c, const char* locale) const override; + + virtual int32_t findBreaks( UText *text, + int32_t startPos, + int32_t endPos, + UVector32 &foundBreaks, + UBool isPhraseBreaking, + UErrorCode &status) const override; + + private: + LocalPointer<ExternalBreakEngine> delegate; +}; + +/******************************************************************* * LanguageBreakFactory */ @@ -125,9 +157,10 @@ class LanguageBreakFactory : public UMemory { * * @param c A character that begins a run for which a LanguageBreakEngine is * sought. + * @param locale The locale. * @return A LanguageBreakEngine with the desired characteristics, or 0. */ - virtual const LanguageBreakEngine *getEngineFor(UChar32 c) = 0; + virtual const LanguageBreakEngine *getEngineFor(UChar32 c, const char* locale) = 0; }; @@ -174,10 +207,11 @@ class UnhandledEngine : public LanguageBreakEngine { * a particular kind of break.</p> * * @param c A character which begins a run that the engine might handle + * @param locale The locale. * @return true if this engine handles the particular character and break * type. */ - virtual UBool handles(UChar32 c) const override; + virtual UBool handles(UChar32 c, const char* locale) const override; /** * <p>Find any breaks within a run in the supplied text.</p> @@ -247,9 +281,18 @@ class ICULanguageBreakFactory : public LanguageBreakFactory { * * @param c A character that begins a run for which a LanguageBreakEngine is * sought. + * @param locale The locale. * @return A LanguageBreakEngine with the desired characteristics, or 0. */ - virtual const LanguageBreakEngine *getEngineFor(UChar32 c) override; + virtual const LanguageBreakEngine *getEngineFor(UChar32 c, const char* locale) override; + + /** + * Add and adopt the engine and return an URegistryKey. + * @param engine The ExternalBreakEngine to be added and adopt. The caller + * pass the ownership and should not release the memory after this. + * @param status the error code. + */ + virtual void addExternalEngine(ExternalBreakEngine* engine, UErrorCode& status); protected: /** @@ -258,9 +301,10 @@ protected: * * @param c A character that begins a run for which a LanguageBreakEngine is * sought. + * @param locale The locale. * @return A LanguageBreakEngine with the desired characteristics, or 0. */ - virtual const LanguageBreakEngine *loadEngineFor(UChar32 c); + virtual const LanguageBreakEngine *loadEngineFor(UChar32 c, const char* locale); /** * <p>Create a DictionaryMatcher for the specified script and break type.</p> @@ -269,6 +313,9 @@ protected: * @return A DictionaryMatcher with the desired characteristics, or nullptr. */ virtual DictionaryMatcher *loadDictionaryMatcherFor(UScriptCode script); + + private: + void ensureEngines(UErrorCode& status); }; U_NAMESPACE_END diff --git a/thirdparty/icu4c/common/brkiter.cpp b/thirdparty/icu4c/common/brkiter.cpp index 41e4e0dff5..b452cf2c05 100644 --- a/thirdparty/icu4c/common/brkiter.cpp +++ b/thirdparty/icu4c/common/brkiter.cpp @@ -27,6 +27,7 @@ #include "unicode/rbbi.h" #include "unicode/brkiter.h" #include "unicode/udata.h" +#include "unicode/uloc.h" #include "unicode/ures.h" #include "unicode/ustring.h" #include "unicode/filteredbrk.h" @@ -121,8 +122,11 @@ BreakIterator::buildInstance(const Locale& loc, const char *type, UErrorCode &st // If there is a result, set the valid locale and actual locale, and the kind if (U_SUCCESS(status) && result != nullptr) { U_LOCALE_BASED(locBased, *(BreakIterator*)result); + locBased.setLocaleIDs(ures_getLocaleByType(b, ULOC_VALID_LOCALE, &status), actualLocale.data()); + uprv_strncpy(result->requestLocale, loc.getName(), ULOC_FULLNAME_CAPACITY); + result->requestLocale[ULOC_FULLNAME_CAPACITY-1] = 0; // always terminate } ures_close(b); @@ -202,18 +206,20 @@ BreakIterator::getAvailableLocales(int32_t& count) BreakIterator::BreakIterator() { - *validLocale = *actualLocale = 0; + *validLocale = *actualLocale = *requestLocale = 0; } BreakIterator::BreakIterator(const BreakIterator &other) : UObject(other) { uprv_strncpy(actualLocale, other.actualLocale, sizeof(actualLocale)); uprv_strncpy(validLocale, other.validLocale, sizeof(validLocale)); + uprv_strncpy(requestLocale, other.requestLocale, sizeof(requestLocale)); } BreakIterator &BreakIterator::operator =(const BreakIterator &other) { if (this != &other) { uprv_strncpy(actualLocale, other.actualLocale, sizeof(actualLocale)); uprv_strncpy(validLocale, other.validLocale, sizeof(validLocale)); + uprv_strncpy(requestLocale, other.requestLocale, sizeof(requestLocale)); } return *this; } @@ -493,12 +499,18 @@ BreakIterator::makeInstance(const Locale& loc, int32_t kind, UErrorCode& status) Locale BreakIterator::getLocale(ULocDataLocaleType type, UErrorCode& status) const { + if (type == ULOC_REQUESTED_LOCALE) { + return Locale(requestLocale); + } U_LOCALE_BASED(locBased, *this); return locBased.getLocale(type, status); } const char * BreakIterator::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const { + if (type == ULOC_REQUESTED_LOCALE) { + return requestLocale; + } U_LOCALE_BASED(locBased, *this); return locBased.getLocaleID(type, status); } diff --git a/thirdparty/icu4c/common/characterproperties.cpp b/thirdparty/icu4c/common/characterproperties.cpp index 978e6761ce..f1e15b488d 100644 --- a/thirdparty/icu4c/common/characterproperties.cpp +++ b/thirdparty/icu4c/common/characterproperties.cpp @@ -169,7 +169,7 @@ void U_CALLCONV initInclusion(UPropertySource src, UErrorCode &errorCode) { case UPROPS_SRC_INPC: case UPROPS_SRC_INSC: case UPROPS_SRC_VO: - uprops_addPropertyStarts((UPropertySource)src, &sa, &errorCode); + uprops_addPropertyStarts(src, &sa, &errorCode); break; case UPROPS_SRC_EMOJI: { const icu::EmojiProps *ep = icu::EmojiProps::getSingleton(errorCode); @@ -178,6 +178,14 @@ void U_CALLCONV initInclusion(UPropertySource src, UErrorCode &errorCode) { } break; } + case UPROPS_SRC_IDSU: + // New in Unicode 15.1 for just two characters. + sa.add(sa.set, 0x2FFE); + sa.add(sa.set, 0x2FFF + 1); + break; + case UPROPS_SRC_ID_COMPAT_MATH: + uprops_addPropertyStarts(src, &sa, &errorCode); + break; default: errorCode = U_INTERNAL_PROGRAM_ERROR; break; diff --git a/thirdparty/icu4c/common/dictbe.cpp b/thirdparty/icu4c/common/dictbe.cpp index 0e420c67c5..3d672c03bf 100644 --- a/thirdparty/icu4c/common/dictbe.cpp +++ b/thirdparty/icu4c/common/dictbe.cpp @@ -42,7 +42,7 @@ DictionaryBreakEngine::~DictionaryBreakEngine() { } UBool -DictionaryBreakEngine::handles(UChar32 c) const { +DictionaryBreakEngine::handles(UChar32 c, const char*) const { return fSet.contains(c); } @@ -54,13 +54,13 @@ DictionaryBreakEngine::findBreaks( UText *text, UBool isPhraseBreaking, UErrorCode& status) const { if (U_FAILURE(status)) return 0; - (void)startPos; // TODO: remove this param? int32_t result = 0; // Find the span of characters included in the set. // The span to break begins at the current position in the text, and // extends towards the start or end of the text, depending on 'reverse'. + utext_setNativeIndex(text, startPos); int32_t start = (int32_t)utext_getNativeIndex(text); int32_t current; int32_t rangeStart; diff --git a/thirdparty/icu4c/common/dictbe.h b/thirdparty/icu4c/common/dictbe.h index a2c761bdc3..e512071fa4 100644 --- a/thirdparty/icu4c/common/dictbe.h +++ b/thirdparty/icu4c/common/dictbe.h @@ -62,10 +62,11 @@ class DictionaryBreakEngine : public LanguageBreakEngine { * a particular kind of break.</p> * * @param c A character which begins a run that the engine might handle + * @param locale The locale. * @return true if this engine handles the particular character and break * type. */ - virtual UBool handles(UChar32 c) const override; + virtual UBool handles(UChar32 c, const char* locale) const override; /** * <p>Find any breaks within a run in the supplied text.</p> diff --git a/thirdparty/icu4c/common/loadednormalizer2impl.cpp b/thirdparty/icu4c/common/loadednormalizer2impl.cpp index 768564edc8..99b8f3e86c 100644 --- a/thirdparty/icu4c/common/loadednormalizer2impl.cpp +++ b/thirdparty/icu4c/common/loadednormalizer2impl.cpp @@ -143,6 +143,9 @@ static icu::UInitOnce nfkcInitOnce {}; static Norm2AllModes *nfkc_cfSingleton; static icu::UInitOnce nfkc_cfInitOnce {}; +static Norm2AllModes *nfkc_scfSingleton; +static icu::UInitOnce nfkc_scfInitOnce {}; + static UHashtable *cache=nullptr; // UInitOnce singleton initialization function @@ -156,6 +159,8 @@ static void U_CALLCONV initSingletons(const char *what, UErrorCode &errorCode) { nfkcSingleton = Norm2AllModes::createInstance(nullptr, "nfkc", errorCode); } else if (uprv_strcmp(what, "nfkc_cf") == 0) { nfkc_cfSingleton = Norm2AllModes::createInstance(nullptr, "nfkc_cf", errorCode); + } else if (uprv_strcmp(what, "nfkc_scf") == 0) { + nfkc_scfSingleton = Norm2AllModes::createInstance(nullptr, "nfkc_scf", errorCode); } else { UPRV_UNREACHABLE_EXIT; // Unknown singleton } @@ -183,6 +188,10 @@ static UBool U_CALLCONV uprv_loaded_normalizer2_cleanup() { nfkc_cfSingleton = nullptr; nfkc_cfInitOnce.reset(); + delete nfkc_scfSingleton; + nfkc_scfSingleton = nullptr; + nfkc_scfInitOnce.reset(); + uhash_close(cache); cache=nullptr; return true; @@ -213,6 +222,13 @@ Norm2AllModes::getNFKC_CFInstance(UErrorCode &errorCode) { return nfkc_cfSingleton; } +const Norm2AllModes * +Norm2AllModes::getNFKC_SCFInstance(UErrorCode &errorCode) { + if(U_FAILURE(errorCode)) { return nullptr; } + umtx_initOnce(nfkc_scfInitOnce, &initSingletons, "nfkc_scf", errorCode); + return nfkc_scfSingleton; +} + #if !NORM2_HARDCODE_NFC_DATA const Normalizer2 * Normalizer2::getNFCInstance(UErrorCode &errorCode) { @@ -262,6 +278,12 @@ Normalizer2::getNFKCCasefoldInstance(UErrorCode &errorCode) { } const Normalizer2 * +Normalizer2::getNFKCSimpleCasefoldInstance(UErrorCode &errorCode) { + const Norm2AllModes *allModes=Norm2AllModes::getNFKC_SCFInstance(errorCode); + return allModes!=nullptr ? &allModes->comp : nullptr; +} + +const Normalizer2 * Normalizer2::getInstance(const char *packageName, const char *name, UNormalization2Mode mode, @@ -281,6 +303,8 @@ Normalizer2::getInstance(const char *packageName, allModes=Norm2AllModes::getNFKCInstance(errorCode); } else if(0==uprv_strcmp(name, "nfkc_cf")) { allModes=Norm2AllModes::getNFKC_CFInstance(errorCode); + } else if(0==uprv_strcmp(name, "nfkc_scf")) { + allModes=Norm2AllModes::getNFKC_SCFInstance(errorCode); } } if(allModes==nullptr && U_SUCCESS(errorCode)) { @@ -394,6 +418,11 @@ unorm2_getNFKCCasefoldInstance(UErrorCode *pErrorCode) { } U_CAPI const UNormalizer2 * U_EXPORT2 +unorm2_getNFKCSimpleCasefoldInstance(UErrorCode *pErrorCode) { + return (const UNormalizer2 *)Normalizer2::getNFKCSimpleCasefoldInstance(*pErrorCode); +} + +U_CAPI const UNormalizer2 * U_EXPORT2 unorm2_getInstance(const char *packageName, const char *name, UNormalization2Mode mode, diff --git a/thirdparty/icu4c/common/localefallback_data.h b/thirdparty/icu4c/common/localefallback_data.h index d2eb7eaafd..c847edefff 100644 --- a/thirdparty/icu4c/common/localefallback_data.h +++ b/thirdparty/icu4c/common/localefallback_data.h @@ -18,94 +18,93 @@ const char scriptCodeChars[] = "Kana\0Kawi\0Khar\0Khmr\0Kits\0Knda\0Kore\0Lana\0Laoo\0Lepc\0Lina\0" "Linb\0Lisu\0Lyci\0Lydi\0Mand\0Mani\0Marc\0Medf\0Merc\0Mlym\0Modi\0" "Mong\0Mroo\0Mtei\0Mymr\0Narb\0Newa\0Nkoo\0Nshu\0Ogam\0Olck\0Orkh\0" - "Orya\0Osge\0Ougr\0Pauc\0Phli\0Phnx\0Plrd\0Prti\0Rjng\0Rohg\0Runr\0" - "Samr\0Sarb\0Saur\0Sgnw\0Sinh\0Sogd\0Sora\0Soyo\0Syrc\0Tagb\0Takr\0" - "Tale\0Talu\0Taml\0Tang\0Tavt\0Telu\0Tfng\0Thaa\0Thai\0Tibt\0Tnsa\0" - "Toto\0Ugar\0Vaii\0Wcho\0Xpeo\0Xsux\0Yiii\0"; + "Orya\0Osge\0Pauc\0Phli\0Phnx\0Plrd\0Prti\0Rjng\0Rohg\0Runr\0Samr\0" + "Sarb\0Saur\0Sgnw\0Sinh\0Sogd\0Sora\0Soyo\0Syrc\0Tagb\0Takr\0Tale\0" + "Talu\0Taml\0Tang\0Tavt\0Telu\0Tfng\0Thaa\0Thai\0Tibt\0Tnsa\0Toto\0" + "Ugar\0Vaii\0Wcho\0Xpeo\0Xsux\0Yiii\0"; const char dsLocaleIDChars[] = - "aaf\0aao\0aat\0ab\0abh\0abl\0abq\0abv\0acm\0acq\0acw\0acx\0adf\0" - "adp\0adx\0ady\0ae\0aeb\0aec\0aee\0aeq\0afb\0agi\0agj\0agx\0ahg\0" - "aho\0ahr\0aib\0aij\0ain\0aio\0aiq\0ajp\0ajt\0akk\0akv\0alk\0all\0" - "alr\0alt\0alw\0am\0ams\0amw\0ani\0anp\0anr\0anu\0aot\0apc\0apd\0" - "aph\0aqc\0ar\0arc\0arq\0ars\0ary\0arz\0as\0ase\0ask\0atn\0atv\0" - "auj\0auz\0av\0avd\0avl\0awa\0awn\0axm\0ayh\0ayl\0ayn\0ayp\0az_IQ\0" - "az_IR\0az_RU\0azb\0ba\0bal\0bap\0bax\0bbl\0bcq\0bdv\0bdz\0be\0" - "bee\0bej\0bfb\0bfq\0bft\0bfu\0bfw\0bfy\0bfz\0bg\0bgc\0bgd\0bgn\0" - "bgp\0bgq\0bgw\0bgx\0bha\0bhb\0bhd\0bhe\0bhh\0bhi\0bhj\0bhm\0bhn\0" - "bho\0bht\0bhu\0biy\0bjf\0bji\0bjj\0bjm\0blk\0blt\0bmj\0bn\0bns\0" - "bo\0bph\0bpx\0bpy\0bqi\0bra\0brb\0brd\0brh\0brk\0brv\0brx\0bsh\0" - "bsk\0bsq\0bst\0btd\0btm\0btv\0bua\0bwe\0bxm\0bxu\0byh\0byn\0byw\0" - "bzi\0cbn\0ccp\0cde\0cdh\0cdi\0cdj\0cdm\0cdo\0cdz\0ce\0cgk\0chg\0" - "chm\0chr\0chx\0cih\0cja\0cji\0cjm\0cjy\0ckb\0ckt\0clh\0clw\0cmg\0" - "cna\0cnp\0cog\0cop\0cpg\0cr\0crh\0crj\0crk\0crl\0crm\0csh\0csp\0" - "csw\0ctd\0ctg\0ctn\0ctt\0cu\0cuu\0cv\0czh\0czk\0daq\0dar\0dcc\0" - "ddo\0def\0deh\0der\0dgl\0dhi\0dhn\0dho\0dhw\0dka\0dlg\0dmf\0dmk\0" - "dml\0dng\0dnu\0dnv\0doi\0dox\0dre\0drh\0drq\0drs\0dry\0dso\0dty\0" - "dub\0duh\0dus\0dv\0dwk\0dwz\0dz\0dzl\0ecr\0ecy\0egy\0eky\0el\0" - "emg\0emu\0enf\0enh\0era\0esg\0esh\0ett\0eve\0evn\0fa\0fay\0faz\0" - "fia\0fmu\0fub\0gan\0gaq\0gas\0gau\0gbj\0gbk\0gbl\0gbm\0gbz\0gdb\0" - "gdo\0gdx\0gez\0ggg\0ggn\0gha\0ghe\0ghr\0ght\0gig\0gin\0gjk\0gju\0" - "gld\0glh\0glk\0gmv\0gmy\0goe\0gof\0gok\0gom\0gon\0got\0gra\0grc\0" - "grt\0gru\0gu\0gvr\0gwc\0gwf\0gwt\0gyo\0gzi\0ha_CM\0ha_SD\0hac\0" - "hak\0har\0haz\0hbo\0hdy\0he\0hi\0hii\0hit\0hkh\0hlb\0hlu\0hmd\0" - "hmj\0hmq\0hnd\0hne\0hnj\0hnj_AU\0hnj_CN\0hnj_FR\0hnj_GF\0hnj_LA\0" - "hnj_MM\0hnj_SR\0hnj_TH\0hnj_US\0hnj_VN\0hno\0hoc\0hoh\0hoj\0how\0" - "hoy\0hpo\0hrt\0hrz\0hsn\0hss\0htx\0hut\0huy\0huz\0hy\0hyw\0ii\0" - "imy\0inh\0int\0ior\0iru\0isk\0itk\0itl\0iu\0iw\0ja\0jad\0jat\0" - "jbe\0jbn\0jct\0jda\0jdg\0jdt\0jee\0jge\0ji\0jje\0jkm\0jml\0jna\0" - "jnd\0jnl\0jns\0jog\0jpa\0jpr\0jul\0jun\0juy\0jya\0jye\0ka\0kaa\0" - "kap\0kaw\0kbd\0kbu\0kby\0kca\0kdq\0kdt\0ket\0kex\0key\0kfa\0kfb\0" - "kfc\0kfd\0kfe\0kfh\0kfi\0kfk\0kfm\0kfp\0kfq\0kfr\0kfs\0kfx\0kfy\0" - "kgj\0kgy\0khb\0khf\0khg\0khn\0kht\0khv\0khw\0kif\0kim\0kip\0kjg\0" - "kjh\0kjl\0kjo\0kjp\0kjt\0kk\0kk_AF\0kk_CN\0kk_IR\0kk_MN\0kkf\0" - "kkh\0kkt\0kle\0klj\0klr\0km\0kmj\0kmz\0kn\0ko\0koi\0kok\0kpt\0" - "kpy\0kqd\0kqy\0kra\0krc\0krk\0krr\0kru\0krv\0ks\0ksu\0ksw\0ksz\0" - "ktb\0ktl\0ktp\0ku_LB\0kuf\0kum\0kv\0kva\0kvq\0kvt\0kvx\0kvy\0" - "kxc\0kxf\0kxk\0kxl\0kxm\0kxp\0kxv\0ky\0ky_CN\0kyu\0kyv\0kyw\0" - "kzh\0lab\0lad\0lae\0lah\0lbc\0lbe\0lbf\0lbj\0lbm\0lbo\0lbr\0lcp\0" - "lep\0lez\0lhm\0lhs\0lif\0lis\0lkh\0lki\0lmh\0lmn\0lo\0loy\0lpo\0" - "lrc\0lrk\0lrl\0lsa\0lsd\0lss\0luk\0luu\0luv\0luz\0lwl\0lwm\0lya\0" - "lzh\0mag\0mai\0man_GN\0mby\0mde\0mdf\0mdx\0mdy\0mfa\0mfi\0mgp\0" - "mhj\0mid\0mjl\0mjq\0mjr\0mjt\0mju\0mjv\0mjz\0mk\0mkb\0mke\0mki\0" - "mkm\0ml\0mlf\0mn\0mn_CN\0mni\0mnj\0mns\0mnw\0mpz\0mr\0mra\0mrd\0" - "mrj\0mro\0mrr\0ms_CC\0mtm\0mtr\0mud\0muk\0mut\0muv\0muz\0mvf\0" - "mvy\0mvz\0mwr\0mwt\0mww\0my\0mym\0myv\0myz\0mzn\0nan\0nao\0ncd\0" - "ncq\0ndf\0ne\0neg\0neh\0nei\0new\0ngt\0nio\0nit\0niv\0nli\0nlm\0" - "nlx\0nmm\0nnp\0nod\0noe\0nog\0noi\0non\0nos\0npb\0nqo\0nsd\0nsf\0" - "nsk\0nst\0nsv\0nty\0ntz\0nwc\0nwx\0nyl\0nyq\0oaa\0oac\0oar\0oav\0" - "obm\0obr\0odk\0oht\0oj\0ojs\0okm\0oko\0okz\0ola\0ole\0omk\0omp\0" - "omr\0oon\0or\0ort\0oru\0orv\0os\0osa\0osc\0osi\0ota\0otb\0otk\0" - "oty\0oui\0pa\0pa_PK\0pal\0paq\0pbt\0pcb\0pce\0pcf\0pcg\0pch\0" - "pci\0pcj\0peg\0peo\0pgd\0pgg\0pgl\0pgn\0phd\0phk\0phl\0phn\0pho\0" - "phr\0pht\0phv\0phw\0pi\0pka\0pkr\0plk\0pll\0pmh\0pnt\0ppa\0pra\0" + "aaf\0aao\0aat\0ab\0abh\0abl\0abv\0acm\0acq\0acw\0acx\0adf\0adx\0" + "ady\0ae\0aeb\0aec\0aee\0aeq\0afb\0agi\0agj\0agx\0ahg\0aho\0ahr\0" + "aib\0aij\0ain\0aio\0aiq\0ajp\0akk\0akv\0alk\0all\0alr\0alt\0alw\0" + "am\0ams\0amw\0ani\0anp\0anr\0anu\0aot\0apc\0apd\0aph\0aqc\0ar\0" + "arc\0arq\0ars\0ary\0arz\0as\0ase\0ask\0atn\0atv\0auj\0auz\0av\0" + "avd\0avl\0awa\0awn\0axm\0ayh\0ayl\0ayn\0ayp\0az_IQ\0az_IR\0az_RU\0" + "azb\0ba\0bal\0bap\0bax\0bbl\0bcq\0bdv\0bdz\0be\0bee\0bej\0bfb\0" + "bfq\0bft\0bfu\0bfw\0bfy\0bfz\0bg\0bgc\0bgd\0bgn\0bgp\0bgq\0bgw\0" + "bgx\0bha\0bhb\0bhd\0bhe\0bhh\0bhi\0bhj\0bhm\0bhn\0bho\0bht\0bhu\0" + "biy\0bjf\0bjj\0bjm\0blk\0blt\0bmj\0bn\0bns\0bo\0bph\0bpx\0bpy\0" + "bqi\0bra\0brb\0brd\0brh\0brk\0brv\0brx\0bsh\0bsk\0bsq\0bst\0btd\0" + "btm\0btv\0bua\0bwe\0bxm\0bxu\0byh\0byn\0byw\0bzi\0cbn\0ccp\0cde\0" + "cdh\0cdi\0cdj\0cdm\0cdo\0cdz\0ce\0cgk\0chg\0chm\0chr\0chx\0cih\0" + "cja\0cji\0cjm\0cjy\0ckb\0ckt\0clh\0clw\0cmg\0cna\0cnp\0cog\0cop\0" + "cpg\0cr\0crh\0crj\0crk\0crl\0crm\0csh\0csp\0csw\0ctd\0ctg\0ctn\0" + "ctt\0cu\0cuu\0cv\0czh\0czk\0daq\0dar\0dcc\0ddo\0def\0deh\0der\0" + "dhi\0dhn\0dho\0dhw\0dka\0dlg\0dmf\0dmk\0dml\0dng\0dnu\0dnv\0doi\0" + "dox\0dre\0drq\0drs\0dry\0dso\0dty\0dub\0duh\0dus\0dv\0dwk\0dwz\0" + "dz\0dzl\0ecr\0ecy\0egy\0eky\0el\0emg\0emu\0enf\0enh\0era\0esg\0" + "esh\0ett\0eve\0evn\0fa\0fay\0faz\0fia\0fmu\0fub\0gan\0gaq\0gas\0" + "gau\0gbj\0gbk\0gbl\0gbm\0gbz\0gdb\0gdo\0gdx\0gez\0ggg\0gha\0ghe\0" + "ghr\0ght\0gig\0gin\0gjk\0gju\0gld\0glh\0glk\0gmv\0gmy\0goe\0gof\0" + "gok\0gom\0gon\0got\0gra\0grc\0grt\0gru\0gu\0gvr\0gwc\0gwf\0gwt\0" + "gyo\0gzi\0ha_CM\0ha_SD\0hac\0hak\0har\0haz\0hbo\0hdy\0he\0hi\0" + "hii\0hit\0hkh\0hlb\0hlu\0hmd\0hmj\0hmq\0hnd\0hne\0hnj\0hnj_AU\0" + "hnj_CN\0hnj_FR\0hnj_GF\0hnj_LA\0hnj_MM\0hnj_SR\0hnj_TH\0hnj_VN\0" + "hno\0hoc\0hoh\0hoj\0how\0hoy\0hpo\0hrt\0hrz\0hsn\0hss\0htx\0hut\0" + "huy\0huz\0hy\0hyw\0ii\0imy\0inh\0int\0ior\0iru\0isk\0itk\0itl\0" + "iu\0iw\0ja\0jad\0jat\0jbe\0jbn\0jct\0jda\0jdg\0jdt\0jee\0jge\0" + "ji\0jje\0jkm\0jml\0jna\0jnd\0jnl\0jns\0jog\0jpa\0jpr\0jrb\0jrb_MA\0" + "jul\0jun\0juy\0jya\0jye\0ka\0kaa\0kap\0kaw\0kbd\0kbu\0kby\0kca\0" + "kdq\0kdt\0ket\0kex\0key\0kfa\0kfb\0kfc\0kfd\0kfe\0kfh\0kfi\0kfk\0" + "kfm\0kfp\0kfq\0kfr\0kfs\0kfx\0kfy\0kgj\0kgy\0khb\0khf\0khg\0khn\0" + "kht\0khv\0khw\0kif\0kim\0kip\0kjg\0kjh\0kjl\0kjo\0kjp\0kjt\0kk\0" + "kk_AF\0kk_CN\0kk_IR\0kk_MN\0kkf\0kkh\0kkt\0kle\0klj\0klr\0km\0" + "kmj\0kmz\0kn\0ko\0koi\0kok\0kpt\0kpy\0kqd\0kqy\0kra\0krc\0krk\0" + "krr\0kru\0krv\0ks\0ksu\0ksw\0ksz\0ktb\0ktl\0ktp\0ku_LB\0kuf\0" + "kum\0kv\0kva\0kvq\0kvt\0kvx\0kvy\0kxf\0kxk\0kxm\0kxp\0ky\0ky_CN\0" + "kyu\0kyv\0kyw\0lab\0lad\0lae\0lah\0lbc\0lbe\0lbf\0lbj\0lbm\0lbo\0" + "lbr\0lcp\0lep\0lez\0lhm\0lhs\0lif\0lis\0lkh\0lki\0lmh\0lmn\0lo\0" + "loy\0lpo\0lrc\0lrk\0lrl\0lsa\0lsd\0lss\0luk\0luu\0luv\0luz\0lwl\0" + "lwm\0lya\0lzh\0mag\0mai\0man_GN\0mby\0mde\0mdf\0mdx\0mdy\0mfa\0" + "mfi\0mgp\0mhj\0mid\0mjl\0mjq\0mjr\0mjt\0mju\0mjv\0mjz\0mk\0mkb\0" + "mke\0mki\0mkm\0ml\0mlf\0mn\0mn_CN\0mni\0mnj\0mns\0mnw\0mpz\0mr\0" + "mra\0mrd\0mrj\0mro\0mrr\0ms_CC\0mtm\0mtr\0mud\0muk\0mut\0muv\0" + "muz\0mvf\0mvy\0mvz\0mwr\0mwt\0mww\0my\0mym\0myv\0myz\0mzn\0nan\0" + "nao\0ncd\0ncq\0ndf\0ne\0neg\0neh\0nei\0new\0ngt\0nio\0nit\0niv\0" + "nli\0nlm\0nlx\0nmm\0nnp\0nod\0noe\0nog\0noi\0non\0nos\0npb\0nqo\0" + "nsd\0nsf\0nsk\0nst\0nsv\0nty\0ntz\0nwc\0nwx\0nyl\0nyq\0oaa\0oac\0" + "oar\0oav\0obm\0obr\0odk\0oht\0oj\0ojs\0okm\0oko\0okz\0ola\0ole\0" + "omk\0omp\0omr\0oon\0or\0ort\0oru\0orv\0os\0osa\0osc\0osi\0ota\0" + "otb\0otk\0oty\0pa\0pa_PK\0pal\0paq\0pbt\0pcb\0pce\0pcf\0pcg\0" + "pch\0pci\0pcj\0peg\0peo\0pgd\0pgg\0pgl\0pgn\0phd\0phk\0phl\0phn\0" + "pho\0phr\0pht\0phv\0phw\0pi\0pka\0pkr\0plk\0pll\0pmh\0pnt\0pra\0" "prc\0prd\0prp\0prt\0prx\0ps\0psh\0psi\0pst\0pum\0pwo\0pwr\0pww\0" "pyx\0qxq\0raa\0rab\0raf\0rah\0raj\0rav\0rbb\0rdb\0rei\0rhg\0rji\0" - "rjs\0rka\0rki\0rkt\0rmi\0rmt\0rmz\0rsk\0rtw\0ru\0rue\0rut\0rwr\0" - "ryu\0sa\0sah\0sam\0sat\0saz\0sbn\0sbu\0sck\0scl\0scp\0sct\0scu\0" - "scx\0sd\0sd_IN\0sdb\0sdf\0sdg\0sdh\0sds\0sel\0sfm\0sga\0sgh\0" - "sgj\0sgr\0sgt\0sgw\0sgy\0shd\0shi\0shm\0shn\0shu\0shv\0si\0sia\0" - "sip\0siy\0siz\0sjd\0sjp\0sjt\0skb\0skj\0skr\0slq\0smh\0smp\0smu\0" - "smy\0soa\0sog\0soi\0sou\0spt\0spv\0sqo\0sqq\0sqt\0sr\0srb\0srh\0" - "srx\0srz\0ssh\0sss\0sts\0stv\0sty\0suz\0sva\0swb\0swi\0swv\0syc\0" - "syl\0syn\0syr\0syw\0ta\0tab\0taj\0tbk\0tcn\0tco\0tcx\0tcy\0tda\0" - "tdb\0tdd\0tdg\0tdh\0te\0tes\0tg\0tg_PK\0tge\0tgf\0th\0the\0thf\0" - "thi\0thl\0thm\0thq\0thr\0ths\0ti\0tig\0tij\0tin\0tjl\0tjo\0tkb\0" - "tks\0tkt\0tmk\0tmr\0tnv\0tov\0tpu\0tra\0trg\0trm\0trw\0tsd\0tsf\0" - "tsj\0tt\0tth\0tto\0tts\0tvn\0twm\0txg\0txo\0tyr\0tyv\0ude\0udg\0" - "udi\0udm\0ug\0ug_KZ\0ug_MN\0uga\0ugh\0ugo\0uk\0uki\0ulc\0unr\0" - "unr_NP\0unx\0ur\0urk\0ush\0uum\0uz_AF\0uz_CN\0uzs\0vaa\0vaf\0" - "vah\0vai\0vas\0vav\0vay\0vgr\0vmd\0vmh\0wal\0wbk\0wbq\0wbr\0wlo\0" - "wme\0wne\0wni\0wsg\0wsv\0wtm\0wuu\0xal\0xan\0xas\0xco\0xcr\0xdq\0" - "xhe\0xhm\0xis\0xka\0xkc\0xkj\0xkp\0xlc\0xld\0xly\0xmf\0xmn\0xmr\0" - "xna\0xnr\0xpg\0xpi\0xpm\0xpr\0xrm\0xrn\0xsa\0xsr\0xss\0xub\0xuj\0" - "xve\0xvi\0xwo\0xzh\0yai\0ybh\0ybi\0ydg\0yea\0yej\0yeu\0ygp\0yhd\0" - "yi\0yig\0yih\0yiv\0ykg\0yna\0ynk\0yoi\0yoy\0yrk\0ysd\0ysn\0ysp\0" - "ysr\0ysy\0yud\0yue\0yue_CN\0yug\0yux\0ywq\0ywu\0zau\0zba\0zch\0" - "zdj\0zeh\0zen\0zgb\0zgh\0zgm\0zgn\0zh\0zh_AU\0zh_BN\0zh_GB\0zh_GF\0" - "zh_HK\0zh_ID\0zh_MO\0zh_PA\0zh_PF\0zh_PH\0zh_SR\0zh_TH\0zh_TW\0" - "zh_US\0zh_VN\0zhd\0zhx\0zkb\0zko\0zkt\0zkz\0zlj\0zln\0zlq\0zqe\0" - "zrp\0zum\0zyg\0zyn\0zzj\0"; + "rjs\0rka\0rki\0rkt\0rmi\0rmt\0rmz\0rom_BG\0rsk\0rtw\0ru\0rue\0" + "rut\0rwr\0ryu\0sa\0sah\0sam\0sat\0saz\0sbn\0sbu\0sck\0scl\0scl_IN\0" + "scp\0sct\0scu\0scx\0sd\0sd_IN\0sdb\0sdf\0sdg\0sdh\0sds\0sel\0" + "sfm\0sga\0sgh\0sgj\0sgr\0sgt\0sgw\0sgy\0shd\0shi\0shm\0shn\0shu\0" + "shv\0si\0sia\0sip\0siy\0siz\0sjd\0sjp\0sjt\0skb\0skj\0skr\0slq\0" + "smh\0smp\0smu\0smy\0soa\0sog\0soi\0sou\0spt\0spv\0sqo\0sqq\0sqt\0" + "sr\0srb\0srh\0srx\0srz\0ssh\0sss\0sts\0stv\0sty\0suz\0sva\0swb\0" + "swi\0swv\0syc\0syl\0syn\0syr\0syw\0ta\0tab\0taj\0tbk\0tcn\0tco\0" + "tcx\0tcy\0tda\0tdb\0tdd\0tdg\0tdh\0te\0tes\0tg\0tg_PK\0tge\0tgf\0" + "th\0the\0thf\0thi\0thl\0thm\0thq\0thr\0ths\0ti\0tig\0tij\0tin\0" + "tjl\0tjo\0tkb\0tks\0tkt\0tmk\0tmr\0tnv\0tov\0tpu\0tra\0trg\0trm\0" + "trw\0tsd\0tsj\0tt\0tth\0tto\0tts\0tvn\0twm\0txg\0txo\0tyr\0tyv\0" + "ude\0udg\0udi\0udm\0ug\0ug_KZ\0ug_MN\0uga\0ugh\0ugo\0uk\0uki\0" + "ulc\0unr\0unr_NP\0unx\0ur\0urk\0ush\0uum\0uz_AF\0uz_CN\0uzs\0" + "vaa\0vaf\0vah\0vai\0vas\0vav\0vay\0vgr\0vmd\0vmh\0wal\0wbk\0wbq\0" + "wbr\0wlo\0wme\0wne\0wni\0wsg\0wsv\0wtm\0wuu\0xal\0xan\0xas\0xco\0" + "xcr\0xdq\0xhe\0xhm\0xis\0xka\0xkc\0xkj\0xkp\0xlc\0xld\0xly\0xmf\0" + "xmn\0xmr\0xna\0xnr\0xpg\0xpi\0xpm\0xpr\0xrm\0xrn\0xsa\0xsr\0xss\0" + "xub\0xuj\0xve\0xvi\0xwo\0xzh\0yai\0ybh\0ybi\0ydg\0yea\0yej\0yeu\0" + "ygp\0yhd\0yi\0yig\0yih\0yiv\0ykg\0yna\0ynk\0yoi\0yoy\0yrk\0ysd\0" + "ysn\0ysp\0ysr\0ysy\0yud\0yue\0yue_CN\0yug\0yux\0ywq\0ywu\0zau\0" + "zba\0zch\0zdj\0zeh\0zen\0zgb\0zgh\0zgm\0zgn\0zh\0zh_AU\0zh_BN\0" + "zh_GB\0zh_GF\0zh_HK\0zh_ID\0zh_MO\0zh_PA\0zh_PF\0zh_PH\0zh_SR\0" + "zh_TH\0zh_TW\0zh_US\0zh_VN\0zhd\0zhx\0zkb\0zko\0zkt\0zkz\0zlj\0" + "zln\0zlq\0zqe\0zrp\0zum\0zyg\0zyn\0zzj\0"; const int32_t defaultScriptTable[] = { 0, 320, // aaf -> Mlym @@ -113,1033 +112,1022 @@ const int32_t defaultScriptTable[] = { 8, 150, // aat -> Grek 12, 100, // ab -> Cyrl 15, 10, // abh -> Arab - 19, 425, // abl -> Rjng - 23, 100, // abq -> Cyrl - 27, 10, // abv -> Arab - 31, 10, // acm -> Arab - 35, 10, // acq -> Arab - 39, 10, // acw -> Arab - 43, 10, // acx -> Arab - 47, 10, // adf -> Arab - 51, 540, // adp -> Tibt - 55, 540, // adx -> Tibt - 59, 100, // ady -> Cyrl - 63, 25, // ae -> Avst - 66, 10, // aeb -> Arab - 70, 10, // aec -> Arab - 74, 10, // aee -> Arab - 78, 10, // aeq -> Arab - 82, 10, // afb -> Arab - 86, 105, // agi -> Deva - 90, 120, // agj -> Ethi - 94, 100, // agx -> Cyrl - 98, 120, // ahg -> Ethi - 102, 5, // aho -> Ahom - 106, 105, // ahr -> Deva - 110, 10, // aib -> Arab - 114, 185, // aij -> Hebr - 118, 220, // ain -> Kana - 122, 345, // aio -> Mymr - 126, 10, // aiq -> Arab - 130, 10, // ajp -> Arab - 134, 10, // ajt -> Arab - 138, 575, // akk -> Xsux - 142, 100, // akv -> Cyrl - 146, 260, // alk -> Laoo - 150, 320, // all -> Mlym - 154, 100, // alr -> Cyrl - 158, 100, // alt -> Cyrl - 162, 120, // alw -> Ethi - 166, 120, // am -> Ethi - 169, 210, // ams -> Jpan - 173, 480, // amw -> Syrc - 177, 100, // ani -> Cyrl - 181, 105, // anp -> Deva - 185, 105, // anr -> Deva - 189, 120, // anu -> Ethi - 193, 45, // aot -> Beng - 197, 10, // apc -> Arab - 201, 10, // apd -> Arab - 205, 105, // aph -> Deva - 209, 100, // aqc -> Cyrl - 213, 10, // ar -> Arab - 216, 15, // arc -> Armi - 220, 10, // arq -> Arab - 224, 10, // ars -> Arab - 228, 10, // ary -> Arab - 232, 10, // arz -> Arab - 236, 45, // as -> Beng - 239, 455, // ase -> Sgnw - 243, 10, // ask -> Arab - 247, 10, // atn -> Arab - 251, 100, // atv -> Cyrl - 255, 10, // auj -> Arab - 259, 10, // auz -> Arab - 263, 100, // av -> Cyrl - 266, 10, // avd -> Arab - 270, 10, // avl -> Arab - 274, 105, // awa -> Deva - 278, 120, // awn -> Ethi - 282, 20, // axm -> Armn - 286, 10, // ayh -> Arab - 290, 10, // ayl -> Arab - 294, 10, // ayn -> Arab - 298, 10, // ayp -> Arab - 302, 10, // az_IQ -> Arab - 308, 10, // az_IR -> Arab - 314, 100, // az_RU -> Cyrl - 320, 10, // azb -> Arab - 324, 100, // ba -> Cyrl - 327, 10, // bal -> Arab - 331, 105, // bap -> Deva - 335, 30, // bax -> Bamu - 339, 125, // bbl -> Geor - 343, 120, // bcq -> Ethi - 347, 385, // bdv -> Orya - 351, 10, // bdz -> Arab - 355, 100, // be -> Cyrl - 358, 105, // bee -> Deva - 362, 10, // bej -> Arab - 366, 105, // bfb -> Deva - 370, 505, // bfq -> Taml - 374, 10, // bft -> Arab - 378, 540, // bfu -> Tibt - 382, 385, // bfw -> Orya - 386, 105, // bfy -> Deva - 390, 105, // bfz -> Deva - 394, 100, // bg -> Cyrl - 397, 105, // bgc -> Deva - 401, 105, // bgd -> Deva - 405, 10, // bgn -> Arab - 409, 10, // bgp -> Arab - 413, 105, // bgq -> Deva - 417, 105, // bgw -> Deva - 421, 150, // bgx -> Grek - 425, 105, // bha -> Deva - 429, 105, // bhb -> Deva - 433, 105, // bhd -> Deva - 437, 10, // bhe -> Arab - 441, 100, // bhh -> Cyrl - 445, 105, // bhi -> Deva - 449, 105, // bhj -> Deva - 453, 10, // bhm -> Arab - 457, 480, // bhn -> Syrc - 461, 105, // bho -> Deva - 465, 490, // bht -> Takr - 469, 105, // bhu -> Deva - 473, 105, // biy -> Deva - 477, 480, // bjf -> Syrc - 481, 120, // bji -> Ethi - 485, 105, // bjj -> Deva - 489, 10, // bjm -> Arab - 493, 345, // blk -> Mymr - 497, 515, // blt -> Tavt - 501, 105, // bmj -> Deva - 505, 45, // bn -> Beng - 508, 105, // bns -> Deva - 512, 540, // bo -> Tibt - 515, 100, // bph -> Cyrl - 519, 105, // bpx -> Deva - 523, 45, // bpy -> Beng - 527, 10, // bqi -> Arab - 531, 105, // bra -> Deva - 535, 235, // brb -> Khmr - 539, 105, // brd -> Deva - 543, 10, // brh -> Arab - 547, 10, // brk -> Arab - 551, 260, // brv -> Laoo - 555, 105, // brx -> Deva - 559, 10, // bsh -> Arab - 563, 10, // bsk -> Arab - 567, 35, // bsq -> Bass - 571, 120, // bst -> Ethi - 575, 40, // btd -> Batk - 579, 40, // btm -> Batk - 583, 105, // btv -> Deva - 587, 100, // bua -> Cyrl - 591, 345, // bwe -> Mymr - 595, 100, // bxm -> Cyrl - 599, 330, // bxu -> Mong - 603, 105, // byh -> Deva - 607, 120, // byn -> Ethi - 611, 105, // byw -> Deva - 615, 535, // bzi -> Thai - 619, 535, // cbn -> Thai - 623, 60, // ccp -> Cakm - 627, 520, // cde -> Telu - 631, 105, // cdh -> Deva - 635, 155, // cdi -> Gujr - 639, 105, // cdj -> Deva - 643, 105, // cdm -> Deva - 647, 175, // cdo -> Hans - 651, 45, // cdz -> Beng - 655, 100, // ce -> Cyrl - 658, 540, // cgk -> Tibt - 662, 10, // chg -> Arab - 666, 100, // chm -> Cyrl - 670, 80, // chr -> Cher - 674, 105, // chx -> Deva - 678, 105, // cih -> Deva - 682, 10, // cja -> Arab - 686, 100, // cji -> Cyrl - 690, 75, // cjm -> Cham - 694, 175, // cjy -> Hans - 698, 10, // ckb -> Arab - 702, 100, // ckt -> Cyrl - 706, 10, // clh -> Arab - 710, 100, // clw -> Cyrl - 714, 475, // cmg -> Soyo - 718, 540, // cna -> Tibt - 722, 175, // cnp -> Hans - 726, 535, // cog -> Thai - 730, 90, // cop -> Copt - 734, 150, // cpg -> Grek - 738, 65, // cr -> Cans - 741, 100, // crh -> Cyrl - 745, 65, // crj -> Cans - 749, 65, // crk -> Cans - 753, 65, // crl -> Cans - 757, 65, // crm -> Cans - 761, 345, // csh -> Mymr - 765, 175, // csp -> Hans - 769, 65, // csw -> Cans - 773, 400, // ctd -> Pauc - 777, 45, // ctg -> Beng - 781, 105, // ctn -> Deva - 785, 505, // ctt -> Taml - 789, 100, // cu -> Cyrl - 792, 255, // cuu -> Lana - 796, 100, // cv -> Cyrl - 799, 175, // czh -> Hans - 803, 185, // czk -> Hebr - 807, 105, // daq -> Deva - 811, 100, // dar -> Cyrl - 815, 10, // dcc -> Arab - 819, 100, // ddo -> Cyrl - 823, 10, // def -> Arab - 827, 10, // deh -> Arab - 831, 45, // der -> Beng - 835, 10, // dgl -> Arab - 839, 105, // dhi -> Deva - 843, 155, // dhn -> Gujr - 847, 105, // dho -> Deva - 851, 105, // dhw -> Deva - 855, 540, // dka -> Tibt - 859, 100, // dlg -> Cyrl - 863, 310, // dmf -> Medf - 867, 10, // dmk -> Arab - 871, 10, // dml -> Arab - 875, 100, // dng -> Cyrl - 879, 345, // dnu -> Mymr - 883, 345, // dnv -> Mymr - 887, 105, // doi -> Deva - 891, 120, // dox -> Ethi - 895, 540, // dre -> Tibt - 899, 330, // drh -> Mong - 903, 105, // drq -> Deva - 907, 120, // drs -> Ethi - 911, 105, // dry -> Deva - 915, 385, // dso -> Orya - 919, 105, // dty -> Deva - 923, 155, // dub -> Gujr - 927, 105, // duh -> Deva - 931, 105, // dus -> Deva - 935, 530, // dv -> Thaa - 938, 385, // dwk -> Orya - 942, 105, // dwz -> Deva - 946, 540, // dz -> Tibt - 949, 540, // dzl -> Tibt - 953, 150, // ecr -> Grek - 957, 95, // ecy -> Cprt - 961, 110, // egy -> Egyp - 965, 215, // eky -> Kali - 969, 150, // el -> Grek - 972, 105, // emg -> Deva - 976, 105, // emu -> Deva - 980, 100, // enf -> Cyrl - 984, 100, // enh -> Cyrl - 988, 505, // era -> Taml - 992, 135, // esg -> Gonm - 996, 10, // esh -> Arab - 1000, 200, // ett -> Ital - 1004, 100, // eve -> Cyrl - 1008, 100, // evn -> Cyrl - 1012, 10, // fa -> Arab - 1015, 10, // fay -> Arab - 1019, 10, // faz -> Arab - 1023, 10, // fia -> Arab - 1027, 105, // fmu -> Deva - 1031, 10, // fub -> Arab - 1035, 175, // gan -> Hans - 1039, 385, // gaq -> Orya - 1043, 155, // gas -> Gujr - 1047, 520, // gau -> Telu - 1051, 385, // gbj -> Orya - 1055, 105, // gbk -> Deva - 1059, 155, // gbl -> Gujr - 1063, 105, // gbm -> Deva - 1067, 10, // gbz -> Arab - 1071, 385, // gdb -> Orya - 1075, 100, // gdo -> Cyrl - 1079, 105, // gdx -> Deva - 1083, 120, // gez -> Ethi - 1087, 10, // ggg -> Arab - 1091, 105, // ggn -> Deva - 1095, 10, // gha -> Arab - 1099, 105, // ghe -> Deva - 1103, 10, // ghr -> Arab - 1107, 540, // ght -> Tibt - 1111, 10, // gig -> Arab - 1115, 100, // gin -> Cyrl - 1119, 10, // gjk -> Arab - 1123, 10, // gju -> Arab - 1127, 100, // gld -> Cyrl - 1131, 10, // glh -> Arab - 1135, 10, // glk -> Arab - 1139, 120, // gmv -> Ethi - 1143, 275, // gmy -> Linb - 1147, 540, // goe -> Tibt - 1151, 120, // gof -> Ethi - 1155, 105, // gok -> Deva - 1159, 105, // gom -> Deva - 1163, 520, // gon -> Telu - 1167, 140, // got -> Goth - 1171, 105, // gra -> Deva - 1175, 95, // grc -> Cprt - 1179, 45, // grt -> Beng - 1183, 120, // gru -> Ethi - 1187, 155, // gu -> Gujr - 1190, 105, // gvr -> Deva - 1194, 10, // gwc -> Arab - 1198, 10, // gwf -> Arab - 1202, 10, // gwt -> Arab - 1206, 105, // gyo -> Deva - 1210, 10, // gzi -> Arab - 1214, 10, // ha_CM -> Arab - 1220, 10, // ha_SD -> Arab - 1226, 10, // hac -> Arab - 1230, 175, // hak -> Hans - 1234, 120, // har -> Ethi - 1238, 10, // haz -> Arab - 1242, 185, // hbo -> Hebr - 1246, 120, // hdy -> Ethi - 1250, 185, // he -> Hebr - 1253, 105, // hi -> Deva - 1256, 490, // hii -> Takr - 1260, 575, // hit -> Xsux - 1264, 10, // hkh -> Arab - 1268, 105, // hlb -> Deva - 1272, 190, // hlu -> Hluw - 1276, 415, // hmd -> Plrd - 1280, 50, // hmj -> Bopo - 1284, 50, // hmq -> Bopo - 1288, 10, // hnd -> Arab - 1292, 105, // hne -> Deva - 1296, 195, // hnj -> Hmnp - 1300, 260, // hnj_AU -> Laoo - 1307, 260, // hnj_CN -> Laoo - 1314, 260, // hnj_FR -> Laoo - 1321, 260, // hnj_GF -> Laoo - 1328, 260, // hnj_LA -> Laoo - 1335, 260, // hnj_MM -> Laoo - 1342, 260, // hnj_SR -> Laoo - 1349, 260, // hnj_TH -> Laoo - 1356, 195, // hnj_US -> Hmnp - 1363, 260, // hnj_VN -> Laoo - 1370, 10, // hno -> Arab - 1374, 105, // hoc -> Deva - 1378, 10, // hoh -> Arab - 1382, 105, // hoj -> Deva - 1386, 170, // how -> Hani - 1390, 105, // hoy -> Deva - 1394, 345, // hpo -> Mymr - 1398, 480, // hrt -> Syrc - 1402, 10, // hrz -> Arab - 1406, 175, // hsn -> Hans - 1410, 10, // hss -> Arab - 1414, 575, // htx -> Xsux - 1418, 105, // hut -> Deva - 1422, 185, // huy -> Hebr - 1426, 100, // huz -> Cyrl - 1430, 20, // hy -> Armn - 1433, 20, // hyw -> Armn - 1437, 580, // ii -> Yiii - 1440, 285, // imy -> Lyci - 1444, 100, // inh -> Cyrl - 1448, 345, // int -> Mymr - 1452, 120, // ior -> Ethi - 1456, 505, // iru -> Taml - 1460, 10, // isk -> Arab - 1464, 185, // itk -> Hebr - 1468, 100, // itl -> Cyrl - 1472, 65, // iu -> Cans - 1475, 185, // iw -> Hebr - 1478, 210, // ja -> Jpan - 1481, 10, // jad -> Arab - 1485, 10, // jat -> Arab - 1489, 185, // jbe -> Hebr - 1493, 10, // jbn -> Arab - 1497, 100, // jct -> Cyrl - 1501, 540, // jda -> Tibt - 1505, 10, // jdg -> Arab - 1509, 100, // jdt -> Cyrl - 1513, 105, // jee -> Deva - 1517, 125, // jge -> Geor - 1521, 185, // ji -> Hebr - 1524, 165, // jje -> Hang - 1528, 345, // jkm -> Mymr - 1532, 105, // jml -> Deva - 1536, 490, // jna -> Takr - 1540, 10, // jnd -> Arab - 1544, 105, // jnl -> Deva - 1548, 105, // jns -> Deva - 1552, 10, // jog -> Arab - 1556, 185, // jpa -> Hebr - 1560, 185, // jpr -> Hebr - 1564, 105, // jul -> Deva - 1568, 385, // jun -> Orya - 1572, 385, // juy -> Orya - 1576, 540, // jya -> Tibt - 1580, 185, // jye -> Hebr - 1584, 125, // ka -> Geor - 1587, 100, // kaa -> Cyrl - 1591, 100, // kap -> Cyrl - 1595, 225, // kaw -> Kawi - 1599, 100, // kbd -> Cyrl - 1603, 10, // kbu -> Arab - 1607, 10, // kby -> Arab - 1611, 100, // kca -> Cyrl - 1615, 45, // kdq -> Beng - 1619, 535, // kdt -> Thai - 1623, 100, // ket -> Cyrl - 1627, 105, // kex -> Deva - 1631, 520, // key -> Telu - 1635, 245, // kfa -> Knda - 1639, 105, // kfb -> Deva - 1643, 520, // kfc -> Telu - 1647, 245, // kfd -> Knda - 1651, 505, // kfe -> Taml - 1655, 320, // kfh -> Mlym - 1659, 505, // kfi -> Taml - 1663, 105, // kfk -> Deva - 1667, 10, // kfm -> Arab - 1671, 105, // kfp -> Deva - 1675, 105, // kfq -> Deva - 1679, 105, // kfr -> Deva - 1683, 105, // kfs -> Deva - 1687, 105, // kfx -> Deva - 1691, 105, // kfy -> Deva - 1695, 105, // kgj -> Deva - 1699, 105, // kgy -> Deva - 1703, 500, // khb -> Talu - 1707, 535, // khf -> Thai - 1711, 540, // khg -> Tibt - 1715, 105, // khn -> Deva - 1719, 345, // kht -> Mymr - 1723, 100, // khv -> Cyrl - 1727, 10, // khw -> Arab - 1731, 105, // kif -> Deva - 1735, 100, // kim -> Cyrl - 1739, 105, // kip -> Deva - 1743, 260, // kjg -> Laoo - 1747, 100, // kjh -> Cyrl - 1751, 105, // kjl -> Deva - 1755, 105, // kjo -> Deva - 1759, 345, // kjp -> Mymr - 1763, 535, // kjt -> Thai - 1767, 100, // kk -> Cyrl - 1770, 10, // kk_AF -> Arab - 1776, 10, // kk_CN -> Arab - 1782, 10, // kk_IR -> Arab - 1788, 10, // kk_MN -> Arab - 1794, 540, // kkf -> Tibt - 1798, 255, // kkh -> Lana - 1802, 105, // kkt -> Deva - 1806, 105, // kle -> Deva - 1810, 10, // klj -> Arab - 1814, 105, // klr -> Deva - 1818, 235, // km -> Khmr - 1821, 105, // kmj -> Deva - 1825, 10, // kmz -> Arab - 1829, 245, // kn -> Knda - 1832, 250, // ko -> Kore - 1835, 100, // koi -> Cyrl - 1839, 105, // kok -> Deva - 1843, 100, // kpt -> Cyrl - 1847, 100, // kpy -> Cyrl - 1851, 480, // kqd -> Syrc - 1855, 120, // kqy -> Ethi - 1859, 105, // kra -> Deva - 1863, 100, // krc -> Cyrl - 1867, 100, // krk -> Cyrl - 1871, 235, // krr -> Khmr - 1875, 105, // kru -> Deva - 1879, 235, // krv -> Khmr - 1883, 10, // ks -> Arab - 1886, 345, // ksu -> Mymr - 1890, 345, // ksw -> Mymr - 1894, 105, // ksz -> Deva - 1898, 120, // ktb -> Ethi - 1902, 10, // ktl -> Arab - 1906, 415, // ktp -> Plrd - 1910, 10, // ku_LB -> Arab - 1916, 260, // kuf -> Laoo - 1920, 100, // kum -> Cyrl - 1924, 100, // kv -> Cyrl - 1927, 100, // kva -> Cyrl - 1931, 345, // kvq -> Mymr - 1935, 345, // kvt -> Mymr - 1939, 10, // kvx -> Arab - 1943, 215, // kvy -> Kali - 1947, 120, // kxc -> Ethi - 1951, 345, // kxf -> Mymr - 1955, 345, // kxk -> Mymr - 1959, 105, // kxl -> Deva - 1963, 535, // kxm -> Thai - 1967, 10, // kxp -> Arab - 1971, 385, // kxv -> Orya - 1975, 100, // ky -> Cyrl - 1978, 10, // ky_CN -> Arab - 1984, 215, // kyu -> Kali - 1988, 105, // kyv -> Deva - 1992, 105, // kyw -> Deva - 1996, 10, // kzh -> Arab - 2000, 270, // lab -> Lina - 2004, 185, // lad -> Hebr - 2008, 105, // lae -> Deva - 2012, 10, // lah -> Arab - 2016, 280, // lbc -> Lisu - 2020, 100, // lbe -> Cyrl - 2024, 105, // lbf -> Deva - 2028, 540, // lbj -> Tibt - 2032, 105, // lbm -> Deva - 2036, 260, // lbo -> Laoo - 2040, 105, // lbr -> Deva - 2044, 535, // lcp -> Thai - 2048, 265, // lep -> Lepc - 2052, 100, // lez -> Cyrl - 2056, 105, // lhm -> Deva - 2060, 480, // lhs -> Syrc - 2064, 105, // lif -> Deva - 2068, 280, // lis -> Lisu - 2072, 540, // lkh -> Tibt - 2076, 10, // lki -> Arab - 2080, 105, // lmh -> Deva - 2084, 520, // lmn -> Telu - 2088, 260, // lo -> Laoo - 2091, 105, // loy -> Deva - 2095, 415, // lpo -> Plrd - 2099, 10, // lrc -> Arab - 2103, 10, // lrk -> Arab - 2107, 10, // lrl -> Arab - 2111, 10, // lsa -> Arab - 2115, 185, // lsd -> Hebr - 2119, 10, // lss -> Arab - 2123, 540, // luk -> Tibt - 2127, 105, // luu -> Deva - 2131, 10, // luv -> Arab - 2135, 10, // luz -> Arab - 2139, 535, // lwl -> Thai - 2143, 535, // lwm -> Thai - 2147, 540, // lya -> Tibt - 2151, 175, // lzh -> Hans - 2155, 105, // mag -> Deva - 2159, 105, // mai -> Deva - 2163, 360, // man_GN -> Nkoo - 2170, 10, // mby -> Arab - 2174, 10, // mde -> Arab - 2178, 100, // mdf -> Cyrl - 2182, 120, // mdx -> Ethi - 2186, 120, // mdy -> Ethi - 2190, 10, // mfa -> Arab - 2194, 10, // mfi -> Arab - 2198, 105, // mgp -> Deva - 2202, 10, // mhj -> Arab - 2206, 295, // mid -> Mand - 2210, 105, // mjl -> Deva - 2214, 320, // mjq -> Mlym - 2218, 320, // mjr -> Mlym - 2222, 105, // mjt -> Deva - 2226, 520, // mju -> Telu - 2230, 320, // mjv -> Mlym - 2234, 105, // mjz -> Deva - 2238, 100, // mk -> Cyrl - 2241, 105, // mkb -> Deva - 2245, 105, // mke -> Deva - 2249, 10, // mki -> Arab - 2253, 535, // mkm -> Thai - 2257, 320, // ml -> Mlym - 2260, 535, // mlf -> Thai - 2264, 100, // mn -> Cyrl - 2267, 330, // mn_CN -> Mong - 2273, 45, // mni -> Beng - 2277, 10, // mnj -> Arab - 2281, 100, // mns -> Cyrl - 2285, 345, // mnw -> Mymr - 2289, 535, // mpz -> Thai - 2293, 105, // mr -> Deva - 2296, 535, // mra -> Thai - 2300, 105, // mrd -> Deva - 2304, 100, // mrj -> Cyrl - 2308, 335, // mro -> Mroo - 2312, 105, // mrr -> Deva - 2316, 10, // ms_CC -> Arab - 2322, 100, // mtm -> Cyrl - 2326, 105, // mtr -> Deva - 2330, 100, // mud -> Cyrl - 2334, 540, // muk -> Tibt - 2338, 105, // mut -> Deva - 2342, 505, // muv -> Taml - 2346, 120, // muz -> Ethi - 2350, 330, // mvf -> Mong - 2354, 10, // mvy -> Arab - 2358, 120, // mvz -> Ethi - 2362, 105, // mwr -> Deva - 2366, 345, // mwt -> Mymr - 2370, 195, // mww -> Hmnp - 2374, 345, // my -> Mymr - 2377, 120, // mym -> Ethi - 2381, 100, // myv -> Cyrl - 2385, 295, // myz -> Mand - 2389, 10, // mzn -> Arab - 2393, 175, // nan -> Hans - 2397, 105, // nao -> Deva - 2401, 105, // ncd -> Deva - 2405, 260, // ncq -> Laoo - 2409, 100, // ndf -> Cyrl - 2413, 105, // ne -> Deva - 2416, 100, // neg -> Cyrl - 2420, 540, // neh -> Tibt - 2424, 575, // nei -> Xsux - 2428, 105, // new -> Deva - 2432, 260, // ngt -> Laoo - 2436, 100, // nio -> Cyrl - 2440, 520, // nit -> Telu - 2444, 100, // niv -> Cyrl - 2448, 10, // nli -> Arab - 2452, 10, // nlm -> Arab - 2456, 105, // nlx -> Deva - 2460, 105, // nmm -> Deva - 2464, 565, // nnp -> Wcho - 2468, 255, // nod -> Lana - 2472, 105, // noe -> Deva - 2476, 100, // nog -> Cyrl - 2480, 105, // noi -> Deva - 2484, 435, // non -> Runr - 2488, 580, // nos -> Yiii - 2492, 540, // npb -> Tibt - 2496, 360, // nqo -> Nkoo - 2500, 580, // nsd -> Yiii - 2504, 580, // nsf -> Yiii - 2508, 65, // nsk -> Cans - 2512, 545, // nst -> Tnsa - 2516, 580, // nsv -> Yiii - 2520, 580, // nty -> Yiii - 2524, 10, // ntz -> Arab - 2528, 355, // nwc -> Newa - 2532, 105, // nwx -> Deva - 2536, 535, // nyl -> Thai - 2540, 10, // nyq -> Arab - 2544, 100, // oaa -> Cyrl - 2548, 100, // oac -> Cyrl - 2552, 480, // oar -> Syrc - 2556, 125, // oav -> Geor - 2560, 410, // obm -> Phnx - 2564, 345, // obr -> Mymr - 2568, 10, // odk -> Arab - 2572, 575, // oht -> Xsux - 2576, 65, // oj -> Cans - 2579, 65, // ojs -> Cans - 2583, 165, // okm -> Hang - 2587, 170, // oko -> Hani - 2591, 235, // okz -> Khmr - 2595, 105, // ola -> Deva - 2599, 540, // ole -> Tibt - 2603, 100, // omk -> Cyrl - 2607, 340, // omp -> Mtei - 2611, 325, // omr -> Modi - 2615, 105, // oon -> Deva - 2619, 385, // or -> Orya - 2622, 520, // ort -> Telu - 2626, 10, // oru -> Arab - 2630, 100, // orv -> Cyrl - 2634, 100, // os -> Cyrl - 2637, 390, // osa -> Osge - 2641, 200, // osc -> Ital - 2645, 205, // osi -> Java - 2649, 10, // ota -> Arab - 2653, 540, // otb -> Tibt - 2657, 380, // otk -> Orkh - 2661, 145, // oty -> Gran - 2665, 395, // oui -> Ougr - 2669, 160, // pa -> Guru - 2672, 10, // pa_PK -> Arab - 2678, 405, // pal -> Phli - 2682, 100, // paq -> Cyrl - 2686, 10, // pbt -> Arab - 2690, 235, // pcb -> Khmr - 2694, 345, // pce -> Mymr - 2698, 320, // pcf -> Mlym - 2702, 320, // pcg -> Mlym - 2706, 105, // pch -> Deva - 2710, 105, // pci -> Deva - 2714, 520, // pcj -> Telu - 2718, 385, // peg -> Orya - 2722, 570, // peo -> Xpeo - 2726, 230, // pgd -> Khar - 2730, 105, // pgg -> Deva - 2734, 370, // pgl -> Ogam - 2738, 200, // pgn -> Ital - 2742, 105, // phd -> Deva - 2746, 345, // phk -> Mymr - 2750, 10, // phl -> Arab - 2754, 410, // phn -> Phnx - 2758, 260, // pho -> Laoo - 2762, 10, // phr -> Arab - 2766, 535, // pht -> Thai - 2770, 10, // phv -> Arab - 2774, 105, // phw -> Deva - 2778, 460, // pi -> Sinh - 2781, 55, // pka -> Brah - 2785, 320, // pkr -> Mlym - 2789, 10, // plk -> Arab - 2793, 345, // pll -> Mymr - 2797, 55, // pmh -> Brah - 2801, 150, // pnt -> Grek - 2805, 105, // ppa -> Deva - 2809, 230, // pra -> Khar - 2813, 10, // prc -> Arab - 2817, 10, // prd -> Arab - 2821, 155, // prp -> Gujr - 2825, 535, // prt -> Thai - 2829, 10, // prx -> Arab - 2833, 10, // ps -> Arab - 2836, 10, // psh -> Arab - 2840, 10, // psi -> Arab - 2844, 10, // pst -> Arab - 2848, 105, // pum -> Deva - 2852, 345, // pwo -> Mymr - 2856, 105, // pwr -> Deva - 2860, 535, // pww -> Thai - 2864, 345, // pyx -> Mymr - 2868, 10, // qxq -> Arab - 2872, 105, // raa -> Deva - 2876, 105, // rab -> Deva - 2880, 105, // raf -> Deva - 2884, 45, // rah -> Beng - 2888, 105, // raj -> Deva - 2892, 105, // rav -> Deva - 2896, 345, // rbb -> Mymr - 2900, 10, // rdb -> Arab - 2904, 385, // rei -> Orya - 2908, 430, // rhg -> Rohg - 2912, 105, // rji -> Deva - 2916, 105, // rjs -> Deva - 2920, 235, // rka -> Khmr - 2924, 345, // rki -> Mymr - 2928, 45, // rkt -> Beng - 2932, 20, // rmi -> Armn - 2936, 10, // rmt -> Arab - 2940, 345, // rmz -> Mymr - 2944, 100, // rsk -> Cyrl - 2948, 105, // rtw -> Deva - 2952, 100, // ru -> Cyrl - 2955, 100, // rue -> Cyrl - 2959, 100, // rut -> Cyrl - 2963, 105, // rwr -> Deva - 2967, 220, // ryu -> Kana - 2971, 105, // sa -> Deva - 2974, 100, // sah -> Cyrl - 2978, 440, // sam -> Samr - 2982, 375, // sat -> Olck - 2986, 450, // saz -> Saur - 2990, 10, // sbn -> Arab - 2994, 540, // sbu -> Tibt - 2998, 105, // sck -> Deva - 3002, 10, // scl -> Arab - 3006, 105, // scp -> Deva - 3010, 260, // sct -> Laoo - 3014, 490, // scu -> Takr - 3018, 150, // scx -> Grek - 3022, 10, // sd -> Arab - 3025, 105, // sd_IN -> Deva - 3031, 10, // sdb -> Arab - 3035, 10, // sdf -> Arab - 3039, 10, // sdg -> Arab - 3043, 10, // sdh -> Arab - 3047, 10, // sds -> Arab - 3051, 100, // sel -> Cyrl - 3055, 415, // sfm -> Plrd - 3059, 370, // sga -> Ogam - 3063, 100, // sgh -> Cyrl - 3067, 105, // sgj -> Deva - 3071, 10, // sgr -> Arab - 3075, 540, // sgt -> Tibt - 3079, 120, // sgw -> Ethi - 3083, 10, // sgy -> Arab - 3087, 10, // shd -> Arab - 3091, 525, // shi -> Tfng - 3095, 10, // shm -> Arab - 3099, 345, // shn -> Mymr - 3103, 10, // shu -> Arab - 3107, 10, // shv -> Arab - 3111, 460, // si -> Sinh - 3114, 100, // sia -> Cyrl - 3118, 540, // sip -> Tibt - 3122, 10, // siy -> Arab - 3126, 10, // siz -> Arab - 3130, 100, // sjd -> Cyrl - 3134, 105, // sjp -> Deva - 3138, 100, // sjt -> Cyrl - 3142, 535, // skb -> Thai - 3146, 105, // skj -> Deva - 3150, 10, // skr -> Arab - 3154, 10, // slq -> Arab - 3158, 580, // smh -> Yiii - 3162, 440, // smp -> Samr - 3166, 235, // smu -> Khmr - 3170, 10, // smy -> Arab - 3174, 515, // soa -> Tavt - 3178, 465, // sog -> Sogd - 3182, 105, // soi -> Deva - 3186, 535, // sou -> Thai - 3190, 540, // spt -> Tibt - 3194, 385, // spv -> Orya - 3198, 10, // sqo -> Arab - 3202, 260, // sqq -> Laoo - 3206, 10, // sqt -> Arab - 3210, 100, // sr -> Cyrl - 3213, 470, // srb -> Sora - 3217, 10, // srh -> Arab - 3221, 105, // srx -> Deva - 3225, 10, // srz -> Arab - 3229, 10, // ssh -> Arab - 3233, 260, // sss -> Laoo - 3237, 10, // sts -> Arab - 3241, 120, // stv -> Ethi - 3245, 100, // sty -> Cyrl - 3249, 105, // suz -> Deva - 3253, 125, // sva -> Geor - 3257, 10, // swb -> Arab - 3261, 170, // swi -> Hani - 3265, 105, // swv -> Deva - 3269, 480, // syc -> Syrc - 3273, 45, // syl -> Beng - 3277, 480, // syn -> Syrc - 3281, 480, // syr -> Syrc - 3285, 105, // syw -> Deva - 3289, 505, // ta -> Taml - 3292, 100, // tab -> Cyrl - 3296, 105, // taj -> Deva - 3300, 485, // tbk -> Tagb - 3304, 540, // tcn -> Tibt - 3308, 345, // tco -> Mymr - 3312, 505, // tcx -> Taml - 3316, 245, // tcy -> Knda - 3320, 525, // tda -> Tfng - 3324, 105, // tdb -> Deva - 3328, 495, // tdd -> Tale - 3332, 105, // tdg -> Deva - 3336, 105, // tdh -> Deva - 3340, 520, // te -> Telu - 3343, 205, // tes -> Java - 3347, 100, // tg -> Cyrl - 3350, 10, // tg_PK -> Arab - 3356, 105, // tge -> Deva - 3360, 540, // tgf -> Tibt - 3364, 535, // th -> Thai - 3367, 105, // the -> Deva - 3371, 105, // thf -> Deva - 3375, 495, // thi -> Tale - 3379, 105, // thl -> Deva - 3383, 535, // thm -> Thai - 3387, 105, // thq -> Deva - 3391, 105, // thr -> Deva - 3395, 105, // ths -> Deva - 3399, 120, // ti -> Ethi - 3402, 120, // tig -> Ethi - 3406, 105, // tij -> Deva - 3410, 100, // tin -> Cyrl - 3414, 345, // tjl -> Mymr - 3418, 10, // tjo -> Arab - 3422, 105, // tkb -> Deva - 3426, 10, // tks -> Arab - 3430, 105, // tkt -> Deva - 3434, 105, // tmk -> Deva - 3438, 480, // tmr -> Syrc - 3442, 60, // tnv -> Cakm - 3446, 10, // tov -> Arab - 3450, 235, // tpu -> Khmr - 3454, 10, // tra -> Arab - 3458, 185, // trg -> Hebr - 3462, 10, // trm -> Arab - 3466, 10, // trw -> Arab - 3470, 150, // tsd -> Grek - 3474, 105, // tsf -> Deva - 3478, 540, // tsj -> Tibt - 3482, 100, // tt -> Cyrl - 3485, 260, // tth -> Laoo - 3489, 260, // tto -> Laoo - 3493, 535, // tts -> Thai - 3497, 345, // tvn -> Mymr - 3501, 105, // twm -> Deva - 3505, 510, // txg -> Tang - 3509, 550, // txo -> Toto - 3513, 515, // tyr -> Tavt - 3517, 100, // tyv -> Cyrl - 3521, 100, // ude -> Cyrl - 3525, 320, // udg -> Mlym - 3529, 0, // udi -> Aghb - 3533, 100, // udm -> Cyrl - 3537, 10, // ug -> Arab - 3540, 100, // ug_KZ -> Cyrl - 3546, 100, // ug_MN -> Cyrl - 3552, 555, // uga -> Ugar - 3556, 100, // ugh -> Cyrl - 3560, 535, // ugo -> Thai - 3564, 100, // uk -> Cyrl - 3567, 385, // uki -> Orya - 3571, 100, // ulc -> Cyrl - 3575, 45, // unr -> Beng - 3579, 105, // unr_NP -> Deva - 3586, 45, // unx -> Beng - 3590, 10, // ur -> Arab - 3593, 535, // urk -> Thai - 3597, 10, // ush -> Arab - 3601, 150, // uum -> Grek - 3605, 10, // uz_AF -> Arab - 3611, 100, // uz_CN -> Cyrl - 3617, 10, // uzs -> Arab - 3621, 505, // vaa -> Taml - 3625, 10, // vaf -> Arab - 3629, 105, // vah -> Deva - 3633, 560, // vai -> Vaii - 3637, 105, // vas -> Deva - 3641, 105, // vav -> Deva - 3645, 105, // vay -> Deva - 3649, 10, // vgr -> Arab - 3653, 245, // vmd -> Knda - 3657, 10, // vmh -> Arab - 3661, 120, // wal -> Ethi - 3665, 10, // wbk -> Arab - 3669, 520, // wbq -> Telu - 3673, 105, // wbr -> Deva - 3677, 10, // wlo -> Arab - 3681, 105, // wme -> Deva - 3685, 10, // wne -> Arab - 3689, 10, // wni -> Arab - 3693, 130, // wsg -> Gong - 3697, 10, // wsv -> Arab - 3701, 105, // wtm -> Deva - 3705, 175, // wuu -> Hans - 3709, 100, // xal -> Cyrl - 3713, 120, // xan -> Ethi - 3717, 100, // xas -> Cyrl - 3721, 85, // xco -> Chrs - 3725, 70, // xcr -> Cari - 3729, 100, // xdq -> Cyrl - 3733, 10, // xhe -> Arab - 3737, 235, // xhm -> Khmr - 3741, 385, // xis -> Orya - 3745, 10, // xka -> Arab - 3749, 10, // xkc -> Arab - 3753, 10, // xkj -> Arab - 3757, 10, // xkp -> Arab - 3761, 285, // xlc -> Lyci - 3765, 290, // xld -> Lydi - 3769, 115, // xly -> Elym - 3773, 125, // xmf -> Geor - 3777, 300, // xmn -> Mani - 3781, 315, // xmr -> Merc - 3785, 350, // xna -> Narb - 3789, 105, // xnr -> Deva - 3793, 150, // xpg -> Grek - 3797, 370, // xpi -> Ogam - 3801, 100, // xpm -> Cyrl - 3805, 420, // xpr -> Prti - 3809, 100, // xrm -> Cyrl - 3813, 100, // xrn -> Cyrl - 3817, 445, // xsa -> Sarb - 3821, 105, // xsr -> Deva - 3825, 100, // xss -> Cyrl - 3829, 505, // xub -> Taml - 3833, 505, // xuj -> Taml - 3837, 200, // xve -> Ital - 3841, 10, // xvi -> Arab - 3845, 100, // xwo -> Cyrl - 3849, 305, // xzh -> Marc - 3853, 100, // yai -> Cyrl - 3857, 105, // ybh -> Deva - 3861, 105, // ybi -> Deva - 3865, 10, // ydg -> Arab - 3869, 320, // yea -> Mlym - 3873, 150, // yej -> Grek - 3877, 520, // yeu -> Telu - 3881, 415, // ygp -> Plrd - 3885, 185, // yhd -> Hebr - 3889, 185, // yi -> Hebr - 3892, 580, // yig -> Yiii - 3896, 185, // yih -> Hebr - 3900, 580, // yiv -> Yiii - 3904, 100, // ykg -> Cyrl - 3908, 415, // yna -> Plrd - 3912, 100, // ynk -> Cyrl - 3916, 210, // yoi -> Jpan - 3920, 535, // yoy -> Thai - 3924, 100, // yrk -> Cyrl - 3928, 580, // ysd -> Yiii - 3932, 580, // ysn -> Yiii - 3936, 580, // ysp -> Yiii - 3940, 100, // ysr -> Cyrl - 3944, 415, // ysy -> Plrd - 3948, 185, // yud -> Hebr - 3952, 180, // yue -> Hant - 3956, 175, // yue_CN -> Hans - 3963, 100, // yug -> Cyrl - 3967, 100, // yux -> Cyrl - 3971, 415, // ywq -> Plrd - 3975, 415, // ywu -> Plrd - 3979, 540, // zau -> Tibt - 3983, 10, // zba -> Arab - 3987, 170, // zch -> Hani - 3991, 10, // zdj -> Arab - 3995, 170, // zeh -> Hani - 3999, 525, // zen -> Tfng - 4003, 170, // zgb -> Hani - 4007, 525, // zgh -> Tfng - 4011, 170, // zgm -> Hani - 4015, 170, // zgn -> Hani - 4019, 175, // zh -> Hans - 4022, 180, // zh_AU -> Hant - 4028, 180, // zh_BN -> Hant - 4034, 180, // zh_GB -> Hant - 4040, 180, // zh_GF -> Hant - 4046, 180, // zh_HK -> Hant - 4052, 180, // zh_ID -> Hant - 4058, 180, // zh_MO -> Hant - 4064, 180, // zh_PA -> Hant - 4070, 180, // zh_PF -> Hant - 4076, 180, // zh_PH -> Hant - 4082, 180, // zh_SR -> Hant - 4088, 180, // zh_TH -> Hant - 4094, 180, // zh_TW -> Hant - 4100, 180, // zh_US -> Hant - 4106, 180, // zh_VN -> Hant - 4112, 170, // zhd -> Hani - 4116, 365, // zhx -> Nshu - 4120, 100, // zkb -> Cyrl - 4124, 100, // zko -> Cyrl - 4128, 240, // zkt -> Kits - 4132, 100, // zkz -> Cyrl - 4136, 170, // zlj -> Hani - 4140, 170, // zln -> Hani - 4144, 170, // zlq -> Hani - 4148, 170, // zqe -> Hani - 4152, 185, // zrp -> Hebr - 4156, 10, // zum -> Arab - 4160, 170, // zyg -> Hani - 4164, 170, // zyn -> Hani - 4168, 170, // zzj -> Hani + 19, 420, // abl -> Rjng + 23, 10, // abv -> Arab + 27, 10, // acm -> Arab + 31, 10, // acq -> Arab + 35, 10, // acw -> Arab + 39, 10, // acx -> Arab + 43, 10, // adf -> Arab + 47, 535, // adx -> Tibt + 51, 100, // ady -> Cyrl + 55, 25, // ae -> Avst + 58, 10, // aeb -> Arab + 62, 10, // aec -> Arab + 66, 10, // aee -> Arab + 70, 10, // aeq -> Arab + 74, 10, // afb -> Arab + 78, 105, // agi -> Deva + 82, 120, // agj -> Ethi + 86, 100, // agx -> Cyrl + 90, 120, // ahg -> Ethi + 94, 5, // aho -> Ahom + 98, 105, // ahr -> Deva + 102, 10, // aib -> Arab + 106, 185, // aij -> Hebr + 110, 220, // ain -> Kana + 114, 345, // aio -> Mymr + 118, 10, // aiq -> Arab + 122, 10, // ajp -> Arab + 126, 570, // akk -> Xsux + 130, 100, // akv -> Cyrl + 134, 260, // alk -> Laoo + 138, 320, // all -> Mlym + 142, 100, // alr -> Cyrl + 146, 100, // alt -> Cyrl + 150, 120, // alw -> Ethi + 154, 120, // am -> Ethi + 157, 210, // ams -> Jpan + 161, 475, // amw -> Syrc + 165, 100, // ani -> Cyrl + 169, 105, // anp -> Deva + 173, 105, // anr -> Deva + 177, 120, // anu -> Ethi + 181, 45, // aot -> Beng + 185, 10, // apc -> Arab + 189, 10, // apd -> Arab + 193, 105, // aph -> Deva + 197, 100, // aqc -> Cyrl + 201, 10, // ar -> Arab + 204, 15, // arc -> Armi + 208, 10, // arq -> Arab + 212, 10, // ars -> Arab + 216, 10, // ary -> Arab + 220, 10, // arz -> Arab + 224, 45, // as -> Beng + 227, 450, // ase -> Sgnw + 231, 10, // ask -> Arab + 235, 10, // atn -> Arab + 239, 100, // atv -> Cyrl + 243, 10, // auj -> Arab + 247, 10, // auz -> Arab + 251, 100, // av -> Cyrl + 254, 10, // avd -> Arab + 258, 10, // avl -> Arab + 262, 105, // awa -> Deva + 266, 120, // awn -> Ethi + 270, 20, // axm -> Armn + 274, 10, // ayh -> Arab + 278, 10, // ayl -> Arab + 282, 10, // ayn -> Arab + 286, 10, // ayp -> Arab + 290, 10, // az_IQ -> Arab + 296, 10, // az_IR -> Arab + 302, 100, // az_RU -> Cyrl + 308, 10, // azb -> Arab + 312, 100, // ba -> Cyrl + 315, 10, // bal -> Arab + 319, 105, // bap -> Deva + 323, 30, // bax -> Bamu + 327, 125, // bbl -> Geor + 331, 120, // bcq -> Ethi + 335, 385, // bdv -> Orya + 339, 10, // bdz -> Arab + 343, 100, // be -> Cyrl + 346, 105, // bee -> Deva + 350, 10, // bej -> Arab + 354, 105, // bfb -> Deva + 358, 500, // bfq -> Taml + 362, 10, // bft -> Arab + 366, 535, // bfu -> Tibt + 370, 385, // bfw -> Orya + 374, 105, // bfy -> Deva + 378, 105, // bfz -> Deva + 382, 100, // bg -> Cyrl + 385, 105, // bgc -> Deva + 389, 105, // bgd -> Deva + 393, 10, // bgn -> Arab + 397, 10, // bgp -> Arab + 401, 105, // bgq -> Deva + 405, 105, // bgw -> Deva + 409, 150, // bgx -> Grek + 413, 105, // bha -> Deva + 417, 105, // bhb -> Deva + 421, 105, // bhd -> Deva + 425, 10, // bhe -> Arab + 429, 100, // bhh -> Cyrl + 433, 105, // bhi -> Deva + 437, 105, // bhj -> Deva + 441, 10, // bhm -> Arab + 445, 475, // bhn -> Syrc + 449, 105, // bho -> Deva + 453, 485, // bht -> Takr + 457, 105, // bhu -> Deva + 461, 105, // biy -> Deva + 465, 475, // bjf -> Syrc + 469, 105, // bjj -> Deva + 473, 10, // bjm -> Arab + 477, 345, // blk -> Mymr + 481, 510, // blt -> Tavt + 485, 105, // bmj -> Deva + 489, 45, // bn -> Beng + 492, 105, // bns -> Deva + 496, 535, // bo -> Tibt + 499, 100, // bph -> Cyrl + 503, 105, // bpx -> Deva + 507, 45, // bpy -> Beng + 511, 10, // bqi -> Arab + 515, 105, // bra -> Deva + 519, 235, // brb -> Khmr + 523, 105, // brd -> Deva + 527, 10, // brh -> Arab + 531, 10, // brk -> Arab + 535, 260, // brv -> Laoo + 539, 105, // brx -> Deva + 543, 10, // bsh -> Arab + 547, 10, // bsk -> Arab + 551, 35, // bsq -> Bass + 555, 120, // bst -> Ethi + 559, 40, // btd -> Batk + 563, 40, // btm -> Batk + 567, 105, // btv -> Deva + 571, 100, // bua -> Cyrl + 575, 345, // bwe -> Mymr + 579, 100, // bxm -> Cyrl + 583, 330, // bxu -> Mong + 587, 105, // byh -> Deva + 591, 120, // byn -> Ethi + 595, 105, // byw -> Deva + 599, 530, // bzi -> Thai + 603, 530, // cbn -> Thai + 607, 60, // ccp -> Cakm + 611, 515, // cde -> Telu + 615, 105, // cdh -> Deva + 619, 155, // cdi -> Gujr + 623, 105, // cdj -> Deva + 627, 105, // cdm -> Deva + 631, 175, // cdo -> Hans + 635, 45, // cdz -> Beng + 639, 100, // ce -> Cyrl + 642, 535, // cgk -> Tibt + 646, 10, // chg -> Arab + 650, 100, // chm -> Cyrl + 654, 80, // chr -> Cher + 658, 105, // chx -> Deva + 662, 105, // cih -> Deva + 666, 10, // cja -> Arab + 670, 100, // cji -> Cyrl + 674, 75, // cjm -> Cham + 678, 175, // cjy -> Hans + 682, 10, // ckb -> Arab + 686, 100, // ckt -> Cyrl + 690, 10, // clh -> Arab + 694, 100, // clw -> Cyrl + 698, 470, // cmg -> Soyo + 702, 535, // cna -> Tibt + 706, 175, // cnp -> Hans + 710, 530, // cog -> Thai + 714, 90, // cop -> Copt + 718, 150, // cpg -> Grek + 722, 65, // cr -> Cans + 725, 100, // crh -> Cyrl + 729, 65, // crj -> Cans + 733, 65, // crk -> Cans + 737, 65, // crl -> Cans + 741, 65, // crm -> Cans + 745, 345, // csh -> Mymr + 749, 175, // csp -> Hans + 753, 65, // csw -> Cans + 757, 395, // ctd -> Pauc + 761, 45, // ctg -> Beng + 765, 105, // ctn -> Deva + 769, 500, // ctt -> Taml + 773, 100, // cu -> Cyrl + 776, 255, // cuu -> Lana + 780, 100, // cv -> Cyrl + 783, 175, // czh -> Hans + 787, 185, // czk -> Hebr + 791, 105, // daq -> Deva + 795, 100, // dar -> Cyrl + 799, 10, // dcc -> Arab + 803, 100, // ddo -> Cyrl + 807, 10, // def -> Arab + 811, 10, // deh -> Arab + 815, 45, // der -> Beng + 819, 105, // dhi -> Deva + 823, 155, // dhn -> Gujr + 827, 105, // dho -> Deva + 831, 105, // dhw -> Deva + 835, 535, // dka -> Tibt + 839, 100, // dlg -> Cyrl + 843, 310, // dmf -> Medf + 847, 10, // dmk -> Arab + 851, 10, // dml -> Arab + 855, 100, // dng -> Cyrl + 859, 345, // dnu -> Mymr + 863, 345, // dnv -> Mymr + 867, 105, // doi -> Deva + 871, 120, // dox -> Ethi + 875, 535, // dre -> Tibt + 879, 105, // drq -> Deva + 883, 120, // drs -> Ethi + 887, 105, // dry -> Deva + 891, 385, // dso -> Orya + 895, 105, // dty -> Deva + 899, 155, // dub -> Gujr + 903, 105, // duh -> Deva + 907, 105, // dus -> Deva + 911, 525, // dv -> Thaa + 914, 385, // dwk -> Orya + 918, 105, // dwz -> Deva + 922, 535, // dz -> Tibt + 925, 535, // dzl -> Tibt + 929, 150, // ecr -> Grek + 933, 95, // ecy -> Cprt + 937, 110, // egy -> Egyp + 941, 215, // eky -> Kali + 945, 150, // el -> Grek + 948, 105, // emg -> Deva + 952, 105, // emu -> Deva + 956, 100, // enf -> Cyrl + 960, 100, // enh -> Cyrl + 964, 500, // era -> Taml + 968, 135, // esg -> Gonm + 972, 10, // esh -> Arab + 976, 200, // ett -> Ital + 980, 100, // eve -> Cyrl + 984, 100, // evn -> Cyrl + 988, 10, // fa -> Arab + 991, 10, // fay -> Arab + 995, 10, // faz -> Arab + 999, 10, // fia -> Arab + 1003, 105, // fmu -> Deva + 1007, 10, // fub -> Arab + 1011, 175, // gan -> Hans + 1015, 385, // gaq -> Orya + 1019, 155, // gas -> Gujr + 1023, 515, // gau -> Telu + 1027, 385, // gbj -> Orya + 1031, 105, // gbk -> Deva + 1035, 155, // gbl -> Gujr + 1039, 105, // gbm -> Deva + 1043, 10, // gbz -> Arab + 1047, 385, // gdb -> Orya + 1051, 100, // gdo -> Cyrl + 1055, 105, // gdx -> Deva + 1059, 120, // gez -> Ethi + 1063, 10, // ggg -> Arab + 1067, 10, // gha -> Arab + 1071, 105, // ghe -> Deva + 1075, 10, // ghr -> Arab + 1079, 535, // ght -> Tibt + 1083, 10, // gig -> Arab + 1087, 100, // gin -> Cyrl + 1091, 10, // gjk -> Arab + 1095, 10, // gju -> Arab + 1099, 100, // gld -> Cyrl + 1103, 10, // glh -> Arab + 1107, 10, // glk -> Arab + 1111, 120, // gmv -> Ethi + 1115, 275, // gmy -> Linb + 1119, 535, // goe -> Tibt + 1123, 120, // gof -> Ethi + 1127, 105, // gok -> Deva + 1131, 105, // gom -> Deva + 1135, 515, // gon -> Telu + 1139, 140, // got -> Goth + 1143, 105, // gra -> Deva + 1147, 95, // grc -> Cprt + 1151, 45, // grt -> Beng + 1155, 120, // gru -> Ethi + 1159, 155, // gu -> Gujr + 1162, 105, // gvr -> Deva + 1166, 10, // gwc -> Arab + 1170, 10, // gwf -> Arab + 1174, 10, // gwt -> Arab + 1178, 105, // gyo -> Deva + 1182, 10, // gzi -> Arab + 1186, 10, // ha_CM -> Arab + 1192, 10, // ha_SD -> Arab + 1198, 10, // hac -> Arab + 1202, 175, // hak -> Hans + 1206, 120, // har -> Ethi + 1210, 10, // haz -> Arab + 1214, 185, // hbo -> Hebr + 1218, 120, // hdy -> Ethi + 1222, 185, // he -> Hebr + 1225, 105, // hi -> Deva + 1228, 485, // hii -> Takr + 1232, 570, // hit -> Xsux + 1236, 10, // hkh -> Arab + 1240, 105, // hlb -> Deva + 1244, 190, // hlu -> Hluw + 1248, 410, // hmd -> Plrd + 1252, 50, // hmj -> Bopo + 1256, 50, // hmq -> Bopo + 1260, 10, // hnd -> Arab + 1264, 105, // hne -> Deva + 1268, 195, // hnj -> Hmnp + 1272, 260, // hnj_AU -> Laoo + 1279, 260, // hnj_CN -> Laoo + 1286, 260, // hnj_FR -> Laoo + 1293, 260, // hnj_GF -> Laoo + 1300, 260, // hnj_LA -> Laoo + 1307, 260, // hnj_MM -> Laoo + 1314, 260, // hnj_SR -> Laoo + 1321, 260, // hnj_TH -> Laoo + 1328, 260, // hnj_VN -> Laoo + 1335, 10, // hno -> Arab + 1339, 105, // hoc -> Deva + 1343, 10, // hoh -> Arab + 1347, 105, // hoj -> Deva + 1351, 170, // how -> Hani + 1355, 105, // hoy -> Deva + 1359, 345, // hpo -> Mymr + 1363, 475, // hrt -> Syrc + 1367, 10, // hrz -> Arab + 1371, 175, // hsn -> Hans + 1375, 10, // hss -> Arab + 1379, 570, // htx -> Xsux + 1383, 105, // hut -> Deva + 1387, 185, // huy -> Hebr + 1391, 100, // huz -> Cyrl + 1395, 20, // hy -> Armn + 1398, 20, // hyw -> Armn + 1402, 575, // ii -> Yiii + 1405, 285, // imy -> Lyci + 1409, 100, // inh -> Cyrl + 1413, 345, // int -> Mymr + 1417, 120, // ior -> Ethi + 1421, 500, // iru -> Taml + 1425, 10, // isk -> Arab + 1429, 185, // itk -> Hebr + 1433, 100, // itl -> Cyrl + 1437, 65, // iu -> Cans + 1440, 185, // iw -> Hebr + 1443, 210, // ja -> Jpan + 1446, 10, // jad -> Arab + 1450, 10, // jat -> Arab + 1454, 185, // jbe -> Hebr + 1458, 10, // jbn -> Arab + 1462, 100, // jct -> Cyrl + 1466, 535, // jda -> Tibt + 1470, 10, // jdg -> Arab + 1474, 100, // jdt -> Cyrl + 1478, 105, // jee -> Deva + 1482, 125, // jge -> Geor + 1486, 185, // ji -> Hebr + 1489, 165, // jje -> Hang + 1493, 345, // jkm -> Mymr + 1497, 105, // jml -> Deva + 1501, 485, // jna -> Takr + 1505, 10, // jnd -> Arab + 1509, 105, // jnl -> Deva + 1513, 105, // jns -> Deva + 1517, 10, // jog -> Arab + 1521, 185, // jpa -> Hebr + 1525, 185, // jpr -> Hebr + 1529, 185, // jrb -> Hebr + 1533, 10, // jrb_MA -> Arab + 1540, 105, // jul -> Deva + 1544, 385, // jun -> Orya + 1548, 385, // juy -> Orya + 1552, 535, // jya -> Tibt + 1556, 185, // jye -> Hebr + 1560, 125, // ka -> Geor + 1563, 100, // kaa -> Cyrl + 1567, 100, // kap -> Cyrl + 1571, 225, // kaw -> Kawi + 1575, 100, // kbd -> Cyrl + 1579, 10, // kbu -> Arab + 1583, 10, // kby -> Arab + 1587, 100, // kca -> Cyrl + 1591, 45, // kdq -> Beng + 1595, 530, // kdt -> Thai + 1599, 100, // ket -> Cyrl + 1603, 105, // kex -> Deva + 1607, 515, // key -> Telu + 1611, 245, // kfa -> Knda + 1615, 105, // kfb -> Deva + 1619, 515, // kfc -> Telu + 1623, 245, // kfd -> Knda + 1627, 500, // kfe -> Taml + 1631, 320, // kfh -> Mlym + 1635, 500, // kfi -> Taml + 1639, 105, // kfk -> Deva + 1643, 10, // kfm -> Arab + 1647, 105, // kfp -> Deva + 1651, 105, // kfq -> Deva + 1655, 105, // kfr -> Deva + 1659, 105, // kfs -> Deva + 1663, 105, // kfx -> Deva + 1667, 105, // kfy -> Deva + 1671, 105, // kgj -> Deva + 1675, 105, // kgy -> Deva + 1679, 495, // khb -> Talu + 1683, 530, // khf -> Thai + 1687, 535, // khg -> Tibt + 1691, 105, // khn -> Deva + 1695, 345, // kht -> Mymr + 1699, 100, // khv -> Cyrl + 1703, 10, // khw -> Arab + 1707, 105, // kif -> Deva + 1711, 100, // kim -> Cyrl + 1715, 105, // kip -> Deva + 1719, 260, // kjg -> Laoo + 1723, 100, // kjh -> Cyrl + 1727, 105, // kjl -> Deva + 1731, 105, // kjo -> Deva + 1735, 345, // kjp -> Mymr + 1739, 530, // kjt -> Thai + 1743, 100, // kk -> Cyrl + 1746, 10, // kk_AF -> Arab + 1752, 10, // kk_CN -> Arab + 1758, 10, // kk_IR -> Arab + 1764, 10, // kk_MN -> Arab + 1770, 535, // kkf -> Tibt + 1774, 255, // kkh -> Lana + 1778, 105, // kkt -> Deva + 1782, 105, // kle -> Deva + 1786, 10, // klj -> Arab + 1790, 105, // klr -> Deva + 1794, 235, // km -> Khmr + 1797, 105, // kmj -> Deva + 1801, 10, // kmz -> Arab + 1805, 245, // kn -> Knda + 1808, 250, // ko -> Kore + 1811, 100, // koi -> Cyrl + 1815, 105, // kok -> Deva + 1819, 100, // kpt -> Cyrl + 1823, 100, // kpy -> Cyrl + 1827, 475, // kqd -> Syrc + 1831, 120, // kqy -> Ethi + 1835, 105, // kra -> Deva + 1839, 100, // krc -> Cyrl + 1843, 100, // krk -> Cyrl + 1847, 235, // krr -> Khmr + 1851, 105, // kru -> Deva + 1855, 235, // krv -> Khmr + 1859, 10, // ks -> Arab + 1862, 345, // ksu -> Mymr + 1866, 345, // ksw -> Mymr + 1870, 105, // ksz -> Deva + 1874, 120, // ktb -> Ethi + 1878, 10, // ktl -> Arab + 1882, 410, // ktp -> Plrd + 1886, 10, // ku_LB -> Arab + 1892, 260, // kuf -> Laoo + 1896, 100, // kum -> Cyrl + 1900, 100, // kv -> Cyrl + 1903, 100, // kva -> Cyrl + 1907, 345, // kvq -> Mymr + 1911, 345, // kvt -> Mymr + 1915, 10, // kvx -> Arab + 1919, 215, // kvy -> Kali + 1923, 345, // kxf -> Mymr + 1927, 345, // kxk -> Mymr + 1931, 530, // kxm -> Thai + 1935, 10, // kxp -> Arab + 1939, 100, // ky -> Cyrl + 1942, 10, // ky_CN -> Arab + 1948, 215, // kyu -> Kali + 1952, 105, // kyv -> Deva + 1956, 105, // kyw -> Deva + 1960, 270, // lab -> Lina + 1964, 185, // lad -> Hebr + 1968, 105, // lae -> Deva + 1972, 10, // lah -> Arab + 1976, 280, // lbc -> Lisu + 1980, 100, // lbe -> Cyrl + 1984, 105, // lbf -> Deva + 1988, 535, // lbj -> Tibt + 1992, 105, // lbm -> Deva + 1996, 260, // lbo -> Laoo + 2000, 105, // lbr -> Deva + 2004, 530, // lcp -> Thai + 2008, 265, // lep -> Lepc + 2012, 100, // lez -> Cyrl + 2016, 105, // lhm -> Deva + 2020, 475, // lhs -> Syrc + 2024, 105, // lif -> Deva + 2028, 280, // lis -> Lisu + 2032, 535, // lkh -> Tibt + 2036, 10, // lki -> Arab + 2040, 105, // lmh -> Deva + 2044, 515, // lmn -> Telu + 2048, 260, // lo -> Laoo + 2051, 105, // loy -> Deva + 2055, 410, // lpo -> Plrd + 2059, 10, // lrc -> Arab + 2063, 10, // lrk -> Arab + 2067, 10, // lrl -> Arab + 2071, 10, // lsa -> Arab + 2075, 185, // lsd -> Hebr + 2079, 10, // lss -> Arab + 2083, 535, // luk -> Tibt + 2087, 105, // luu -> Deva + 2091, 10, // luv -> Arab + 2095, 10, // luz -> Arab + 2099, 530, // lwl -> Thai + 2103, 530, // lwm -> Thai + 2107, 535, // lya -> Tibt + 2111, 175, // lzh -> Hans + 2115, 105, // mag -> Deva + 2119, 105, // mai -> Deva + 2123, 360, // man_GN -> Nkoo + 2130, 10, // mby -> Arab + 2134, 10, // mde -> Arab + 2138, 100, // mdf -> Cyrl + 2142, 120, // mdx -> Ethi + 2146, 120, // mdy -> Ethi + 2150, 10, // mfa -> Arab + 2154, 10, // mfi -> Arab + 2158, 105, // mgp -> Deva + 2162, 10, // mhj -> Arab + 2166, 295, // mid -> Mand + 2170, 105, // mjl -> Deva + 2174, 320, // mjq -> Mlym + 2178, 320, // mjr -> Mlym + 2182, 105, // mjt -> Deva + 2186, 515, // mju -> Telu + 2190, 320, // mjv -> Mlym + 2194, 105, // mjz -> Deva + 2198, 100, // mk -> Cyrl + 2201, 105, // mkb -> Deva + 2205, 105, // mke -> Deva + 2209, 10, // mki -> Arab + 2213, 530, // mkm -> Thai + 2217, 320, // ml -> Mlym + 2220, 530, // mlf -> Thai + 2224, 100, // mn -> Cyrl + 2227, 330, // mn_CN -> Mong + 2233, 45, // mni -> Beng + 2237, 10, // mnj -> Arab + 2241, 100, // mns -> Cyrl + 2245, 345, // mnw -> Mymr + 2249, 530, // mpz -> Thai + 2253, 105, // mr -> Deva + 2256, 530, // mra -> Thai + 2260, 105, // mrd -> Deva + 2264, 100, // mrj -> Cyrl + 2268, 335, // mro -> Mroo + 2272, 105, // mrr -> Deva + 2276, 10, // ms_CC -> Arab + 2282, 100, // mtm -> Cyrl + 2286, 105, // mtr -> Deva + 2290, 100, // mud -> Cyrl + 2294, 535, // muk -> Tibt + 2298, 105, // mut -> Deva + 2302, 500, // muv -> Taml + 2306, 120, // muz -> Ethi + 2310, 330, // mvf -> Mong + 2314, 10, // mvy -> Arab + 2318, 120, // mvz -> Ethi + 2322, 105, // mwr -> Deva + 2326, 345, // mwt -> Mymr + 2330, 195, // mww -> Hmnp + 2334, 345, // my -> Mymr + 2337, 120, // mym -> Ethi + 2341, 100, // myv -> Cyrl + 2345, 295, // myz -> Mand + 2349, 10, // mzn -> Arab + 2353, 175, // nan -> Hans + 2357, 105, // nao -> Deva + 2361, 105, // ncd -> Deva + 2365, 260, // ncq -> Laoo + 2369, 100, // ndf -> Cyrl + 2373, 105, // ne -> Deva + 2376, 100, // neg -> Cyrl + 2380, 535, // neh -> Tibt + 2384, 570, // nei -> Xsux + 2388, 105, // new -> Deva + 2392, 260, // ngt -> Laoo + 2396, 100, // nio -> Cyrl + 2400, 515, // nit -> Telu + 2404, 100, // niv -> Cyrl + 2408, 10, // nli -> Arab + 2412, 10, // nlm -> Arab + 2416, 105, // nlx -> Deva + 2420, 105, // nmm -> Deva + 2424, 560, // nnp -> Wcho + 2428, 255, // nod -> Lana + 2432, 105, // noe -> Deva + 2436, 100, // nog -> Cyrl + 2440, 105, // noi -> Deva + 2444, 430, // non -> Runr + 2448, 575, // nos -> Yiii + 2452, 535, // npb -> Tibt + 2456, 360, // nqo -> Nkoo + 2460, 575, // nsd -> Yiii + 2464, 575, // nsf -> Yiii + 2468, 65, // nsk -> Cans + 2472, 540, // nst -> Tnsa + 2476, 575, // nsv -> Yiii + 2480, 575, // nty -> Yiii + 2484, 10, // ntz -> Arab + 2488, 355, // nwc -> Newa + 2492, 105, // nwx -> Deva + 2496, 530, // nyl -> Thai + 2500, 10, // nyq -> Arab + 2504, 100, // oaa -> Cyrl + 2508, 100, // oac -> Cyrl + 2512, 475, // oar -> Syrc + 2516, 125, // oav -> Geor + 2520, 405, // obm -> Phnx + 2524, 345, // obr -> Mymr + 2528, 10, // odk -> Arab + 2532, 570, // oht -> Xsux + 2536, 65, // oj -> Cans + 2539, 65, // ojs -> Cans + 2543, 165, // okm -> Hang + 2547, 170, // oko -> Hani + 2551, 235, // okz -> Khmr + 2555, 105, // ola -> Deva + 2559, 535, // ole -> Tibt + 2563, 100, // omk -> Cyrl + 2567, 340, // omp -> Mtei + 2571, 325, // omr -> Modi + 2575, 105, // oon -> Deva + 2579, 385, // or -> Orya + 2582, 515, // ort -> Telu + 2586, 10, // oru -> Arab + 2590, 100, // orv -> Cyrl + 2594, 100, // os -> Cyrl + 2597, 390, // osa -> Osge + 2601, 200, // osc -> Ital + 2605, 205, // osi -> Java + 2609, 10, // ota -> Arab + 2613, 535, // otb -> Tibt + 2617, 380, // otk -> Orkh + 2621, 145, // oty -> Gran + 2625, 160, // pa -> Guru + 2628, 10, // pa_PK -> Arab + 2634, 400, // pal -> Phli + 2638, 100, // paq -> Cyrl + 2642, 10, // pbt -> Arab + 2646, 235, // pcb -> Khmr + 2650, 345, // pce -> Mymr + 2654, 320, // pcf -> Mlym + 2658, 320, // pcg -> Mlym + 2662, 105, // pch -> Deva + 2666, 105, // pci -> Deva + 2670, 515, // pcj -> Telu + 2674, 385, // peg -> Orya + 2678, 565, // peo -> Xpeo + 2682, 230, // pgd -> Khar + 2686, 105, // pgg -> Deva + 2690, 370, // pgl -> Ogam + 2694, 200, // pgn -> Ital + 2698, 105, // phd -> Deva + 2702, 345, // phk -> Mymr + 2706, 10, // phl -> Arab + 2710, 405, // phn -> Phnx + 2714, 260, // pho -> Laoo + 2718, 10, // phr -> Arab + 2722, 530, // pht -> Thai + 2726, 10, // phv -> Arab + 2730, 105, // phw -> Deva + 2734, 455, // pi -> Sinh + 2737, 55, // pka -> Brah + 2741, 320, // pkr -> Mlym + 2745, 10, // plk -> Arab + 2749, 345, // pll -> Mymr + 2753, 55, // pmh -> Brah + 2757, 150, // pnt -> Grek + 2761, 230, // pra -> Khar + 2765, 10, // prc -> Arab + 2769, 10, // prd -> Arab + 2773, 155, // prp -> Gujr + 2777, 530, // prt -> Thai + 2781, 10, // prx -> Arab + 2785, 10, // ps -> Arab + 2788, 10, // psh -> Arab + 2792, 10, // psi -> Arab + 2796, 10, // pst -> Arab + 2800, 105, // pum -> Deva + 2804, 345, // pwo -> Mymr + 2808, 105, // pwr -> Deva + 2812, 530, // pww -> Thai + 2816, 345, // pyx -> Mymr + 2820, 10, // qxq -> Arab + 2824, 105, // raa -> Deva + 2828, 105, // rab -> Deva + 2832, 105, // raf -> Deva + 2836, 45, // rah -> Beng + 2840, 105, // raj -> Deva + 2844, 105, // rav -> Deva + 2848, 345, // rbb -> Mymr + 2852, 10, // rdb -> Arab + 2856, 385, // rei -> Orya + 2860, 425, // rhg -> Rohg + 2864, 105, // rji -> Deva + 2868, 105, // rjs -> Deva + 2872, 235, // rka -> Khmr + 2876, 345, // rki -> Mymr + 2880, 45, // rkt -> Beng + 2884, 20, // rmi -> Armn + 2888, 10, // rmt -> Arab + 2892, 345, // rmz -> Mymr + 2896, 100, // rom_BG -> Cyrl + 2903, 100, // rsk -> Cyrl + 2907, 105, // rtw -> Deva + 2911, 100, // ru -> Cyrl + 2914, 100, // rue -> Cyrl + 2918, 100, // rut -> Cyrl + 2922, 105, // rwr -> Deva + 2926, 220, // ryu -> Kana + 2930, 105, // sa -> Deva + 2933, 100, // sah -> Cyrl + 2937, 435, // sam -> Samr + 2941, 375, // sat -> Olck + 2945, 445, // saz -> Saur + 2949, 10, // sbn -> Arab + 2953, 535, // sbu -> Tibt + 2957, 105, // sck -> Deva + 2961, 10, // scl -> Arab + 2965, 10, // scl_IN -> Arab + 2972, 105, // scp -> Deva + 2976, 260, // sct -> Laoo + 2980, 485, // scu -> Takr + 2984, 150, // scx -> Grek + 2988, 10, // sd -> Arab + 2991, 105, // sd_IN -> Deva + 2997, 10, // sdb -> Arab + 3001, 10, // sdf -> Arab + 3005, 10, // sdg -> Arab + 3009, 10, // sdh -> Arab + 3013, 10, // sds -> Arab + 3017, 100, // sel -> Cyrl + 3021, 410, // sfm -> Plrd + 3025, 370, // sga -> Ogam + 3029, 100, // sgh -> Cyrl + 3033, 105, // sgj -> Deva + 3037, 10, // sgr -> Arab + 3041, 535, // sgt -> Tibt + 3045, 120, // sgw -> Ethi + 3049, 10, // sgy -> Arab + 3053, 10, // shd -> Arab + 3057, 520, // shi -> Tfng + 3061, 10, // shm -> Arab + 3065, 345, // shn -> Mymr + 3069, 10, // shu -> Arab + 3073, 10, // shv -> Arab + 3077, 455, // si -> Sinh + 3080, 100, // sia -> Cyrl + 3084, 535, // sip -> Tibt + 3088, 10, // siy -> Arab + 3092, 10, // siz -> Arab + 3096, 100, // sjd -> Cyrl + 3100, 105, // sjp -> Deva + 3104, 100, // sjt -> Cyrl + 3108, 530, // skb -> Thai + 3112, 105, // skj -> Deva + 3116, 10, // skr -> Arab + 3120, 10, // slq -> Arab + 3124, 575, // smh -> Yiii + 3128, 435, // smp -> Samr + 3132, 235, // smu -> Khmr + 3136, 10, // smy -> Arab + 3140, 510, // soa -> Tavt + 3144, 460, // sog -> Sogd + 3148, 105, // soi -> Deva + 3152, 530, // sou -> Thai + 3156, 535, // spt -> Tibt + 3160, 385, // spv -> Orya + 3164, 10, // sqo -> Arab + 3168, 260, // sqq -> Laoo + 3172, 10, // sqt -> Arab + 3176, 100, // sr -> Cyrl + 3179, 465, // srb -> Sora + 3183, 10, // srh -> Arab + 3187, 105, // srx -> Deva + 3191, 10, // srz -> Arab + 3195, 10, // ssh -> Arab + 3199, 260, // sss -> Laoo + 3203, 10, // sts -> Arab + 3207, 120, // stv -> Ethi + 3211, 100, // sty -> Cyrl + 3215, 105, // suz -> Deva + 3219, 125, // sva -> Geor + 3223, 10, // swb -> Arab + 3227, 170, // swi -> Hani + 3231, 105, // swv -> Deva + 3235, 475, // syc -> Syrc + 3239, 45, // syl -> Beng + 3243, 475, // syn -> Syrc + 3247, 475, // syr -> Syrc + 3251, 105, // syw -> Deva + 3255, 500, // ta -> Taml + 3258, 100, // tab -> Cyrl + 3262, 105, // taj -> Deva + 3266, 480, // tbk -> Tagb + 3270, 535, // tcn -> Tibt + 3274, 345, // tco -> Mymr + 3278, 500, // tcx -> Taml + 3282, 245, // tcy -> Knda + 3286, 520, // tda -> Tfng + 3290, 105, // tdb -> Deva + 3294, 490, // tdd -> Tale + 3298, 105, // tdg -> Deva + 3302, 105, // tdh -> Deva + 3306, 515, // te -> Telu + 3309, 205, // tes -> Java + 3313, 100, // tg -> Cyrl + 3316, 10, // tg_PK -> Arab + 3322, 105, // tge -> Deva + 3326, 535, // tgf -> Tibt + 3330, 530, // th -> Thai + 3333, 105, // the -> Deva + 3337, 105, // thf -> Deva + 3341, 490, // thi -> Tale + 3345, 105, // thl -> Deva + 3349, 530, // thm -> Thai + 3353, 105, // thq -> Deva + 3357, 105, // thr -> Deva + 3361, 105, // ths -> Deva + 3365, 120, // ti -> Ethi + 3368, 120, // tig -> Ethi + 3372, 105, // tij -> Deva + 3376, 100, // tin -> Cyrl + 3380, 345, // tjl -> Mymr + 3384, 10, // tjo -> Arab + 3388, 105, // tkb -> Deva + 3392, 10, // tks -> Arab + 3396, 105, // tkt -> Deva + 3400, 105, // tmk -> Deva + 3404, 475, // tmr -> Syrc + 3408, 60, // tnv -> Cakm + 3412, 10, // tov -> Arab + 3416, 235, // tpu -> Khmr + 3420, 10, // tra -> Arab + 3424, 185, // trg -> Hebr + 3428, 10, // trm -> Arab + 3432, 10, // trw -> Arab + 3436, 150, // tsd -> Grek + 3440, 535, // tsj -> Tibt + 3444, 100, // tt -> Cyrl + 3447, 260, // tth -> Laoo + 3451, 260, // tto -> Laoo + 3455, 530, // tts -> Thai + 3459, 345, // tvn -> Mymr + 3463, 105, // twm -> Deva + 3467, 505, // txg -> Tang + 3471, 545, // txo -> Toto + 3475, 510, // tyr -> Tavt + 3479, 100, // tyv -> Cyrl + 3483, 100, // ude -> Cyrl + 3487, 320, // udg -> Mlym + 3491, 0, // udi -> Aghb + 3495, 100, // udm -> Cyrl + 3499, 10, // ug -> Arab + 3502, 100, // ug_KZ -> Cyrl + 3508, 100, // ug_MN -> Cyrl + 3514, 550, // uga -> Ugar + 3518, 100, // ugh -> Cyrl + 3522, 530, // ugo -> Thai + 3526, 100, // uk -> Cyrl + 3529, 385, // uki -> Orya + 3533, 100, // ulc -> Cyrl + 3537, 45, // unr -> Beng + 3541, 105, // unr_NP -> Deva + 3548, 45, // unx -> Beng + 3552, 10, // ur -> Arab + 3555, 530, // urk -> Thai + 3559, 10, // ush -> Arab + 3563, 150, // uum -> Grek + 3567, 10, // uz_AF -> Arab + 3573, 100, // uz_CN -> Cyrl + 3579, 10, // uzs -> Arab + 3583, 500, // vaa -> Taml + 3587, 10, // vaf -> Arab + 3591, 105, // vah -> Deva + 3595, 555, // vai -> Vaii + 3599, 105, // vas -> Deva + 3603, 105, // vav -> Deva + 3607, 105, // vay -> Deva + 3611, 10, // vgr -> Arab + 3615, 245, // vmd -> Knda + 3619, 10, // vmh -> Arab + 3623, 120, // wal -> Ethi + 3627, 10, // wbk -> Arab + 3631, 515, // wbq -> Telu + 3635, 105, // wbr -> Deva + 3639, 10, // wlo -> Arab + 3643, 105, // wme -> Deva + 3647, 10, // wne -> Arab + 3651, 10, // wni -> Arab + 3655, 130, // wsg -> Gong + 3659, 10, // wsv -> Arab + 3663, 105, // wtm -> Deva + 3667, 175, // wuu -> Hans + 3671, 100, // xal -> Cyrl + 3675, 120, // xan -> Ethi + 3679, 100, // xas -> Cyrl + 3683, 85, // xco -> Chrs + 3687, 70, // xcr -> Cari + 3691, 100, // xdq -> Cyrl + 3695, 10, // xhe -> Arab + 3699, 235, // xhm -> Khmr + 3703, 385, // xis -> Orya + 3707, 10, // xka -> Arab + 3711, 10, // xkc -> Arab + 3715, 10, // xkj -> Arab + 3719, 10, // xkp -> Arab + 3723, 285, // xlc -> Lyci + 3727, 290, // xld -> Lydi + 3731, 115, // xly -> Elym + 3735, 125, // xmf -> Geor + 3739, 300, // xmn -> Mani + 3743, 315, // xmr -> Merc + 3747, 350, // xna -> Narb + 3751, 105, // xnr -> Deva + 3755, 150, // xpg -> Grek + 3759, 370, // xpi -> Ogam + 3763, 100, // xpm -> Cyrl + 3767, 415, // xpr -> Prti + 3771, 100, // xrm -> Cyrl + 3775, 100, // xrn -> Cyrl + 3779, 440, // xsa -> Sarb + 3783, 105, // xsr -> Deva + 3787, 100, // xss -> Cyrl + 3791, 500, // xub -> Taml + 3795, 500, // xuj -> Taml + 3799, 200, // xve -> Ital + 3803, 10, // xvi -> Arab + 3807, 100, // xwo -> Cyrl + 3811, 305, // xzh -> Marc + 3815, 100, // yai -> Cyrl + 3819, 105, // ybh -> Deva + 3823, 105, // ybi -> Deva + 3827, 10, // ydg -> Arab + 3831, 320, // yea -> Mlym + 3835, 150, // yej -> Grek + 3839, 515, // yeu -> Telu + 3843, 410, // ygp -> Plrd + 3847, 185, // yhd -> Hebr + 3851, 185, // yi -> Hebr + 3854, 575, // yig -> Yiii + 3858, 185, // yih -> Hebr + 3862, 575, // yiv -> Yiii + 3866, 100, // ykg -> Cyrl + 3870, 410, // yna -> Plrd + 3874, 100, // ynk -> Cyrl + 3878, 210, // yoi -> Jpan + 3882, 530, // yoy -> Thai + 3886, 100, // yrk -> Cyrl + 3890, 575, // ysd -> Yiii + 3894, 575, // ysn -> Yiii + 3898, 575, // ysp -> Yiii + 3902, 100, // ysr -> Cyrl + 3906, 410, // ysy -> Plrd + 3910, 185, // yud -> Hebr + 3914, 180, // yue -> Hant + 3918, 175, // yue_CN -> Hans + 3925, 100, // yug -> Cyrl + 3929, 100, // yux -> Cyrl + 3933, 410, // ywq -> Plrd + 3937, 410, // ywu -> Plrd + 3941, 535, // zau -> Tibt + 3945, 10, // zba -> Arab + 3949, 170, // zch -> Hani + 3953, 10, // zdj -> Arab + 3957, 170, // zeh -> Hani + 3961, 520, // zen -> Tfng + 3965, 170, // zgb -> Hani + 3969, 520, // zgh -> Tfng + 3973, 170, // zgm -> Hani + 3977, 170, // zgn -> Hani + 3981, 175, // zh -> Hans + 3984, 180, // zh_AU -> Hant + 3990, 180, // zh_BN -> Hant + 3996, 180, // zh_GB -> Hant + 4002, 180, // zh_GF -> Hant + 4008, 180, // zh_HK -> Hant + 4014, 180, // zh_ID -> Hant + 4020, 180, // zh_MO -> Hant + 4026, 180, // zh_PA -> Hant + 4032, 180, // zh_PF -> Hant + 4038, 180, // zh_PH -> Hant + 4044, 180, // zh_SR -> Hant + 4050, 180, // zh_TH -> Hant + 4056, 180, // zh_TW -> Hant + 4062, 180, // zh_US -> Hant + 4068, 180, // zh_VN -> Hant + 4074, 170, // zhd -> Hani + 4078, 365, // zhx -> Nshu + 4082, 100, // zkb -> Cyrl + 4086, 100, // zko -> Cyrl + 4090, 240, // zkt -> Kits + 4094, 100, // zkz -> Cyrl + 4098, 170, // zlj -> Hani + 4102, 170, // zln -> Hani + 4106, 170, // zlq -> Hani + 4110, 170, // zqe -> Hani + 4114, 185, // zrp -> Hebr + 4118, 10, // zum -> Arab + 4122, 170, // zyg -> Hani + 4126, 170, // zyn -> Hani + 4130, 170, // zzj -> Hani }; //====================================================================== @@ -1150,35 +1138,36 @@ const char parentLocaleChars[] = "en_AU\0en_BB\0en_BE\0en_BM\0en_BS\0en_BW\0en_BZ\0en_CC\0en_CH\0" "en_CK\0en_CM\0en_CX\0en_CY\0en_DE\0en_DG\0en_DK\0en_DM\0en_Dsrt\0" "en_ER\0en_FI\0en_FJ\0en_FK\0en_FM\0en_GB\0en_GD\0en_GG\0en_GH\0" - "en_GI\0en_GM\0en_GY\0en_HK\0en_IE\0en_IL\0en_IM\0en_IN\0en_IO\0" - "en_JE\0en_JM\0en_KE\0en_KI\0en_KN\0en_KY\0en_LC\0en_LR\0en_LS\0" - "en_MG\0en_MO\0en_MS\0en_MT\0en_MU\0en_MV\0en_MW\0en_MY\0en_NA\0" - "en_NF\0en_NG\0en_NL\0en_NR\0en_NU\0en_NZ\0en_PG\0en_PK\0en_PN\0" - "en_PW\0en_RW\0en_SB\0en_SC\0en_SD\0en_SE\0en_SG\0en_SH\0en_SI\0" - "en_SL\0en_SS\0en_SX\0en_SZ\0en_Shaw\0en_TC\0en_TK\0en_TO\0en_TT\0" - "en_TV\0en_TZ\0en_UG\0en_VC\0en_VG\0en_VU\0en_WS\0en_ZA\0en_ZM\0" - "en_ZW\0es_419\0es_AR\0es_BO\0es_BR\0es_BZ\0es_CL\0es_CO\0es_CR\0" - "es_CU\0es_DO\0es_EC\0es_GT\0es_HN\0es_MX\0es_NI\0es_PA\0es_PE\0" - "es_PR\0es_PY\0es_SV\0es_US\0es_UY\0es_VE\0ff_Adlm\0ff_Arab\0fr_HT\0" - "ha_Arab\0hi_Latn\0ht\0iu_Latn\0kk_Arab\0ks_Deva\0ku_Arab\0ky_Arab\0" - "ky_Latn\0ml_Arab\0mn_Mong\0mni_Mtei\0ms_Arab\0nb\0nn\0no\0no_NO\0" - "pa_Arab\0pt_AO\0pt_CH\0pt_CV\0pt_FR\0pt_GQ\0pt_GW\0pt_LU\0pt_MO\0" - "pt_MZ\0pt_PT\0pt_ST\0pt_TL\0root\0sat_Deva\0sd_Deva\0sd_Khoj\0" - "sd_Sind\0shi_Latn\0so_Arab\0sr_Latn\0sw_Arab\0tg_Arab\0ug_Cyrl\0" - "uz_Arab\0uz_Cyrl\0vai_Latn\0wo_Arab\0yo_Arab\0yue_Hans\0zh_Hant\0" - "zh_Hant_HK\0zh_Hant_MO\0"; + "en_GI\0en_GM\0en_GY\0en_HK\0en_ID\0en_IE\0en_IL\0en_IM\0en_IN\0" + "en_IO\0en_JE\0en_JM\0en_KE\0en_KI\0en_KN\0en_KY\0en_LC\0en_LR\0" + "en_LS\0en_MG\0en_MO\0en_MS\0en_MT\0en_MU\0en_MV\0en_MW\0en_MY\0" + "en_NA\0en_NF\0en_NG\0en_NL\0en_NR\0en_NU\0en_NZ\0en_PG\0en_PK\0" + "en_PN\0en_PW\0en_RW\0en_SB\0en_SC\0en_SD\0en_SE\0en_SG\0en_SH\0" + "en_SI\0en_SL\0en_SS\0en_SX\0en_SZ\0en_Shaw\0en_TC\0en_TK\0en_TO\0" + "en_TT\0en_TV\0en_TZ\0en_UG\0en_VC\0en_VG\0en_VU\0en_WS\0en_ZA\0" + "en_ZM\0en_ZW\0es_419\0es_AR\0es_BO\0es_BR\0es_BZ\0es_CL\0es_CO\0" + "es_CR\0es_CU\0es_DO\0es_EC\0es_GT\0es_HN\0es_JP\0es_MX\0es_NI\0" + "es_PA\0es_PE\0es_PR\0es_PY\0es_SV\0es_US\0es_UY\0es_VE\0ff_Adlm\0" + "ff_Arab\0fr_HT\0ha_Arab\0hi_Latn\0ht\0iu_Latn\0kk_Arab\0ks_Deva\0" + "ku_Arab\0kxv_Deva\0kxv_Orya\0kxv_Telu\0ky_Arab\0ky_Latn\0ml_Arab\0" + "mn_Mong\0mni_Mtei\0ms_Arab\0nb\0nn\0no\0no_NO\0pa_Arab\0pt_AO\0" + "pt_CH\0pt_CV\0pt_FR\0pt_GQ\0pt_GW\0pt_LU\0pt_MO\0pt_MZ\0pt_PT\0" + "pt_ST\0pt_TL\0root\0sat_Deva\0sd_Deva\0sd_Khoj\0sd_Sind\0shi_Latn\0" + "so_Arab\0sr_Latn\0sw_Arab\0tg_Arab\0ug_Cyrl\0uz_Arab\0uz_Cyrl\0" + "vai_Latn\0wo_Arab\0yo_Arab\0yue_Hans\0zh_Hant\0zh_Hant_HK\0zh_Hant_MO\0" + ""; const int32_t parentLocaleTable[] = { - 0, 1023, // az_Arab -> root - 8, 1023, // az_Cyrl -> root - 16, 1023, // bal_Latn -> root - 25, 1023, // blt_Latn -> root - 34, 1023, // bm_Nkoo -> root - 42, 1023, // bs_Cyrl -> root - 50, 1023, // byn_Latn -> root - 59, 1023, // cu_Glag -> root - 67, 1023, // dje_Arab -> root - 76, 1023, // dyo_Arab -> root + 0, 1062, // az_Arab -> root + 8, 1062, // az_Cyrl -> root + 16, 1062, // bal_Latn -> root + 25, 1062, // blt_Latn -> root + 34, 1062, // bm_Nkoo -> root + 42, 1062, // bs_Cyrl -> root + 50, 1062, // byn_Latn -> root + 59, 1062, // cu_Glag -> root + 67, 1062, // dje_Arab -> root + 76, 1062, // dyo_Arab -> root 92, 85, // en_150 -> en_001 99, 85, // en_AG -> en_001 105, 85, // en_AI -> en_001 @@ -1200,7 +1189,7 @@ const int32_t parentLocaleTable[] = { 201, 85, // en_DG -> en_001 207, 92, // en_DK -> en_150 213, 85, // en_DM -> en_001 - 219, 1023, // en_Dsrt -> root + 219, 1062, // en_Dsrt -> root 227, 85, // en_ER -> en_001 233, 92, // en_FI -> en_150 239, 85, // en_FJ -> en_001 @@ -1214,136 +1203,141 @@ const int32_t parentLocaleTable[] = { 287, 85, // en_GM -> en_001 293, 85, // en_GY -> en_001 299, 85, // en_HK -> en_001 - 305, 85, // en_IE -> en_001 - 311, 85, // en_IL -> en_001 - 317, 85, // en_IM -> en_001 - 323, 85, // en_IN -> en_001 - 329, 85, // en_IO -> en_001 - 335, 85, // en_JE -> en_001 - 341, 85, // en_JM -> en_001 - 347, 85, // en_KE -> en_001 - 353, 85, // en_KI -> en_001 - 359, 85, // en_KN -> en_001 - 365, 85, // en_KY -> en_001 - 371, 85, // en_LC -> en_001 - 377, 85, // en_LR -> en_001 - 383, 85, // en_LS -> en_001 - 389, 85, // en_MG -> en_001 - 395, 85, // en_MO -> en_001 - 401, 85, // en_MS -> en_001 - 407, 85, // en_MT -> en_001 - 413, 85, // en_MU -> en_001 - 419, 85, // en_MV -> en_001 - 425, 85, // en_MW -> en_001 - 431, 85, // en_MY -> en_001 - 437, 85, // en_NA -> en_001 - 443, 85, // en_NF -> en_001 - 449, 85, // en_NG -> en_001 - 455, 92, // en_NL -> en_150 - 461, 85, // en_NR -> en_001 - 467, 85, // en_NU -> en_001 - 473, 85, // en_NZ -> en_001 - 479, 85, // en_PG -> en_001 - 485, 85, // en_PK -> en_001 - 491, 85, // en_PN -> en_001 - 497, 85, // en_PW -> en_001 - 503, 85, // en_RW -> en_001 - 509, 85, // en_SB -> en_001 - 515, 85, // en_SC -> en_001 - 521, 85, // en_SD -> en_001 - 527, 92, // en_SE -> en_150 - 533, 85, // en_SG -> en_001 - 539, 85, // en_SH -> en_001 - 545, 92, // en_SI -> en_150 - 551, 85, // en_SL -> en_001 - 557, 85, // en_SS -> en_001 - 563, 85, // en_SX -> en_001 - 569, 85, // en_SZ -> en_001 - 575, 1023, // en_Shaw -> root - 583, 85, // en_TC -> en_001 - 589, 85, // en_TK -> en_001 - 595, 85, // en_TO -> en_001 - 601, 85, // en_TT -> en_001 - 607, 85, // en_TV -> en_001 - 613, 85, // en_TZ -> en_001 - 619, 85, // en_UG -> en_001 - 625, 85, // en_VC -> en_001 - 631, 85, // en_VG -> en_001 - 637, 85, // en_VU -> en_001 - 643, 85, // en_WS -> en_001 - 649, 85, // en_ZA -> en_001 - 655, 85, // en_ZM -> en_001 - 661, 85, // en_ZW -> en_001 - 674, 667, // es_AR -> es_419 - 680, 667, // es_BO -> es_419 - 686, 667, // es_BR -> es_419 - 692, 667, // es_BZ -> es_419 - 698, 667, // es_CL -> es_419 - 704, 667, // es_CO -> es_419 - 710, 667, // es_CR -> es_419 - 716, 667, // es_CU -> es_419 - 722, 667, // es_DO -> es_419 - 728, 667, // es_EC -> es_419 - 734, 667, // es_GT -> es_419 - 740, 667, // es_HN -> es_419 - 746, 667, // es_MX -> es_419 - 752, 667, // es_NI -> es_419 - 758, 667, // es_PA -> es_419 - 764, 667, // es_PE -> es_419 - 770, 667, // es_PR -> es_419 - 776, 667, // es_PY -> es_419 - 782, 667, // es_SV -> es_419 - 788, 667, // es_US -> es_419 - 794, 667, // es_UY -> es_419 - 800, 667, // es_VE -> es_419 - 806, 1023, // ff_Adlm -> root - 814, 1023, // ff_Arab -> root - 828, 1023, // ha_Arab -> root - 836, 323, // hi_Latn -> en_IN - 844, 822, // ht -> fr_HT - 847, 1023, // iu_Latn -> root - 855, 1023, // kk_Arab -> root - 863, 1023, // ks_Deva -> root - 871, 1023, // ku_Arab -> root - 879, 1023, // ky_Arab -> root - 887, 1023, // ky_Latn -> root - 895, 1023, // ml_Arab -> root - 903, 1023, // mn_Mong -> root - 911, 1023, // mni_Mtei -> root - 920, 1023, // ms_Arab -> root - 928, 934, // nb -> no - 931, 934, // nn -> no - 937, 934, // no_NO -> no - 943, 1023, // pa_Arab -> root - 951, 1005, // pt_AO -> pt_PT - 957, 1005, // pt_CH -> pt_PT - 963, 1005, // pt_CV -> pt_PT - 969, 1005, // pt_FR -> pt_PT - 975, 1005, // pt_GQ -> pt_PT - 981, 1005, // pt_GW -> pt_PT - 987, 1005, // pt_LU -> pt_PT - 993, 1005, // pt_MO -> pt_PT - 999, 1005, // pt_MZ -> pt_PT - 1011, 1005, // pt_ST -> pt_PT - 1017, 1005, // pt_TL -> pt_PT - 1028, 1023, // sat_Deva -> root - 1037, 1023, // sd_Deva -> root - 1045, 1023, // sd_Khoj -> root - 1053, 1023, // sd_Sind -> root - 1061, 1023, // shi_Latn -> root - 1070, 1023, // so_Arab -> root - 1078, 1023, // sr_Latn -> root - 1086, 1023, // sw_Arab -> root - 1094, 1023, // tg_Arab -> root - 1102, 1023, // ug_Cyrl -> root - 1110, 1023, // uz_Arab -> root - 1118, 1023, // uz_Cyrl -> root - 1126, 1023, // vai_Latn -> root - 1135, 1023, // wo_Arab -> root - 1143, 1023, // yo_Arab -> root - 1151, 1023, // yue_Hans -> root - 1160, 1023, // zh_Hant -> root - 1179, 1168, // zh_Hant_MO -> zh_Hant_HK + 305, 85, // en_ID -> en_001 + 311, 85, // en_IE -> en_001 + 317, 85, // en_IL -> en_001 + 323, 85, // en_IM -> en_001 + 329, 85, // en_IN -> en_001 + 335, 85, // en_IO -> en_001 + 341, 85, // en_JE -> en_001 + 347, 85, // en_JM -> en_001 + 353, 85, // en_KE -> en_001 + 359, 85, // en_KI -> en_001 + 365, 85, // en_KN -> en_001 + 371, 85, // en_KY -> en_001 + 377, 85, // en_LC -> en_001 + 383, 85, // en_LR -> en_001 + 389, 85, // en_LS -> en_001 + 395, 85, // en_MG -> en_001 + 401, 85, // en_MO -> en_001 + 407, 85, // en_MS -> en_001 + 413, 85, // en_MT -> en_001 + 419, 85, // en_MU -> en_001 + 425, 85, // en_MV -> en_001 + 431, 85, // en_MW -> en_001 + 437, 85, // en_MY -> en_001 + 443, 85, // en_NA -> en_001 + 449, 85, // en_NF -> en_001 + 455, 85, // en_NG -> en_001 + 461, 92, // en_NL -> en_150 + 467, 85, // en_NR -> en_001 + 473, 85, // en_NU -> en_001 + 479, 85, // en_NZ -> en_001 + 485, 85, // en_PG -> en_001 + 491, 85, // en_PK -> en_001 + 497, 85, // en_PN -> en_001 + 503, 85, // en_PW -> en_001 + 509, 85, // en_RW -> en_001 + 515, 85, // en_SB -> en_001 + 521, 85, // en_SC -> en_001 + 527, 85, // en_SD -> en_001 + 533, 92, // en_SE -> en_150 + 539, 85, // en_SG -> en_001 + 545, 85, // en_SH -> en_001 + 551, 92, // en_SI -> en_150 + 557, 85, // en_SL -> en_001 + 563, 85, // en_SS -> en_001 + 569, 85, // en_SX -> en_001 + 575, 85, // en_SZ -> en_001 + 581, 1062, // en_Shaw -> root + 589, 85, // en_TC -> en_001 + 595, 85, // en_TK -> en_001 + 601, 85, // en_TO -> en_001 + 607, 85, // en_TT -> en_001 + 613, 85, // en_TV -> en_001 + 619, 85, // en_TZ -> en_001 + 625, 85, // en_UG -> en_001 + 631, 85, // en_VC -> en_001 + 637, 85, // en_VG -> en_001 + 643, 85, // en_VU -> en_001 + 649, 85, // en_WS -> en_001 + 655, 85, // en_ZA -> en_001 + 661, 85, // en_ZM -> en_001 + 667, 85, // en_ZW -> en_001 + 680, 673, // es_AR -> es_419 + 686, 673, // es_BO -> es_419 + 692, 673, // es_BR -> es_419 + 698, 673, // es_BZ -> es_419 + 704, 673, // es_CL -> es_419 + 710, 673, // es_CO -> es_419 + 716, 673, // es_CR -> es_419 + 722, 673, // es_CU -> es_419 + 728, 673, // es_DO -> es_419 + 734, 673, // es_EC -> es_419 + 740, 673, // es_GT -> es_419 + 746, 673, // es_HN -> es_419 + 752, 673, // es_JP -> es_419 + 758, 673, // es_MX -> es_419 + 764, 673, // es_NI -> es_419 + 770, 673, // es_PA -> es_419 + 776, 673, // es_PE -> es_419 + 782, 673, // es_PR -> es_419 + 788, 673, // es_PY -> es_419 + 794, 673, // es_SV -> es_419 + 800, 673, // es_US -> es_419 + 806, 673, // es_UY -> es_419 + 812, 673, // es_VE -> es_419 + 818, 1062, // ff_Adlm -> root + 826, 1062, // ff_Arab -> root + 840, 1062, // ha_Arab -> root + 848, 329, // hi_Latn -> en_IN + 856, 834, // ht -> fr_HT + 859, 1062, // iu_Latn -> root + 867, 1062, // kk_Arab -> root + 875, 1062, // ks_Deva -> root + 883, 1062, // ku_Arab -> root + 891, 1062, // kxv_Deva -> root + 900, 1062, // kxv_Orya -> root + 909, 1062, // kxv_Telu -> root + 918, 1062, // ky_Arab -> root + 926, 1062, // ky_Latn -> root + 934, 1062, // ml_Arab -> root + 942, 1062, // mn_Mong -> root + 950, 1062, // mni_Mtei -> root + 959, 1062, // ms_Arab -> root + 967, 973, // nb -> no + 970, 973, // nn -> no + 976, 973, // no_NO -> no + 982, 1062, // pa_Arab -> root + 990, 1044, // pt_AO -> pt_PT + 996, 1044, // pt_CH -> pt_PT + 1002, 1044, // pt_CV -> pt_PT + 1008, 1044, // pt_FR -> pt_PT + 1014, 1044, // pt_GQ -> pt_PT + 1020, 1044, // pt_GW -> pt_PT + 1026, 1044, // pt_LU -> pt_PT + 1032, 1044, // pt_MO -> pt_PT + 1038, 1044, // pt_MZ -> pt_PT + 1050, 1044, // pt_ST -> pt_PT + 1056, 1044, // pt_TL -> pt_PT + 1067, 1062, // sat_Deva -> root + 1076, 1062, // sd_Deva -> root + 1084, 1062, // sd_Khoj -> root + 1092, 1062, // sd_Sind -> root + 1100, 1062, // shi_Latn -> root + 1109, 1062, // so_Arab -> root + 1117, 1062, // sr_Latn -> root + 1125, 1062, // sw_Arab -> root + 1133, 1062, // tg_Arab -> root + 1141, 1062, // ug_Cyrl -> root + 1149, 1062, // uz_Arab -> root + 1157, 1062, // uz_Cyrl -> root + 1165, 1062, // vai_Latn -> root + 1174, 1062, // wo_Arab -> root + 1182, 1062, // yo_Arab -> root + 1190, 1062, // yue_Hans -> root + 1199, 1062, // zh_Hant -> root + 1218, 1207, // zh_Hant_MO -> zh_Hant_HK }; diff --git a/thirdparty/icu4c/common/localematcher.cpp b/thirdparty/icu4c/common/localematcher.cpp index 5f8c703df7..6fc578af11 100644 --- a/thirdparty/icu4c/common/localematcher.cpp +++ b/thirdparty/icu4c/common/localematcher.cpp @@ -307,7 +307,7 @@ LSR getMaximalLsrOrUnd(const XLikelySubtags &likelySubtags, const Locale &locale if (U_FAILURE(errorCode) || locale.isBogus() || *locale.getName() == 0 /* "und" */) { return UND_LSR; } else { - return likelySubtags.makeMaximizedLsrFrom(locale, errorCode); + return likelySubtags.makeMaximizedLsrFrom(locale, false, errorCode); } } diff --git a/thirdparty/icu4c/common/locid.cpp b/thirdparty/icu4c/common/locid.cpp index 70a794ae07..64ff63f361 100644 --- a/thirdparty/icu4c/common/locid.cpp +++ b/thirdparty/icu4c/common/locid.cpp @@ -563,7 +563,7 @@ private: LocalMemory<int32_t>& replacementIndexes, int32_t &length, void (*checkType)(const char* type), - void (*checkReplacement)(const UnicodeString& replacement), + void (*checkReplacement)(const UChar* replacement), UErrorCode &status); // Read the languageAlias data from alias to @@ -700,7 +700,7 @@ AliasDataBuilder::readAlias( LocalMemory<int32_t>& replacementIndexes, int32_t &length, void (*checkType)(const char* type), - void (*checkReplacement)(const UnicodeString& replacement), + void (*checkReplacement)(const UChar* replacement), UErrorCode &status) { if (U_FAILURE(status)) { return; @@ -720,8 +720,8 @@ AliasDataBuilder::readAlias( LocalUResourceBundlePointer res( ures_getNextResource(alias, nullptr, &status)); const char* aliasFrom = ures_getKey(res.getAlias()); - UnicodeString aliasTo = - ures_getUnicodeStringByKey(res.getAlias(), "replacement", &status); + const UChar* aliasTo = + ures_getStringByKey(res.getAlias(), "replacement", nullptr, &status); if (U_FAILURE(status)) return; checkType(aliasFrom); @@ -766,7 +766,7 @@ AliasDataBuilder::readLanguageAlias( #else [](const char*) {}, #endif - [](const UnicodeString&) {}, status); + [](const UChar*) {}, status); } /** @@ -790,12 +790,12 @@ AliasDataBuilder::readScriptAlias( [](const char* type) { U_ASSERT(uprv_strlen(type) == 4); }, - [](const UnicodeString& replacement) { - U_ASSERT(replacement.length() == 4); + [](const UChar* replacement) { + U_ASSERT(u_strlen(replacement) == 4); }, #else [](const char*) {}, - [](const UnicodeString&) { }, + [](const UChar*) { }, #endif status); } @@ -824,7 +824,7 @@ AliasDataBuilder::readTerritoryAlias( #else [](const char*) {}, #endif - [](const UnicodeString&) { }, + [](const UChar*) { }, status); } @@ -851,15 +851,16 @@ AliasDataBuilder::readVariantAlias( U_ASSERT(uprv_strlen(type) != 4 || (type[0] >= '0' && type[0] <= '9')); }, - [](const UnicodeString& replacement) { - U_ASSERT(replacement.length() >= 4 && replacement.length() <= 8); - U_ASSERT(replacement.length() != 4 || - (replacement.charAt(0) >= u'0' && - replacement.charAt(0) <= u'9')); + [](const UChar* replacement) { + int32_t len = u_strlen(replacement); + U_ASSERT(len >= 4 && len <= 8); + U_ASSERT(len != 4 || + (*replacement >= u'0' && + *replacement <= u'9')); }, #else [](const char*) {}, - [](const UnicodeString&) { }, + [](const UChar*) { }, #endif status); } @@ -888,7 +889,7 @@ AliasDataBuilder::readSubdivisionAlias( #else [](const char*) {}, #endif - [](const UnicodeString&) { }, + [](const UChar*) { }, status); } @@ -1066,7 +1067,13 @@ class AliasReplacer { public: AliasReplacer(UErrorCode status) : language(nullptr), script(nullptr), region(nullptr), - extensions(nullptr), variants(status), + extensions(nullptr), + // store value in variants only once + variants(nullptr, + ([](UElement e1, UElement e2) -> UBool { + return 0==uprv_strcmp((const char*)e1.pointer, + (const char*)e2.pointer);}), + status), data(nullptr) { } ~AliasReplacer() { @@ -1652,10 +1659,16 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status while ((end = uprv_strchr(start, SEP_CHAR)) != nullptr && U_SUCCESS(status)) { *end = NULL_CHAR; // null terminate inside variantsBuff - variants.addElement(start, status); + // do not add "" or duplicate data to variants + if (*start && !variants.contains(start)) { + variants.addElement(start, status); + } start = end + 1; } - variants.addElement(start, status); + // do not add "" or duplicate data to variants + if (*start && !variants.contains(start)) { + variants.addElement(start, status); + } } if (U_FAILURE(status)) { return false; } @@ -2079,6 +2092,10 @@ Locale::addLikelySubtags(UErrorCode& status) { void Locale::minimizeSubtags(UErrorCode& status) { + Locale::minimizeSubtags(false, status); +} +void +Locale::minimizeSubtags(bool favorScript, UErrorCode& status) { if (U_FAILURE(status)) { return; } @@ -2086,7 +2103,7 @@ Locale::minimizeSubtags(UErrorCode& status) { CharString minimizedLocaleID; { CharStringByteSink sink(&minimizedLocaleID); - ulocimp_minimizeSubtags(fullName, sink, &status); + ulocimp_minimizeSubtags(fullName, sink, favorScript, &status); } if (U_FAILURE(status)) { @@ -2402,8 +2419,9 @@ Locale::getLocaleCache() } class KeywordEnumeration : public StringEnumeration { -private: +protected: char *keywords; +private: char *current; int32_t length; UnicodeString currUSKey; @@ -2510,6 +2528,17 @@ public: if (resultLength != nullptr) *resultLength = 0; return nullptr; } + virtual int32_t count(UErrorCode &/*status*/) const override { + char *kw = keywords; + int32_t result = 0; + while(*kw) { + if (uloc_toUnicodeLocaleKey(kw) != nullptr) { + result++; + } + kw += uprv_strlen(kw)+1; + } + return result; + } }; // Out-of-line virtual destructor to serve as the "key function". diff --git a/thirdparty/icu4c/common/loclikely.cpp b/thirdparty/icu4c/common/loclikely.cpp index d2a05c6364..eedfb8149e 100644 --- a/thirdparty/icu4c/common/loclikely.cpp +++ b/thirdparty/icu4c/common/loclikely.cpp @@ -31,83 +31,11 @@ #include "charstr.h" #include "cmemory.h" #include "cstring.h" +#include "loclikelysubtags.h" #include "ulocimp.h" #include "ustr_imp.h" /** - * These are the canonical strings for unknown languages, scripts and regions. - **/ -static const char* const unknownLanguage = "und"; -static const char* const unknownScript = "Zzzz"; -static const char* const unknownRegion = "ZZ"; - -/** - * This function looks for the localeID in the likelySubtags resource. - * - * @param localeID The tag to find. - * @param buffer A buffer to hold the matching entry - * @param bufferLength The length of the output buffer - * @return A pointer to "buffer" if found, or a null pointer if not. - */ -static const char* U_CALLCONV -findLikelySubtags(const char* localeID, - char* buffer, - int32_t bufferLength, - UErrorCode* err) { - const char* result = nullptr; - - if (!U_FAILURE(*err)) { - int32_t resLen = 0; - const char16_t* s = nullptr; - UErrorCode tmpErr = U_ZERO_ERROR; - icu::LocalUResourceBundlePointer subtags(ures_openDirect(nullptr, "likelySubtags", &tmpErr)); - if (U_SUCCESS(tmpErr)) { - icu::CharString und; - if (localeID != nullptr) { - if (*localeID == '\0') { - localeID = unknownLanguage; - } else if (*localeID == '_') { - und.append(unknownLanguage, *err); - und.append(localeID, *err); - if (U_FAILURE(*err)) { - return nullptr; - } - localeID = und.data(); - } - } - s = ures_getStringByKey(subtags.getAlias(), localeID, &resLen, &tmpErr); - - if (U_FAILURE(tmpErr)) { - /* - * If a resource is missing, it's not really an error, it's - * just that we don't have any data for that particular locale ID. - */ - if (tmpErr != U_MISSING_RESOURCE_ERROR) { - *err = tmpErr; - } - } - else if (resLen >= bufferLength) { - /* The buffer should never overflow. */ - *err = U_INTERNAL_PROGRAM_ERROR; - } - else { - u_UCharsToChars(s, buffer, resLen + 1); - if (resLen >= 3 && - uprv_strnicmp(buffer, unknownLanguage, 3) == 0 && - (resLen == 3 || buffer[3] == '_')) { - uprv_memmove(buffer, buffer + 3, resLen - 3 + 1); - } - result = buffer; - } - } else { - *err = tmpErr; - } - } - - return result; -} - -/** * Append a tag to a buffer, adding the separator if necessary. The buffer * must be large enough to contain the resulting tag plus any separator * necessary. The tag must not be a zero-length string. @@ -361,57 +289,6 @@ error: } /** - * Create a tag string from the supplied parameters. The lang, script and region - * parameters may be nullptr pointers. If they are, their corresponding length parameters - * must be less than or equal to 0. If the lang parameter is an empty string, the - * default value for an unknown language is written to the output buffer. - * - * If the length of the new string exceeds the capacity of the output buffer, - * the function copies as many bytes to the output buffer as it can, and returns - * the error U_BUFFER_OVERFLOW_ERROR. - * - * If an illegal argument is provided, the function returns the error - * U_ILLEGAL_ARGUMENT_ERROR. - * - * @param lang The language tag to use. - * @param langLength The length of the language tag. - * @param script The script tag to use. - * @param scriptLength The length of the script tag. - * @param region The region tag to use. - * @param regionLength The length of the region tag. - * @param trailing Any trailing data to append to the new tag. - * @param trailingLength The length of the trailing data. - * @param sink The output sink receiving the tag string. - * @param err A pointer to a UErrorCode for error reporting. - **/ -static void U_CALLCONV -createTagString( - const char* lang, - int32_t langLength, - const char* script, - int32_t scriptLength, - const char* region, - int32_t regionLength, - const char* trailing, - int32_t trailingLength, - icu::ByteSink& sink, - UErrorCode* err) -{ - createTagStringWithAlternates( - lang, - langLength, - script, - scriptLength, - region, - regionLength, - trailing, - trailingLength, - nullptr, - sink, - err); -} - -/** * Parse the language, script, and region subtags from a tag string, and copy the * results into the corresponding output parameters. The buffers are null-terminated, * unless overflow occurs. @@ -494,13 +371,6 @@ parseTagString( *scriptLength = subtagLength; if (*scriptLength > 0) { - if (uprv_strnicmp(script, unknownScript, *scriptLength) == 0) { - /** - * If the script part is the "unknown" script, then don't return it. - **/ - *scriptLength = 0; - } - /* * Move past any separator. */ @@ -517,14 +387,7 @@ parseTagString( *regionLength = subtagLength; - if (*regionLength > 0) { - if (uprv_strnicmp(region, unknownRegion, *regionLength) == 0) { - /** - * If the region part is the "unknown" region, then don't return it. - **/ - *regionLength = 0; - } - } else if (*position != 0 && *position != '@') { + if (*regionLength <= 0 && *position != 0 && *position != '@') { /* back up over consumed trailing separator */ --position; } @@ -546,264 +409,6 @@ error: goto exit; } -static UBool U_CALLCONV -createLikelySubtagsString( - const char* lang, - int32_t langLength, - const char* script, - int32_t scriptLength, - const char* region, - int32_t regionLength, - const char* variants, - int32_t variantsLength, - icu::ByteSink& sink, - UErrorCode* err) { - /** - * ULOC_FULLNAME_CAPACITY will provide enough capacity - * that we can build a string that contains the language, - * script and region code without worrying about overrunning - * the user-supplied buffer. - **/ - char likelySubtagsBuffer[ULOC_FULLNAME_CAPACITY]; - - if(U_FAILURE(*err)) { - goto error; - } - - /** - * Try the language with the script and region first. - **/ - if (scriptLength > 0 && regionLength > 0) { - - const char* likelySubtags = nullptr; - - icu::CharString tagBuffer; - { - icu::CharStringByteSink sink(&tagBuffer); - createTagString( - lang, - langLength, - script, - scriptLength, - region, - regionLength, - nullptr, - 0, - sink, - err); - } - if(U_FAILURE(*err)) { - goto error; - } - - likelySubtags = - findLikelySubtags( - tagBuffer.data(), - likelySubtagsBuffer, - sizeof(likelySubtagsBuffer), - err); - if(U_FAILURE(*err)) { - goto error; - } - - if (likelySubtags != nullptr) { - /* Always use the language tag from the - maximal string, since it may be more - specific than the one provided. */ - createTagStringWithAlternates( - nullptr, - 0, - nullptr, - 0, - nullptr, - 0, - variants, - variantsLength, - likelySubtags, - sink, - err); - return true; - } - } - - /** - * Try the language with just the script. - **/ - if (scriptLength > 0) { - - const char* likelySubtags = nullptr; - - icu::CharString tagBuffer; - { - icu::CharStringByteSink sink(&tagBuffer); - createTagString( - lang, - langLength, - script, - scriptLength, - nullptr, - 0, - nullptr, - 0, - sink, - err); - } - if(U_FAILURE(*err)) { - goto error; - } - - likelySubtags = - findLikelySubtags( - tagBuffer.data(), - likelySubtagsBuffer, - sizeof(likelySubtagsBuffer), - err); - if(U_FAILURE(*err)) { - goto error; - } - - if (likelySubtags != nullptr) { - /* Always use the language tag from the - maximal string, since it may be more - specific than the one provided. */ - createTagStringWithAlternates( - nullptr, - 0, - nullptr, - 0, - region, - regionLength, - variants, - variantsLength, - likelySubtags, - sink, - err); - return true; - } - } - - /** - * Try the language with just the region. - **/ - if (regionLength > 0) { - - const char* likelySubtags = nullptr; - - icu::CharString tagBuffer; - { - icu::CharStringByteSink sink(&tagBuffer); - createTagString( - lang, - langLength, - nullptr, - 0, - region, - regionLength, - nullptr, - 0, - sink, - err); - } - if(U_FAILURE(*err)) { - goto error; - } - - likelySubtags = - findLikelySubtags( - tagBuffer.data(), - likelySubtagsBuffer, - sizeof(likelySubtagsBuffer), - err); - if(U_FAILURE(*err)) { - goto error; - } - - if (likelySubtags != nullptr) { - /* Always use the language tag from the - maximal string, since it may be more - specific than the one provided. */ - createTagStringWithAlternates( - nullptr, - 0, - script, - scriptLength, - nullptr, - 0, - variants, - variantsLength, - likelySubtags, - sink, - err); - return true; - } - } - - /** - * Finally, try just the language. - **/ - { - const char* likelySubtags = nullptr; - - icu::CharString tagBuffer; - { - icu::CharStringByteSink sink(&tagBuffer); - createTagString( - lang, - langLength, - nullptr, - 0, - nullptr, - 0, - nullptr, - 0, - sink, - err); - } - if(U_FAILURE(*err)) { - goto error; - } - - likelySubtags = - findLikelySubtags( - tagBuffer.data(), - likelySubtagsBuffer, - sizeof(likelySubtagsBuffer), - err); - if(U_FAILURE(*err)) { - goto error; - } - - if (likelySubtags != nullptr) { - /* Always use the language tag from the - maximal string, since it may be more - specific than the one provided. */ - createTagStringWithAlternates( - nullptr, - 0, - script, - scriptLength, - region, - regionLength, - variants, - variantsLength, - likelySubtags, - sink, - err); - return true; - } - } - - return false; - -error: - - if (!U_FAILURE(*err)) { - *err = U_ILLEGAL_ARGUMENT_ERROR; - } - - return false; -} - #define CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength) UPRV_BLOCK_MACRO_BEGIN { \ int32_t count = 0; \ int32_t i; \ @@ -836,7 +441,6 @@ _uloc_addLikelySubtags(const char* localeID, const char* trailing = ""; int32_t trailingLength = 0; int32_t trailingIndex = 0; - UBool success = false; if(U_FAILURE(*err)) { goto error; @@ -862,6 +466,9 @@ _uloc_addLikelySubtags(const char* localeID, goto error; } + if (langLength > 3) { + goto error; + } /* Find the length of the trailing portion. */ while (_isIDSeparator(localeID[trailingIndex])) { @@ -871,30 +478,42 @@ _uloc_addLikelySubtags(const char* localeID, trailingLength = (int32_t)uprv_strlen(trailing); CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength); - - success = - createLikelySubtagsString( - lang, - langLength, - script, - scriptLength, - region, - regionLength, + { + const icu::XLikelySubtags* likelySubtags = icu::XLikelySubtags::getSingleton(*err); + if(U_FAILURE(*err)) { + goto error; + } + // We need to keep l on the stack because lsr may point into internal + // memory of l. + icu::Locale l = icu::Locale::createFromName(localeID); + if (l.isBogus()) { + goto error; + } + icu::LSR lsr = likelySubtags->makeMaximizedLsrFrom(l, true, *err); + if(U_FAILURE(*err)) { + goto error; + } + const char* language = lsr.language; + if (uprv_strcmp(language, "und") == 0) { + language = ""; + } + createTagStringWithAlternates( + language, + (int32_t)uprv_strlen(language), + lsr.script, + (int32_t)uprv_strlen(lsr.script), + lsr.region, + (int32_t)uprv_strlen(lsr.region), trailing, trailingLength, + nullptr, sink, err); - - if (!success) { - const int32_t localIDLength = (int32_t)uprv_strlen(localeID); - - /* - * If we get here, we need to return localeID. - */ - sink.Append(localeID, localIDLength); + if(U_FAILURE(*err)) { + goto error; + } } - - return success; + return true; error: @@ -913,6 +532,7 @@ static UBool _ulocimp_addLikelySubtags(const char*, icu::ByteSink&, UErrorCode*) static void _uloc_minimizeSubtags(const char* localeID, icu::ByteSink& sink, + bool favorScript, UErrorCode* err) { icu::CharString maximizedTagBuffer; @@ -925,7 +545,6 @@ _uloc_minimizeSubtags(const char* localeID, const char* trailing = ""; int32_t trailingLength = 0; int32_t trailingIndex = 0; - UBool successGetMax = false; if(U_FAILURE(*err)) { goto error; @@ -964,213 +583,38 @@ _uloc_minimizeSubtags(const char* localeID, CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength); { - icu::CharString base; - { - icu::CharStringByteSink baseSink(&base); - createTagString( - lang, - langLength, - script, - scriptLength, - region, - regionLength, - nullptr, - 0, - baseSink, - err); - } - - /** - * First, we need to first get the maximization - * from AddLikelySubtags. - **/ - { - icu::CharStringByteSink maxSink(&maximizedTagBuffer); - successGetMax = _ulocimp_addLikelySubtags(base.data(), maxSink, err); - } - } - - if(U_FAILURE(*err)) { - goto error; - } - - if (!successGetMax) { - /** - * If we got here, return the locale ID parameter unchanged. - **/ - const int32_t localeIDLength = (int32_t)uprv_strlen(localeID); - sink.Append(localeID, localeIDLength); - return; - } - - // In the following, the lang, script, region are referring to those in - // the maximizedTagBuffer, not the one in the localeID. - langLength = sizeof(lang); - scriptLength = sizeof(script); - regionLength = sizeof(region); - parseTagString( - maximizedTagBuffer.data(), - lang, - &langLength, - script, - &scriptLength, - region, - ®ionLength, - err); - if(U_FAILURE(*err)) { - goto error; - } - - /** - * Start first with just the language. - **/ - { - icu::CharString tagBuffer; - { - icu::CharStringByteSink tagSink(&tagBuffer); - createLikelySubtagsString( - lang, - langLength, - nullptr, - 0, - nullptr, - 0, - nullptr, - 0, - tagSink, - err); - } - + const icu::XLikelySubtags* likelySubtags = icu::XLikelySubtags::getSingleton(*err); if(U_FAILURE(*err)) { goto error; } - else if (!tagBuffer.isEmpty() && - uprv_strnicmp( - maximizedTagBuffer.data(), - tagBuffer.data(), - tagBuffer.length()) == 0) { - - createTagString( - lang, - langLength, - nullptr, - 0, - nullptr, - 0, - trailing, - trailingLength, - sink, - err); - return; - } - } - - /** - * Next, try the language and region. - **/ - if (regionLength > 0) { - - icu::CharString tagBuffer; - { - icu::CharStringByteSink tagSink(&tagBuffer); - createLikelySubtagsString( - lang, - langLength, - nullptr, - 0, - region, - regionLength, - nullptr, - 0, - tagSink, - err); - } - + icu::LSR lsr = likelySubtags->minimizeSubtags( + {lang, langLength}, + {script, scriptLength}, + {region, regionLength}, + favorScript, + *err); if(U_FAILURE(*err)) { goto error; } - else if (!tagBuffer.isEmpty() && - uprv_strnicmp( - maximizedTagBuffer.data(), - tagBuffer.data(), - tagBuffer.length()) == 0) { - - createTagString( - lang, - langLength, - nullptr, - 0, - region, - regionLength, - trailing, - trailingLength, - sink, - err); - return; - } - } - - /** - * Finally, try the language and script. This is our last chance, - * since trying with all three subtags would only yield the - * maximal version that we already have. - **/ - if (scriptLength > 0) { - icu::CharString tagBuffer; - { - icu::CharStringByteSink tagSink(&tagBuffer); - createLikelySubtagsString( - lang, - langLength, - script, - scriptLength, - nullptr, - 0, - nullptr, - 0, - tagSink, - err); - } - + const char* language = lsr.language; + if (uprv_strcmp(language, "und") == 0) { + language = ""; + } + createTagStringWithAlternates( + language, + (int32_t)uprv_strlen(language), + lsr.script, + (int32_t)uprv_strlen(lsr.script), + lsr.region, + (int32_t)uprv_strlen(lsr.region), + trailing, + trailingLength, + nullptr, + sink, + err); if(U_FAILURE(*err)) { goto error; } - else if (!tagBuffer.isEmpty() && - uprv_strnicmp( - maximizedTagBuffer.data(), - tagBuffer.data(), - tagBuffer.length()) == 0) { - - createTagString( - lang, - langLength, - script, - scriptLength, - nullptr, - 0, - trailing, - trailingLength, - sink, - err); - return; - } - } - - { - /** - * If we got here, return the max + trail. - **/ - createTagString( - lang, - langLength, - script, - scriptLength, - region, - regionLength, - trailing, - trailingLength, - sink, - err); return; } @@ -1181,31 +625,6 @@ error: } } -static int32_t -do_canonicalize(const char* localeID, - char* buffer, - int32_t bufferCapacity, - UErrorCode* err) -{ - int32_t canonicalizedSize = uloc_canonicalize( - localeID, - buffer, - bufferCapacity, - err); - - if (*err == U_STRING_NOT_TERMINATED_WARNING || - *err == U_BUFFER_OVERFLOW_ERROR) { - return canonicalizedSize; - } - else if (U_FAILURE(*err)) { - - return -1; - } - else { - return canonicalizedSize; - } -} - U_CAPI int32_t U_EXPORT2 uloc_addLikelySubtags(const char* localeID, char* maximizedLocaleID, @@ -1239,14 +658,13 @@ static UBool _ulocimp_addLikelySubtags(const char* localeID, icu::ByteSink& sink, UErrorCode* status) { - PreflightingLocaleIDBuffer localeBuffer; - do { - localeBuffer.requestedCapacity = do_canonicalize(localeID, localeBuffer.getBuffer(), - localeBuffer.getCapacity(), status); - } while (localeBuffer.needToTryAgain(status)); - + icu::CharString localeBuffer; + { + icu::CharStringByteSink localeSink(&localeBuffer); + ulocimp_canonicalize(localeID, localeSink, status); + } if (U_SUCCESS(*status)) { - return _uloc_addLikelySubtags(localeBuffer.getBuffer(), sink, status); + return _uloc_addLikelySubtags(localeBuffer.data(), sink, status); } else { return false; } @@ -1271,7 +689,7 @@ uloc_minimizeSubtags(const char* localeID, icu::CheckedArrayByteSink sink( minimizedLocaleID, minimizedLocaleIDCapacity); - ulocimp_minimizeSubtags(localeID, sink, status); + ulocimp_minimizeSubtags(localeID, sink, false, status); int32_t reslen = sink.NumberOfBytesAppended(); if (U_FAILURE(*status)) { @@ -1291,14 +709,14 @@ uloc_minimizeSubtags(const char* localeID, U_CAPI void U_EXPORT2 ulocimp_minimizeSubtags(const char* localeID, icu::ByteSink& sink, + bool favorScript, UErrorCode* status) { - PreflightingLocaleIDBuffer localeBuffer; - do { - localeBuffer.requestedCapacity = do_canonicalize(localeID, localeBuffer.getBuffer(), - localeBuffer.getCapacity(), status); - } while (localeBuffer.needToTryAgain(status)); - - _uloc_minimizeSubtags(localeBuffer.getBuffer(), sink, status); + icu::CharString localeBuffer; + { + icu::CharStringByteSink localeSink(&localeBuffer); + ulocimp_canonicalize(localeID, localeSink, status); + } + _uloc_minimizeSubtags(localeBuffer.data(), sink, favorScript, status); } // Pairs of (language subtag, + or -) for finding out fast if common languages @@ -1374,16 +792,26 @@ ulocimp_getRegionForSupplementalData(const char *localeID, UBool inferRegion, UErrorCode rgStatus = U_ZERO_ERROR; // First check for rg keyword value - int32_t rgLen = uloc_getKeywordValue(localeID, "rg", rgBuf, ULOC_RG_BUFLEN, &rgStatus); - if (U_FAILURE(rgStatus) || rgLen != 6) { + icu::CharString rg; + { + icu::CharStringByteSink sink(&rg); + ulocimp_getKeywordValue(localeID, "rg", sink, &rgStatus); + } + int32_t rgLen = rg.length(); + if (U_FAILURE(rgStatus) || rgLen < 3 || rgLen > 7) { rgLen = 0; } else { - // rgBuf guaranteed to be zero terminated here, with text len 6 - char *rgPtr = rgBuf; - for (; *rgPtr!= 0; rgPtr++) { - *rgPtr = uprv_toupper(*rgPtr); + // chop off the subdivision code (which will generally be "zzzz" anyway) + const char* const data = rg.data(); + if (uprv_isASCIILetter(data[0])) { + rgLen = 2; + rgBuf[0] = uprv_toupper(data[0]); + rgBuf[1] = uprv_toupper(data[1]); + } else { + // assume three-digit region code + rgLen = 3; + uprv_memcpy(rgBuf, data, rgLen); } - rgLen = (uprv_strcmp(rgBuf+2, "ZZZZ") == 0)? 2: 0; } if (rgLen == 0) { diff --git a/thirdparty/icu4c/common/loclikelysubtags.cpp b/thirdparty/icu4c/common/loclikelysubtags.cpp index e913c66a35..c2a7011b50 100644 --- a/thirdparty/icu4c/common/loclikelysubtags.cpp +++ b/thirdparty/icu4c/common/loclikelysubtags.cpp @@ -11,6 +11,7 @@ #include "unicode/locid.h" #include "unicode/uobject.h" #include "unicode/ures.h" +#include "unicode/uscript.h" #include "charstr.h" #include "cstring.h" #include "loclikelysubtags.h" @@ -23,6 +24,7 @@ #include "uniquecharstr.h" #include "uresdata.h" #include "uresimp.h" +#include "uvector.h" U_NAMESPACE_BEGIN @@ -81,11 +83,18 @@ struct XLikelySubtagsData { // Read all strings in the resource bundle and convert them to invariant char *. LocalMemory<int32_t> languageIndexes, regionIndexes, lsrSubtagIndexes; int32_t languagesLength = 0, regionsLength = 0, lsrSubtagsLength = 0; + ResourceArray m49Array; + if (likelyTable.findValue("m49", value)) { + m49Array = value.getArray(errorCode); + } else { + errorCode = U_MISSING_RESOURCE_ERROR; + return; + } if (!readStrings(likelyTable, "languageAliases", value, languageIndexes, languagesLength, errorCode) || !readStrings(likelyTable, "regionAliases", value, regionIndexes, regionsLength, errorCode) || - !readStrings(likelyTable, "lsrs", value, + !readLSREncodedStrings(likelyTable, "lsrnum", value, m49Array, lsrSubtagIndexes,lsrSubtagsLength, errorCode)) { return; } @@ -136,7 +145,7 @@ struct XLikelySubtagsData { if (!readStrings(matchTable, "partitions", value, partitionIndexes, partitionsLength, errorCode) || - !readStrings(matchTable, "paradigms", value, + !readLSREncodedStrings(matchTable, "paradigmnum", value, m49Array, paradigmSubtagIndexes, paradigmSubtagsLength, errorCode)) { return; } @@ -233,10 +242,96 @@ private: return false; } for (int i = 0; i < length; ++i) { - stringArray.getValue(i, value); // returns true because i < length - rawIndexes[i] = strings.add(value.getUnicodeString(errorCode), errorCode); + if (stringArray.getValue(i, value)) { // returns true because i < length + int32_t strLength = 0; + rawIndexes[i] = strings.add(value.getString(strLength, errorCode), errorCode); + if (U_FAILURE(errorCode)) { return false; } + } + } + } + return true; + } + UnicodeString toLanguage(int encoded) { + if (encoded == 0) { + return UNICODE_STRING_SIMPLE(""); + } + if (encoded == 1) { + return UNICODE_STRING_SIMPLE("skip"); + } + encoded &= 0x00ffffff; + encoded %= 27*27*27; + char lang[3]; + lang[0] = 'a' + ((encoded % 27) - 1); + lang[1] = 'a' + (((encoded / 27 ) % 27) - 1); + if (encoded / (27 * 27) == 0) { + return UnicodeString(lang, 2, US_INV); + } + lang[2] = 'a' + ((encoded / (27 * 27)) - 1); + return UnicodeString(lang, 3, US_INV); + } + UnicodeString toScript(int encoded) { + if (encoded == 0) { + return UNICODE_STRING_SIMPLE(""); + } + if (encoded == 1) { + return UNICODE_STRING_SIMPLE("script"); + } + encoded = (encoded >> 24) & 0x000000ff; + const char* script = uscript_getShortName(static_cast<UScriptCode>(encoded)); + if (script == nullptr) { + return UNICODE_STRING_SIMPLE(""); + } + U_ASSERT(uprv_strlen(script) == 4); + return UnicodeString(script, 4, US_INV); + } + UnicodeString m49IndexToCode(const ResourceArray &m49Array, ResourceValue &value, int index, UErrorCode &errorCode) { + if (U_FAILURE(errorCode)) { + return UNICODE_STRING_SIMPLE(""); + } + if (m49Array.getValue(index, value)) { + return value.getUnicodeString(errorCode); + } + // "m49" does not include the index. + errorCode = U_MISSING_RESOURCE_ERROR; + return UNICODE_STRING_SIMPLE(""); + } + + UnicodeString toRegion(const ResourceArray& m49Array, ResourceValue &value, int encoded, UErrorCode &errorCode) { + if (encoded == 0 || encoded == 1) { + return UNICODE_STRING_SIMPLE(""); + } + encoded &= 0x00ffffff; + encoded /= 27 * 27 * 27; + encoded %= 27 * 27; + if (encoded < 27) { + // Selected M49 code index, find the code from "m49" resource. + return m49IndexToCode(m49Array, value, encoded, errorCode); + } + char region[2]; + region[0] = 'A' + ((encoded % 27) - 1); + region[1] = 'A' + (((encoded / 27) % 27) - 1); + return UnicodeString(region, 2, US_INV); + } + + bool readLSREncodedStrings(const ResourceTable &table, const char* key, ResourceValue &value, const ResourceArray& m49Array, + LocalMemory<int32_t> &indexes, int32_t &length, UErrorCode &errorCode) { + if (table.findValue(key, value)) { + const int32_t* vectors = value.getIntVector(length, errorCode); + if (U_FAILURE(errorCode)) { return false; } + if (length == 0) { return true; } + int32_t *rawIndexes = indexes.allocateInsteadAndCopy(length * 3); + if (rawIndexes == nullptr) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + return false; + } + for (int i = 0; i < length; ++i) { + rawIndexes[i*3] = strings.addByValue(toLanguage(vectors[i]), errorCode); + rawIndexes[i*3+1] = strings.addByValue(toScript(vectors[i]), errorCode); + rawIndexes[i*3+2] = strings.addByValue( + toRegion(m49Array, value, vectors[i], errorCode), errorCode); if (U_FAILURE(errorCode)) { return false; } } + length *= 3; } return true; } @@ -245,15 +340,52 @@ private: namespace { XLikelySubtags *gLikelySubtags = nullptr; +UVector *gMacroregions = nullptr; UInitOnce gInitOnce {}; UBool U_CALLCONV cleanup() { delete gLikelySubtags; gLikelySubtags = nullptr; + delete gMacroregions; + gMacroregions = nullptr; gInitOnce.reset(); return true; } +static const char16_t RANGE_MARKER = 0x7E; /* '~' */ +UVector* loadMacroregions(UErrorCode &status) { + LocalPointer<UVector> newMacroRegions(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status); + + LocalUResourceBundlePointer supplementalData(ures_openDirect(nullptr,"supplementalData",&status)); + LocalUResourceBundlePointer idValidity(ures_getByKey(supplementalData.getAlias(),"idValidity",nullptr,&status)); + LocalUResourceBundlePointer regionList(ures_getByKey(idValidity.getAlias(),"region",nullptr,&status)); + LocalUResourceBundlePointer regionMacro(ures_getByKey(regionList.getAlias(),"macroregion",nullptr,&status)); + + if (U_FAILURE(status)) { + return nullptr; + } + + while (U_SUCCESS(status) && ures_hasNext(regionMacro.getAlias())) { + UnicodeString regionName = ures_getNextUnicodeString(regionMacro.getAlias(),nullptr,&status); + int32_t rangeMarkerLocation = regionName.indexOf(RANGE_MARKER); + char16_t buf[6]; + regionName.extract(buf,6,status); + if ( rangeMarkerLocation > 0 ) { + char16_t endRange = regionName.charAt(rangeMarkerLocation+1); + buf[rangeMarkerLocation] = 0; + while ( buf[rangeMarkerLocation-1] <= endRange && U_SUCCESS(status)) { + LocalPointer<UnicodeString> newRegion(new UnicodeString(buf), status); + newMacroRegions->adoptElement(newRegion.orphan(),status); + buf[rangeMarkerLocation-1]++; + } + } else { + LocalPointer<UnicodeString> newRegion(new UnicodeString(regionName), status); + newMacroRegions->adoptElement(newRegion.orphan(),status); + } + } + return newMacroRegions.orphan(); +} + } // namespace void U_CALLCONV XLikelySubtags::initLikelySubtags(UErrorCode &errorCode) { @@ -263,10 +395,14 @@ void U_CALLCONV XLikelySubtags::initLikelySubtags(UErrorCode &errorCode) { data.load(errorCode); if (U_FAILURE(errorCode)) { return; } gLikelySubtags = new XLikelySubtags(data); - if (gLikelySubtags == nullptr) { + gMacroregions = loadMacroregions(errorCode); + if (U_FAILURE(errorCode) || gLikelySubtags == nullptr || gMacroregions == nullptr) { + delete gLikelySubtags; + delete gMacroregions; errorCode = U_MEMORY_ALLOCATION_ERROR; return; } + ucln_common_registerCleanup(UCLN_COMMON_LIKELY_SUBTAGS, cleanup); } @@ -317,15 +453,32 @@ XLikelySubtags::~XLikelySubtags() { delete[] lsrs; } -LSR XLikelySubtags::makeMaximizedLsrFrom(const Locale &locale, UErrorCode &errorCode) const { +LSR XLikelySubtags::makeMaximizedLsrFrom(const Locale &locale, + bool returnInputIfUnmatch, + UErrorCode &errorCode) const { + if (locale.isBogus()) { + errorCode = U_ILLEGAL_ARGUMENT_ERROR; + return LSR("", "", "", LSR::EXPLICIT_LSR); + } const char *name = locale.getName(); if (uprv_isAtSign(name[0]) && name[1] == 'x' && name[2] == '=') { // name.startsWith("@x=") // Private use language tag x-subtag-subtag... which CLDR changes to // und-x-subtag-subtag... return LSR(name, "", "", LSR::EXPLICIT_LSR); } - return makeMaximizedLsr(locale.getLanguage(), locale.getScript(), locale.getCountry(), - locale.getVariant(), errorCode); + LSR max = makeMaximizedLsr(locale.getLanguage(), locale.getScript(), locale.getCountry(), + locale.getVariant(), returnInputIfUnmatch, errorCode); + + if (uprv_strlen(max.language) == 0 && + uprv_strlen(max.script) == 0 && + uprv_strlen(max.region) == 0) { + // No match. ICU API mandate us to + // If the provided ULocale instance is already in the maximal form, or + // there is no data available available for maximization, it will be + // returned. + return LSR(locale.getLanguage(), locale.getScript(), locale.getCountry(), LSR::EXPLICIT_LSR, errorCode); + } + return max; } namespace { @@ -338,7 +491,9 @@ const char *getCanonical(const CharStringMap &aliases, const char *alias) { } // namespace LSR XLikelySubtags::makeMaximizedLsr(const char *language, const char *script, const char *region, - const char *variant, UErrorCode &errorCode) const { + const char *variant, + bool returnInputIfUnmatch, + UErrorCode &errorCode) const { // Handle pseudolocales like en-XA, ar-XB, fr-PSCRACK. // They should match only themselves, // not other locales with what looks like the same language and script subtags. @@ -378,64 +533,91 @@ LSR XLikelySubtags::makeMaximizedLsr(const char *language, const char *script, c language = getCanonical(languageAliases, language); // (We have no script mappings.) region = getCanonical(regionAliases, region); - return maximize(language, script, region); + return maximize(language, script, region, returnInputIfUnmatch, errorCode); } -LSR XLikelySubtags::maximize(const char *language, const char *script, const char *region) const { - if (uprv_strcmp(language, "und") == 0) { +LSR XLikelySubtags::maximize(const char *language, const char *script, const char *region, + bool returnInputIfUnmatch, + UErrorCode &errorCode) const { + return maximize({language, (int32_t)uprv_strlen(language)}, + {script, (int32_t)uprv_strlen(script)}, + {region, (int32_t)uprv_strlen(region)}, + returnInputIfUnmatch, + errorCode); +} + +bool XLikelySubtags::isMacroregion(StringPiece& region, UErrorCode& errorCode) const { + // In Java, we use Region class. In C++, since Region is under i18n, + // we read the same data used by Region into gMacroregions avoid dependency + // from common to i18n/region.cpp + if (U_FAILURE(errorCode)) { return false; } + umtx_initOnce(gInitOnce, &XLikelySubtags::initLikelySubtags, errorCode); + if (U_FAILURE(errorCode)) { return false; } + UnicodeString str(UnicodeString::fromUTF8(region)); + return gMacroregions->contains((void *)&str); +} + +LSR XLikelySubtags::maximize(StringPiece language, StringPiece script, StringPiece region, + bool returnInputIfUnmatch, + UErrorCode &errorCode) const { + if (U_FAILURE(errorCode)) { + return LSR(language, script, region, LSR::EXPLICIT_LSR, errorCode); + } + if (language.compare("und") == 0) { language = ""; } - if (uprv_strcmp(script, "Zzzz") == 0) { + if (script.compare("Zzzz") == 0) { script = ""; } - if (uprv_strcmp(region, "ZZ") == 0) { + if (region.compare("ZZ") == 0) { region = ""; } - if (*script != 0 && *region != 0 && *language != 0) { - return LSR(language, script, region, LSR::EXPLICIT_LSR); // already maximized + if (!script.empty() && !region.empty() && !language.empty()) { + return LSR(language, script, region, LSR::EXPLICIT_LSR, errorCode); // already maximized } + bool retainLanguage = false; + bool retainScript = false; + bool retainRegion = false; - uint32_t retainOldMask = 0; BytesTrie iter(trie); uint64_t state; int32_t value; // Small optimization: Array lookup for first language letter. int32_t c0; - if (0 <= (c0 = uprv_lowerOrdinal(language[0])) && c0 <= 25 && - language[1] != 0 && // language.length() >= 2 + if (0 <= (c0 = uprv_lowerOrdinal(language.data()[0])) && c0 <= 25 && + language.length() >= 2 && (state = trieFirstLetterStates[c0]) != 0) { value = trieNext(iter.resetToState64(state), language, 1); } else { value = trieNext(iter, language, 0); } + bool matchLanguage = (value >= 0); + bool matchScript = false; if (value >= 0) { - if (*language != 0) { - retainOldMask |= 4; - } + retainLanguage = !language.empty(); state = iter.getState64(); } else { - retainOldMask |= 4; + retainLanguage = true; iter.resetToState64(trieUndState); // "und" ("*") state = 0; } + if (value >= 0 && !script.empty()) { + matchScript = true; + } if (value > 0) { // Intermediate or final value from just language. if (value == SKIP_SCRIPT) { value = 0; } - if (*script != 0) { - retainOldMask |= 2; - } + retainScript = !script.empty(); } else { value = trieNext(iter, script, 0); if (value >= 0) { - if (*script != 0) { - retainOldMask |= 2; - } + retainScript = !script.empty(); state = iter.getState64(); } else { - retainOldMask |= 2; + retainScript = true; if (state == 0) { iter.resetToState64(trieUndZzzzState); // "und-Zzzz" ("**") } else { @@ -447,19 +629,19 @@ LSR XLikelySubtags::maximize(const char *language, const char *script, const cha } } + bool matchRegion = false; if (value > 0) { // Final value from just language or language+script. - if (*region != 0) { - retainOldMask |= 1; - } + retainRegion = !region.empty(); } else { value = trieNext(iter, region, 0); if (value >= 0) { - if (*region != 0) { - retainOldMask |= 1; + if (!region.empty() && !isMacroregion(region, errorCode)) { + retainRegion = true; + matchRegion = true; } } else { - retainOldMask |= 1; + retainRegion = true; if (state == 0) { value = defaultLsrIndex; } else { @@ -470,28 +652,33 @@ LSR XLikelySubtags::maximize(const char *language, const char *script, const cha } } U_ASSERT(value < lsrsLength); - const LSR &result = lsrs[value]; + const LSR &matched = lsrs[value]; - if (*language == 0) { - language = "und"; + if (returnInputIfUnmatch && + (!(matchLanguage || matchScript || (matchRegion && language.empty())))) { + return LSR("", "", "", LSR::EXPLICIT_LSR, errorCode); // no matching. + } + if (language.empty()) { + language = StringPiece("und"); } - if (retainOldMask == 0) { + if (!(retainLanguage || retainScript || retainRegion)) { // Quickly return a copy of the lookup-result LSR // without new allocation of the subtags. - return LSR(result.language, result.script, result.region, result.flags); + return LSR(matched.language, matched.script, matched.region, matched.flags); } - if ((retainOldMask & 4) == 0) { - language = result.language; + if (!retainLanguage) { + language = matched.language; } - if ((retainOldMask & 2) == 0) { - script = result.script; + if (!retainScript) { + script = matched.script; } - if ((retainOldMask & 1) == 0) { - region = result.region; + if (!retainRegion) { + region = matched.region; } + int32_t retainMask = (retainLanguage ? 4 : 0) + (retainScript ? 2 : 0) + (retainRegion ? 1 : 0); // retainOldMask flags = LSR explicit-subtag flags - return LSR(language, script, region, retainOldMask); + return LSR(language, script, region, retainMask, errorCode); } int32_t XLikelySubtags::compareLikely(const LSR &lsr, const LSR &other, int32_t likelyInfo) const { @@ -627,57 +814,97 @@ int32_t XLikelySubtags::trieNext(BytesTrie &iter, const char *s, int32_t i) { default: return -1; } } +int32_t XLikelySubtags::trieNext(BytesTrie &iter, StringPiece s, int32_t i) { + UStringTrieResult result; + uint8_t c; + if (s.length() == i) { + result = iter.next(u'*'); + } else { + c = s.data()[i]; + for (;;) { + c = uprv_invCharToAscii(c); + // EBCDIC: If s[i] is not an invariant character, + // then c is now 0 and will simply not match anything, which is harmless. + if (i+1 != s.length()) { + if (!USTRINGTRIE_HAS_NEXT(iter.next(c))) { + return -1; + } + c = s.data()[++i]; + } else { + // last character of this subtag + result = iter.next(c | 0x80); + break; + } + } + } + switch (result) { + case USTRINGTRIE_NO_MATCH: return -1; + case USTRINGTRIE_NO_VALUE: return 0; + case USTRINGTRIE_INTERMEDIATE_VALUE: + U_ASSERT(iter.getValue() == SKIP_SCRIPT); + return SKIP_SCRIPT; + case USTRINGTRIE_FINAL_VALUE: return iter.getValue(); + default: return -1; + } +} -// TODO(ICU-20777): Switch Locale/uloc_ likely-subtags API from the old code -// in loclikely.cpp to this new code, including activating this -// minimizeSubtags() function. The LocaleMatcher does not minimize. -#if 0 -LSR XLikelySubtags::minimizeSubtags(const char *languageIn, const char *scriptIn, - const char *regionIn, ULocale.Minimize fieldToFavor, +LSR XLikelySubtags::minimizeSubtags(StringPiece language, StringPiece script, + StringPiece region, + bool favorScript, UErrorCode &errorCode) const { - LSR result = maximize(languageIn, scriptIn, regionIn); - - // We could try just a series of checks, like: - // LSR result2 = addLikelySubtags(languageIn, "", ""); - // if result.equals(result2) return result2; - // However, we can optimize 2 of the cases: - // (languageIn, "", "") - // (languageIn, "", regionIn) - - // value00 = lookup(result.language, "", "") - BytesTrie iter = new BytesTrie(trie); - int value = trieNext(iter, result.language, 0); - U_ASSERT(value >= 0); - if (value == 0) { - value = trieNext(iter, "", 0); - U_ASSERT(value >= 0); - if (value == 0) { - value = trieNext(iter, "", 0); - } - } - U_ASSERT(value > 0); - LSR value00 = lsrs[value]; - boolean favorRegionOk = false; - if (result.script.equals(value00.script)) { //script is default - if (result.region.equals(value00.region)) { - return new LSR(result.language, "", "", LSR.DONT_CARE_FLAGS); - } else if (fieldToFavor == ULocale.Minimize.FAVOR_REGION) { - return new LSR(result.language, "", result.region, LSR.DONT_CARE_FLAGS); - } else { - favorRegionOk = true; + LSR max = maximize(language, script, region, true, errorCode); + if (U_FAILURE(errorCode)) { + return max; + } + // If no match, return it. + if (uprv_strlen(max.language) == 0 && + uprv_strlen(max.script) == 0 && + uprv_strlen(max.region) == 0) { + // No match. ICU API mandate us to + // "If this Locale is already in the minimal form, or not valid, or + // there is no data available for minimization, the Locale will be + // unchanged." + return LSR(language, script, region, LSR::EXPLICIT_LSR, errorCode); + } + // try language + LSR test = maximize(max.language, "", "", true, errorCode); + if (U_FAILURE(errorCode)) { + return max; + } + if (test.isEquivalentTo(max)) { + return LSR(max.language, "", "", LSR::DONT_CARE_FLAGS, errorCode); + } + + if (!favorScript) { + // favor Region + // try language and region + test = maximize(max.language, "", max.region, true, errorCode); + if (U_FAILURE(errorCode)) { + return max; + } + if (test.isEquivalentTo(max)) { + return LSR(max.language, "", max.region, LSR::DONT_CARE_FLAGS, errorCode); } } - - // The last case is not as easy to optimize. - // Maybe do later, but for now use the straightforward code. - LSR result2 = maximize(languageIn, scriptIn, ""); - if (result2.equals(result)) { - return new LSR(result.language, result.script, "", LSR.DONT_CARE_FLAGS); - } else if (favorRegionOk) { - return new LSR(result.language, "", result.region, LSR.DONT_CARE_FLAGS); + // try language and script + test = maximize(max.language, max.script, "", true, errorCode); + if (U_FAILURE(errorCode)) { + return max; + } + if (test.isEquivalentTo(max)) { + return LSR(max.language, max.script, "", LSR::DONT_CARE_FLAGS, errorCode); + } + if (favorScript) { + // try language and region + test = maximize(max.language, "", max.region, true, errorCode); + if (U_FAILURE(errorCode)) { + return max; + } + if (test.isEquivalentTo(max)) { + return LSR(max.language, "", max.region, LSR::DONT_CARE_FLAGS, errorCode); + } } - return result; + return LSR(max.language, max.script, max.region, LSR::DONT_CARE_FLAGS, errorCode); } -#endif U_NAMESPACE_END diff --git a/thirdparty/icu4c/common/loclikelysubtags.h b/thirdparty/icu4c/common/loclikelysubtags.h index 14a01a5eac..ebd9c15306 100644 --- a/thirdparty/icu4c/common/loclikelysubtags.h +++ b/thirdparty/icu4c/common/loclikelysubtags.h @@ -11,6 +11,7 @@ #include "unicode/utypes.h" #include "unicode/bytestrie.h" #include "unicode/locid.h" +#include "unicode/stringpiece.h" #include "unicode/uobject.h" #include "unicode/ures.h" #include "charstrmap.h" @@ -47,7 +48,9 @@ public: static const XLikelySubtags *getSingleton(UErrorCode &errorCode); // VisibleForTesting - LSR makeMaximizedLsrFrom(const Locale &locale, UErrorCode &errorCode) const; + LSR makeMaximizedLsrFrom(const Locale &locale, + bool returnInputIfUnmatch, + UErrorCode &errorCode) const; /** * Tests whether lsr is "more likely" than other. @@ -61,13 +64,9 @@ public: */ int32_t compareLikely(const LSR &lsr, const LSR &other, int32_t likelyInfo) const; - // TODO(ICU-20777): Switch Locale/uloc_ likely-subtags API from the old code - // in loclikely.cpp to this new code, including activating this - // minimizeSubtags() function. The LocaleMatcher does not minimize. -#if 0 - LSR minimizeSubtags(const char *languageIn, const char *scriptIn, const char *regionIn, - ULocale.Minimize fieldToFavor, UErrorCode &errorCode) const; -#endif + LSR minimizeSubtags(StringPiece language, StringPiece script, StringPiece region, + bool favorScript, + UErrorCode &errorCode) const; // visible for LocaleDistance const LocaleDistanceData &getDistanceData() const { return distanceData; } @@ -80,16 +79,25 @@ private: static void initLikelySubtags(UErrorCode &errorCode); LSR makeMaximizedLsr(const char *language, const char *script, const char *region, - const char *variant, UErrorCode &errorCode) const; + const char *variant, + bool returnInputIfUnmatch, + UErrorCode &errorCode) const; /** * Raw access to addLikelySubtags. Input must be in canonical format, eg "en", not "eng" or "EN". */ - LSR maximize(const char *language, const char *script, const char *region) const; + LSR maximize(const char *language, const char *script, const char *region, + bool returnInputIfUnmatch, + UErrorCode &errorCode) const; + LSR maximize(StringPiece language, StringPiece script, StringPiece region, + bool returnInputIfUnmatch, + UErrorCode &errorCode) const; int32_t getLikelyIndex(const char *language, const char *script) const; + bool isMacroregion(StringPiece& region, UErrorCode &errorCode) const; static int32_t trieNext(BytesTrie &iter, const char *s, int32_t i); + static int32_t trieNext(BytesTrie &iter, StringPiece s, int32_t i); UResourceBundle *langInfoBundle; // We could store the strings by value, except that if there were few enough strings, diff --git a/thirdparty/icu4c/common/locmap.cpp b/thirdparty/icu4c/common/locmap.cpp index 7a0e90e8bd..e41cfd1027 100644 --- a/thirdparty/icu4c/common/locmap.cpp +++ b/thirdparty/icu4c/common/locmap.cpp @@ -1170,7 +1170,7 @@ uprv_convertToLCIDPlatform(const char* localeID, UErrorCode* status) // conversion functionality when available. #if U_PLATFORM_HAS_WIN32_API && UCONFIG_USE_WINDOWS_LCID_MAPPING_API int32_t len; - char baseName[ULOC_FULLNAME_CAPACITY] = {}; + icu::CharString baseName; const char * mylocaleID = localeID; // Check any for keywords. @@ -1189,19 +1189,23 @@ uprv_convertToLCIDPlatform(const char* localeID, UErrorCode* status) else { // If the locale ID contains keywords other than collation, just use the base name. - len = uloc_getBaseName(localeID, baseName, UPRV_LENGTHOF(baseName) - 1, status); - - if (U_SUCCESS(*status) && len > 0) { - baseName[len] = 0; - mylocaleID = baseName; + icu::CharStringByteSink sink(&baseName); + ulocimp_getBaseName(localeID, sink, status); + } + if (U_SUCCESS(*status) && !baseName.isEmpty()) + { + mylocaleID = baseName.data(); } } } - char asciiBCP47Tag[LOCALE_NAME_MAX_LENGTH] = {}; // this will change it from de_DE@collation=phonebook to de-DE-u-co-phonebk form - (void)uloc_toLanguageTag(mylocaleID, asciiBCP47Tag, UPRV_LENGTHOF(asciiBCP47Tag), false, status); + icu::CharString asciiBCP47Tag; + { + icu::CharStringByteSink sink(&asciiBCP47Tag); + ulocimp_toLanguageTag(mylocaleID, sink, false, status); + } if (U_SUCCESS(*status)) { diff --git a/thirdparty/icu4c/common/locresdata.cpp b/thirdparty/icu4c/common/locresdata.cpp index 7a0969dff5..c9d1cdddde 100644 --- a/thirdparty/icu4c/common/locresdata.cpp +++ b/thirdparty/icu4c/common/locresdata.cpp @@ -24,6 +24,8 @@ #include "unicode/putil.h" #include "unicode/uloc.h" #include "unicode/ures.h" +#include "bytesinkutil.h" +#include "charstr.h" #include "cstring.h" #include "ulocimp.h" #include "uresimp.h" @@ -156,16 +158,18 @@ _uloc_getOrientationHelper(const char* localeId, ULayoutType result = ULOC_LAYOUT_UNKNOWN; if (!U_FAILURE(*status)) { - int32_t length = 0; - char localeBuffer[ULOC_FULLNAME_CAPACITY]; - - uloc_canonicalize(localeId, localeBuffer, sizeof(localeBuffer), status); + icu::CharString localeBuffer; + { + icu::CharStringByteSink sink(&localeBuffer); + ulocimp_canonicalize(localeId, sink, status); + } if (!U_FAILURE(*status)) { + int32_t length = 0; const char16_t* const value = uloc_getTableStringWithFallback( nullptr, - localeBuffer, + localeBuffer.data(), "layout", nullptr, key, diff --git a/thirdparty/icu4c/common/lsr.cpp b/thirdparty/icu4c/common/lsr.cpp index 39eb46df27..bd231ecdb5 100644 --- a/thirdparty/icu4c/common/lsr.cpp +++ b/thirdparty/icu4c/common/lsr.cpp @@ -31,6 +31,26 @@ LSR::LSR(char prefix, const char *lang, const char *scr, const char *r, int32_t } } +LSR::LSR(StringPiece lang, StringPiece scr, StringPiece r, int32_t f, + UErrorCode &errorCode) : + language(nullptr), script(nullptr), region(nullptr), + regionIndex(indexForRegion(r.data())), flags(f) { + if (U_SUCCESS(errorCode)) { + CharString data; + data.append(lang, errorCode).append('\0', errorCode); + int32_t scriptOffset = data.length(); + data.append(scr, errorCode).append('\0', errorCode); + int32_t regionOffset = data.length(); + data.append(r, errorCode); + owned = data.cloneData(errorCode); + if (U_SUCCESS(errorCode)) { + language = owned; + script = owned + scriptOffset; + region = owned + regionOffset; + } + } +} + LSR::LSR(LSR &&other) noexcept : language(other.language), script(other.script), region(other.region), owned(other.owned), regionIndex(other.regionIndex), flags(other.flags), diff --git a/thirdparty/icu4c/common/lsr.h b/thirdparty/icu4c/common/lsr.h index a2f7c8bb15..313286e93d 100644 --- a/thirdparty/icu4c/common/lsr.h +++ b/thirdparty/icu4c/common/lsr.h @@ -7,6 +7,7 @@ #ifndef __LSR_H__ #define __LSR_H__ +#include "unicode/stringpiece.h" #include "unicode/utypes.h" #include "unicode/uobject.h" #include "cstring.h" @@ -45,6 +46,8 @@ struct LSR final : public UMemory { */ LSR(char prefix, const char *lang, const char *scr, const char *r, int32_t f, UErrorCode &errorCode); + LSR(StringPiece lang, StringPiece scr, StringPiece r, int32_t f, + UErrorCode &errorCode); LSR(LSR &&other) noexcept; LSR(const LSR &other) = delete; inline ~LSR() { diff --git a/thirdparty/icu4c/common/norm2_nfc_data.h b/thirdparty/icu4c/common/norm2_nfc_data.h index ebe3e6ba90..3dada06c57 100644 --- a/thirdparty/icu4c/common/norm2_nfc_data.h +++ b/thirdparty/icu4c/common/norm2_nfc_data.h @@ -10,7 +10,7 @@ #ifdef INCLUDED_FROM_NORMALIZER2_CPP static const UVersionInfo norm2_nfc_data_formatVersion={4,0,0,0}; -static const UVersionInfo norm2_nfc_data_dataVersion={0xf,0,0,0}; +static const UVersionInfo norm2_nfc_data_dataVersion={0xf,1,0,0}; static const int32_t norm2_nfc_data_indexes[Normalizer2Impl::IX_COUNT]={ 0x50,0x4cb8,0x8920,0x8a20,0x8a20,0x8a20,0x8a20,0x8a20,0xc0,0x300,0xae2,0x29e0,0x3c66,0xfc00,0x1288,0x3b9c, diff --git a/thirdparty/icu4c/common/norm2allmodes.h b/thirdparty/icu4c/common/norm2allmodes.h index 6347fba9cb..a2cfc89c1a 100644 --- a/thirdparty/icu4c/common/norm2allmodes.h +++ b/thirdparty/icu4c/common/norm2allmodes.h @@ -391,6 +391,7 @@ struct Norm2AllModes : public UMemory { static const Norm2AllModes *getNFCInstance(UErrorCode &errorCode); static const Norm2AllModes *getNFKCInstance(UErrorCode &errorCode); static const Norm2AllModes *getNFKC_CFInstance(UErrorCode &errorCode); + static const Norm2AllModes *getNFKC_SCFInstance(UErrorCode &errorCode); Normalizer2Impl *impl; ComposeNormalizer2 comp; diff --git a/thirdparty/icu4c/common/normalizer2impl.h b/thirdparty/icu4c/common/normalizer2impl.h index 2cca33d349..f5ede24fc2 100644 --- a/thirdparty/icu4c/common/normalizer2impl.h +++ b/thirdparty/icu4c/common/normalizer2impl.h @@ -789,7 +789,8 @@ unorm_getFCD16(UChar32 c); * * Normalizer2 .nrm data files provide data for the Unicode Normalization algorithms. * ICU ships with data files for standard Unicode Normalization Forms - * NFC and NFD (nfc.nrm), NFKC and NFKD (nfkc.nrm) and NFKC_Casefold (nfkc_cf.nrm). + * NFC and NFD (nfc.nrm), NFKC and NFKD (nfkc.nrm), + * NFKC_Casefold (nfkc_cf.nrm) and NFKC_Simple_Casefold (nfkc_scf.nrm). * Custom (application-specific) data can be built into additional .nrm files * with the gennorm2 build tool. * ICU ships with one such file, uts46.nrm, for the implementation of UTS #46. diff --git a/thirdparty/icu4c/common/propname_data.h b/thirdparty/icu4c/common/propname_data.h index 1e247874b6..7bdbe8ec43 100644 --- a/thirdparty/icu4c/common/propname_data.h +++ b/thirdparty/icu4c/common/propname_data.h @@ -11,101 +11,102 @@ U_NAMESPACE_BEGIN -const int32_t PropNameData::indexes[8]={0x20,0x1660,0x5294,0xacd0,0xacd0,0xacd0,0x31,0}; +const int32_t PropNameData::indexes[8]={0x20,0x1690,0x5337,0xae61,0xae61,0xae61,0x31,0}; -const int32_t PropNameData::valueMaps[1424]={ -6,0,0x48,0,0xf1,0x368,0xf1,0x37e,0xf1,0x393,0xf1,0x3a9,0xf1,0x3b4,0xf1,0x3d5, -0xf1,0x3e5,0xf1,0x3f4,0xf1,0x402,0xf1,0x426,0xf1,0x43d,0xf1,0x455,0xf1,0x46c,0xf1,0x47b, -0xf1,0x48a,0xf1,0x49b,0xf1,0x4a9,0xf1,0x4bb,0xf1,0x4d5,0xf1,0x4f0,0xf1,0x505,0xf1,0x522, -0xf1,0x533,0xf1,0x53e,0xf1,0x55d,0xf1,0x573,0xf1,0x584,0xf1,0x594,0xf1,0x5af,0xf1,0x5c8, -0xf1,0x5d9,0xf1,0x5f3,0xf1,0x606,0xf1,0x616,0xf1,0x630,0xf1,0x649,0xf1,0x660,0xf1,0x674, -0xf1,0x68a,0xf1,0x69e,0xf1,0x6b4,0xf1,0x6ce,0xf1,0x6e6,0xf1,0x702,0xf1,0x70a,0xf1,0x712, -0xf1,0x71a,0xf1,0x722,0xf1,0x72b,0xf1,0x738,0xf1,0x74b,0xf1,0x768,0xf1,0x785,0xf1,0x7a2, -0xf1,0x7c0,0xf1,0x7de,0xf1,0x802,0xf1,0x80f,0xf1,0x829,0xf1,0x83e,0xf1,0x859,0xf1,0x870, -0xf1,0x887,0xf1,0x8a9,0xf1,0x8c8,0xf1,0x8e1,0xf1,0x90e,0xf1,0x947,0xf1,0x978,0xf1,0x9a7, -0xf1,0x9d6,0xf1,0x1000,0x1019,0x9eb,0x16d,0xc0b,0x188,0x3279,0xf7,0x3298,0x2d4,0x33d6,0x2ea,0x3430, -0x2f4,0x368d,0x316,0x3fb8,0x382,0x4028,0x38c,0x42c2,0x3bb,0x4300,0x3c3,0x4e45,0x48f,0x4ec3,0x499,0x4ee8, -0x49f,0x4f02,0x4a5,0x4f23,0x4ac,0x4f3d,0xf7,0x4f62,0xf7,0x4f88,0x4b3,0x5032,0x4c9,0x50ab,0x4dc,0x515d, -0x4f7,0x5194,0x4fe,0x5374,0x512,0x57f4,0x53a,0x2000,0x2001,0x5853,0x542,0x3000,0x3001,0x58df,0,0x4000, -0x400e,0x58f1,0,0x58fa,0,0x5914,0,0x5925,0,0x5936,0,0x594c,0,0x5955,0,0x5972, -0,0x5990,0,0x59ae,0,0x59cc,0,0x59e2,0,0x59f6,0,0x5a0c,0,0x7000,0x7001,0x5a25, -0,0x844,0x12,0,1,0x12,0x20,0x862,0x4a,0,1,6,7,8,9,0xa, -0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a, -0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x54,0x5b,0x67,0x6b,0x76,0x7a, -0x81,0x82,0x84,0x85,0xc8,0xca,0xd6,0xd8,0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8, -0xe9,0xea,0xf0,0x2e,0x40,0x4c,0x5e,0x68,0x79,0x84,0x91,0x9e,0xab,0xb8,0xc5,0xd2, -0xdf,0xec,0xf9,0x106,0x113,0x120,0x12d,0x13a,0x147,0x154,0x161,0x16e,0x17b,0x188,0x195,0x1a2, -0x1af,0x1bc,0x1c9,0x1d6,0x1e3,0x1f0,0x1fd,0x20c,0x21b,0x22a,0x239,0x248,0x257,0x266,0x275,0x28f, -0x2a3,0x2b7,0x2d2,0x2e1,0x2ea,0x2fa,0x302,0x30b,0x31a,0x323,0x333,0x344,0x355,0xa03,1,0, -0x17,0x9fa,0xa0b,0xa1c,0xa30,0xa47,0xa5f,0xa71,0xa86,0xa9d,0xab2,0xac2,0xad4,0xaf1,0xb0d,0xb1f, -0xb3c,0xb58,0xb74,0xb89,0xb9e,0xbb8,0xbd3,0xbee,0xba5,1,0,0x148,0xc16,0xc23,0xc36,0xc5e, -0xc7c,0xc9a,0xcb2,0xcdd,0xd07,0xd1f,0xd32,0xd45,0xd54,0xd63,0xd72,0xd81,0xd98,0xda9,0xdbc,0xdcf, -0xddc,0xde9,0xdf8,0xe09,0xe1e,0xe2f,0xe3a,0xe43,0xe54,0xe65,0xe78,0xe8a,0xe9d,0xeb0,0xeef,0xefc, -0xf09,0xf16,0xf2b,0xf5b,0xf75,0xf96,0xfc1,0xfe4,0x1042,0x1069,0x1084,0x1093,0x10ba,0x10e2,0x1105,0x1128, -0x1152,0x116b,0x118a,0x11ad,0x11d1,0x11e4,0x11fe,0x1228,0x1240,0x1268,0x1291,0x12a4,0x12b7,0x12ca,0x12f1,0x1300, -0x1320,0x134e,0x136c,0x139a,0x13b6,0x13d1,0x13ea,0x1403,0x1424,0x1454,0x1473,0x1495,0x14c9,0x14f6,0x153b,0x155c, -0x1586,0x15a7,0x15d0,0x15e3,0x1616,0x162d,0x163c,0x164d,0x1678,0x168f,0x16c0,0x16ee,0x1731,0x173c,0x1775,0x1786, -0x1797,0x17a4,0x17b7,0x17f1,0x1815,0x1839,0x1873,0x18ab,0x18d6,0x18ee,0x191a,0x1946,0x1953,0x1962,0x197f,0x19a1, -0x19cf,0x19ef,0x1a16,0x1a3d,0x1a5c,0x1a6f,0x1a80,0x1a91,0x1ab6,0x1adb,0x1b02,0x1b36,0x1b63,0x1b81,0x1b94,0x1bad, -0x1be6,0x1bf5,0x1c15,0x1c37,0x1c59,0x1c70,0x1c87,0x1cb4,0x1ccd,0x1ce6,0x1d17,0x1d41,0x1d5c,0x1d6f,0x1d8e,0x1d97, -0x1daa,0x1dc8,0x1de6,0x1df9,0x1e10,0x1e25,0x1e5a,0x1e7e,0x1e93,0x1ea2,0x1eb5,0x1ed9,0x1ee2,0x1f06,0x1f1d,0x1f30, -0x1f3f,0x1f4a,0x1f6b,0x1f83,0x1f92,0x1fa1,0x1fb0,0x1fc7,0x1fdc,0x1ff1,0x202a,0x203d,0x2059,0x2064,0x2071,0x209f, -0x20c3,0x20e6,0x20f9,0x211b,0x212e,0x2149,0x216c,0x218f,0x21b4,0x21c5,0x21f4,0x2221,0x2238,0x2253,0x2262,0x228d, -0x22c5,0x22ff,0x232d,0x233e,0x234b,0x236f,0x237e,0x239a,0x23b4,0x23d1,0x2409,0x241e,0x244b,0x246a,0x2498,0x24b8, -0x24ec,0x24fb,0x2525,0x2548,0x2573,0x257e,0x258f,0x25aa,0x25ce,0x25db,0x25f0,0x2617,0x2642,0x2679,0x268c,0x269d, -0x26cd,0x26de,0x26ed,0x2702,0x2720,0x2733,0x2746,0x275d,0x277a,0x2785,0x278e,0x27b0,0x27c5,0x27ea,0x2801,0x282a, -0x2845,0x285a,0x2873,0x2894,0x28c9,0x28da,0x290b,0x292f,0x2940,0x2959,0x2964,0x2991,0x29b3,0x29e1,0x2a14,0x2a23, -0x2a34,0x2a51,0x2a93,0x2aba,0x2ac7,0x2adc,0x2b00,0x2b26,0x2b5f,0x2b70,0x2b94,0x2b9f,0x2bac,0x2bbb,0x2be0,0x2c0e, -0x2c2a,0x2c47,0x2c54,0x2c65,0x2c83,0x2ca6,0x2cc3,0x2cd0,0x2cf0,0x2d0d,0x2d2e,0x2d57,0x2d68,0x2d87,0x2da0,0x2db9, -0x2dca,0x2e13,0x2e24,0x2e3d,0x2e6c,0x2e99,0x2ebe,0x2f00,0x2f1c,0x2f2b,0x2f42,0x2f70,0x2f89,0x2fb2,0x2fcc,0x3007, -0x3025,0x3034,0x3054,0x306f,0x3093,0x30af,0x30cd,0x30eb,0x3102,0x3111,0x311c,0x3159,0x316c,0x3196,0x31b6,0x31e4, -0x3208,0x3230,0x3255,0x3260,0x1fa9,1,0,0x12,0x32af,0x32bf,0x32d2,0x32e2,0x32f2,0x3301,0x3311,0x3323, -0x3336,0x3348,0x3358,0x3368,0x3377,0x3386,0x3396,0x33a3,0x33b2,0x33c6,0x2067,1,0,6,0x33eb,0x33f6, -0x3403,0x3410,0x341d,0x3428,0x20ab,1,0,0x1e,0x3445,0x3454,0x3469,0x347e,0x3493,0x34a7,0x34b8,0x34cc, -0x34df,0x34f0,0x3509,0x351b,0x352c,0x3540,0x3553,0x356b,0x357d,0x3588,0x3598,0x35a6,0x35bb,0x35d0,0x35e6,0x3600, -0x3616,0x3626,0x363a,0x364e,0x365f,0x3677,0x22d6,1,0,0x68,0x369f,0x36c2,0x36cb,0x36d8,0x36e3,0x36ec, -0x36f7,0x3700,0x3719,0x371e,0x3727,0x3744,0x374d,0x375a,0x3763,0x3787,0x378e,0x3797,0x37aa,0x37b5,0x37be,0x37c9, -0x37e2,0x37eb,0x37fa,0x3805,0x380e,0x3819,0x3822,0x3829,0x3832,0x383d,0x3846,0x385f,0x3868,0x3875,0x3880,0x3891, -0x389c,0x38b1,0x38c8,0x38d1,0x38da,0x38f3,0x38fe,0x3907,0x3910,0x3927,0x3944,0x394f,0x3960,0x396b,0x3972,0x397f, -0x398c,0x39b9,0x39ce,0x39d7,0x39f2,0x3a15,0x3a36,0x3a57,0x3a7c,0x3aa3,0x3ac4,0x3ae7,0x3b08,0x3b2f,0x3b50,0x3b75, -0x3b94,0x3bb3,0x3bd2,0x3bef,0x3c10,0x3c31,0x3c54,0x3c79,0x3c98,0x3cb7,0x3cd8,0x3cff,0x3d24,0x3d43,0x3d64,0x3d87, -0x3da2,0x3dbb,0x3dd6,0x3def,0x3e0c,0x3e27,0x3e44,0x3e63,0x3e80,0x3e9d,0x3ebc,0x3ed9,0x3ef4,0x3f11,0x3f2e,0x3f61, -0x3f88,0x3f9b,0x2639,1,0,6,0x3fc9,0x3fd8,0x3fe8,0x3ff8,0x4008,0x4019,0x2697,1,0,0x2b, -0x4037,0x4043,0x4051,0x4060,0x406f,0x407f,0x4090,0x40a4,0x40b9,0x40cf,0x40e2,0x40f6,0x4106,0x410f,0x411a,0x412a, -0x4146,0x4158,0x4166,0x4175,0x4181,0x4196,0x41aa,0x41bd,0x41cb,0x41df,0x41ed,0x41f7,0x4209,0x4215,0x4223,0x4233, -0x423a,0x4241,0x4248,0x424f,0x4256,0x426c,0x428d,0x870,0x429f,0x42aa,0x42b9,0x28f0,1,0,4,0x42d3, -0x42de,0x42ea,0x42f4,0x2916,1,0,0xc8,0x430b,0x4318,0x432d,0x433a,0x4349,0x4357,0x4366,0x4375,0x4387, -0x4396,0x43a4,0x43b5,0x43c4,0x43d3,0x43e0,0x43ec,0x43fb,0x440a,0x4414,0x4421,0x442e,0x443d,0x444b,0x445a,0x4466, -0x4470,0x447c,0x448c,0x449c,0x44aa,0x44b6,0x44c7,0x44d3,0x44df,0x44ed,0x44fa,0x4506,0x4513,0xe2f,0x4520,0x452e, -0x4548,0x4551,0x455f,0x456d,0x4579,0x4588,0x4596,0x45a4,0x45b0,0x45bf,0x45cd,0x45db,0x45e8,0x45f7,0x4612,0x4621, -0x4632,0x4643,0x4656,0x4668,0x4677,0x4689,0x4698,0x46a4,0x46af,0x1f3f,0x46bc,0x46c7,0x46d2,0x46dd,0x46e8,0x4703, -0x470e,0x4719,0x4724,0x4737,0x474b,0x4756,0x4765,0x4774,0x477f,0x478a,0x4797,0x47a6,0x47b4,0x47bf,0x47da,0x47e4, -0x47f5,0x4806,0x4815,0x4826,0x4831,0x483c,0x4847,0x4852,0x485d,0x4868,0x4873,0x487d,0x4888,0x4898,0x48a3,0x48b1, -0x48be,0x48c9,0x48d8,0x48e5,0x48f2,0x4901,0x490e,0x491f,0x4931,0x4941,0x494c,0x495f,0x4976,0x4984,0x4991,0x499c, -0x49a9,0x49ba,0x49d6,0x49ec,0x49f7,0x4a14,0x4a24,0x4a33,0x4a3e,0x4a49,0x2059,0x4a55,0x4a60,0x4a78,0x4a88,0x4a97, -0x4aa5,0x4ab3,0x4abe,0x4ac9,0x4add,0x4af4,0x4b0c,0x4b1c,0x4b2c,0x4b3c,0x4b4e,0x4b59,0x4b64,0x4b6e,0x4b7a,0x4b88, -0x4b9b,0x4ba7,0x4bb4,0x4bbf,0x4bdb,0x4be8,0x4bf6,0x4c0f,0x2959,0x4c1e,0x277a,0x4c2b,0x4c39,0x4c4b,0x4c59,0x4c65, -0x4c75,0x2b94,0x4c83,0x4c8f,0x4c9a,0x4ca5,0x4cb0,0x4cc4,0x4cd2,0x4ce9,0x4cf5,0x4d09,0x4d17,0x4d29,0x4d3f,0x4d4d, -0x4d5f,0x4d6d,0x4d8a,0x4d9c,0x4da9,0x4dba,0x4dcc,0x4de6,0x4df3,0x4e06,0x4e17,0x3111,0x4e24,0x3255,0x4e33,0x3370, -1,0,6,0x4e5f,0x4e72,0x4e82,0x4e90,0x4ea1,0x4eb1,0x33cc,0x12,0,1,0x4edb,0x4ee1,0x33d9, -0x12,0,1,0x4edb,0x4ee1,0x33e6,1,0,3,0x4edb,0x4ee1,0x4f1a,0x33fc,1,0,3, -0x4edb,0x4ee1,0x4f1a,0x3412,1,0,0x12,0x4fa4,0x4fae,0x4fba,0x4fc1,0x4fcc,0x4fd1,0x4fd8,0x4fdf,0x4fe8, -0x4fed,0x4ff2,0x5002,0x870,0x429f,0x500e,0x42aa,0x501e,0x42b9,0x34bb,1,0,0xf,0x4fa4,0x5045,0x504f, -0x5059,0x5064,0x4175,0x506e,0x507a,0x5082,0x5089,0x5093,0x4fba,0x4fc1,0x4fd1,0x509d,0x3542,1,0,0x17, -0x4fa4,0x50ba,0x5059,0x50c6,0x50d3,0x50e1,0x4175,0x50ec,0x4fba,0x50fd,0x4fd1,0x510c,0x511a,0x870,0x428d,0x5126, -0x5137,0x429f,0x500e,0x42aa,0x501e,0x42b9,0x5148,0x365f,1,0,3,0x517b,0x5183,0x518b,0x3678,1, -0,0x10,0x51b4,0x51bb,0x51ca,0x51eb,0x520e,0x5219,0x5238,0x524f,0x525c,0x5265,0x5284,0x52b7,0x52d2,0x5301, -0x531e,0x5343,0x3711,1,0,0x24,0x5392,0x539f,0x53b2,0x53bf,0x53ec,0x5411,0x5426,0x5445,0x5466,0x5493, -0x54cc,0x54ef,0x5512,0x553f,0x5574,0x559b,0x55c4,0x55fb,0x562a,0x564b,0x5670,0x567f,0x56a2,0x56b9,0x56c6,0x56d5, -0x56f2,0x570b,0x572e,0x5753,0x576c,0x5781,0x5790,0x57a1,0x57ae,0x57cf,0x38e1,1,0,4,0x580d,0x5818, -0x5830,0x5848,0x391d,0x36,1,2,4,8,0xe,0x10,0x20,0x3e,0x40,0x80,0x100,0x1c0, -0x200,0x400,0x800,0xe00,0x1000,0x2000,0x4000,0x7000,0x8000,0x10000,0x20000,0x40000,0x78001,0x80000,0x100000,0x200000, -0x400000,0x800000,0x1000000,0x2000000,0x4000000,0x8000000,0xf000000,0x10000000,0x20000000,0x30f80000,0x3445,0x3454,0x3469,0x347e,0x5881,0x3493, -0x34a7,0x5877,0x34b8,0x34cc,0x34df,0x5892,0x34f0,0x3509,0x351b,0x58a9,0x352c,0x3540,0x3553,0x58d2,0x356b,0x357d, -0x3588,0x3598,0x586e,0x35a6,0x35bb,0x35d0,0x35e6,0x3600,0x3616,0x3626,0x363a,0x364e,0x58c8,0x365f,0x3677,0x58b3 +const int32_t PropNameData::valueMaps[1436]={ +6,0,0x4b,0,0xf7,0x368,0xf7,0x37e,0xf7,0x393,0xf7,0x3a9,0xf7,0x3b4,0xf7,0x3d5, +0xf7,0x3e5,0xf7,0x3f4,0xf7,0x402,0xf7,0x426,0xf7,0x43d,0xf7,0x455,0xf7,0x46c,0xf7,0x47b, +0xf7,0x48a,0xf7,0x49b,0xf7,0x4a9,0xf7,0x4bb,0xf7,0x4d5,0xf7,0x4f0,0xf7,0x505,0xf7,0x522, +0xf7,0x533,0xf7,0x53e,0xf7,0x55d,0xf7,0x573,0xf7,0x584,0xf7,0x594,0xf7,0x5af,0xf7,0x5c8, +0xf7,0x5d9,0xf7,0x5f3,0xf7,0x606,0xf7,0x616,0xf7,0x630,0xf7,0x649,0xf7,0x660,0xf7,0x674, +0xf7,0x68a,0xf7,0x69e,0xf7,0x6b4,0xf7,0x6ce,0xf7,0x6e6,0xf7,0x702,0xf7,0x70a,0xf7,0x712, +0xf7,0x71a,0xf7,0x722,0xf7,0x72b,0xf7,0x738,0xf7,0x74b,0xf7,0x768,0xf7,0x785,0xf7,0x7a2, +0xf7,0x7c0,0xf7,0x7de,0xf7,0x802,0xf7,0x80f,0xf7,0x829,0xf7,0x83e,0xf7,0x859,0xf7,0x870, +0xf7,0x887,0xf7,0x8a9,0xf7,0x8c8,0xf7,0x8e1,0xf7,0x90e,0xf7,0x947,0xf7,0x978,0xf7,0x9a7, +0xf7,0x9d6,0xf7,0x9eb,0xf7,0xa04,0xf7,0xa2f,0xf7,0x1000,0x1019,0xa60,0x173,0xc80,0x18e,0x331c, +0xfd,0x333b,0x2db,0x3479,0x2f1,0x34d3,0x2fb,0x3730,0x31d,0x405b,0x389,0x40cb,0x393,0x43b0,0x3c7,0x43ee, +0x3cf,0x4f33,0x49b,0x4fb1,0x4a5,0x4fd6,0x4ab,0x4ff0,0x4b1,0x5011,0x4b8,0x502b,0xfd,0x5050,0xfd,0x5076, +0x4bf,0x5120,0x4d5,0x5199,0x4e8,0x524b,0x503,0x5282,0x50a,0x5462,0x51e,0x58e2,0x546,0x2000,0x2001,0x5941, +0x54e,0x3000,0x3001,0x59cd,0,0x4000,0x400e,0x59df,0,0x59e8,0,0x5a02,0,0x5a13,0,0x5a24, +0,0x5a3a,0,0x5a43,0,0x5a60,0,0x5a7e,0,0x5a9c,0,0x5aba,0,0x5ad0,0,0x5ae4, +0,0x5afa,0,0x7000,0x7001,0x5b13,0,0x87a,0x12,0,1,0x12,0x20,0x898,0x4a,0, +1,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14, +0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24, +0x54,0x5b,0x67,0x6b,0x76,0x7a,0x81,0x82,0x84,0x85,0xc8,0xca,0xd6,0xd8,0xda,0xdc, +0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xe9,0xea,0xf0,0x2e,0x40,0x4c,0x5e,0x68,0x79,0x84, +0x91,0x9e,0xab,0xb8,0xc5,0xd2,0xdf,0xec,0xf9,0x106,0x113,0x120,0x12d,0x13a,0x147,0x154, +0x161,0x16e,0x17b,0x188,0x195,0x1a2,0x1af,0x1bc,0x1c9,0x1d6,0x1e3,0x1f0,0x1fd,0x20c,0x21b,0x22a, +0x239,0x248,0x257,0x266,0x275,0x28f,0x2a3,0x2b7,0x2d2,0x2e1,0x2ea,0x2fa,0x302,0x30b,0x31a,0x323, +0x333,0x344,0x355,0xa39,1,0,0x17,0xa6f,0xa80,0xa91,0xaa5,0xabc,0xad4,0xae6,0xafb,0xb12, +0xb27,0xb37,0xb49,0xb66,0xb82,0xb94,0xbb1,0xbcd,0xbe9,0xbfe,0xc13,0xc2d,0xc48,0xc63,0xbdb,1, +0,0x149,0xc8b,0xc98,0xcab,0xcd3,0xcf1,0xd0f,0xd27,0xd52,0xd7c,0xd94,0xda7,0xdba,0xdc9,0xdd8, +0xde7,0xdf6,0xe0d,0xe1e,0xe31,0xe44,0xe51,0xe5e,0xe6d,0xe7e,0xe93,0xea4,0xeaf,0xeb8,0xec9,0xeda, +0xeed,0xeff,0xf12,0xf25,0xf64,0xf71,0xf7e,0xf8b,0xfa0,0xfd0,0xfea,0x100b,0x1036,0x1059,0x10b7,0x10de, +0x10f9,0x1108,0x112f,0x1157,0x117a,0x119d,0x11c7,0x11e0,0x11ff,0x1222,0x1246,0x1259,0x1273,0x129d,0x12b5,0x12dd, +0x1306,0x1319,0x132c,0x133f,0x1366,0x1375,0x1395,0x13c3,0x13e1,0x140f,0x142b,0x1446,0x145f,0x1478,0x1499,0x14c9, +0x14e8,0x150a,0x153e,0x156b,0x15b0,0x15d1,0x15fb,0x161c,0x1645,0x1658,0x168b,0x16a2,0x16b1,0x16c2,0x16ed,0x1704, +0x1735,0x1763,0x17a6,0x17b1,0x17ea,0x17fb,0x180c,0x1819,0x182c,0x1866,0x188a,0x18ae,0x18e8,0x1920,0x194b,0x1963, +0x198f,0x19bb,0x19c8,0x19d7,0x19f4,0x1a16,0x1a44,0x1a64,0x1a8b,0x1ab2,0x1ad1,0x1ae4,0x1af5,0x1b06,0x1b2b,0x1b50, +0x1b77,0x1bab,0x1bd8,0x1bf6,0x1c09,0x1c22,0x1c5b,0x1c6a,0x1c8a,0x1cac,0x1cce,0x1ce5,0x1cfc,0x1d29,0x1d42,0x1d5b, +0x1d8c,0x1db6,0x1dd1,0x1de4,0x1e03,0x1e0c,0x1e1f,0x1e3d,0x1e5b,0x1e6e,0x1e85,0x1e9a,0x1ecf,0x1ef3,0x1f08,0x1f17, +0x1f2a,0x1f4e,0x1f57,0x1f7b,0x1f92,0x1fa5,0x1fb4,0x1fbf,0x1fe0,0x1ff8,0x2007,0x2016,0x2025,0x203c,0x2051,0x2066, +0x209f,0x20b2,0x20ce,0x20d9,0x20e6,0x2114,0x2138,0x215b,0x216e,0x2190,0x21a3,0x21be,0x21e1,0x2204,0x2229,0x223a, +0x2269,0x2296,0x22ad,0x22c8,0x22d7,0x2302,0x233a,0x2374,0x23a2,0x23b3,0x23c0,0x23e4,0x23f3,0x240f,0x2429,0x2446, +0x247e,0x2493,0x24c0,0x24df,0x250d,0x252d,0x2561,0x2570,0x259a,0x25bd,0x25e8,0x25f3,0x2604,0x261f,0x2643,0x2650, +0x2665,0x268c,0x26b7,0x26ee,0x2701,0x2712,0x2742,0x2753,0x2762,0x2777,0x2795,0x27a8,0x27bb,0x27d2,0x27ef,0x27fa, +0x2803,0x2825,0x283a,0x285f,0x2876,0x289f,0x28ba,0x28cf,0x28e8,0x2909,0x293e,0x294f,0x2980,0x29a4,0x29b5,0x29ce, +0x29d9,0x2a06,0x2a28,0x2a56,0x2a89,0x2a98,0x2aa9,0x2ac6,0x2b08,0x2b2f,0x2b3c,0x2b51,0x2b75,0x2b9b,0x2bd4,0x2be5, +0x2c09,0x2c14,0x2c21,0x2c30,0x2c55,0x2c83,0x2c9f,0x2cbc,0x2cc9,0x2cda,0x2cf8,0x2d1b,0x2d38,0x2d45,0x2d65,0x2d82, +0x2da3,0x2dcc,0x2ddd,0x2dfc,0x2e15,0x2e2e,0x2e3f,0x2e88,0x2e99,0x2eb2,0x2ee1,0x2f0e,0x2f33,0x2f75,0x2f91,0x2fa0, +0x2fb7,0x2fe5,0x2ffe,0x3027,0x3041,0x307c,0x309a,0x30a9,0x30c9,0x30e4,0x3108,0x3124,0x3142,0x3160,0x3177,0x3186, +0x3191,0x31ce,0x31e1,0x320b,0x322b,0x3259,0x327d,0x32a5,0x32ca,0x32d5,0x32ee,0x1fe5,1,0,0x12,0x3352, +0x3362,0x3375,0x3385,0x3395,0x33a4,0x33b4,0x33c6,0x33d9,0x33eb,0x33fb,0x340b,0x341a,0x3429,0x3439,0x3446,0x3455, +0x3469,0x20a3,1,0,6,0x348e,0x3499,0x34a6,0x34b3,0x34c0,0x34cb,0x20e7,1,0,0x1e,0x34e8, +0x34f7,0x350c,0x3521,0x3536,0x354a,0x355b,0x356f,0x3582,0x3593,0x35ac,0x35be,0x35cf,0x35e3,0x35f6,0x360e,0x3620, +0x362b,0x363b,0x3649,0x365e,0x3673,0x3689,0x36a3,0x36b9,0x36c9,0x36dd,0x36f1,0x3702,0x371a,0x2312,1,0, +0x68,0x3742,0x3765,0x376e,0x377b,0x3786,0x378f,0x379a,0x37a3,0x37bc,0x37c1,0x37ca,0x37e7,0x37f0,0x37fd,0x3806, +0x382a,0x3831,0x383a,0x384d,0x3858,0x3861,0x386c,0x3885,0x388e,0x389d,0x38a8,0x38b1,0x38bc,0x38c5,0x38cc,0x38d5, +0x38e0,0x38e9,0x3902,0x390b,0x3918,0x3923,0x3934,0x393f,0x3954,0x396b,0x3974,0x397d,0x3996,0x39a1,0x39aa,0x39b3, +0x39ca,0x39e7,0x39f2,0x3a03,0x3a0e,0x3a15,0x3a22,0x3a2f,0x3a5c,0x3a71,0x3a7a,0x3a95,0x3ab8,0x3ad9,0x3afa,0x3b1f, +0x3b46,0x3b67,0x3b8a,0x3bab,0x3bd2,0x3bf3,0x3c18,0x3c37,0x3c56,0x3c75,0x3c92,0x3cb3,0x3cd4,0x3cf7,0x3d1c,0x3d3b, +0x3d5a,0x3d7b,0x3da2,0x3dc7,0x3de6,0x3e07,0x3e2a,0x3e45,0x3e5e,0x3e79,0x3e92,0x3eaf,0x3eca,0x3ee7,0x3f06,0x3f23, +0x3f40,0x3f5f,0x3f7c,0x3f97,0x3fb4,0x3fd1,0x4004,0x402b,0x403e,0x2675,1,0,6,0x406c,0x407b,0x408b, +0x409b,0x40ab,0x40bc,0x26d3,1,0,0x30,0x40da,0x40e6,0x40f4,0x4103,0x4112,0x4122,0x4133,0x4147,0x415c, +0x4172,0x4185,0x4199,0x41a9,0x41b2,0x41bd,0x41cd,0x41e9,0x41fb,0x4209,0x4218,0x4224,0x4239,0x424d,0x4260,0x426e, +0x4282,0x4290,0x429a,0x42ac,0x42b8,0x42c6,0x42d6,0x42dd,0x42e4,0x42eb,0x42f2,0x42f9,0x430f,0x4330,0x870,0x4342, +0x434d,0x435c,0x4365,0x4370,0x4383,0x4394,0x43a5,0x2963,1,0,4,0x43c1,0x43cc,0x43d8,0x43e2,0x2989, +1,0,0xc8,0x43f9,0x4406,0x441b,0x4428,0x4437,0x4445,0x4454,0x4463,0x4475,0x4484,0x4492,0x44a3,0x44b2, +0x44c1,0x44ce,0x44da,0x44e9,0x44f8,0x4502,0x450f,0x451c,0x452b,0x4539,0x4548,0x4554,0x455e,0x456a,0x457a,0x458a, +0x4598,0x45a4,0x45b5,0x45c1,0x45cd,0x45db,0x45e8,0x45f4,0x4601,0xea4,0x460e,0x461c,0x4636,0x463f,0x464d,0x465b, +0x4667,0x4676,0x4684,0x4692,0x469e,0x46ad,0x46bb,0x46c9,0x46d6,0x46e5,0x4700,0x470f,0x4720,0x4731,0x4744,0x4756, +0x4765,0x4777,0x4786,0x4792,0x479d,0x1fb4,0x47aa,0x47b5,0x47c0,0x47cb,0x47d6,0x47f1,0x47fc,0x4807,0x4812,0x4825, +0x4839,0x4844,0x4853,0x4862,0x486d,0x4878,0x4885,0x4894,0x48a2,0x48ad,0x48c8,0x48d2,0x48e3,0x48f4,0x4903,0x4914, +0x491f,0x492a,0x4935,0x4940,0x494b,0x4956,0x4961,0x496b,0x4976,0x4986,0x4991,0x499f,0x49ac,0x49b7,0x49c6,0x49d3, +0x49e0,0x49ef,0x49fc,0x4a0d,0x4a1f,0x4a2f,0x4a3a,0x4a4d,0x4a64,0x4a72,0x4a7f,0x4a8a,0x4a97,0x4aa8,0x4ac4,0x4ada, +0x4ae5,0x4b02,0x4b12,0x4b21,0x4b2c,0x4b37,0x20ce,0x4b43,0x4b4e,0x4b66,0x4b76,0x4b85,0x4b93,0x4ba1,0x4bac,0x4bb7, +0x4bcb,0x4be2,0x4bfa,0x4c0a,0x4c1a,0x4c2a,0x4c3c,0x4c47,0x4c52,0x4c5c,0x4c68,0x4c76,0x4c89,0x4c95,0x4ca2,0x4cad, +0x4cc9,0x4cd6,0x4ce4,0x4cfd,0x29ce,0x4d0c,0x27ef,0x4d19,0x4d27,0x4d39,0x4d47,0x4d53,0x4d63,0x2c09,0x4d71,0x4d7d, +0x4d88,0x4d93,0x4d9e,0x4db2,0x4dc0,0x4dd7,0x4de3,0x4df7,0x4e05,0x4e17,0x4e2d,0x4e3b,0x4e4d,0x4e5b,0x4e78,0x4e8a, +0x4e97,0x4ea8,0x4eba,0x4ed4,0x4ee1,0x4ef4,0x4f05,0x3186,0x4f12,0x32ca,0x4f21,0x33e3,1,0,6,0x4f4d, +0x4f60,0x4f70,0x4f7e,0x4f8f,0x4f9f,0x343f,0x12,0,1,0x4fc9,0x4fcf,0x344c,0x12,0,1,0x4fc9, +0x4fcf,0x3459,1,0,3,0x4fc9,0x4fcf,0x5008,0x346f,1,0,3,0x4fc9,0x4fcf,0x5008,0x3485, +1,0,0x12,0x5092,0x509c,0x50a8,0x50af,0x50ba,0x50bf,0x50c6,0x50cd,0x50d6,0x50db,0x50e0,0x50f0,0x870, +0x4342,0x50fc,0x434d,0x510c,0x435c,0x352e,1,0,0xf,0x5092,0x5133,0x513d,0x5147,0x5152,0x4218,0x515c, +0x5168,0x5170,0x5177,0x5181,0x50a8,0x50af,0x50bf,0x518b,0x35b5,1,0,0x17,0x5092,0x51a8,0x5147,0x51b4, +0x51c1,0x51cf,0x4218,0x51da,0x50a8,0x51eb,0x50bf,0x51fa,0x5208,0x870,0x4330,0x5214,0x5225,0x4342,0x50fc,0x434d, +0x510c,0x435c,0x5236,0x36d2,1,0,3,0x5269,0x5271,0x5279,0x36eb,1,0,0x10,0x52a2,0x52a9, +0x52b8,0x52d9,0x52fc,0x5307,0x5326,0x533d,0x534a,0x5353,0x5372,0x53a5,0x53c0,0x53ef,0x540c,0x5431,0x3784,1, +0,0x24,0x5480,0x548d,0x54a0,0x54ad,0x54da,0x54ff,0x5514,0x5533,0x5554,0x5581,0x55ba,0x55dd,0x5600,0x562d, +0x5662,0x5689,0x56b2,0x56e9,0x5718,0x5739,0x575e,0x576d,0x5790,0x57a7,0x57b4,0x57c3,0x57e0,0x57f9,0x581c,0x5841, +0x585a,0x586f,0x587e,0x588f,0x589c,0x58bd,0x3954,1,0,4,0x58fb,0x5906,0x591e,0x5936,0x3990,0x36, +1,2,4,8,0xe,0x10,0x20,0x3e,0x40,0x80,0x100,0x1c0,0x200,0x400,0x800,0xe00, +0x1000,0x2000,0x4000,0x7000,0x8000,0x10000,0x20000,0x40000,0x78001,0x80000,0x100000,0x200000,0x400000,0x800000,0x1000000,0x2000000, +0x4000000,0x8000000,0xf000000,0x10000000,0x20000000,0x30f80000,0x34e8,0x34f7,0x350c,0x3521,0x596f,0x3536,0x354a,0x5965,0x355b,0x356f, +0x3582,0x5980,0x3593,0x35ac,0x35be,0x5997,0x35cf,0x35e3,0x35f6,0x59c0,0x360e,0x3620,0x362b,0x363b,0x595c,0x3649, +0x365e,0x3673,0x3689,0x36a3,0x36b9,0x36c9,0x36dd,0x36f1,0x59b6,0x3702,0x371a,0x59a1 }; -const uint8_t PropNameData::bytesTries[15412]={ +const uint8_t PropNameData::bytesTries[15527]={ 0,0x15,0x6d,0xc3,0xc7,0x73,0xc2,0x12,0x76,0x7a,0x76,0x6a,0x77,0xa2,0x52,0x78, 1,0x64,0x50,0x69,0x10,0x64,1,0x63,0x30,0x73,0x62,0x13,0x74,0x61,0x72,0x74, 0x63,0x60,0x16,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x61,0x13,0x69,0x67,0x69,0x74, @@ -166,913 +167,920 @@ const uint8_t PropNameData::bytesTries[15412]={ 0x30,0x77,0x10,0x73,0x77,0x11,0x79,0x6e,0x75,0x12,0x65,0x72,0x6e,1,0x73,0x38, 0x77,0x18,0x68,0x69,0x74,0x65,0x73,0x70,0x61,0x63,0x65,0x77,0x14,0x79,0x6e,0x74, 0x61,0x78,0x75,0x10,0x6d,0x9f,1,0x6d,0x3c,0x75,0x1a,0x6f,0x74,0x61,0x74,0x69, -0x6f,0x6e,0x6d,0x61,0x72,0x6b,0x53,0x12,0x61,0x72,0x6b,0x53,0x66,0xc1,0xf8,0x69, -0xc1,0x3c,0x69,0xa2,0x6f,0x6a,0xa4,9,0x6c,4,0x62,0xc3,8,0x63,0x8c,0x65, +0x6f,0x6e,0x6d,0x61,0x72,0x6b,0x53,0x12,0x61,0x72,0x6b,0x53,0x66,0xc2,0x2e,0x69, +0xc1,0x72,0x69,0xa2,0x6f,0x6a,0xa4,0x3f,0x6c,4,0x62,0xc3,8,0x63,0x8c,0x65, 0x98,0x69,0xa2,0x56,0x6f,2,0x65,0x4b,0x67,0x4c,0x77,0x11,0x65,0x72,0x4c,0x13, 0x63,0x61,0x73,0x65,0x4c,0x16,0x6d,0x61,0x70,0x70,0x69,0x6e,0x67,0xd9,0x40,4, 0x11,0x69,0x63,0x1f,0x61,0x6c,0x6f,0x72,0x64,0x65,0x72,0x65,0x78,0x63,0x65,0x70, 0x74,0x69,0x6f,0x6e,0x4b,0xd8,0x40,4,0x11,0x63,0x63,0xc3,0x10,0x18,0x61,0x64, 0x63,0x61,0x6e,0x6f,0x6e,0x69,0x63,0x1f,0x61,0x6c,0x63,0x6f,0x6d,0x62,0x69,0x6e, 0x69,0x6e,0x67,0x63,0x6c,0x61,0x73,0x73,0xc3,0x10,0x16,0x6e,0x65,0x62,0x72,0x65, -0x61,0x6b,0xc3,8,2,0x64,0x4a,0x6e,0xa2,0x5b,0x73,1,0x63,0xd9,0x40,3, -0x6f,0x16,0x63,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0xd9,0x40,3,2,0x63,0x80,0x65, -0x90,0x73,0x40,1,0x62,0x52,0x74,0x46,1,0x61,0x40,0x72,0x1c,0x69,0x6e,0x61, -0x72,0x79,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x47,0x11,0x72,0x74,0x41,0x44, -0x1c,0x69,0x6e,0x61,0x72,0x79,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x45,0x3e, -0x16,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3f,0x10,0x6f,0x42,0x16,0x67,0x72,0x61, -0x70,0x68,0x69,0x63,0x43,2,0x64,0x2e,0x70,0x86,0x73,0x10,0x63,0xc3,0x17,0x11, -0x69,0x63,1,0x70,0x46,0x73,0x1e,0x79,0x6c,0x6c,0x61,0x62,0x69,0x63,0x63,0x61, -0x74,0x65,0x67,0x6f,0x72,0x79,0xc3,0x17,0x10,0x6f,0x1f,0x73,0x69,0x74,0x69,0x6f, -0x6e,0x61,0x6c,0x63,0x61,0x74,0x65,0x67,0x6f,0x72,0x79,0xc3,0x16,0x10,0x63,0xc3, -0x16,2,0x67,0xc3,6,0x6f,0x26,0x74,0xc3,7,0x11,0x69,0x6e,1,0x63,0x4a, -0x69,0x11,0x6e,0x67,1,0x67,0x2e,0x74,0x12,0x79,0x70,0x65,0xc3,7,0x13,0x72, -0x6f,0x75,0x70,0xc3,6,0x48,0x15,0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x49,0x66,0x86, -0x67,0xa2,0x4a,0x68,3,0x61,0x36,0x65,0x58,0x73,0x68,0x79,0x13,0x70,0x68,0x65, -0x6e,0x3d,0x1f,0x6e,0x67,0x75,0x6c,0x73,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x74, -0x79,0x70,0x65,0xc3,0xb,0x10,0x78,0x3a,0x14,0x64,0x69,0x67,0x69,0x74,0x3b,0x10, -0x74,0xc3,0xb,0x16,0x75,0x6c,0x6c,0x63,0x6f,0x6d,0x70,0x1f,0x6f,0x73,0x69,0x74, -0x69,0x6f,0x6e,0x65,0x78,0x63,0x6c,0x75,0x73,0x69,0x6f,0x6e,0x33,2,0x63,0xa2, -0x44,0x65,0xa2,0x4b,0x72,3,0x61,0x34,0x62,0x84,0x65,0x8a,0x6c,0x12,0x69,0x6e, -0x6b,0x39,0x11,0x70,0x68,0x7c,0x12,0x65,0x6d,0x65,3,0x62,0x5e,0x63,0x30,0x65, -0x48,0x6c,0x12,0x69,0x6e,0x6b,0x39,0x1a,0x6c,0x75,0x73,0x74,0x65,0x72,0x62,0x72, -0x65,0x61,0x6b,0xc3,0x12,0x14,0x78,0x74,0x65,0x6e,0x64,0x37,0x12,0x61,0x73,0x65, -0x35,0x11,0x78,0x74,0x37,0xc2,5,1,0x62,0xc3,0x12,0x6d,0xd9,0x20,0,0x1c, -0x6e,0x65,0x72,0x61,0x6c,0x63,0x61,0x74,0x65,0x67,0x6f,0x72,0x79,0xc2,5,0x13, -0x6d,0x61,0x73,0x6b,0xd9,0x20,0,0x61,0xa2,0xa2,0x62,0xa2,0xd0,0x63,0xa4,0x4f, -0x64,0xa6,0x1c,0x65,5,0x6d,0x75,0x6d,0x6e,0x70,0xa2,0x6b,0x78,0x10,0x74,0x30, -1,0x65,0x2c,0x70,0x12,0x69,0x63,0x74,0xa1,0x12,0x6e,0x64,0x65,1,0x64,0x24, -0x72,0x31,0x1b,0x70,0x69,0x63,0x74,0x6f,0x67,0x72,0x61,0x70,0x68,0x69,0x63,0xa1, -0x10,0x6f,1,0x64,0x97,0x6a,0x10,0x69,0x92,3,0x63,0x44,0x6b,0x54,0x6d,0x70, -0x70,0x1a,0x72,0x65,0x73,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x95,0x17,0x6f, -0x6d,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x9b,0x1c,0x65,0x79,0x63,0x61,0x70,0x73,0x65, -0x71,0x75,0x65,0x6e,0x63,0x65,0xa3,0x42,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,0x72, -0x96,0x13,0x62,0x61,0x73,0x65,0x99,0x12,0x72,0x65,0x73,0x95,0x61,0x30,0x62,0x4e, -0x63,0x12,0x6f,0x6d,0x70,0x9b,0xc2,4,0x1b,0x73,0x74,0x61,0x73,0x69,0x61,0x6e, -0x77,0x69,0x64,0x74,0x68,0xc3,4,0x12,0x61,0x73,0x65,0x99,3,0x67,0x44,0x68, -0x4a,0x6c,0x4e,0x73,0x1a,0x63,0x69,0x69,0x68,0x65,0x78,0x64,0x69,0x67,0x69,0x74, -0x23,0x10,0x65,0xd9,0x40,0,0x11,0x65,0x78,0x23,1,0x6e,0x38,0x70,0x11,0x68, -0x61,0x20,0x14,0x62,0x65,0x74,0x69,0x63,0x21,0x11,0x75,0x6d,0x79,5,0x6c,0x22, -0x6c,0x36,0x6d,0x52,0x70,1,0x62,0xd9,0x40,0xd,0x74,0xc3,0x15,2,0x61,0x32, -0x6b,0xc3,1,0x6f,0x11,0x63,0x6b,0xc3,1,0x11,0x6e,0x6b,0x7b,0x10,0x67,0xd9, -0x40,1,0x61,0xa2,0x4f,0x63,0xc3,0,0x69,0x11,0x64,0x69,2,0x63,0x54,0x6d, -0x74,0x70,0x1b,0x61,0x69,0x72,0x65,0x64,0x62,0x72,0x61,0x63,0x6b,0x65,0x74,0xd8, -0x40,0xd,0x13,0x74,0x79,0x70,0x65,0xc3,0x15,0x24,1,0x6c,0x30,0x6f,0x14,0x6e, -0x74,0x72,0x6f,0x6c,0x25,0x12,0x61,0x73,0x73,0xc3,0,0x26,0x14,0x69,0x72,0x72, -0x6f,0x72,1,0x65,0x38,0x69,0x16,0x6e,0x67,0x67,0x6c,0x79,0x70,0x68,0xd9,0x40, -1,0x10,0x64,0x27,0x17,0x73,0x69,0x63,0x65,0x6d,0x6f,0x6a,0x69,0xa3,0x41,6, -0x68,0x7c,0x68,0x54,0x69,0x85,0x6f,0xa2,0x6f,0x77,4,0x63,0x30,0x6b,0x36,0x6c, -0x87,0x74,0x8b,0x75,0x89,1,0x66,0x8d,0x6d,0x8f,0x11,0x63,0x66,0x91,0x18,0x61, -0x6e,0x67,0x65,0x73,0x77,0x68,0x65,0x6e,4,0x63,0x44,0x6c,0x6c,0x6e,0x7e,0x74, -0x98,0x75,0x18,0x70,0x70,0x65,0x72,0x63,0x61,0x73,0x65,0x64,0x89,0x12,0x61,0x73, -0x65,1,0x66,0x30,0x6d,0x14,0x61,0x70,0x70,0x65,0x64,0x8f,0x14,0x6f,0x6c,0x64, -0x65,0x64,0x8d,0x18,0x6f,0x77,0x65,0x72,0x63,0x61,0x73,0x65,0x64,0x87,0x1c,0x66, -0x6b,0x63,0x63,0x61,0x73,0x65,0x66,0x6f,0x6c,0x64,0x65,0x64,0x91,0x18,0x69,0x74, -0x6c,0x65,0x63,0x61,0x73,0x65,0x64,0x8b,0x13,0x6d,0x70,0x65,0x78,0x33,0x61,0x2e, -0x63,0xa2,0x48,0x66,0xd9,0x40,2,1,0x6e,0x72,0x73,0x10,0x65,3,0x64,0x83, -0x66,0x3a,0x69,0x4a,0x73,0x17,0x65,0x6e,0x73,0x69,0x74,0x69,0x76,0x65,0x65,0x15, -0x6f,0x6c,0x64,0x69,0x6e,0x67,0xd9,0x40,2,0x17,0x67,0x6e,0x6f,0x72,0x61,0x62, -0x6c,0x65,0x85,0x13,0x6f,0x6e,0x69,0x63,0x1f,0x61,0x6c,0x63,0x6f,0x6d,0x62,0x69, -0x6e,0x69,0x6e,0x67,0x63,0x6c,0x61,0x73,0x73,0xc3,2,0x10,0x63,0xc3,2,3, -0x61,0x30,0x65,0x34,0x69,0xa2,0x41,0x74,0xc3,3,0x11,0x73,0x68,0x29,2,0x63, -0x3a,0x66,0x58,0x70,0x2c,0x16,0x72,0x65,0x63,0x61,0x74,0x65,0x64,0x2d,0x1d,0x6f, -0x6d,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x74,0x79,0x70,0x65,0xc3,3,0x15, -0x61,0x75,0x6c,0x74,0x69,0x67,0x1f,0x6e,0x6f,0x72,0x61,0x62,0x6c,0x65,0x63,0x6f, -0x64,0x65,0x70,0x6f,0x69,0x6e,0x74,0x2b,0x2a,0x10,0x61,0x2e,0x15,0x63,0x72,0x69, -0x74,0x69,0x63,0x2f,3,0x66,0x34,0x6e,0x3e,0x74,0x42,0x79,0x22,0x11,0x65,0x73, -0x23,0x20,0x13,0x61,0x6c,0x73,0x65,0x21,0x20,0x10,0x6f,0x21,0x22,0x12,0x72,0x75, -0x65,0x23,0xb,0x6b,0x5b,0x6f,0x23,0x6f,0x3c,0x72,0x4c,0x76,1,0x69,0x24,0x72, -0x33,0x13,0x72,0x61,0x6d,0x61,0x33,0x10,0x76,0x22,0x14,0x65,0x72,0x6c,0x61,0x79, -0x23,0xa2,0xe2,0x13,0x69,0x67,0x68,0x74,0xa3,0xe2,0x6b,0x58,0x6c,0x74,0x6e,3, -0x6b,0x2f,0x6f,0x30,0x72,0x21,0x75,0x12,0x6b,0x74,0x61,0x2f,0x19,0x74,0x72,0x65, -0x6f,0x72,0x64,0x65,0x72,0x65,0x64,0x21,1,0x61,0x24,0x76,0x31,0x18,0x6e,0x61, -0x76,0x6f,0x69,0x63,0x69,0x6e,0x67,0x31,0xa2,0xe0,0x12,0x65,0x66,0x74,0xa3,0xe0, -0x64,0x45,0x64,0x4e,0x68,0x88,0x69,1,0x6f,0x26,0x73,0xa3,0xf0,0x1a,0x74,0x61, -0x73,0x75,0x62,0x73,0x63,0x72,0x69,0x70,0x74,0xa3,0xf0,2,0x61,0xa3,0xea,0x62, -0xa3,0xe9,0x6f,0x13,0x75,0x62,0x6c,0x65,1,0x61,0x30,0x62,0x13,0x65,0x6c,0x6f, -0x77,0xa3,0xe9,0x13,0x62,0x6f,0x76,0x65,0xa3,0xea,0x12,0x61,0x6e,0x72,0x2c,0x15, -0x65,0x61,0x64,0x69,0x6e,0x67,0x2d,0x61,0xa2,0x7b,0x62,0xa2,0xd4,0x63,0x11,0x63, -0x63,4,0x31,0x3c,0x32,0xa2,0x42,0x33,0xa2,0x56,0x38,0xa2,0x64,0x39,0x10,0x31, -0xa3,0x5b,9,0x35,0xa,0x35,0x3f,0x36,0x41,0x37,0x43,0x38,0x45,0x39,0x47,0x30, -0x30,0x31,0x3c,0x32,0x42,0x33,0x4e,0x34,0x3d,0x34,1,0x33,0xa3,0x67,0x37,0xa3, -0x6b,0x36,0x10,0x38,0xa3,0x76,0x38,1,0x32,0xa3,0x7a,0x39,0xa3,0x81,0x3a,2, -0x30,0xa3,0x82,0x32,0xa3,0x84,0x33,0xa3,0x85,9,0x35,0xa,0x35,0x53,0x36,0x55, -0x37,0x57,0x38,0x59,0x39,0x5b,0x30,0x49,0x31,0x4b,0x32,0x4d,0x33,0x4f,0x34,0x51, -6,0x33,8,0x33,0x63,0x34,0x65,0x35,0x67,0x36,0x69,0x30,0x5d,0x31,0x5f,0x32, -0x61,0x10,0x34,0xa3,0x54,0xa2,0xe6,3,0x62,0xa0,0x6c,0xa3,0xe4,0x72,0xa3,0xe8, -0x74,2,0x61,0x74,0x62,0x7c,0x74,0x14,0x61,0x63,0x68,0x65,0x64,1,0x61,0x3e, -0x62,0x13,0x65,0x6c,0x6f,0x77,0xa2,0xca,0x13,0x6c,0x65,0x66,0x74,0xa3,0xc8,0x13, -0x62,0x6f,0x76,0x65,0xa2,0xd6,0x14,0x72,0x69,0x67,0x68,0x74,0xa3,0xd8,0xa2,0xd6, -0x10,0x72,0xa3,0xd8,0xa2,0xca,0x10,0x6c,0xa3,0xc8,0x12,0x6f,0x76,0x65,0xa2,0xe6, -1,0x6c,0x30,0x72,0x13,0x69,0x67,0x68,0x74,0xa3,0xe8,0x12,0x65,0x66,0x74,0xa3, -0xe4,0xa2,0xdc,2,0x65,0x2c,0x6c,0xa3,0xda,0x72,0xa3,0xde,0x12,0x6c,0x6f,0x77, -0xa2,0xdc,1,0x6c,0x30,0x72,0x13,0x69,0x67,0x68,0x74,0xa3,0xde,0x12,0x65,0x66, -0x74,0xa3,0xda,0xb,0x6e,0xc0,0xca,0x72,0x5f,0x72,0x46,0x73,0xa2,0x48,0x77,1, -0x68,0x24,0x73,0x33,0x17,0x69,0x74,0x65,0x73,0x70,0x61,0x63,0x65,0x33,0x22,1, -0x69,0x30,0x6c,2,0x65,0x3d,0x69,0x4b,0x6f,0x3f,0x18,0x67,0x68,0x74,0x74,0x6f, -0x6c,0x65,0x66,0x74,0x22,2,0x65,0x38,0x69,0x48,0x6f,0x16,0x76,0x65,0x72,0x72, -0x69,0x64,0x65,0x3f,0x17,0x6d,0x62,0x65,0x64,0x64,0x69,0x6e,0x67,0x3d,0x15,0x73, -0x6f,0x6c,0x61,0x74,0x65,0x4b,0x30,0x1e,0x65,0x67,0x6d,0x65,0x6e,0x74,0x73,0x65, -0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x31,0x6e,0xa2,0x41,0x6f,0xa2,0x53,0x70,2, -0x61,0x66,0x64,0x86,0x6f,0x1b,0x70,0x64,0x69,0x72,0x65,0x63,0x74,0x69,0x6f,0x6e, -0x61,0x6c,1,0x66,0x32,0x69,0x15,0x73,0x6f,0x6c,0x61,0x74,0x65,0x4d,0x14,0x6f, -0x72,0x6d,0x61,0x74,0x41,0x1f,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x70, -0x61,0x72,0x61,0x74,0x6f,0x72,0x2f,1,0x66,0x41,0x69,0x4d,1,0x6f,0x28,0x73, -0x10,0x6d,0x43,0x1b,0x6e,0x73,0x70,0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b, -0x43,1,0x6e,0x35,0x74,0x19,0x68,0x65,0x72,0x6e,0x65,0x75,0x74,0x72,0x61,0x6c, -0x35,0x65,0x88,0x65,0x98,0x66,0xa2,0x6a,0x6c,0x20,1,0x65,0x30,0x72,2,0x65, -0x37,0x69,0x49,0x6f,0x39,0x18,0x66,0x74,0x74,0x6f,0x72,0x69,0x67,0x68,0x74,0x20, -2,0x65,0x38,0x69,0x48,0x6f,0x16,0x76,0x65,0x72,0x72,0x69,0x64,0x65,0x39,0x17, -0x6d,0x62,0x65,0x64,0x64,0x69,0x6e,0x67,0x37,0x15,0x73,0x6f,0x6c,0x61,0x74,0x65, -0x49,3,0x6e,0x25,0x73,0x27,0x74,0x29,0x75,0x15,0x72,0x6f,0x70,0x65,0x61,0x6e, -2,0x6e,0x3c,0x73,0x46,0x74,0x18,0x65,0x72,0x6d,0x69,0x6e,0x61,0x74,0x6f,0x72, -0x29,0x14,0x75,0x6d,0x62,0x65,0x72,0x25,0x17,0x65,0x70,0x61,0x72,0x61,0x74,0x6f, -0x72,0x27,1,0x69,0x28,0x73,0x10,0x69,0x47,0x1f,0x72,0x73,0x74,0x73,0x74,0x72, -0x6f,0x6e,0x67,0x69,0x73,0x6f,0x6c,0x61,0x74,0x65,0x47,0x61,0x4e,0x62,0x84,0x63, -1,0x6f,0x24,0x73,0x2d,0x1c,0x6d,0x6d,0x6f,0x6e,0x73,0x65,0x70,0x61,0x72,0x61, -0x74,0x6f,0x72,0x2d,2,0x6c,0x3b,0x6e,0x2b,0x72,0x13,0x61,0x62,0x69,0x63,1, -0x6c,0x30,0x6e,0x14,0x75,0x6d,0x62,0x65,0x72,0x2b,0x14,0x65,0x74,0x74,0x65,0x72, -0x3b,0x2e,1,0x6e,0x45,0x6f,0x1c,0x75,0x6e,0x64,0x61,0x72,0x79,0x6e,0x65,0x75, -0x74,0x72,0x61,0x6c,0x45,0,0x16,0x6d,0xc9,0x20,0x74,0xc2,0x30,0x77,0x89,0x77, -0x86,0x79,0xa2,0x46,0x7a,1,0x61,0x58,0x6e,0x1a,0x61,0x6d,0x65,0x6e,0x6e,0x79, -0x6d,0x75,0x73,0x69,0x63,0xa4,0x40,0x19,0x61,0x6c,0x6e,0x6f,0x74,0x61,0x74,0x69, -0x6f,0x6e,0xa5,0x40,0x1c,0x6e,0x61,0x62,0x61,0x7a,0x61,0x72,0x73,0x71,0x75,0x61, -0x72,0x65,0xa5,0x18,0x10,0x61,1,0x6e,0x36,0x72,0x16,0x61,0x6e,0x67,0x63,0x69, -0x74,0x69,0xa3,0xfc,0x12,0x63,0x68,0x6f,0xa5,0x2c,1,0x65,0x88,0x69,2,0x6a, -0x3c,0x72,0x68,0x73,0x17,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x73,0xa3,0x48,0x12, -0x69,0x6e,0x67,0xa2,0x74,0x1e,0x68,0x65,0x78,0x61,0x67,0x72,0x61,0x6d,0x73,0x79, -0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x74,0x16,0x61,0x64,0x69,0x63,0x61,0x6c,0x73,0xa3, -0x49,0x13,0x7a,0x69,0x64,0x69,0xa5,0x34,0x74,0xa2,0x65,0x75,0xa4,0x4f,0x76,3, -0x61,0x3c,0x65,0x80,0x69,0xa2,0x50,0x73,0xa2,0x6c,0x12,0x73,0x75,0x70,0xa3,0x7d, -1,0x69,0xa3,0x9f,0x72,0x1e,0x69,0x61,0x74,0x69,0x6f,0x6e,0x73,0x65,0x6c,0x65, -0x63,0x74,0x6f,0x72,0x73,0xa2,0x6c,0x19,0x73,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65, -0x6e,0x74,0xa3,0x7d,1,0x64,0x3c,0x72,0x19,0x74,0x69,0x63,0x61,0x6c,0x66,0x6f, -0x72,0x6d,0x73,0xa3,0x91,0x14,0x69,0x63,0x65,0x78,0x74,0xa2,0xaf,0x16,0x65,0x6e, -0x73,0x69,0x6f,0x6e,0x73,0xa3,0xaf,0x15,0x74,0x68,0x6b,0x75,0x71,0x69,0xa5,0x3f, -5,0x69,0x3f,0x69,0x5a,0x6f,0x8c,0x72,0x1c,0x61,0x6e,0x73,0x70,0x6f,0x72,0x74, -0x61,0x6e,0x64,0x6d,0x61,0x70,0xa2,0xcf,0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73, -0xa3,0xcf,2,0x62,0x34,0x66,0x3c,0x72,0x13,0x68,0x75,0x74,0x61,0xa3,0xfb,0x13, -0x65,0x74,0x61,0x6e,0x57,0x14,0x69,0x6e,0x61,0x67,0x68,0xa3,0x90,0x11,0x74,0x6f, -0xa5,0x3d,0x61,0x3e,0x65,0xa2,0xa0,0x68,0x10,0x61,1,0x61,0x24,0x69,0x53,0x11, -0x6e,0x61,0x3d,4,0x67,0x8e,0x69,0xa2,0x49,0x6b,0xa2,0x72,0x6d,0xa2,0x74,0x6e, -0x10,0x67,1,0x73,0x68,0x75,0x10,0x74,0xa4,0x10,1,0x63,0x40,0x73,0x11,0x75, -0x70,0xa4,0x33,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0x33,0x18,0x6f,0x6d, -0x70,0x6f,0x6e,0x65,0x6e,0x74,0x73,0xa5,0x11,0x10,0x61,0xa5,0x3c,2,0x61,0x2a, -0x62,0x32,0x73,0xa3,0x60,0x12,0x6c,0x6f,0x67,0xa3,0x62,0x13,0x61,0x6e,0x77,0x61, -0xa3,0x65,3,0x6c,0x52,0x74,0x56,0x76,0x5e,0x78,0x16,0x75,0x61,0x6e,0x6a,0x69, -0x6e,0x67,0xa2,0x7c,0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x7c,0x10,0x65, -0xa3,0x70,0x12,0x68,0x61,0x6d,0xa3,0xae,0x12,0x69,0x65,0x74,0xa3,0xb7,0x11,0x72, -0x69,0xa3,0xdc,0x11,0x69,0x6c,0x48,0x12,0x73,0x75,0x70,0xa4,0x2b,0x16,0x70,0x6c, -0x65,0x6d,0x65,0x6e,0x74,0xa5,0x2b,0x13,0x6c,0x75,0x67,0x75,0x4b,2,0x63,0x8c, -0x67,0xa2,0x41,0x6e,0x1f,0x69,0x66,0x69,0x65,0x64,0x63,0x61,0x6e,0x61,0x64,0x69, -0x61,0x6e,0x61,0x62,0x6f,0x1f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x73,0x79,0x6c, -0x6c,0x61,0x62,0x69,0x63,0x73,0x62,0x17,0x65,0x78,0x74,0x65,0x6e,0x64,0x65,0x64, -0xa2,0xad,0x10,0x61,0xa5,0x3e,0x11,0x61,0x73,0x62,0x12,0x65,0x78,0x74,0xa2,0xad, -0x10,0x61,0xa5,0x3e,0x15,0x61,0x72,0x69,0x74,0x69,0x63,0xa3,0x78,0x70,0xc3,0x4b, -0x70,0xa6,0x61,0x72,0xa8,0x1d,0x73,7,0x6f,0xc1,0xbe,0x6f,0xa2,0x69,0x70,0xa2, -0x85,0x75,0xa2,0xa4,0x79,2,0x6c,0x50,0x6d,0x62,0x72,0x12,0x69,0x61,0x63,0x3a, -0x12,0x73,0x75,0x70,0xa4,0x17,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0x17, -0x17,0x6f,0x74,0x69,0x6e,0x61,0x67,0x72,0x69,0xa3,0x8f,0x13,0x62,0x6f,0x6c,0x73, -1,0x61,0x4c,0x66,0x10,0x6f,0x1f,0x72,0x6c,0x65,0x67,0x61,0x63,0x79,0x63,0x6f, -0x6d,0x70,0x75,0x74,0x69,0x6e,0x67,0xa5,0x32,0x1f,0x6e,0x64,0x70,0x69,0x63,0x74, -0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x78,0x74,1,0x61,0xa5,0x2a,0x65,0x14, -0x6e,0x64,0x65,0x64,0x61,0xa5,0x2a,2,0x67,0x34,0x72,0x3e,0x79,0x13,0x6f,0x6d, -0x62,0x6f,0xa5,0x16,0x13,0x64,0x69,0x61,0x6e,0xa5,0x23,0x17,0x61,0x73,0x6f,0x6d, -0x70,0x65,0x6e,0x67,0xa3,0xda,1,0x61,0x32,0x65,0x14,0x63,0x69,0x61,0x6c,0x73, -0xa3,0x56,0x12,0x63,0x69,0x6e,0x1f,0x67,0x6d,0x6f,0x64,0x69,0x66,0x69,0x65,0x72, -0x6c,0x65,0x74,0x74,0x65,0x72,0x73,0x2d,2,0x6e,0x48,0x70,0x76,0x74,0x1d,0x74, -0x6f,0x6e,0x73,0x69,0x67,0x6e,0x77,0x72,0x69,0x74,0x69,0x6e,0x67,0xa5,6,0x15, -0x64,0x61,0x6e,0x65,0x73,0x65,0xa2,0x9b,0x12,0x73,0x75,0x70,0xa2,0xdb,0x16,0x70, -0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xdb,4,0x61,0xa2,0xa8,0x65,0x5c,0x6d,0x9e, -0x70,0xa2,0x4b,0x73,0x13,0x79,0x6d,0x62,0x6f,0x1f,0x6c,0x73,0x61,0x6e,0x64,0x70, -0x69,0x63,0x74,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa5,5,0x10,0x72,1,0x61, -0x4e,0x73,0x12,0x63,0x72,0x69,0x1f,0x70,0x74,0x73,0x61,0x6e,0x64,0x73,0x75,0x62, -0x73,0x63,0x72,0x69,0x70,0x74,0x73,0x73,0x14,0x6e,0x64,0x73,0x75,0x62,0x73,0x1b, -0x61,0x74,0x68,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73,0xa3,0x6a,1,0x6c, -0x40,0x75,1,0x61,0x6e,0x6e,0x17,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xa3, -0x8e,0x15,0x65,0x6d,0x65,0x6e,0x74,0x61,1,0x6c,0x50,0x72,0x1e,0x79,0x70,0x72, -0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0x61,0x72,0x65,0x61,1,0x61,0xa3,0x6d, -0x62,0xa3,0x6e,3,0x61,0x5c,0x6d,0x78,0x70,0xa2,0x41,0x73,0x13,0x79,0x6d,0x62, -0x6f,0x1f,0x6c,0x73,0x61,0x6e,0x64,0x70,0x69,0x63,0x74,0x6f,0x67,0x72,0x61,0x70, -0x68,0x73,0xa5,5,0x14,0x72,0x72,0x6f,0x77,0x73,2,0x61,0xa3,0x67,0x62,0xa3, -0x68,0x63,0xa3,0xfa,0x13,0x61,0x74,0x68,0x65,0x1f,0x6d,0x61,0x74,0x69,0x63,0x61, -0x6c,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73,0xa3,0x6a,0x19,0x75,0x6e,0x63, -0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xa3,0x8e,0x61,0x88,0x68,0xa2,0x48,0x69,0xa2, -0x71,0x6d,0x12,0x61,0x6c,0x6c,1,0x66,0x46,0x6b,0x15,0x61,0x6e,0x61,0x65,0x78, -0x74,0xa4,0x29,0x15,0x65,0x6e,0x73,0x69,0x6f,0x6e,0xa5,0x29,0x12,0x6f,0x72,0x6d, -1,0x73,0xa3,0x54,0x76,0x16,0x61,0x72,0x69,0x61,0x6e,0x74,0x73,0xa3,0x54,1, -0x6d,0x36,0x75,0x16,0x72,0x61,0x73,0x68,0x74,0x72,0x61,0xa3,0xa1,0x15,0x61,0x72, -0x69,0x74,0x61,0x6e,0xa3,0xac,1,0x61,0x52,0x6f,0x13,0x72,0x74,0x68,0x61,0x1f, -0x6e,0x64,0x66,0x6f,0x72,0x6d,0x61,0x74,0x63,0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x73, -0xa3,0xf7,1,0x72,0x2e,0x76,0x12,0x69,0x61,0x6e,0xa3,0x79,0x12,0x61,0x64,0x61, -0xa3,0xd9,1,0x64,0x50,0x6e,0x13,0x68,0x61,0x6c,0x61,0x50,0x1d,0x61,0x72,0x63, -0x68,0x61,0x69,0x63,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0xf9,0x13,0x64,0x68, -0x61,0x6d,0xa3,0xf8,5,0x72,0x35,0x72,0x44,0x73,0x64,0x75,1,0x61,0xa3,0x4e, -0x6e,0x17,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x71,0x17,0x69,0x76,0x61,0x74, -0x65,0x75,0x73,0x65,0xa2,0x4e,0x13,0x61,0x72,0x65,0x61,0xa3,0x4e,0x1b,0x61,0x6c, -0x74,0x65,0x72,0x70,0x61,0x68,0x6c,0x61,0x76,0x69,0xa3,0xf6,0x61,0x40,0x68,0x82, -0x6c,0x19,0x61,0x79,0x69,0x6e,0x67,0x63,0x61,0x72,0x64,0x73,0xa3,0xcc,2,0x68, -0x38,0x6c,0x4a,0x75,0x15,0x63,0x69,0x6e,0x68,0x61,0x75,0xa3,0xf5,0x17,0x61,0x77, -0x68,0x68,0x6d,0x6f,0x6e,0x67,0xa3,0xf3,0x15,0x6d,0x79,0x72,0x65,0x6e,0x65,0xa3, -0xf4,1,0x61,0x8e,0x6f,1,0x65,0x74,0x6e,0x16,0x65,0x74,0x69,0x63,0x65,0x78, -0x74,0xa2,0x72,1,0x65,0x2c,0x73,0x11,0x75,0x70,0xa3,0x8d,0x15,0x6e,0x73,0x69, -0x6f,0x6e,0x73,0xa2,0x72,0x19,0x73,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74, -0xa3,0x8d,0x15,0x6e,0x69,0x63,0x69,0x61,0x6e,0xa3,0x97,1,0x67,0x3e,0x69,0x13, -0x73,0x74,0x6f,0x73,0xa2,0xa6,0x13,0x64,0x69,0x73,0x63,0xa3,0xa6,0x12,0x73,0x70, -0x61,0xa3,0x96,1,0x65,0x5c,0x75,1,0x6d,0x2a,0x6e,0x11,0x69,0x63,0x67,0x10, -0x69,0xa2,0xc0,0x1d,0x6e,0x75,0x6d,0x65,0x72,0x61,0x6c,0x73,0x79,0x6d,0x62,0x6f, -0x6c,0x73,0xa3,0xc0,0x13,0x6a,0x61,0x6e,0x67,0xa3,0xa3,0x6d,0xa2,0xf0,0x6e,0xa8, -0x23,0x6f,6,0x70,0x63,0x70,0x56,0x72,0x8a,0x73,0xa2,0x4c,0x74,0x10,0x74,0x1f, -0x6f,0x6d,0x61,0x6e,0x73,0x69,0x79,0x61,0x71,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73, -0xa5,0x28,0x18,0x74,0x69,0x63,0x61,0x6c,0x63,0x68,0x61,0x72,0x1f,0x61,0x63,0x74, -0x65,0x72,0x72,0x65,0x63,0x6f,0x67,0x6e,0x69,0x74,0x69,0x6f,0x6e,0x85,1,0x69, -0x46,0x6e,0x1e,0x61,0x6d,0x65,0x6e,0x74,0x61,0x6c,0x64,0x69,0x6e,0x67,0x62,0x61, -0x74,0x73,0xa3,0xf2,0x11,0x79,0x61,0x47,1,0x61,0x30,0x6d,0x13,0x61,0x6e,0x79, -0x61,0xa3,0x7a,0x11,0x67,0x65,0xa5,0xf,0x63,0xa2,0x7b,0x67,0xa2,0x7b,0x6c,1, -0x63,0xa2,0x6c,0x64,6,0x70,0x42,0x70,0x3a,0x73,0x5a,0x74,0x88,0x75,0x14,0x79, -0x67,0x68,0x75,0x72,0xa5,0x3b,0x11,0x65,0x72,1,0x6d,0x2e,0x73,0x12,0x69,0x61, -0x6e,0xa3,0x8c,0x11,0x69,0x63,0xa3,0xf1,0x10,0x6f,1,0x67,0x3a,0x75,0x18,0x74, -0x68,0x61,0x72,0x61,0x62,0x69,0x61,0x6e,0xa3,0xbb,0x13,0x64,0x69,0x61,0x6e,0xa5, -0x22,0x14,0x75,0x72,0x6b,0x69,0x63,0xa3,0xbf,0x68,0x42,0x69,0x54,0x6e,0x1a,0x6f, -0x72,0x74,0x68,0x61,0x72,0x61,0x62,0x69,0x61,0x6e,0xa3,0xf0,0x17,0x75,0x6e,0x67, -0x61,0x72,0x69,0x61,0x6e,0xa5,4,0x14,0x74,0x61,0x6c,0x69,0x63,0xa3,0x58,0x13, -0x68,0x69,0x6b,0x69,0xa3,0x9d,0x10,0x72,0x85,0x12,0x68,0x61,0x6d,0x65,6,0x6f, -0x86,0x6f,0x6c,0x72,0xa2,0x61,0x75,0xa2,0x62,0x79,0x14,0x61,0x6e,0x6d,0x61,0x72, -0x58,0x12,0x65,0x78,0x74,2,0x61,0xa3,0xb6,0x62,0xa3,0xee,0x65,0x13,0x6e,0x64, -0x65,0x64,1,0x61,0xa3,0xb6,0x62,0xa3,0xee,1,0x64,0x52,0x6e,0x15,0x67,0x6f, -0x6c,0x69,0x61,0x6e,0x6a,0x12,0x73,0x75,0x70,0xa4,0xd,0x16,0x70,0x6c,0x65,0x6d, -0x65,0x6e,0x74,0xa5,0xd,0x10,0x69,0xa2,0xec,0x13,0x66,0x69,0x65,0x72,1,0x6c, -0x3c,0x74,0x19,0x6f,0x6e,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x73,0xa3,0x8a,0x15, -0x65,0x74,0x74,0x65,0x72,0x73,0x2d,0x10,0x6f,0xa3,0xed,1,0x6c,0x44,0x73,0x11, -0x69,0x63,0xa2,0x5c,0x18,0x61,0x6c,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x5c, -0x13,0x74,0x61,0x6e,0x69,0xa5,3,0x61,0xa2,0x9b,0x65,0xa4,0x4c,0x69,1,0x61, -0xa2,0x8f,0x73,0x10,0x63,5,0x70,0x18,0x70,0xa2,0x71,0x73,0x36,0x74,0x17,0x65, -0x63,0x68,0x6e,0x69,0x63,0x61,0x6c,0x81,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x8f, -0x61,0xa2,0x66,0x65,0x46,0x6d,0x19,0x61,0x74,0x68,0x73,0x79,0x6d,0x62,0x6f,0x6c, -0x73,1,0x61,0xa3,0x66,0x62,0xa3,0x69,0x17,0x6c,0x6c,0x61,0x6e,0x65,0x6f,0x75, -0x73,2,0x6d,0x3a,0x73,0x6c,0x74,0x17,0x65,0x63,0x68,0x6e,0x69,0x63,0x61,0x6c, -0x81,0x11,0x61,0x74,0x1f,0x68,0x65,0x6d,0x61,0x74,0x69,0x63,0x61,0x6c,0x73,0x79, -0x6d,0x62,0x6f,0x6c,0x73,1,0x61,0xa3,0x66,0x62,0xa3,0x69,0x15,0x79,0x6d,0x62, -0x6f,0x6c,0x73,0x8e,0x12,0x61,0x6e,0x64,1,0x61,0x3c,0x70,0x19,0x69,0x63,0x74, -0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa3,0xcd,0x14,0x72,0x72,0x6f,0x77,0x73,0xa3, -0x73,0x10,0x6f,0xa3,0xd8,7,0x72,0x6f,0x72,0x44,0x73,0x4e,0x74,0x62,0x79,0x19, -0x61,0x6e,0x6e,0x75,0x6d,0x65,0x72,0x61,0x6c,0x73,0xa5,0x20,0x13,0x63,0x68,0x65, -0x6e,0xa5,0xc,0x18,0x61,0x72,0x61,0x6d,0x67,0x6f,0x6e,0x64,0x69,0xa5,0x14,0x10, -0x68,2,0x61,0x3a,0x65,0x4a,0x6f,0x17,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73, -0x7f,0x16,0x6c,0x70,0x68,0x61,0x6e,0x75,0x6d,0xa3,0x5d,0x16,0x6d,0x61,0x74,0x69, -0x63,0x61,0x6c,1,0x61,0x36,0x6f,0x17,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73, -0x7f,0x11,0x6c,0x70,0x1f,0x68,0x61,0x6e,0x75,0x6d,0x65,0x72,0x69,0x63,0x73,0x79, -0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x5d,0x68,0x50,0x6b,0x7e,0x6c,0x88,0x6e,1,0x64, -0x34,0x69,0x15,0x63,0x68,0x61,0x65,0x61,0x6e,0xa3,0xea,0x12,0x61,0x69,0x63,0xa3, -0xc6,1,0x61,0x3e,0x6a,0x12,0x6f,0x6e,0x67,0xa2,0xaa,0x14,0x74,0x69,0x6c,0x65, -0x73,0xa3,0xaa,0x13,0x6a,0x61,0x6e,0x69,0xa3,0xe9,0x13,0x61,0x73,0x61,0x72,0xa5, -0x1f,0x15,0x61,0x79,0x61,0x6c,0x61,0x6d,0x4f,3,0x64,0x6c,0x65,0x7e,0x6e,0xa2, -0x47,0x72,0x14,0x6f,0x69,0x74,0x69,0x63,1,0x63,0x3c,0x68,0x19,0x69,0x65,0x72, -0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0xd7,0x15,0x75,0x72,0x73,0x69,0x76,0x65, -0xa3,0xd6,0x17,0x65,0x66,0x61,0x69,0x64,0x72,0x69,0x6e,0xa5,0x21,0x17,0x74,0x65, -0x69,0x6d,0x61,0x79,0x65,0x6b,0xa2,0xb8,0x12,0x65,0x78,0x74,0xa2,0xd5,0x16,0x65, -0x6e,0x73,0x69,0x6f,0x6e,0x73,0xa3,0xd5,0x18,0x64,0x65,0x6b,0x69,0x6b,0x61,0x6b, -0x75,0x69,0xa3,0xeb,6,0x6b,0x3b,0x6b,0x56,0x6f,0x5a,0x75,0x64,0x79,0x11,0x69, -0x61,0x1f,0x6b,0x65,0x6e,0x67,0x70,0x75,0x61,0x63,0x68,0x75,0x65,0x68,0x6d,0x6f, -0x6e,0x67,0xa5,0x27,0x10,0x6f,0xa3,0x92,0x14,0x62,0x6c,0x6f,0x63,0x6b,0x21,1, -0x6d,0x2c,0x73,0x11,0x68,0x75,0xa5,0x15,0x17,0x62,0x65,0x72,0x66,0x6f,0x72,0x6d, -0x73,0x7b,0x61,0x44,0x62,0x21,0x65,0x10,0x77,1,0x61,0xa5,0xe,0x74,0x14,0x61, -0x69,0x6c,0x75,0x65,0xa3,0x8b,2,0x62,0x3c,0x67,0x4a,0x6e,0x17,0x64,0x69,0x6e, -0x61,0x67,0x61,0x72,0x69,0xa5,0x26,0x15,0x61,0x74,0x61,0x65,0x61,0x6e,0xa3,0xef, -0x16,0x6d,0x75,0x6e,0x64,0x61,0x72,0x69,0xa5,0x47,0x67,0xc4,0x5d,0x6a,0xc1,0xe4, -0x6a,0xa2,0xdf,0x6b,0xa2,0xf8,0x6c,4,0x61,0x54,0x65,0xa2,0x6b,0x69,0xa2,0x82, -0x6f,0xa2,0xc1,0x79,1,0x63,0x2e,0x64,0x12,0x69,0x61,0x6e,0xa3,0xa9,0x12,0x69, -0x61,0x6e,0xa3,0xa7,1,0x6f,0x55,0x74,0x11,0x69,0x6e,1,0x31,0x96,0x65,0x11, -0x78,0x74,6,0x64,0x21,0x64,0xa3,0x95,0x65,0x2c,0x66,0xa5,0x39,0x67,0xa5,0x3a, -0xa2,0xe7,0x13,0x6e,0x64,0x65,0x64,6,0x64,0xc,0x64,0xa3,0x95,0x65,0xa3,0xe7, -0x66,0xa5,0x39,0x67,0xa5,0x3a,0x61,0x2a,0x62,0x29,0x63,0xa3,0x94,0x26,0x18,0x64, -0x64,0x69,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x6d,0x24,0x12,0x73,0x75,0x70,0x24,0x16, -0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x25,1,0x70,0x42,0x74,0x1d,0x74,0x65,0x72, -0x6c,0x69,0x6b,0x65,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x79,0x12,0x63,0x68,0x61, -0xa3,0x9c,2,0x6d,0x4e,0x6e,0x54,0x73,0x10,0x75,0xa2,0xb0,0x12,0x73,0x75,0x70, -0xa4,0x31,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0x31,0x11,0x62,0x75,0xa3, -0x6f,0x12,0x65,0x61,0x72,1,0x61,0xa3,0xe8,0x62,1,0x69,0x38,0x73,0x17,0x79, -0x6c,0x6c,0x61,0x62,0x61,0x72,0x79,0xa3,0x75,0x17,0x64,0x65,0x6f,0x67,0x72,0x61, -0x6d,0x73,0xa3,0x76,0x1a,0x77,0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73, -0xa3,0x4d,0x10,0x61,1,0x6d,0x32,0x76,0x14,0x61,0x6e,0x65,0x73,0x65,0xa3,0xb5, -0x10,0x6f,0x5c,0x12,0x65,0x78,0x74,1,0x61,0xa3,0xb4,0x62,0xa3,0xb9,1,0x61, -0xa2,0x43,0x68,4,0x61,0x40,0x69,0x50,0x6d,0x6e,0x6f,0x86,0x75,0x15,0x64,0x61, -0x77,0x61,0x64,0x69,0xa3,0xe6,0x16,0x72,0x6f,0x73,0x68,0x74,0x68,0x69,0xa3,0x89, -0x1d,0x74,0x61,0x6e,0x73,0x6d,0x61,0x6c,0x6c,0x73,0x63,0x72,0x69,0x70,0x74,0xa5, -0x30,0x11,0x65,0x72,0x68,0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x71,0x12, -0x6a,0x6b,0x69,0xa3,0xe5,5,0x74,0x35,0x74,0x34,0x77,0x7a,0x79,0x13,0x61,0x68, -0x6c,0x69,0xa3,0xa2,0x14,0x61,0x6b,0x61,0x6e,0x61,0x9e,1,0x65,0x4c,0x70,0x10, -0x68,0x1f,0x6f,0x6e,0x65,0x74,0x69,0x63,0x65,0x78,0x74,0x65,0x6e,0x73,0x69,0x6f, -0x6e,0x73,0xa3,0x6b,0x11,0x78,0x74,0xa3,0x6b,0x10,0x69,0xa5,0x46,0x69,0xa2,0x4e, -0x6b,0xa2,0x51,0x6e,3,0x61,0x34,0x62,0x84,0x67,0x8a,0x6e,0x12,0x61,0x64,0x61, -0x4d,1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2,0xcb,0x16,0x70,0x6c,0x65,0x6d,0x65, -0x6e,0x74,0xa3,0xcb,0x11,0x78,0x74,2,0x61,0xa5,0x13,0x62,0xa5,0x38,0x65,0x13, -0x6e,0x64,0x65,0x64,1,0x61,0xa5,0x13,0x62,0xa5,0x38,0x11,0x75,0x6e,0xa3,0x42, -0x11,0x78,0x69,0x96,0x17,0x72,0x61,0x64,0x69,0x63,0x61,0x6c,0x73,0x97,0x12,0x74, -0x68,0x69,0xa3,0xc1,0x1c,0x74,0x6f,0x76,0x69,0x6b,0x6e,0x75,0x6d,0x65,0x72,0x61, -0x6c,0x73,0xa5,0x45,0x67,0xa2,0xb5,0x68,0xa4,0x84,0x69,3,0x64,0x4c,0x6d,0xa2, -0x55,0x6e,0xa2,0x62,0x70,0x13,0x61,0x65,0x78,0x74,0x2a,0x16,0x65,0x6e,0x73,0x69, -0x6f,0x6e,0x73,0x2b,1,0x63,0x99,0x65,0x17,0x6f,0x67,0x72,0x61,0x70,0x68,0x69, -0x63,1,0x64,0x56,0x73,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa4,0xb,0x1d,0x61, -0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xa5,0xb,0x13, -0x65,0x73,0x63,0x72,0x1f,0x69,0x70,0x74,0x69,0x6f,0x6e,0x63,0x68,0x61,0x72,0x61, -0x63,0x74,0x65,0x72,0x73,0x99,0x1c,0x70,0x65,0x72,0x69,0x61,0x6c,0x61,0x72,0x61, -0x6d,0x61,0x69,0x63,0xa3,0xba,1,0x64,0x62,0x73,0x1b,0x63,0x72,0x69,0x70,0x74, -0x69,0x6f,0x6e,0x61,0x6c,0x70,0x61,1,0x68,0x32,0x72,0x14,0x74,0x68,0x69,0x61, -0x6e,0xa3,0xbd,0x13,0x6c,0x61,0x76,0x69,0xa3,0xbe,0x11,0x69,0x63,1,0x6e,0x3e, -0x73,0x1a,0x69,0x79,0x61,0x71,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa5,0x1e,0x19, -0x75,0x6d,0x62,0x65,0x72,0x66,0x6f,0x72,0x6d,0x73,0xa3,0xb2,4,0x65,0x74,0x6c, -0xa2,0x82,0x6f,0xa2,0x9a,0x72,0xa2,0x9e,0x75,2,0x6a,0x34,0x6e,0x3e,0x72,0x14, -0x6d,0x75,0x6b,0x68,0x69,0x43,0x14,0x61,0x72,0x61,0x74,0x69,0x45,0x18,0x6a,0x61, -0x6c,0x61,0x67,0x6f,0x6e,0x64,0x69,0xa5,0x1c,1,0x6e,0xa2,0x46,0x6f,1,0x6d, -0x6e,0x72,0x13,0x67,0x69,0x61,0x6e,0x5a,1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2, -0x87,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x87,0x11,0x78,0x74,0xa4,0x1b, -0x14,0x65,0x6e,0x64,0x65,0x64,0xa5,0x1b,0x1a,0x65,0x74,0x72,0x69,0x63,0x73,0x68, -0x61,0x70,0x65,0x73,0x8c,0x12,0x65,0x78,0x74,0xa2,0xe3,0x14,0x65,0x6e,0x64,0x65, -0x64,0xa3,0xe3,0x1e,0x65,0x72,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74, -0x69,0x6f,0x6e,0x71,0x17,0x61,0x67,0x6f,0x6c,0x69,0x74,0x69,0x63,0xa2,0x88,0x12, -0x73,0x75,0x70,0xa4,0xa,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0xa,0x13, -0x74,0x68,0x69,0x63,0xa3,0x59,1,0x61,0x5c,0x65,0x11,0x65,0x6b,0x30,1,0x61, -0x38,0x65,0x11,0x78,0x74,0x6e,0x14,0x65,0x6e,0x64,0x65,0x64,0x6f,0x17,0x6e,0x64, -0x63,0x6f,0x70,0x74,0x69,0x63,0x31,0x13,0x6e,0x74,0x68,0x61,0xa3,0xe4,2,0x61, -0xa2,0x48,0x65,0xa2,0xdf,0x69,1,0x67,0x30,0x72,0x14,0x61,0x67,0x61,0x6e,0x61, -0x9d,0x10,0x68,1,0x70,0x3a,0x73,0x18,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65, -0x73,0xa3,0x4b,1,0x72,0x3c,0x75,0x19,0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74, -0x65,0x73,0xa3,0x4c,0x11,0x69,0x76,0x1f,0x61,0x74,0x65,0x75,0x73,0x65,0x73,0x75, -0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4c,2,0x6c,0x32,0x6e,0x9a,0x74, -0x12,0x72,0x61,0x6e,0xa5,2,0x10,0x66,2,0x61,0x58,0x6d,0x70,0x77,0x14,0x69, -0x64,0x74,0x68,0x61,0x1f,0x6e,0x64,0x66,0x75,0x6c,0x6c,0x77,0x69,0x64,0x74,0x68, -0x66,0x6f,0x72,0x6d,0x73,0xa3,0x57,0x1a,0x6e,0x64,0x66,0x75,0x6c,0x6c,0x66,0x6f, -0x72,0x6d,0x73,0xa3,0x57,0x13,0x61,0x72,0x6b,0x73,0xa3,0x52,2,0x67,0x34,0x69, -0xa2,0x45,0x75,0x12,0x6e,0x6f,0x6f,0xa3,0x63,0x11,0x75,0x6c,0xa2,0x4a,2,0x63, -0x3c,0x6a,0x5e,0x73,0x17,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x73,0xa3,0x4a,0x1f, -0x6f,0x6d,0x70,0x61,0x74,0x69,0x62,0x69,0x6c,0x69,0x74,0x79,0x6a,0x61,0x6d,0x6f, -0xa3,0x41,0x12,0x61,0x6d,0x6f,0x5c,0x17,0x65,0x78,0x74,0x65,0x6e,0x64,0x65,0x64, -1,0x61,0xa3,0xb4,0x62,0xa3,0xb9,0x19,0x66,0x69,0x72,0x6f,0x68,0x69,0x6e,0x67, -0x79,0x61,0xa5,0x1d,0x13,0x62,0x72,0x65,0x77,0x37,0x61,0xa4,0xc,0x62,0xa6,0x59, -0x63,0xa8,0x2e,0x64,0xac,0xe3,0x65,5,0x6d,0xa9,0x6d,0x94,0x6e,0xa2,0x41,0x74, -0x15,0x68,0x69,0x6f,0x70,0x69,0x63,0x5e,1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2, -0x86,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x86,0x11,0x78,0x74,0xa2,0x85, -2,0x61,0xa3,0xc8,0x62,0xa5,0x37,0x65,0x13,0x6e,0x64,0x65,0x64,0xa2,0x85,1, -0x61,0xa3,0xc8,0x62,0xa5,0x37,0x16,0x6f,0x74,0x69,0x63,0x6f,0x6e,0x73,0xa3,0xce, -0x15,0x63,0x6c,0x6f,0x73,0x65,0x64,2,0x61,0x5a,0x63,0x9e,0x69,0x1c,0x64,0x65, -0x6f,0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x73,0x75,0x70,0xa2,0xc4,0x16,0x70,0x6c, -0x65,0x6d,0x65,0x6e,0x74,0xa3,0xc4,0x16,0x6c,0x70,0x68,0x61,0x6e,0x75,0x6d,0x86, -1,0x65,0x2c,0x73,0x11,0x75,0x70,0xa3,0xc3,0x13,0x72,0x69,0x63,0x73,0x86,0x18, -0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xc3,0x11,0x6a,0x6b,0xa2,0x44, -0x1f,0x6c,0x65,0x74,0x74,0x65,0x72,0x73,0x61,0x6e,0x64,0x6d,0x6f,0x6e,0x74,0x68, -0x73,0xa3,0x44,0x61,0x4a,0x67,0x76,0x6c,1,0x62,0x30,0x79,0x13,0x6d,0x61,0x69, -0x63,0xa5,0x25,0x13,0x61,0x73,0x61,0x6e,0xa3,0xe2,0x13,0x72,0x6c,0x79,0x64,0x1f, -0x79,0x6e,0x61,0x73,0x74,0x69,0x63,0x63,0x75,0x6e,0x65,0x69,0x66,0x6f,0x72,0x6d, -0xa5,1,0x1f,0x79,0x70,0x74,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c, -0x79,0x70,0x68,1,0x66,0x26,0x73,0xa3,0xc2,0x1c,0x6f,0x72,0x6d,0x61,0x74,0x63, -0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x73,0xa5,0x24,7,0x6e,0xc0,0xf2,0x6e,0x3e,0x72, -0xa2,0x5d,0x73,0xa2,0xe5,0x76,0x14,0x65,0x73,0x74,0x61,0x6e,0xa3,0xbc,1,0x61, -0x92,0x63,0x13,0x69,0x65,0x6e,0x74,1,0x67,0x34,0x73,0x15,0x79,0x6d,0x62,0x6f, -0x6c,0x73,0xa3,0xa5,0x13,0x72,0x65,0x65,0x6b,1,0x6d,0x34,0x6e,0x15,0x75,0x6d, -0x62,0x65,0x72,0x73,0xa3,0x7f,0x13,0x75,0x73,0x69,0x63,0xa2,0x7e,0x19,0x61,0x6c, -0x6e,0x6f,0x74,0x61,0x74,0x69,0x6f,0x6e,0xa3,0x7e,0x10,0x74,0x1f,0x6f,0x6c,0x69, -0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0xfe,2, -0x61,0x32,0x6d,0xa2,0x7e,0x72,0x12,0x6f,0x77,0x73,0x7d,0x12,0x62,0x69,0x63,0x38, -3,0x65,0x4a,0x6d,0x80,0x70,0xa2,0x50,0x73,0x11,0x75,0x70,0xa2,0x80,0x16,0x70, -0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x80,0x11,0x78,0x74,3,0x61,0xa3,0xd2,0x62, -0xa5,0x35,0x63,0xa5,0x41,0x65,0x13,0x6e,0x64,0x65,0x64,2,0x61,0xa3,0xd2,0x62, -0xa5,0x35,0x63,0xa5,0x41,0x12,0x61,0x74,0x68,0xa2,0xd3,0x18,0x65,0x6d,0x61,0x74, -0x69,0x63,0x61,0x6c,0x61,0x1f,0x6c,0x70,0x68,0x61,0x62,0x65,0x74,0x69,0x63,0x73, -0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xd3,1,0x66,0x42,0x72,0x1e,0x65,0x73,0x65, -0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x66,0x6f,0x72,0x6d,0x73,1,0x61,0xa3,0x51, -0x62,0xa3,0x55,0x14,0x65,0x6e,0x69,0x61,0x6e,0x35,0x12,0x63,0x69,0x69,0x23,0x64, -0x9e,0x65,0xa2,0x42,0x68,0xa2,0x4d,0x6c,1,0x63,0x62,0x70,0x17,0x68,0x61,0x62, -0x65,0x74,0x69,0x63,0x70,1,0x66,0xa3,0x50,0x72,0x1e,0x65,0x73,0x65,0x6e,0x74, -0x61,0x74,0x69,0x6f,0x6e,0x66,0x6f,0x72,0x6d,0x73,0xa3,0x50,0x16,0x68,0x65,0x6d, -0x69,0x63,0x61,0x6c,0xa2,0xd0,0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xd0, -0x12,0x6c,0x61,0x6d,0xa5,7,0x1a,0x67,0x65,0x61,0x6e,0x6e,0x75,0x6d,0x62,0x65, -0x72,0x73,0xa3,0x77,0x11,0x6f,0x6d,0xa3,0xfd,7,0x6f,0x71,0x6f,0x64,0x72,0xa2, -0x41,0x75,0xa2,0x58,0x79,0x1b,0x7a,0x61,0x6e,0x74,0x69,0x6e,0x65,0x6d,0x75,0x73, -0x69,0x63,0xa2,0x5b,0x18,0x61,0x6c,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x5b, -1,0x70,0x34,0x78,0x16,0x64,0x72,0x61,0x77,0x69,0x6e,0x67,0x89,0x14,0x6f,0x6d, -0x6f,0x66,0x6f,0xa0,0x12,0x65,0x78,0x74,0xa2,0x43,0x14,0x65,0x6e,0x64,0x65,0x64, -0xa3,0x43,0x10,0x61,1,0x68,0x40,0x69,0x12,0x6c,0x6c,0x65,0x92,0x17,0x70,0x61, -0x74,0x74,0x65,0x72,0x6e,0x73,0x93,0x11,0x6d,0x69,0xa3,0xc9,1,0x67,0x2c,0x68, -0x11,0x69,0x64,0xa3,0x64,0x14,0x69,0x6e,0x65,0x73,0x65,0xa3,0x81,0x61,0x48,0x65, -0xa2,0x4e,0x68,0xa2,0x52,0x6c,0x1a,0x6f,0x63,0x6b,0x65,0x6c,0x65,0x6d,0x65,0x6e, -0x74,0x73,0x8b,3,0x6c,0x34,0x6d,0x40,0x73,0x66,0x74,0x11,0x61,0x6b,0xa3,0xc7, -0x14,0x69,0x6e,0x65,0x73,0x65,0xa3,0x93,0x11,0x75,0x6d,0xa2,0xb1,0x12,0x73,0x75, -0x70,0xa2,0xca,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xca,1,0x69,0x30, -0x73,0x13,0x61,0x76,0x61,0x68,0xa3,0xdd,0x15,0x63,0x6c,0x61,0x74,0x69,0x6e,0x23, -0x14,0x6e,0x67,0x61,0x6c,0x69,0x41,0x16,0x61,0x69,0x6b,0x73,0x75,0x6b,0x69,0xa5, -8,5,0x6f,0xc1,0x60,0x6f,0xa2,0x69,0x75,0xa4,0x24,0x79,1,0x70,0xa2,0x44, -0x72,0x14,0x69,0x6c,0x6c,0x69,0x63,0x32,1,0x65,0x4c,0x73,0x11,0x75,0x70,0xa2, -0x61,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa2,0x61,0x12,0x61,0x72,0x79,0xa3, -0x61,0x11,0x78,0x74,4,0x61,0xa3,0x9e,0x62,0xa3,0xa0,0x63,0xa5,9,0x64,0xa5, -0x43,0x65,0x13,0x6e,0x64,0x65,0x64,3,0x61,0xa3,0x9e,0x62,0xa3,0xa0,0x63,0xa5, -9,0x64,0xa5,0x43,0x10,0x72,1,0x69,0x34,0x6f,0x15,0x6d,0x69,0x6e,0x6f,0x61, -0x6e,0xa5,0x36,0x1a,0x6f,0x74,0x73,0x79,0x6c,0x6c,0x61,0x62,0x61,0x72,0x79,0xa3, -0x7b,3,0x6d,0x5a,0x6e,0xa2,0x95,0x70,0xa2,0xa0,0x75,0x17,0x6e,0x74,0x69,0x6e, -0x67,0x72,0x6f,0x64,0xa2,0x9a,0x17,0x6e,0x75,0x6d,0x65,0x72,0x61,0x6c,0x73,0xa3, -0x9a,2,0x62,0x3a,0x6d,0xa2,0x5f,0x70,0x15,0x61,0x74,0x6a,0x61,0x6d,0x6f,0xa3, -0x41,0x14,0x69,0x6e,0x69,0x6e,0x67,2,0x64,0x46,0x68,0x9e,0x6d,0x1d,0x61,0x72, -0x6b,0x73,0x66,0x6f,0x72,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x77,0x1e,0x69,0x61, -0x63,0x72,0x69,0x74,0x69,0x63,0x61,0x6c,0x6d,0x61,0x72,0x6b,0x73,0x2e,2,0x65, -0x40,0x66,0xa6,0x4c,0x73,0x18,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3, -0x83,0x16,0x78,0x74,0x65,0x6e,0x64,0x65,0x64,0xa3,0xe0,0x17,0x61,0x6c,0x66,0x6d, -0x61,0x72,0x6b,0x73,0xa3,0x52,0x11,0x6f,0x6e,0x1f,0x69,0x6e,0x64,0x69,0x63,0x6e, -0x75,0x6d,0x62,0x65,0x72,0x66,0x6f,0x72,0x6d,0x73,0xa3,0xb2,0x1b,0x74,0x72,0x6f, -0x6c,0x70,0x69,0x63,0x74,0x75,0x72,0x65,0x73,0x83,0x12,0x74,0x69,0x63,0xa2,0x84, -0x1b,0x65,0x70,0x61,0x63,0x74,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0xdf,1, -0x6e,0x3e,0x72,0x1b,0x72,0x65,0x6e,0x63,0x79,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73, -0x75,0x15,0x65,0x69,0x66,0x6f,0x72,0x6d,0xa2,0x98,0x16,0x6e,0x75,0x6d,0x62,0x65, -0x72,0x73,0xa2,0x99,0x1d,0x61,0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74, -0x69,0x6f,0x6e,0xa3,0x99,0x61,0xa2,0xe4,0x68,0xa4,0xe,0x6a,0x10,0x6b,0xa2,0x47, -4,0x63,0x8c,0x65,0xa2,0x80,0x72,0xa2,0x9b,0x73,0xa2,0xad,0x75,0x1f,0x6e,0x69, -0x66,0x69,0x65,0x64,0x69,0x64,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa2,0x47, -0x18,0x65,0x78,0x74,0x65,0x6e,0x73,0x69,0x6f,0x6e,7,0x65,0x6b,0x65,0xa5,0, -0x66,0xa5,0x12,0x67,0xa5,0x2e,0x68,0xa5,0x42,0x14,0x6f,0x6d,0x70,0x61,0x74,0xa2, -0x45,1,0x66,0x96,0x69,1,0x62,0x44,0x64,0x17,0x65,0x6f,0x67,0x72,0x61,0x70, -0x68,0x73,0xa2,0x4f,0x12,0x73,0x75,0x70,0xa3,0x5f,0x14,0x69,0x6c,0x69,0x74,0x79, -0xa2,0x45,1,0x66,0x54,0x69,0x18,0x64,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x73, -0xa2,0x4f,0x19,0x73,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x5f,0x13, -0x6f,0x72,0x6d,0x73,0xa3,0x53,0x11,0x78,0x74,7,0x65,0xc,0x65,0xa5,0,0x66, -0xa5,0x12,0x67,0xa5,0x2e,0x68,0xa5,0x42,0x61,0xa3,0x46,0x62,0xa3,0x5e,0x63,0xa3, -0xc5,0x64,0xa3,0xd1,0x19,0x61,0x64,0x69,0x63,0x61,0x6c,0x73,0x73,0x75,0x70,0x94, -0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x95,1,0x74,0x50,0x79,0x14,0x6d,0x62, -0x6f,0x6c,0x73,0x9a,0x1d,0x61,0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74, -0x69,0x6f,0x6e,0x9b,0x14,0x72,0x6f,0x6b,0x65,0x73,0xa3,0x82,2,0x6e,0x48,0x72, -0x64,0x75,0x1d,0x63,0x61,0x73,0x69,0x61,0x6e,0x61,0x6c,0x62,0x61,0x6e,0x69,0x61, -0x6e,0xa3,0xde,0x1d,0x61,0x64,0x69,0x61,0x6e,0x73,0x79,0x6c,0x6c,0x61,0x62,0x69, -0x63,0x73,0x63,0x12,0x69,0x61,0x6e,0xa3,0xa8,2,0x61,0x3a,0x65,0x4c,0x6f,0x16, -0x72,0x61,0x73,0x6d,0x69,0x61,0x6e,0xa5,0x2d,1,0x6b,0x26,0x6d,0xa3,0xa4,0x11, -0x6d,0x61,0xa3,0xd4,1,0x72,0x38,0x73,0x17,0x73,0x73,0x79,0x6d,0x62,0x6f,0x6c, -0x73,0xa5,0x19,0x13,0x6f,0x6b,0x65,0x65,0x60,0x12,0x73,0x75,0x70,0xa2,0xff,0x16, -0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xff,3,0x65,0x3e,0x69,0x8e,0x6f,0xa2, -0x71,0x75,0x15,0x70,0x6c,0x6f,0x79,0x61,0x6e,0xa3,0xe1,1,0x73,0x60,0x76,0x16, -0x61,0x6e,0x61,0x67,0x61,0x72,0x69,0x3e,0x12,0x65,0x78,0x74,0xa2,0xb3,1,0x61, -0xa5,0x44,0x65,0x13,0x6e,0x64,0x65,0x64,0xa2,0xb3,0x10,0x61,0xa5,0x44,0x13,0x65, -0x72,0x65,0x74,0xa3,0x5a,2,0x61,0x3a,0x6e,0x82,0x76,0x16,0x65,0x73,0x61,0x6b, -0x75,0x72,0x75,0xa5,0x2f,0x18,0x63,0x72,0x69,0x74,0x69,0x63,0x61,0x6c,0x73,0x2e, -2,0x65,0x30,0x66,0x36,0x73,0x11,0x75,0x70,0xa3,0x83,0x11,0x78,0x74,0xa3,0xe0, -0x18,0x6f,0x72,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x77,0x14,0x67,0x62,0x61,0x74, -0x73,0x91,1,0x67,0x3e,0x6d,0x12,0x69,0x6e,0x6f,0xa2,0xab,0x14,0x74,0x69,0x6c, -0x65,0x73,0xa3,0xab,0x11,0x72,0x61,0xa5,0x1a,8,0x6d,0x5f,0x6d,0x3a,0x6e,0x48, -0x73,0x7a,0x76,0xa2,0x4b,0x77,0x12,0x69,0x64,0x65,0x43,0x11,0x65,0x64,0x32,0x12, -0x69,0x61,0x6c,0x33,2,0x61,0x40,0x62,0x37,0x6f,1,0x62,0x28,0x6e,0x10,0x65, -0x21,0x13,0x72,0x65,0x61,0x6b,0x37,0x10,0x72,0x34,0x12,0x72,0x6f,0x77,0x35,2, -0x6d,0x38,0x71,0x46,0x75,1,0x62,0x3d,0x70,0x3e,0x11,0x65,0x72,0x3f,1,0x61, -0x24,0x6c,0x39,0x11,0x6c,0x6c,0x39,1,0x72,0x3b,0x75,0x12,0x61,0x72,0x65,0x3b, -0x12,0x65,0x72,0x74,0x40,0x13,0x69,0x63,0x61,0x6c,0x41,0x63,0x58,0x65,0x92,0x66, -0x96,0x69,1,0x6e,0x36,0x73,0x10,0x6f,0x30,0x14,0x6c,0x61,0x74,0x65,0x64,0x31, -0x11,0x69,0x74,0x2e,0x12,0x69,0x61,0x6c,0x2f,2,0x61,0x36,0x69,0x48,0x6f,0x10, -0x6d,0x24,0x12,0x70,0x61,0x74,0x25,0x10,0x6e,0x22,0x15,0x6f,0x6e,0x69,0x63,0x61, -0x6c,0x23,0x13,0x72,0x63,0x6c,0x65,0x27,0x11,0x6e,0x63,0x27,2,0x69,0x3a,0x6f, -0x44,0x72,0x10,0x61,0x2c,0x14,0x63,0x74,0x69,0x6f,0x6e,0x2d,0x10,0x6e,0x28,0x11, -0x61,0x6c,0x29,0x11,0x6e,0x74,0x2b,4,0x61,0x3a,0x66,0x4c,0x68,0x5e,0x6e,0x70, -0x77,0x2a,0x12,0x69,0x64,0x65,0x2b,0x22,0x17,0x6d,0x62,0x69,0x67,0x75,0x6f,0x75, -0x73,0x23,0x26,0x17,0x75,0x6c,0x6c,0x77,0x69,0x64,0x74,0x68,0x27,0x24,0x17,0x61, -0x6c,0x66,0x77,0x69,0x64,0x74,0x68,0x25,0x20,1,0x61,0x30,0x65,0x14,0x75,0x74, -0x72,0x61,0x6c,0x21,0x28,0x13,0x72,0x72,0x6f,0x77,0x29,0xd,0x6e,0xc0,0xfb,0x73, -0x6d,0x73,0x3a,0x74,0x98,0x75,0xa2,0x49,0x7a,2,0x6c,0x3b,0x70,0x3d,0x73,0x39, -5,0x6f,0x28,0x6f,0x57,0x70,0x34,0x75,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65, -0x45,0x11,0x61,0x63,1,0x65,0x32,0x69,0x15,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x31, -0x18,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x39,0x63,0x53,0x6b,0x55,0x6d, -0x51,0x1d,0x69,0x74,0x6c,0x65,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72, -0x27,1,0x6e,0x40,0x70,0x1c,0x70,0x65,0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74, -0x74,0x65,0x72,0x23,0x17,0x61,0x73,0x73,0x69,0x67,0x6e,0x65,0x64,0x21,0x6e,0x8a, -0x6f,0xa2,0x47,0x70,8,0x66,0x14,0x66,0x5b,0x69,0x59,0x6f,0x4f,0x72,0x24,0x73, -0x49,0x17,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0x43,0x61,0x2c,0x63,0x4d,0x64, -0x47,0x65,0x4b,0x1f,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x70,0x61,0x72, -0x61,0x74,0x6f,0x72,0x3d,2,0x64,0x33,0x6c,0x35,0x6f,0x36,0x1b,0x6e,0x73,0x70, -0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x2d,1,0x70,0x7c,0x74,0x12,0x68, -0x65,0x72,3,0x6c,0x38,0x6e,0x42,0x70,0x4c,0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c, -0x57,0x14,0x65,0x74,0x74,0x65,0x72,0x2b,0x14,0x75,0x6d,0x62,0x65,0x72,0x37,0x19, -0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x4f,0x1c,0x65,0x6e,0x70,0x75, -0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x49,0x66,0x9e,0x66,0x88,0x69,0xa2, -0x4b,0x6c,0xa2,0x5c,0x6d,4,0x61,0x60,0x63,0x31,0x65,0x2f,0x6e,0x2d,0x6f,0x15, -0x64,0x69,0x66,0x69,0x65,0x72,1,0x6c,0x30,0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c, -0x55,0x14,0x65,0x74,0x74,0x65,0x72,0x29,0x17,0x74,0x68,0x73,0x79,0x6d,0x62,0x6f, -0x6c,0x51,1,0x69,0x2e,0x6f,0x13,0x72,0x6d,0x61,0x74,0x41,0x1d,0x6e,0x61,0x6c, -0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x5b,0x10,0x6e,0x1f,0x69, -0x74,0x69,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x59, -6,0x6d,0x18,0x6d,0x29,0x6f,0x28,0x74,0x27,0x75,0x23,0x2a,0x1c,0x77,0x65,0x72, -0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x25,0x65,0x28,0x69,0x3c,0x6c, -0x25,0x19,0x74,0x74,0x65,0x72,0x6e,0x75,0x6d,0x62,0x65,0x72,0x35,0x1a,0x6e,0x65, -0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x3b,0x63,0x44,0x64,0xa2,0x60,0x65, -0x1b,0x6e,0x63,0x6c,0x6f,0x73,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x2f,6,0x6e, -0x39,0x6e,0x46,0x6f,0x4e,0x73,0x45,0x75,0x1b,0x72,0x72,0x65,0x6e,0x63,0x79,0x73, -0x79,0x6d,0x62,0x6f,0x6c,0x53,0x20,0x12,0x74,0x72,0x6c,0x3f,0x42,0x10,0x6e,1, -0x6e,0x2c,0x74,0x12,0x72,0x6f,0x6c,0x3f,0x1f,0x65,0x63,0x74,0x6f,0x72,0x70,0x75, -0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x4d,0x63,0x3f,0x66,0x41,0x6c,0x1d, -0x6f,0x73,0x65,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x4b,2, -0x61,0x30,0x65,0x4a,0x69,0x12,0x67,0x69,0x74,0x33,0x1c,0x73,0x68,0x70,0x75,0x6e, -0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x47,0x1a,0x63,0x69,0x6d,0x61,0x6c,0x6e, -0x75,0x6d,0x62,0x65,0x72,0x33,0,0x13,0x6e,0xc1,0xf,0x74,0x76,0x74,0x4c,0x76, -0x9a,0x77,0xa2,0x48,0x79,0xa2,0x49,0x7a,1,0x61,0x2c,0x68,0x12,0x61,0x69,0x6e, -0x8b,0x11,0x69,0x6e,0x85,2,0x61,0x36,0x65,0x3c,0x68,0x14,0x69,0x6e,0x79,0x65, -0x68,0xa3,0x66,1,0x68,0x71,0x77,0x73,1,0x68,0x28,0x74,0x10,0x68,0x77,0x16, -0x6d,0x61,0x72,0x62,0x75,0x74,0x61,0x74,0x13,0x67,0x6f,0x61,0x6c,0x3d,0x1a,0x65, -0x72,0x74,0x69,0x63,0x61,0x6c,0x74,0x61,0x69,0x6c,0xa3,0x67,0x11,0x61,0x77,0x79, -1,0x65,0x32,0x75,0x11,0x64,0x68,0x80,0x11,0x68,0x65,0x83,0x10,0x68,0x7a,1, -0x62,0x34,0x77,0x16,0x69,0x74,0x68,0x74,0x61,0x69,0x6c,0x7f,0x14,0x61,0x72,0x72, -0x65,0x65,0x7d,0x6e,0xa2,0x4c,0x70,0xa2,0x69,0x71,0xa2,0x69,0x72,0xa2,0x6f,0x73, -5,0x74,0x22,0x74,0x38,0x77,0x4c,0x79,0x16,0x72,0x69,0x61,0x63,0x77,0x61,0x77, -0x6f,0x18,0x72,0x61,0x69,0x67,0x68,0x74,0x77,0x61,0x77,0xa3,0x55,0x15,0x61,0x73, -0x68,0x6b,0x61,0x66,0x6d,0x61,0x2e,0x65,0x38,0x68,0x11,0x69,0x6e,0x6b,0x10,0x64, -0x62,0x11,0x68,0x65,0x65,1,0x65,0x2e,0x6d,0x13,0x6b,0x61,0x74,0x68,0x69,0x10, -0x6e,0x67,2,0x6f,0x2c,0x75,0x50,0x79,0x10,0x61,0x91,1,0x6a,0x28,0x6f,0x10, -0x6e,0x55,0x1a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x67,0x72,0x6f,0x75,0x70,0x21,0x10, -0x6e,0x57,0x10,0x65,0x59,0x10,0x61,1,0x66,0x5b,0x70,0x10,0x68,0x5d,1,0x65, -0x38,0x6f,0x18,0x68,0x69,0x6e,0x67,0x79,0x61,0x79,0x65,0x68,0x93,1,0x68,0x5f, -0x76,0x16,0x65,0x72,0x73,0x65,0x64,0x70,0x65,0x61,0x67,0xc1,0xc7,0x67,0xa4,0x52, -0x68,0xa4,0x59,0x6b,0xa4,0x99,0x6c,0xa4,0xb2,0x6d,2,0x61,0x2e,0x65,0xa4,0x3e, -0x69,0x10,0x6d,0x53,1,0x6c,0xa2,0xe7,0x6e,0x16,0x69,0x63,0x68,0x61,0x65,0x61, -0x6e,0,0x12,0x6e,0x76,0x73,0x51,0x73,0x3e,0x74,0x5c,0x77,0xa0,0x79,0xa2,0x42, -0x7a,0x13,0x61,0x79,0x69,0x6e,0xa3,0x54,0x10,0x61,1,0x64,0x2e,0x6d,0x12,0x65, -0x6b,0x68,0xa3,0x4c,0x11,0x68,0x65,0xa3,0x4b,3,0x61,0x38,0x65,0x3c,0x68,0x4a, -0x77,0x13,0x65,0x6e,0x74,0x79,0xa3,0x51,0x10,0x77,0xa3,0x4d,1,0x6e,0xa3,0x4e, -0x74,0x10,0x68,0xa3,0x4f,0x14,0x61,0x6d,0x65,0x64,0x68,0xa3,0x50,0x11,0x61,0x77, -0xa3,0x52,0x12,0x6f,0x64,0x68,0xa3,0x53,0x6e,0x3a,0x6f,0x40,0x70,0x46,0x71,0x4a, -0x72,0x12,0x65,0x73,0x68,0xa3,0x4a,0x11,0x75,0x6e,0xa3,0x46,0x11,0x6e,0x65,0xa3, -0x47,0x10,0x65,0xa3,0x48,0x12,0x6f,0x70,0x68,0xa3,0x49,0x67,0x33,0x67,0x38,0x68, -0x40,0x6b,0x5e,0x6c,0x66,0x6d,0x11,0x65,0x6d,0xa3,0x45,0x13,0x69,0x6d,0x65,0x6c, -0xa1,1,0x65,0x32,0x75,0x14,0x6e,0x64,0x72,0x65,0x64,0xa3,0x42,0x11,0x74,0x68, -0xa3,0x41,0x12,0x61,0x70,0x68,0xa3,0x43,0x14,0x61,0x6d,0x65,0x64,0x68,0xa3,0x44, -0x61,0x34,0x62,0x4a,0x64,0x50,0x66,0x12,0x69,0x76,0x65,0x9f,1,0x6c,0x2a,0x79, -0x11,0x69,0x6e,0x97,0x12,0x65,0x70,0x68,0x95,0x12,0x65,0x74,0x68,0x99,1,0x61, -0x30,0x68,0x14,0x61,0x6d,0x65,0x64,0x68,0x9d,0x13,0x6c,0x65,0x74,0x68,0x9b,0x15, -0x61,0x79,0x61,0x6c,0x61,0x6d,6,0x6e,0x2c,0x6e,0x34,0x72,0x5e,0x73,0x62,0x74, -0x11,0x74,0x61,0xa3,0x63,2,0x67,0x2e,0x6e,0x32,0x79,0x10,0x61,0xa3,0x60,0x10, -0x61,0xa3,0x5d,1,0x61,0xa3,0x5e,0x6e,0x10,0x61,0xa3,0x5f,0x10,0x61,0xa3,0x61, -0x11,0x73,0x61,0xa3,0x62,0x62,0x3c,0x6a,0x42,0x6c,0x10,0x6c,1,0x61,0xa3,0x5b, -0x6c,0x10,0x61,0xa3,0x5c,0x11,0x68,0x61,0xa3,0x59,0x10,0x61,0xa3,0x5a,0x11,0x65, -0x6d,0x51,0x10,0x61,1,0x66,0x37,0x6d,0x11,0x61,0x6c,0x39,1,0x61,0x40,0x65, -0x3e,1,0x68,0x28,0x74,0x10,0x68,0x45,0x40,0x13,0x67,0x6f,0x61,0x6c,0x43,2, -0x68,0x3b,0x6d,0x5c,0x6e,0x1a,0x69,0x66,0x69,0x72,0x6f,0x68,0x69,0x6e,0x67,0x79, -0x61,1,0x6b,0x2a,0x70,0x10,0x61,0xa3,0x65,0x15,0x69,0x6e,0x6e,0x61,0x79,0x61, -0xa3,0x64,0x1a,0x7a,0x61,0x6f,0x6e,0x68,0x65,0x68,0x67,0x6f,0x61,0x6c,0x3d,2, -0x61,0x3a,0x68,0x44,0x6e,0x17,0x6f,0x74,0x74,0x65,0x64,0x68,0x65,0x68,0x4b,1, -0x66,0x47,0x70,0x10,0x68,0x49,0x12,0x61,0x70,0x68,0x89,0x11,0x61,0x6d,0x4c,0x12, -0x61,0x64,0x68,0x4f,0x61,0x6e,0x62,0xa2,0x54,0x64,0xa2,0x70,0x65,0x31,0x66,2, -0x61,0x3e,0x65,0x4a,0x69,0x19,0x6e,0x61,0x6c,0x73,0x65,0x6d,0x6b,0x61,0x74,0x68, -0x35,0x15,0x72,0x73,0x69,0x79,0x65,0x68,0x8f,0x86,0x10,0x68,0x33,2,0x66,0x3c, -0x69,0x70,0x6c,1,0x61,0x28,0x65,0x10,0x66,0x27,0x11,0x70,0x68,0x25,0x14,0x72, -0x69,0x63,0x61,0x6e,2,0x66,0x30,0x6e,0x36,0x71,0x11,0x61,0x66,0xa3,0x58,0x11, -0x65,0x68,0xa3,0x56,0x12,0x6f,0x6f,0x6e,0xa3,0x57,0x10,0x6e,0x23,1,0x65,0x4a, -0x75,0x10,0x72,0x1f,0x75,0x73,0x68,0x61,0x73,0x6b,0x69,0x79,0x65,0x68,0x62,0x61, -0x72,0x72,0x65,0x65,0x8d,1,0x68,0x29,0x74,0x10,0x68,0x2b,0x11,0x61,0x6c,0x2c, -0x16,0x61,0x74,0x68,0x72,0x69,0x73,0x68,0x2f,7,0x6e,0x2e,0x6e,0x2c,0x72,0x3e, -0x74,0x56,0x75,0x21,0x18,0x6f,0x6e,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x21,0x28, -0x1a,0x69,0x67,0x68,0x74,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x29,0x2a,0x19,0x72, -0x61,0x6e,0x73,0x70,0x61,0x72,0x65,0x6e,0x74,0x2b,0x63,0x23,0x64,0x40,0x6a,0x56, -0x6c,0x26,0x19,0x65,0x66,0x74,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x27,0x24,0x19, -0x75,0x61,0x6c,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x25,0x19,0x6f,0x69,0x6e,0x63, -0x61,0x75,0x73,0x69,0x6e,0x67,0x23,0,0x13,0x6e,0xc0,0xd0,0x73,0x49,0x73,0x48, -0x75,0x78,0x77,0x84,0x78,0x9c,0x7a,0x10,0x77,0x58,1,0x6a,0x75,0x73,0x13,0x70, -0x61,0x63,0x65,0x59,4,0x61,0x51,0x67,0x53,0x70,0x28,0x75,0x30,0x79,0x57,0x54, -0x12,0x61,0x63,0x65,0x55,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x53,0x15,0x6e, -0x6b,0x6e,0x6f,0x77,0x6e,0x21,1,0x6a,0x5d,0x6f,0x17,0x72,0x64,0x6a,0x6f,0x69, -0x6e,0x65,0x72,0x5d,0x10,0x78,0x21,0x6e,0x60,0x6f,0xa2,0x41,0x70,0xa2,0x50,0x71, -0xa2,0x6e,0x72,1,0x65,0x24,0x69,0x6f,0x1e,0x67,0x69,0x6f,0x6e,0x61,0x6c,0x69, -0x6e,0x64,0x69,0x63,0x61,0x74,0x6f,0x72,0x6f,4,0x65,0x3e,0x6c,0x5b,0x6f,0x46, -0x73,0x45,0x75,0x46,0x14,0x6d,0x65,0x72,0x69,0x63,0x47,0x15,0x78,0x74,0x6c,0x69, -0x6e,0x65,0x5b,0x17,0x6e,0x73,0x74,0x61,0x72,0x74,0x65,0x72,0x45,0x10,0x70,0x48, -0x1c,0x65,0x6e,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x49,1, -0x6f,0x3e,0x72,0x4c,0x1a,0x65,0x66,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,0x69,0x63, -0x4d,0x4a,0x1b,0x73,0x74,0x66,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,0x69,0x63,0x4b, -0x10,0x75,0x4e,0x16,0x6f,0x74,0x61,0x74,0x69,0x6f,0x6e,0x4f,0x68,0x7b,0x68,0x50, -0x69,0x86,0x6a,0xa2,0x61,0x6c,0xa2,0x65,0x6d,0x1c,0x61,0x6e,0x64,0x61,0x74,0x6f, -0x72,0x79,0x62,0x72,0x65,0x61,0x6b,0x2d,4,0x32,0x5f,0x33,0x61,0x65,0x34,0x6c, -0x6d,0x79,0x3a,0x13,0x70,0x68,0x65,0x6e,0x3b,0x19,0x62,0x72,0x65,0x77,0x6c,0x65, -0x74,0x74,0x65,0x72,0x6d,2,0x64,0x28,0x6e,0x3c,0x73,0x41,0x3c,0x18,0x65,0x6f, -0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x3d,0x3e,1,0x66,0x3e,0x73,0x11,0x65,0x70, -1,0x61,0x22,0x65,0x14,0x72,0x61,0x62,0x6c,0x65,0x3f,0x18,0x69,0x78,0x6e,0x75, -0x6d,0x65,0x72,0x69,0x63,0x41,2,0x6c,0x63,0x74,0x65,0x76,0x67,1,0x66,0x43, -0x69,0x15,0x6e,0x65,0x66,0x65,0x65,0x64,0x43,0x61,0x40,0x62,0x70,0x63,0xa2,0x55, -0x65,0xa2,0xdb,0x67,0x10,0x6c,0x38,0x11,0x75,0x65,0x39,2,0x69,0x23,0x6c,0x34, -0x6d,0x16,0x62,0x69,0x67,0x75,0x6f,0x75,0x73,0x23,0x24,0x17,0x70,0x68,0x61,0x62, -0x65,0x74,0x69,0x63,0x25,4,0x32,0x27,0x61,0x29,0x62,0x2b,0x6b,0x2d,0x72,0x12, -0x65,0x61,0x6b,2,0x61,0x36,0x62,0x3e,0x73,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73, -0x57,0x13,0x66,0x74,0x65,0x72,0x29,1,0x65,0x2a,0x6f,0x11,0x74,0x68,0x27,0x13, -0x66,0x6f,0x72,0x65,0x2b,7,0x6d,0x51,0x6d,0x33,0x6f,0x28,0x70,0x69,0x72,0x35, -1,0x6d,0x76,0x6e,1,0x64,0x3c,0x74,0x1a,0x69,0x6e,0x67,0x65,0x6e,0x74,0x62, -0x72,0x65,0x61,0x6b,0x2f,0x15,0x69,0x74,0x69,0x6f,0x6e,0x61,0x1f,0x6c,0x6a,0x61, -0x70,0x61,0x6e,0x65,0x73,0x65,0x73,0x74,0x61,0x72,0x74,0x65,0x72,0x6b,1,0x62, -0x3a,0x70,0x19,0x6c,0x65,0x78,0x63,0x6f,0x6e,0x74,0x65,0x78,0x74,0x51,0x18,0x69, -0x6e,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x33,0x61,0x6a,0x62,0x2f,0x6a,0x6b,0x6c, -0x30,0x13,0x6f,0x73,0x65,0x70,1,0x61,0x38,0x75,0x18,0x6e,0x63,0x74,0x75,0x61, -0x74,0x69,0x6f,0x6e,0x31,0x18,0x72,0x65,0x6e,0x74,0x68,0x65,0x73,0x69,0x73,0x69, -0x1b,0x72,0x72,0x69,0x61,0x67,0x65,0x72,0x65,0x74,0x75,0x72,0x6e,0x35,2,0x62, -0x3e,0x6d,0x46,0x78,0x36,0x18,0x63,0x6c,0x61,0x6d,0x61,0x74,0x69,0x6f,0x6e,0x37, -0x70,0x12,0x61,0x73,0x65,0x71,0x72,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,0x72,0x73, -1,0x64,0x42,0x6e,1,0x6f,0x32,0x75,0x26,0x14,0x6d,0x65,0x72,0x69,0x63,0x27, -0x11,0x6e,0x65,0x21,1,0x65,0x2e,0x69,0x24,0x12,0x67,0x69,0x74,0x25,0x22,0x14, -0x63,0x69,0x6d,0x61,0x6c,0x23,0,0x18,0x6e,0xc4,0x6f,0x74,0xc1,0x91,0x77,0x96, -0x77,0xa2,0x4c,0x78,0xa2,0x70,0x79,0xa2,0x7a,0x7a,6,0x73,0x1e,0x73,0x34,0x78, -0x42,0x79,0x48,0x7a,0x11,0x7a,0x7a,0xa3,0x67,0x10,0x79,1,0x65,0xa3,0xae,0x6d, -0xa3,0x81,0x11,0x78,0x78,0xa3,0x66,0x11,0x79,0x79,0x21,0x61,0x30,0x69,0x58,0x6d, -0x11,0x74,0x68,0xa3,0x80,0x10,0x6e,1,0x61,0x26,0x62,0xa3,0xb1,0x1a,0x62,0x61, -0x7a,0x61,0x72,0x73,0x71,0x75,0x61,0x72,0x65,0xa3,0xb1,0x11,0x6e,0x68,0x23,2, -0x61,0x30,0x63,0x5a,0x6f,0x11,0x6c,0x65,0xa3,0x9b,1,0x6e,0x3c,0x72,0x10,0x61, -0xa2,0x92,0x15,0x6e,0x67,0x63,0x69,0x74,0x69,0xa3,0x92,0x12,0x63,0x68,0x6f,0xa3, -0xbc,0x11,0x68,0x6f,0xa3,0xbc,1,0x70,0x2c,0x73,0x11,0x75,0x78,0xa3,0x65,0x11, -0x65,0x6f,0x9b,1,0x65,0x2c,0x69,0x72,0x11,0x69,0x69,0x73,0x11,0x7a,0x69,0xa2, -0xc0,0x11,0x64,0x69,0xa3,0xc0,0x74,0x66,0x75,0xa2,0xde,0x76,1,0x61,0x48,0x69, -1,0x73,0x38,0x74,0x10,0x68,0xa2,0xc5,0x13,0x6b,0x75,0x71,0x69,0xa3,0xc5,0x10, -0x70,0xa3,0x64,0x10,0x69,0xa2,0x63,0x10,0x69,0xa3,0x63,7,0x68,0x3e,0x68,0x34, -0x69,0x48,0x6e,0x86,0x6f,0x11,0x74,0x6f,0xa3,0xc4,0x10,0x61,1,0x61,0x24,0x69, -0x6d,0x6a,0x11,0x6e,0x61,0x6b,2,0x62,0x3a,0x66,0x4a,0x72,0x10,0x68,0xa2,0x9e, -0x12,0x75,0x74,0x61,0xa3,0x9e,1,0x65,0x24,0x74,0x6f,0x12,0x74,0x61,0x6e,0x6f, -0x14,0x69,0x6e,0x61,0x67,0x68,0x99,0x11,0x73,0x61,0xa3,0xc3,0x61,0x36,0x65,0xa2, -0x65,0x66,0xa2,0x71,0x67,0x11,0x6c,0x67,0x75,6,0x6c,0x28,0x6c,0x32,0x6d,0x38, -0x6e,0x44,0x76,0x10,0x74,0xa3,0x7f,1,0x65,0x89,0x75,0x97,1,0x69,0x24,0x6c, -0x67,0x10,0x6c,0x67,0x10,0x67,0xa2,0x9a,1,0x73,0x2a,0x75,0x10,0x74,0xa3,0x9a, -0x10,0x61,0xa3,0xc3,0x67,0x36,0x69,0x52,0x6b,0x10,0x72,0xa2,0x99,0x10,0x69,0xa3, -0x99,1,0x61,0x30,0x62,0x7a,0x13,0x61,0x6e,0x77,0x61,0x7b,0x12,0x6c,0x6f,0x67, -0x75,2,0x6c,0x32,0x74,0x34,0x76,0x12,0x69,0x65,0x74,0xa3,0x7f,0x10,0x65,0x89, -0x12,0x68,0x61,0x6d,0xa3,0x6a,1,0x6c,0x2a,0x6e,0x10,0x67,0xa3,0x62,0x10,0x75, -0x68,0x11,0x67,0x75,0x69,0x11,0x6e,0x67,0x99,1,0x67,0x32,0x6e,0x14,0x6b,0x6e, -0x6f,0x77,0x6e,0xa3,0x67,0x11,0x61,0x72,0x8a,0x13,0x69,0x74,0x69,0x63,0x8b,0x71, -0xc1,0x13,0x71,0xa2,0xde,0x72,0xa2,0xe3,0x73,6,0x69,0x8a,0x69,0x72,0x6f,0xa2, -0x4c,0x75,0xa2,0x75,0x79,1,0x6c,0x46,0x72,4,0x63,0x65,0x65,0xa3,0x5f,0x69, -0x2c,0x6a,0xa3,0x60,0x6e,0xa3,0x61,0x11,0x61,0x63,0x65,0x10,0x6f,0x94,0x16,0x74, -0x69,0x6e,0x61,0x67,0x72,0x69,0x95,2,0x64,0x3c,0x67,0x4c,0x6e,1,0x64,0xa3, -0x91,0x68,0x62,0x12,0x61,0x6c,0x61,0x63,0x10,0x64,0xa2,0xa6,0x12,0x68,0x61,0x6d, -0xa3,0xa6,0x17,0x6e,0x77,0x72,0x69,0x74,0x69,0x6e,0x67,0xa3,0x70,2,0x67,0x3a, -0x72,0x52,0x79,0x10,0x6f,0xa2,0xb0,0x12,0x6d,0x62,0x6f,0xa3,0xb0,1,0x64,0x26, -0x6f,0xa3,0xb8,0xa2,0xb7,0x12,0x69,0x61,0x6e,0xa3,0xb7,0x10,0x61,0xa2,0x98,0x16, -0x73,0x6f,0x6d,0x70,0x65,0x6e,0x67,0xa3,0x98,0x11,0x6e,0x64,0xa2,0x71,0x14,0x61, -0x6e,0x65,0x73,0x65,0xa3,0x71,0x61,0x5c,0x67,0xa2,0x43,0x68,1,0x61,0x2a,0x72, -0x10,0x64,0xa3,0x97,2,0x72,0x28,0x76,0x30,0x77,0x87,0x12,0x61,0x64,0x61,0xa3, -0x97,0x12,0x69,0x61,0x6e,0x87,2,0x6d,0x40,0x72,0x58,0x75,0x10,0x72,0xa2,0x6f, -0x15,0x61,0x73,0x68,0x74,0x72,0x61,0xa3,0x6f,1,0x61,0x26,0x72,0xa3,0x7e,0x14, -0x72,0x69,0x74,0x61,0x6e,0xa3,0x7e,1,0x61,0xa3,0x5e,0x62,0xa3,0x85,0x11,0x6e, -0x77,0xa3,0x70,0x11,0x61,0x61,1,0x63,0x2f,0x69,0x23,3,0x65,0x3e,0x6a,0x48, -0x6f,0x4e,0x75,0x10,0x6e,1,0x69,0x24,0x72,0x61,0x10,0x63,0x61,0x13,0x6a,0x61, -0x6e,0x67,0xa3,0x6e,0x11,0x6e,0x67,0xa3,0x6e,1,0x68,0x2a,0x72,0x10,0x6f,0xa3, -0x5d,0x10,0x67,0xa3,0xb6,0x6e,0xa2,0x83,0x6f,0xa4,1,0x70,5,0x6c,0x1e,0x6c, -0x44,0x72,0x4a,0x73,0x1b,0x61,0x6c,0x74,0x65,0x72,0x70,0x61,0x68,0x6c,0x61,0x76, -0x69,0xa3,0x7b,0x11,0x72,0x64,0xa3,0x5c,0x11,0x74,0x69,0xa3,0x7d,0x61,0x7c,0x65, -0xa2,0x54,0x68,3,0x61,0x3e,0x6c,0x4e,0x6e,0x5e,0x6f,0x16,0x65,0x6e,0x69,0x63, -0x69,0x61,0x6e,0xa3,0x5b,0x10,0x67,0xa2,0x5a,0x12,0x73,0x70,0x61,0xa3,0x5a,2, -0x69,0xa3,0x7a,0x70,0xa3,0x7b,0x76,0xa3,0x7c,0x10,0x78,0xa3,0x5b,2,0x68,0x3e, -0x6c,0x50,0x75,0x10,0x63,0xa2,0xa5,0x14,0x69,0x6e,0x68,0x61,0x75,0xa3,0xa5,0x17, -0x61,0x77,0x68,0x68,0x6d,0x6f,0x6e,0x67,0xa3,0x4b,0x10,0x6d,0xa2,0x90,0x14,0x79, -0x72,0x65,0x6e,0x65,0xa3,0x90,0x11,0x72,0x6d,0xa3,0x59,6,0x6b,0x36,0x6b,0x56, -0x73,0x6e,0x75,0x74,0x79,0x11,0x69,0x61,0x1f,0x6b,0x65,0x6e,0x67,0x70,0x75,0x61, -0x63,0x68,0x75,0x65,0x68,0x6d,0x6f,0x6e,0x67,0xa3,0xba,1,0x67,0x2e,0x6f,0xa2, -0x57,0x10,0x6f,0xa3,0x57,0x10,0x62,0xa3,0x84,0x11,0x68,0x75,0xa3,0x96,0x12,0x73, -0x68,0x75,0xa3,0x96,0x61,0x42,0x62,0x9e,0x65,0x10,0x77,1,0x61,0xa3,0xaa,0x74, -0x14,0x61,0x69,0x6c,0x75,0x65,0x97,3,0x62,0x32,0x67,0x40,0x6e,0x56,0x72,0x10, -0x62,0xa3,0x8e,0x15,0x61,0x74,0x61,0x65,0x61,0x6e,0xa3,0x8f,0x10,0x6d,0xa2,0xc7, -0x15,0x75,0x6e,0x64,0x61,0x72,0x69,0xa3,0xc7,0x10,0x64,0xa2,0xbb,0x16,0x69,0x6e, -0x61,0x67,0x61,0x72,0x69,0xa3,0xbb,0x11,0x61,0x74,0xa3,0x8f,4,0x67,0x3c,0x6c, -0x4e,0x72,0xa2,0x8e,0x73,0xa2,0x9c,0x75,0x11,0x67,0x72,0xa3,0xc2,1,0x61,0x2a, -0x68,0x11,0x61,0x6d,0x5b,0x10,0x6d,0x5b,1,0x63,0xa2,0x6a,0x64,6,0x70,0x41, -0x70,0x3a,0x73,0x58,0x74,0x86,0x75,0x14,0x79,0x67,0x68,0x75,0x72,0xa3,0xc2,0x11, -0x65,0x72,1,0x6d,0x2c,0x73,0x12,0x69,0x61,0x6e,0x9b,0x11,0x69,0x63,0xa3,0x59, -0x10,0x6f,1,0x67,0x3a,0x75,0x18,0x74,0x68,0x61,0x72,0x61,0x62,0x69,0x61,0x6e, -0xa3,0x85,0x13,0x64,0x69,0x61,0x6e,0xa3,0xb8,0x14,0x75,0x72,0x6b,0x69,0x63,0xa3, -0x58,0x68,0x42,0x69,0x54,0x6e,0x1a,0x6f,0x72,0x74,0x68,0x61,0x72,0x61,0x62,0x69, -0x61,0x6e,0xa3,0x8e,0x17,0x75,0x6e,0x67,0x61,0x72,0x69,0x61,0x6e,0xa3,0x4c,0x14, -0x74,0x61,0x6c,0x69,0x63,0x5d,1,0x68,0x26,0x6b,0xa3,0x6d,0x12,0x69,0x6b,0x69, -0xa3,0x6d,2,0x69,0x2c,0x6b,0x30,0x79,0x10,0x61,0x5f,0x11,0x79,0x61,0x5f,0x10, -0x68,0xa3,0x58,2,0x61,0x36,0x67,0x3c,0x6d,0x10,0x61,0x84,0x12,0x6e,0x79,0x61, -0x85,0x11,0x67,0x65,0xa3,0xab,0x10,0x65,0xa3,0xab,0x68,0xc3,0x15,0x6b,0xc2,0x2c, -0x6b,0xa4,0x17,0x6c,0xa4,0xba,0x6d,8,0x6f,0x46,0x6f,0x48,0x72,0x74,0x74,0x80, -0x75,0x86,0x79,1,0x61,0x28,0x6d,0x10,0x72,0x59,0x13,0x6e,0x6d,0x61,0x72,0x59, -2,0x64,0x2e,0x6e,0x32,0x6f,0x10,0x6e,0xa3,0x72,0x10,0x69,0xa3,0xa3,0x10,0x67, -0x56,0x14,0x6f,0x6c,0x69,0x61,0x6e,0x57,0x10,0x6f,0xa2,0x95,0x10,0x6f,0xa3,0x95, -0x11,0x65,0x69,0xa3,0x73,0x11,0x6c,0x74,0xa2,0xa4,0x12,0x61,0x6e,0x69,0xa3,0xa4, -0x61,0x36,0x65,0xa2,0x67,0x69,0xa2,0xbd,0x6c,0x11,0x79,0x6d,0x55,6,0x6e,0x38, -0x6e,0x32,0x72,0x5c,0x73,0x6c,0x79,0x10,0x61,0xa3,0x55,1,0x64,0x38,0x69,0xa2, -0x79,0x15,0x63,0x68,0x61,0x65,0x61,0x6e,0xa3,0x79,0xa2,0x54,0x12,0x61,0x69,0x63, -0xa3,0x54,0x10,0x63,0xa2,0xa9,0x12,0x68,0x65,0x6e,0xa3,0xa9,0x18,0x61,0x72,0x61, -0x6d,0x67,0x6f,0x6e,0x64,0x69,0xa3,0xaf,0x68,0x36,0x6b,0x4c,0x6c,0x15,0x61,0x79, -0x61,0x6c,0x61,0x6d,0x55,1,0x61,0x26,0x6a,0xa3,0xa0,0x13,0x6a,0x61,0x6e,0x69, -0xa3,0xa0,0x10,0x61,0xa2,0xb4,0x12,0x73,0x61,0x72,0xa3,0xb4,3,0x64,0x78,0x65, -0x94,0x6e,0xa2,0x42,0x72,1,0x63,0xa3,0x8d,0x6f,0xa2,0x56,0x13,0x69,0x74,0x69, -0x63,1,0x63,0x3c,0x68,0x19,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73, -0xa3,0x56,0x15,0x75,0x72,0x73,0x69,0x76,0x65,0xa3,0x8d,1,0x65,0x26,0x66,0xa3, -0xb5,0x16,0x66,0x61,0x69,0x64,0x72,0x69,0x6e,0xa3,0xb5,0x17,0x74,0x65,0x69,0x6d, -0x61,0x79,0x65,0x6b,0xa3,0x73,0x10,0x64,0xa2,0x8c,0x17,0x65,0x6b,0x69,0x6b,0x61, -0x6b,0x75,0x69,0xa3,0x8c,0x11,0x61,0x6f,0xa3,0x5c,6,0x6e,0x1a,0x6e,0x34,0x6f, -0x38,0x70,0x3e,0x74,0x11,0x68,0x69,0xa3,0x78,0x11,0x64,0x61,0x4b,0x11,0x72,0x65, -0xa3,0x77,0x11,0x65,0x6c,0xa3,0x8a,0x61,0x32,0x68,0xa2,0x44,0x69,0x11,0x74,0x73, -0xa3,0xbf,5,0x74,0x23,0x74,0x34,0x77,0x56,0x79,0x13,0x61,0x68,0x6c,0x69,0xa3, -0x4f,0x14,0x61,0x6b,0x61,0x6e,0x61,0x4c,0x19,0x6f,0x72,0x68,0x69,0x72,0x61,0x67, -0x61,0x6e,0x61,0x8d,0x10,0x69,0xa3,0xc6,0x69,0x38,0x6c,0x40,0x6e,1,0x61,0x4d, -0x6e,0x12,0x61,0x64,0x61,0x4b,0x12,0x74,0x68,0x69,0xa3,0x78,0x10,0x69,0xa3,0x4f, -4,0x61,0x40,0x69,0x52,0x6d,0x70,0x6f,0x7c,0x75,0x15,0x64,0x61,0x77,0x61,0x64, -0x69,0xa3,0x91,0x10,0x72,0x92,0x15,0x6f,0x73,0x68,0x74,0x68,0x69,0x93,0x1d,0x74, -0x61,0x6e,0x73,0x6d,0x61,0x6c,0x6c,0x73,0x63,0x72,0x69,0x70,0x74,0xa3,0xbf,1, -0x65,0x24,0x72,0x4f,0x10,0x72,0x4f,0x10,0x6a,0xa2,0x9d,0x11,0x6b,0x69,0xa3,0x9d, -4,0x61,0x5c,0x65,0x90,0x69,0xa0,0x6f,0xa2,0x5d,0x79,1,0x63,0x34,0x64,0x10, -0x69,0xa2,0x6c,0x11,0x61,0x6e,0xa3,0x6c,0x10,0x69,0xa2,0x6b,0x11,0x61,0x6e,0xa3, -0x6b,2,0x6e,0x42,0x6f,0x46,0x74,3,0x66,0xa3,0x50,0x67,0xa3,0x51,0x69,0x24, -0x6e,0x53,0x10,0x6e,0x53,0x10,0x61,0xa3,0x6a,0x50,0x10,0x6f,0x51,0x11,0x70,0x63, -0xa2,0x52,0x11,0x68,0x61,0xa3,0x52,2,0x6d,0x2e,0x6e,0x36,0x73,0x10,0x75,0xa3, -0x83,0x10,0x62,0x80,0x10,0x75,0x81,2,0x61,0xa3,0x53,0x62,0x83,0x65,0x11,0x61, -0x72,1,0x61,0xa3,0x53,0x62,0x83,0x11,0x6d,0x61,0xa3,0x8b,0x68,0x6e,0x69,0xa2, -0x95,0x6a,2,0x61,0x30,0x70,0x52,0x75,0x11,0x72,0x63,0xa3,0x94,1,0x6d,0x38, -0x76,0x10,0x61,0xa2,0x4e,0x13,0x6e,0x65,0x73,0x65,0xa3,0x4e,0x10,0x6f,0xa3,0xad, -0x11,0x61,0x6e,0xa3,0x69,6,0x6c,0x1e,0x6c,0x34,0x6d,0x3a,0x72,0x48,0x75,0x11, -0x6e,0x67,0xa3,0x4c,0x11,0x75,0x77,0xa3,0x9c,0x10,0x6e,1,0x67,0xa3,0x4b,0x70, -0xa3,0xba,0x11,0x6b,0x74,0x8d,0x61,0x3c,0x65,0xa2,0x43,0x69,0x11,0x72,0x61,0x48, -0x13,0x67,0x61,0x6e,0x61,0x49,1,0x6e,0x34,0x74,0x10,0x72,0xa2,0xa2,0x11,0x61, -0x6e,0xa3,0xa2,0x42,6,0x6f,0xe,0x6f,0x77,0x73,0xa3,0x49,0x74,0xa3,0x4a,0x75, -0x12,0x6e,0x6f,0x6f,0x77,0x62,0xa3,0xac,0x67,0x3e,0x69,0x42,0x19,0x66,0x69,0x72, -0x6f,0x68,0x69,0x6e,0x67,0x79,0x61,0xa3,0xb6,0x44,0x11,0x75,0x6c,0x45,0x11,0x62, -0x72,0x46,0x11,0x65,0x77,0x47,2,0x6d,0x2e,0x6e,0x4a,0x74,0x11,0x61,0x6c,0x5d, -0x1c,0x70,0x65,0x72,0x69,0x61,0x6c,0x61,0x72,0x61,0x6d,0x61,0x69,0x63,0xa3,0x74, -2,0x64,0x66,0x68,0x6a,0x73,0x1b,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x61, -0x6c,0x70,0x61,1,0x68,0x32,0x72,0x14,0x74,0x68,0x69,0x61,0x6e,0xa3,0x7d,0x13, -0x6c,0x61,0x76,0x69,0xa3,0x7a,0x10,0x73,0xa3,0x4d,0x15,0x65,0x72,0x69,0x74,0x65, -0x64,0x23,0x64,0xc1,0xd,0x64,0xa2,0x7a,0x65,0xa2,0xc1,0x67,4,0x65,0x82,0x6c, -0x9a,0x6f,0xa2,0x46,0x72,0xa2,0x55,0x75,2,0x6a,0x3c,0x6e,0x4e,0x72,1,0x6d, -0x24,0x75,0x41,0x13,0x75,0x6b,0x68,0x69,0x41,1,0x61,0x24,0x72,0x3f,0x13,0x72, -0x61,0x74,0x69,0x3f,0x18,0x6a,0x61,0x6c,0x61,0x67,0x6f,0x6e,0x64,0x69,0xa3,0xb3, -0x10,0x6f,1,0x6b,0xa3,0x48,0x72,0x38,0x13,0x67,0x69,0x61,0x6e,0x39,0x11,0x61, -0x67,0x90,0x15,0x6f,0x6c,0x69,0x74,0x69,0x63,0x91,1,0x6e,0x30,0x74,0x10,0x68, -0x3a,0x11,0x69,0x63,0x3b,1,0x67,0xa3,0xb3,0x6d,0xa3,0xaf,1,0x61,0x32,0x65, -1,0x65,0x24,0x6b,0x3d,0x10,0x6b,0x3d,0x10,0x6e,0xa2,0x89,0x12,0x74,0x68,0x61, -0xa3,0x89,4,0x65,0x46,0x69,0x6c,0x6f,0x8c,0x73,0x9a,0x75,0x11,0x70,0x6c,0xa2, -0x87,0x13,0x6f,0x79,0x61,0x6e,0xa3,0x87,1,0x73,0x38,0x76,0x10,0x61,0x34,0x15, -0x6e,0x61,0x67,0x61,0x72,0x69,0x35,0x13,0x65,0x72,0x65,0x74,0x33,1,0x61,0x36, -0x76,0x16,0x65,0x73,0x61,0x6b,0x75,0x72,0x75,0xa3,0xbe,0x10,0x6b,0xa3,0xbe,0x11, -0x67,0x72,0xa2,0xb2,0x10,0x61,0xa3,0xb2,0x11,0x72,0x74,0x33,2,0x67,0x3a,0x6c, -0x72,0x74,0x11,0x68,0x69,0x36,0x13,0x6f,0x70,0x69,0x63,0x37,0x10,0x79,2,0x64, -0xa3,0x45,0x68,0xa3,0x46,0x70,0xa2,0x47,0x1e,0x74,0x69,0x61,0x6e,0x68,0x69,0x65, -0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0x47,1,0x62,0x36,0x79,0x10,0x6d, -0xa2,0xb9,0x12,0x61,0x69,0x63,0xa3,0xb9,0x10,0x61,0xa2,0x88,0x12,0x73,0x61,0x6e, -0xa3,0x88,0x61,0xa2,0xc9,0x62,0xa4,0x2e,0x63,6,0x6f,0x52,0x6f,0x76,0x70,0x92, -0x75,0xa2,0x41,0x79,1,0x70,0x3e,0x72,2,0x69,0x2a,0x6c,0x31,0x73,0xa3,0x44, -0x13,0x6c,0x6c,0x69,0x63,0x31,0x10,0x72,1,0x69,0x34,0x6f,0x15,0x6d,0x69,0x6e, -0x6f,0x61,0x6e,0xa3,0xc1,0x11,0x6f,0x74,0x7f,1,0x6d,0x30,0x70,0x10,0x74,0x2e, -0x11,0x69,0x63,0x2f,0x12,0x6d,0x6f,0x6e,0x21,1,0x6d,0x28,0x72,0x10,0x74,0x7f, -0x10,0x6e,0xa3,0xc1,0x16,0x6e,0x65,0x69,0x66,0x6f,0x72,0x6d,0xa3,0x65,0x61,0x32, -0x68,0xa2,0x41,0x69,0x11,0x72,0x74,0xa3,0x43,3,0x6b,0x4c,0x6e,0x50,0x72,0x76, -0x75,0x1d,0x63,0x61,0x73,0x69,0x61,0x6e,0x61,0x6c,0x62,0x61,0x6e,0x69,0x61,0x6e, -0xa3,0x9f,0x10,0x6d,0xa3,0x76,1,0x61,0x24,0x73,0x71,0x1d,0x64,0x69,0x61,0x6e, -0x61,0x62,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x71,0x10,0x69,0xa2,0x68,0x11, -0x61,0x6e,0xa3,0x68,3,0x61,0x32,0x65,0x44,0x6f,0x52,0x72,0x10,0x73,0xa3,0xbd, -1,0x6b,0x26,0x6d,0xa3,0x42,0x11,0x6d,0x61,0xa3,0x76,0x10,0x72,0x2c,0x13,0x6f, -0x6b,0x65,0x65,0x2d,0x16,0x72,0x61,0x73,0x6d,0x69,0x61,0x6e,0xa3,0xbd,6,0x68, -0x4a,0x68,0x48,0x6e,0x4e,0x72,0x76,0x76,1,0x65,0x2a,0x73,0x10,0x74,0xa3,0x75, -0x13,0x73,0x74,0x61,0x6e,0xa3,0x75,0x11,0x6f,0x6d,0xa3,0xa1,0x11,0x61,0x74,0x1f, -0x6f,0x6c,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73, -0xa3,0x9c,1,0x61,0x3e,0x6d,2,0x65,0x2a,0x69,0xa3,0x74,0x6e,0x27,0x13,0x6e, -0x69,0x61,0x6e,0x27,0x10,0x62,0x24,0x11,0x69,0x63,0x25,0x64,0x30,0x66,0x44,0x67, -0x11,0x68,0x62,0xa3,0x9f,0x10,0x6c,1,0x61,0x26,0x6d,0xa3,0xa7,0x10,0x6d,0xa3, -0xa7,0x11,0x61,0x6b,0xa3,0x93,6,0x6c,0x3c,0x6c,0x52,0x6f,0x56,0x72,0x66,0x75, -1,0x67,0x30,0x68,1,0x64,0x79,0x69,0x10,0x64,0x79,0x10,0x69,0x8e,0x13,0x6e, -0x65,0x73,0x65,0x8f,0x11,0x69,0x73,0xa1,0x11,0x70,0x6f,0x2a,0x13,0x6d,0x6f,0x66, -0x6f,0x2b,0x10,0x61,1,0x68,0x2e,0x69,0x7c,0x12,0x6c,0x6c,0x65,0x7d,0xa2,0x41, -0x11,0x6d,0x69,0xa3,0x41,0x61,0x48,0x65,0x9c,0x68,1,0x61,0x2a,0x6b,0x10,0x73, -0xa3,0xa8,0x15,0x69,0x6b,0x73,0x75,0x6b,0x69,0xa3,0xa8,3,0x6c,0x3a,0x6d,0x48, -0x73,0x54,0x74,1,0x61,0x24,0x6b,0x9f,0x10,0x6b,0x9f,0x10,0x69,0x9c,0x13,0x6e, -0x65,0x73,0x65,0x9d,0x10,0x75,0xa2,0x82,0x10,0x6d,0xa3,0x82,0x10,0x73,0xa2,0x86, -0x13,0x61,0x76,0x61,0x68,0xa3,0x86,0x11,0x6e,0x67,0x28,0x12,0x61,0x6c,0x69,0x29, -3,0x6c,0x42,0x6e,0x90,0x74,0xa2,0x46,0x76,0x24,0x17,0x6f,0x77,0x65,0x6c,0x6a, -0x61,0x6d,0x6f,0x25,0x22,1,0x65,0x54,0x76,0x28,1,0x73,0x38,0x74,0x2a,0x17, -0x73,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x2b,0x16,0x79,0x6c,0x6c,0x61,0x62,0x6c, -0x65,0x29,0x18,0x61,0x64,0x69,0x6e,0x67,0x6a,0x61,0x6d,0x6f,0x23,1,0x61,0x21, -0x6f,0x1a,0x74,0x61,0x70,0x70,0x6c,0x69,0x63,0x61,0x62,0x6c,0x65,0x21,0x26,0x1a, -0x72,0x61,0x69,0x6c,0x69,0x6e,0x67,0x6a,0x61,0x6d,0x6f,0x27,1,0x6e,0x2c,0x79, -0x22,0x11,0x65,0x73,0x23,0x20,0x10,0x6f,0x21,1,0x6e,0x2c,0x79,0x22,0x11,0x65, -0x73,0x23,0x20,0x10,0x6f,0x21,2,0x6d,0x30,0x6e,0x3a,0x79,0x22,0x11,0x65,0x73, -0x23,0x24,0x13,0x61,0x79,0x62,0x65,0x25,0x20,0x10,0x6f,0x21,2,0x6d,0x30,0x6e, -0x3a,0x79,0x22,0x11,0x65,0x73,0x23,0x24,0x13,0x61,0x79,0x62,0x65,0x25,0x20,0x10, -0x6f,0x21,0xb,0x72,0x39,0x76,0xc,0x76,0x33,0x78,0x2a,0x7a,0x11,0x77,0x6a,0x43, -0x10,0x78,0x21,0x72,0x28,0x73,0x50,0x74,0x31,1,0x65,0x24,0x69,0x39,0x1e,0x67, -0x69,0x6f,0x6e,0x61,0x6c,0x69,0x6e,0x64,0x69,0x63,0x61,0x74,0x6f,0x72,0x39,1, -0x6d,0x35,0x70,0x18,0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x35,0x6c,0x1f, -0x6c,0x3c,0x6f,0x4a,0x70,1,0x70,0x37,0x72,0x14,0x65,0x70,0x65,0x6e,0x64,0x37, -0x28,1,0x66,0x2b,0x76,0x2c,0x10,0x74,0x2f,0x13,0x74,0x68,0x65,0x72,0x21,0x63, -0x4c,0x65,0x64,0x67,1,0x61,0x3a,0x6c,0x19,0x75,0x65,0x61,0x66,0x74,0x65,0x72, -0x7a,0x77,0x6a,0x41,0x10,0x7a,0x41,2,0x6e,0x23,0x6f,0x24,0x72,0x25,0x14,0x6e, -0x74,0x72,0x6f,0x6c,0x23,2,0x62,0x34,0x6d,0x4e,0x78,0x26,0x13,0x74,0x65,0x6e, -0x64,0x27,0x3a,1,0x61,0x24,0x67,0x3d,0x11,0x73,0x65,0x3a,0x12,0x67,0x61,0x7a, -0x3d,0x3e,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,0x72,0x3f,9,0x6e,0x4a,0x6e,0x34, -0x6f,0x44,0x73,0x60,0x75,0x94,0x78,0x10,0x78,0x21,0x10,0x75,0x2a,0x14,0x6d,0x65, -0x72,0x69,0x63,0x2b,1,0x6c,0x2c,0x74,0x12,0x68,0x65,0x72,0x21,0x14,0x65,0x74, -0x74,0x65,0x72,0x2d,3,0x63,0x36,0x65,0x46,0x70,0x31,0x74,0x32,0x12,0x65,0x72, -0x6d,0x33,0x3c,0x16,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3d,0x2e,0x10,0x70,0x2f, -0x10,0x70,0x34,0x12,0x70,0x65,0x72,0x35,0x61,0x46,0x63,0x52,0x65,0x64,0x66,0x72, -0x6c,2,0x65,0x2d,0x66,0x3b,0x6f,0x28,0x12,0x77,0x65,0x72,0x29,0x10,0x74,0x22, -0x12,0x65,0x72,0x6d,0x23,1,0x6c,0x24,0x72,0x37,0x24,0x12,0x6f,0x73,0x65,0x25, -0x10,0x78,0x38,0x13,0x74,0x65,0x6e,0x64,0x39,0x10,0x6f,0x26,0x13,0x72,0x6d,0x61, -0x74,0x27,0,0x10,0x6c,0x88,0x72,0x40,0x72,0x36,0x73,0x5e,0x77,0x7a,0x78,0x8a, -0x7a,0x11,0x77,0x6a,0x4b,1,0x65,0x24,0x69,0x3b,0x1e,0x67,0x69,0x6f,0x6e,0x61, -0x6c,0x69,0x6e,0x64,0x69,0x63,0x61,0x74,0x6f,0x72,0x3b,1,0x69,0x24,0x71,0x3f, -0x18,0x6e,0x67,0x6c,0x65,0x71,0x75,0x6f,0x74,0x65,0x3f,0x17,0x73,0x65,0x67,0x73, -0x70,0x61,0x63,0x65,0x4d,0x10,0x78,0x21,0x6c,0x36,0x6d,0x3c,0x6e,0x76,0x6f,0x13, -0x74,0x68,0x65,0x72,0x21,1,0x65,0x23,0x66,0x35,3,0x62,0x37,0x69,0x28,0x6c, -0x29,0x6e,0x2b,0x10,0x64,1,0x6c,0x34,0x6e,0x11,0x75,0x6d,0x2a,0x12,0x6c,0x65, -0x74,0x37,0x14,0x65,0x74,0x74,0x65,0x72,0x29,2,0x65,0x36,0x6c,0x39,0x75,0x2c, -0x14,0x6d,0x65,0x72,0x69,0x63,0x2d,0x14,0x77,0x6c,0x69,0x6e,0x65,0x39,0x66,0x3f, -0x66,0x40,0x67,0x4e,0x68,0x70,0x6b,0x10,0x61,0x26,0x15,0x74,0x61,0x6b,0x61,0x6e, -0x61,0x27,0x10,0x6f,0x24,0x13,0x72,0x6d,0x61,0x74,0x25,1,0x61,0x3a,0x6c,0x19, -0x75,0x65,0x61,0x66,0x74,0x65,0x72,0x7a,0x77,0x6a,0x49,0x10,0x7a,0x49,1,0x65, -0x24,0x6c,0x3d,0x19,0x62,0x72,0x65,0x77,0x6c,0x65,0x74,0x74,0x65,0x72,0x3d,0x61, -0x86,0x63,0x92,0x64,0x94,0x65,2,0x62,0x44,0x6d,0x5e,0x78,0x2e,0x13,0x74,0x65, -0x6e,0x64,0x32,0x15,0x6e,0x75,0x6d,0x6c,0x65,0x74,0x2f,0x42,1,0x61,0x24,0x67, -0x45,0x11,0x73,0x65,0x42,0x12,0x67,0x61,0x7a,0x45,0x46,0x16,0x6f,0x64,0x69,0x66, -0x69,0x65,0x72,0x47,0x15,0x6c,0x65,0x74,0x74,0x65,0x72,0x23,0x10,0x72,0x31,1, -0x6f,0x24,0x71,0x41,0x18,0x75,0x62,0x6c,0x65,0x71,0x75,0x6f,0x74,0x65,0x41,2, -0x63,0x32,0x6e,0x3c,0x6f,0x22,0x12,0x70,0x65,0x6e,0x23,0x24,0x13,0x6c,0x6f,0x73, -0x65,0x25,0x20,0x12,0x6f,0x6e,0x65,0x21,6,0x6f,0x65,0x6f,0x4a,0x72,0x5c,0x74, -0x64,0x76,0x1d,0x69,0x73,0x75,0x61,0x6c,0x6f,0x72,0x64,0x65,0x72,0x6c,0x65,0x66, -0x74,0x3d,0x18,0x76,0x65,0x72,0x73,0x74,0x72,0x75,0x63,0x6b,0x2d,0x13,0x69,0x67, -0x68,0x74,0x2f,0x11,0x6f,0x70,0x30,0x12,0x61,0x6e,0x64,2,0x62,0x32,0x6c,0x62, -0x72,0x13,0x69,0x67,0x68,0x74,0x3b,0x14,0x6f,0x74,0x74,0x6f,0x6d,0x32,0x12,0x61, -0x6e,0x64,1,0x6c,0x2e,0x72,0x13,0x69,0x67,0x68,0x74,0x35,0x12,0x65,0x66,0x74, -0x3f,0x12,0x65,0x66,0x74,0x36,0x17,0x61,0x6e,0x64,0x72,0x69,0x67,0x68,0x74,0x39, -0x62,0x2c,0x6c,0x5c,0x6e,0x10,0x61,0x21,0x14,0x6f,0x74,0x74,0x6f,0x6d,0x22,0x12, -0x61,0x6e,0x64,1,0x6c,0x2e,0x72,0x13,0x69,0x67,0x68,0x74,0x27,0x12,0x65,0x66, -0x74,0x25,0x12,0x65,0x66,0x74,0x28,0x17,0x61,0x6e,0x64,0x72,0x69,0x67,0x68,0x74, -0x2b,0xd,0x6e,0xaa,0x72,0x70,0x72,0x92,0x73,0xa2,0x46,0x74,0xa2,0x54,0x76,1, -0x69,0x60,0x6f,0x12,0x77,0x65,0x6c,0x62,1,0x64,0x3a,0x69,0x19,0x6e,0x64,0x65, -0x70,0x65,0x6e,0x64,0x65,0x6e,0x74,0x67,0x17,0x65,0x70,0x65,0x6e,0x64,0x65,0x6e, -0x74,0x65,1,0x72,0x2e,0x73,0x13,0x61,0x72,0x67,0x61,0x61,0x12,0x61,0x6d,0x61, -0x5f,0x1d,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x68,0x69,0x66,0x74,0x65,0x72, -0x57,0x1e,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x6d,0x6f,0x64,0x69,0x66,0x69,0x65, -0x72,0x59,0x12,0x6f,0x6e,0x65,1,0x6c,0x2c,0x6d,0x12,0x61,0x72,0x6b,0x5d,0x14, -0x65,0x74,0x74,0x65,0x72,0x5b,0x6e,0x3c,0x6f,0x7c,0x70,0x18,0x75,0x72,0x65,0x6b, -0x69,0x6c,0x6c,0x65,0x72,0x55,1,0x6f,0x4c,0x75,1,0x6b,0x3c,0x6d,0x12,0x62, -0x65,0x72,0x50,0x15,0x6a,0x6f,0x69,0x6e,0x65,0x72,0x53,0x11,0x74,0x61,0x4f,0x16, -0x6e,0x6a,0x6f,0x69,0x6e,0x65,0x72,0x4d,0x13,0x74,0x68,0x65,0x72,0x21,0x67,0x3e, -0x67,0x4a,0x69,0x64,0x6a,0x82,0x6d,0x1d,0x6f,0x64,0x69,0x66,0x79,0x69,0x6e,0x67, -0x6c,0x65,0x74,0x74,0x65,0x72,0x4b,0x1c,0x65,0x6d,0x69,0x6e,0x61,0x74,0x69,0x6f, -0x6e,0x6d,0x61,0x72,0x6b,0x45,0x1e,0x6e,0x76,0x69,0x73,0x69,0x62,0x6c,0x65,0x73, -0x74,0x61,0x63,0x6b,0x65,0x72,0x47,0x14,0x6f,0x69,0x6e,0x65,0x72,0x49,0x61,0xa2, -0xba,0x62,0xa2,0xc0,0x63,1,0x61,0xa2,0xa2,0x6f,0x16,0x6e,0x73,0x6f,0x6e,0x61, -0x6e,0x74,0x2a,8,0x6b,0x67,0x6b,0x48,0x6d,0x52,0x70,0x5c,0x73,0xa2,0x42,0x77, -0x19,0x69,0x74,0x68,0x73,0x74,0x61,0x63,0x6b,0x65,0x72,0x43,0x14,0x69,0x6c,0x6c, -0x65,0x72,0x35,0x14,0x65,0x64,0x69,0x61,0x6c,0x37,1,0x6c,0x52,0x72,0x10,0x65, -1,0x63,0x2e,0x66,0x13,0x69,0x78,0x65,0x64,0x3d,0x19,0x65,0x64,0x69,0x6e,0x67, -0x72,0x65,0x70,0x68,0x61,0x3b,0x18,0x61,0x63,0x65,0x68,0x6f,0x6c,0x64,0x65,0x72, -0x39,0x10,0x75,1,0x62,0x3e,0x63,0x1b,0x63,0x65,0x65,0x64,0x69,0x6e,0x67,0x72, -0x65,0x70,0x68,0x61,0x41,0x15,0x6a,0x6f,0x69,0x6e,0x65,0x64,0x3f,0x64,0x4c,0x66, -0x52,0x68,0x5a,0x69,0x1e,0x6e,0x69,0x74,0x69,0x61,0x6c,0x70,0x6f,0x73,0x74,0x66, -0x69,0x78,0x65,0x64,0x33,0x12,0x65,0x61,0x64,0x2d,0x13,0x69,0x6e,0x61,0x6c,0x2f, -0x18,0x65,0x61,0x64,0x6c,0x65,0x74,0x74,0x65,0x72,0x31,0x1d,0x6e,0x74,0x69,0x6c, -0x6c,0x61,0x74,0x69,0x6f,0x6e,0x6d,0x61,0x72,0x6b,0x29,0x16,0x76,0x61,0x67,0x72, -0x61,0x68,0x61,0x23,1,0x69,0x4a,0x72,0x10,0x61,0x1f,0x68,0x6d,0x69,0x6a,0x6f, -0x69,0x6e,0x69,0x6e,0x67,0x6e,0x75,0x6d,0x62,0x65,0x72,0x27,0x12,0x6e,0x64,0x75, -0x25,2,0x72,0x38,0x74,0x46,0x75,0x26,0x15,0x70,0x72,0x69,0x67,0x68,0x74,0x27, -0x20,0x15,0x6f,0x74,0x61,0x74,0x65,0x64,0x21,1,0x72,0x24,0x75,0x25,0x22,0x18, -0x61,0x6e,0x73,0x66,0x6f,0x72,0x6d,0x65,0x64,1,0x72,0x32,0x75,0x15,0x70,0x72, -0x69,0x67,0x68,0x74,0x25,0x15,0x6f,0x74,0x61,0x74,0x65,0x64,0x23,0xd,0x6e,0xc1, -0x86,0x73,0xa8,0x73,0x4c,0x74,0xa2,0x76,0x75,0xa2,0x83,0x7a,0xd8,0x70,0,2, -0x6c,0xd9,0x20,0,0x70,0xd9,0x40,0,0x73,0xc3,0,0xfe,0xf,0,0,0, -7,0x6f,0x3c,0x6f,0xff,8,0,0,0,0x70,0x3a,0x75,0x6e,0x79,0x13,0x6d, -0x62,0x6f,0x6c,0xff,0xf,0,0,0,0x11,0x61,0x63,1,0x65,0x34,0x69,0x15, -0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa5,0,0x18,0x73,0x65,0x70,0x61,0x72,0x61,0x74, -0x6f,0x72,0xc3,0,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0xe1,0,0,0x63, -0xff,2,0,0,0,0x65,0x38,0x6b,0xff,4,0,0,0,0x6d,0xff,1, -0,0,0,0x16,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,0x70,0,0x1d,0x69, -0x74,0x6c,0x65,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x31,1,0x6e, -0x40,0x70,0x1c,0x70,0x65,0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72, -0x25,0x17,0x61,0x73,0x73,0x69,0x67,0x6e,0x65,0x64,0x23,0x6e,0xa2,0x69,0x6f,0xa2, -0x89,0x70,0xfe,0x30,0xf8,0,0,9,0x69,0x33,0x69,0xff,0x10,0,0,0, -0x6f,0xfd,0x80,0,0,0x72,0x54,0x73,0xf9,0,0,0x75,0x12,0x6e,0x63,0x74, -0xfe,0x30,0xf8,0,0,0x15,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff,0x30,0xf8,0, -0,0x17,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0xdd,0,0,0x61,0x48,0x63, -0xfd,0x40,0,0,0x64,0xe9,0,0,0x65,0xfd,0x20,0,0,0x66,0xff,0x20, -0,0,0,0x1f,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x70,0x61,0x72, -0x61,0x74,0x6f,0x72,0xd9,0x40,0,0xbe,0,3,0x64,0xa7,0,0x6c,0xab,0, -0x6f,0x30,0x75,0x13,0x6d,0x62,0x65,0x72,0xbf,0,0xb2,0,0x1b,0x6e,0x73,0x70, -0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa1,1,0x70,0x92,0x74,0x12,0x68, -0x65,0x72,0xe6,0x80,1,3,0x6c,0x40,0x6e,0x4a,0x70,0x56,0x73,0x14,0x79,0x6d, -0x62,0x6f,0x6c,0xff,8,0,0,0,0x14,0x65,0x74,0x74,0x65,0x72,0x61,0x14, -0x75,0x6d,0x62,0x65,0x72,0xb3,0,0x19,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69, -0x6f,0x6e,0xfd,0x80,0,0,0x1c,0x65,0x6e,0x70,0x75,0x6e,0x63,0x74,0x75,0x61, -0x74,0x69,0x6f,0x6e,0xf9,0,0,0x66,0xc0,0xc4,0x66,0xa2,0x47,0x69,0xa2,0x64, -0x6c,0xa2,0x79,0x6d,0xa4,0xc0,4,0x61,0x6c,0x63,0xa5,0,0x65,0xa3,0x80,0x6e, -0xa1,0x6f,0x15,0x64,0x69,0x66,0x69,0x65,0x72,1,0x6c,0x38,0x73,0x14,0x79,0x6d, -0x62,0x6f,0x6c,0xff,4,0,0,0,0x14,0x65,0x74,0x74,0x65,0x72,0x41,1, -0x72,0x3c,0x74,0x16,0x68,0x73,0x79,0x6d,0x62,0x6f,0x6c,0xff,1,0,0,0, -0x10,0x6b,0xa5,0xc0,1,0x69,0x32,0x6f,0x13,0x72,0x6d,0x61,0x74,0xdb,0,0, -0x1d,0x6e,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff, -0x20,0,0,0,0x10,0x6e,0x1f,0x69,0x74,0x69,0x61,0x6c,0x70,0x75,0x6e,0x63, -0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff,0x10,0,0,0,0x9c,7,0x6d,0x18, -0x6d,0x41,0x6f,0x28,0x74,0x31,0x75,0x25,0x60,0x1c,0x77,0x65,0x72,0x63,0x61,0x73, -0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x29,0x63,0x3d,0x65,0x28,0x69,0x42,0x6c,0x29, -0x13,0x74,0x74,0x65,0x72,0x9c,0x15,0x6e,0x75,0x6d,0x62,0x65,0x72,0xab,0,0x1a, -0x6e,0x65,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,0x20,0,0x63,0x46, -0x64,0xa2,0x96,0x65,0x1b,0x6e,0x63,0x6c,0x6f,0x73,0x69,0x6e,0x67,0x6d,0x61,0x72, -0x6b,0xa3,0x80,0xe6,0x80,1,7,0x6e,0x57,0x6e,0x52,0x6f,0x5e,0x73,0xe1,0, -0,0x75,0x1b,0x72,0x72,0x65,0x6e,0x63,0x79,0x73,0x79,0x6d,0x62,0x6f,0x6c,0xff, -2,0,0,0,0x22,0x12,0x74,0x72,0x6c,0xd9,0x80,0,0xdc,0,0,1, -0x6d,0x62,0x6e,1,0x6e,0x30,0x74,0x12,0x72,0x6f,0x6c,0xd9,0x80,0,0x1f,0x65, -0x63,0x74,0x6f,0x72,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xfd, -0x40,0,0,0x19,0x62,0x69,0x6e,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa5,0xc0, -0x61,0x58,0x63,0xd9,0x80,0,0x66,0xdb,0,0,0x6c,0x1d,0x6f,0x73,0x65,0x70, -0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xfd,0x20,0,0,0x18,0x73, -0x65,0x64,0x6c,0x65,0x74,0x74,0x65,0x72,0x3d,2,0x61,0x32,0x65,0x50,0x69,0x12, -0x67,0x69,0x74,0xa7,0,0x1c,0x73,0x68,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74, -0x69,0x6f,0x6e,0xe9,0,0,0x1a,0x63,0x69,0x6d,0x61,0x6c,0x6e,0x75,0x6d,0x62, -0x65,0x72,0xa7,0 +0x61,0x6b,0xc3,8,2,0x64,0x4a,0x6e,0xa2,0x91,0x73,1,0x63,0xd9,0x40,3, +0x6f,0x16,0x63,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0xd9,0x40,3,2,0x63,0xa2,0x44, +0x65,0xa2,0x6c,0x73,0x40,2,0x62,0x48,0x74,0x64,0x75,0xa2,0x48,0x1b,0x6e,0x61, +0x72,0x79,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0xa3,0x48,0x44,0x1c,0x69,0x6e, +0x61,0x72,0x79,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x45,0x46,1,0x61,0x40, +0x72,0x1c,0x69,0x6e,0x61,0x72,0x79,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x47, +0x11,0x72,0x74,0x41,0x3e,0x10,0x6f,1,0x6d,0x30,0x6e,0x14,0x74,0x69,0x6e,0x75, +0x65,0x3f,0x16,0x70,0x61,0x74,0x6d,0x61,0x74,0x68,1,0x63,0x30,0x73,0x13,0x74, +0x61,0x72,0x74,0xa3,0x49,0x16,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0xa3,0x4a,0x10, +0x6f,0x42,0x16,0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x43,2,0x64,0x2e,0x70,0x86, +0x73,0x10,0x63,0xc3,0x17,0x11,0x69,0x63,1,0x70,0x46,0x73,0x1e,0x79,0x6c,0x6c, +0x61,0x62,0x69,0x63,0x63,0x61,0x74,0x65,0x67,0x6f,0x72,0x79,0xc3,0x17,0x10,0x6f, +0x1f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x63,0x61,0x74,0x65,0x67,0x6f,0x72, +0x79,0xc3,0x16,0x10,0x63,0xc3,0x16,2,0x67,0xc3,6,0x6f,0x26,0x74,0xc3,7, +0x11,0x69,0x6e,1,0x63,0x4a,0x69,0x11,0x6e,0x67,1,0x67,0x2e,0x74,0x12,0x79, +0x70,0x65,0xc3,7,0x13,0x72,0x6f,0x75,0x70,0xc3,6,0x48,0x15,0x6f,0x6e,0x74, +0x72,0x6f,0x6c,0x49,0x66,0x86,0x67,0xa2,0x4a,0x68,3,0x61,0x36,0x65,0x58,0x73, +0x68,0x79,0x13,0x70,0x68,0x65,0x6e,0x3d,0x1f,0x6e,0x67,0x75,0x6c,0x73,0x79,0x6c, +0x6c,0x61,0x62,0x6c,0x65,0x74,0x79,0x70,0x65,0xc3,0xb,0x10,0x78,0x3a,0x14,0x64, +0x69,0x67,0x69,0x74,0x3b,0x10,0x74,0xc3,0xb,0x16,0x75,0x6c,0x6c,0x63,0x6f,0x6d, +0x70,0x1f,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x65,0x78,0x63,0x6c,0x75,0x73,0x69, +0x6f,0x6e,0x33,2,0x63,0xa2,0x44,0x65,0xa2,0x4b,0x72,3,0x61,0x34,0x62,0x84, +0x65,0x8a,0x6c,0x12,0x69,0x6e,0x6b,0x39,0x11,0x70,0x68,0x7c,0x12,0x65,0x6d,0x65, +3,0x62,0x5e,0x63,0x30,0x65,0x48,0x6c,0x12,0x69,0x6e,0x6b,0x39,0x1a,0x6c,0x75, +0x73,0x74,0x65,0x72,0x62,0x72,0x65,0x61,0x6b,0xc3,0x12,0x14,0x78,0x74,0x65,0x6e, +0x64,0x37,0x12,0x61,0x73,0x65,0x35,0x11,0x78,0x74,0x37,0xc2,5,1,0x62,0xc3, +0x12,0x6d,0xd9,0x20,0,0x1c,0x6e,0x65,0x72,0x61,0x6c,0x63,0x61,0x74,0x65,0x67, +0x6f,0x72,0x79,0xc2,5,0x13,0x6d,0x61,0x73,0x6b,0xd9,0x20,0,0x61,0xa2,0xa2, +0x62,0xa2,0xd0,0x63,0xa4,0x4f,0x64,0xa6,0x1c,0x65,5,0x6d,0x75,0x6d,0x6e,0x70, +0xa2,0x6b,0x78,0x10,0x74,0x30,1,0x65,0x2c,0x70,0x12,0x69,0x63,0x74,0xa1,0x12, +0x6e,0x64,0x65,1,0x64,0x24,0x72,0x31,0x1b,0x70,0x69,0x63,0x74,0x6f,0x67,0x72, +0x61,0x70,0x68,0x69,0x63,0xa1,0x10,0x6f,1,0x64,0x97,0x6a,0x10,0x69,0x92,3, +0x63,0x44,0x6b,0x54,0x6d,0x70,0x70,0x1a,0x72,0x65,0x73,0x65,0x6e,0x74,0x61,0x74, +0x69,0x6f,0x6e,0x95,0x17,0x6f,0x6d,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x9b,0x1c,0x65, +0x79,0x63,0x61,0x70,0x73,0x65,0x71,0x75,0x65,0x6e,0x63,0x65,0xa3,0x42,0x16,0x6f, +0x64,0x69,0x66,0x69,0x65,0x72,0x96,0x13,0x62,0x61,0x73,0x65,0x99,0x12,0x72,0x65, +0x73,0x95,0x61,0x30,0x62,0x4e,0x63,0x12,0x6f,0x6d,0x70,0x9b,0xc2,4,0x1b,0x73, +0x74,0x61,0x73,0x69,0x61,0x6e,0x77,0x69,0x64,0x74,0x68,0xc3,4,0x12,0x61,0x73, +0x65,0x99,3,0x67,0x44,0x68,0x4a,0x6c,0x4e,0x73,0x1a,0x63,0x69,0x69,0x68,0x65, +0x78,0x64,0x69,0x67,0x69,0x74,0x23,0x10,0x65,0xd9,0x40,0,0x11,0x65,0x78,0x23, +1,0x6e,0x38,0x70,0x11,0x68,0x61,0x20,0x14,0x62,0x65,0x74,0x69,0x63,0x21,0x11, +0x75,0x6d,0x79,5,0x6c,0x22,0x6c,0x36,0x6d,0x52,0x70,1,0x62,0xd9,0x40,0xd, +0x74,0xc3,0x15,2,0x61,0x32,0x6b,0xc3,1,0x6f,0x11,0x63,0x6b,0xc3,1,0x11, +0x6e,0x6b,0x7b,0x10,0x67,0xd9,0x40,1,0x61,0xa2,0x4f,0x63,0xc3,0,0x69,0x11, +0x64,0x69,2,0x63,0x54,0x6d,0x74,0x70,0x1b,0x61,0x69,0x72,0x65,0x64,0x62,0x72, +0x61,0x63,0x6b,0x65,0x74,0xd8,0x40,0xd,0x13,0x74,0x79,0x70,0x65,0xc3,0x15,0x24, +1,0x6c,0x30,0x6f,0x14,0x6e,0x74,0x72,0x6f,0x6c,0x25,0x12,0x61,0x73,0x73,0xc3, +0,0x26,0x14,0x69,0x72,0x72,0x6f,0x72,1,0x65,0x38,0x69,0x16,0x6e,0x67,0x67, +0x6c,0x79,0x70,0x68,0xd9,0x40,1,0x10,0x64,0x27,0x17,0x73,0x69,0x63,0x65,0x6d, +0x6f,0x6a,0x69,0xa3,0x41,6,0x68,0x7c,0x68,0x54,0x69,0x85,0x6f,0xa2,0x6f,0x77, +4,0x63,0x30,0x6b,0x36,0x6c,0x87,0x74,0x8b,0x75,0x89,1,0x66,0x8d,0x6d,0x8f, +0x11,0x63,0x66,0x91,0x18,0x61,0x6e,0x67,0x65,0x73,0x77,0x68,0x65,0x6e,4,0x63, +0x44,0x6c,0x6c,0x6e,0x7e,0x74,0x98,0x75,0x18,0x70,0x70,0x65,0x72,0x63,0x61,0x73, +0x65,0x64,0x89,0x12,0x61,0x73,0x65,1,0x66,0x30,0x6d,0x14,0x61,0x70,0x70,0x65, +0x64,0x8f,0x14,0x6f,0x6c,0x64,0x65,0x64,0x8d,0x18,0x6f,0x77,0x65,0x72,0x63,0x61, +0x73,0x65,0x64,0x87,0x1c,0x66,0x6b,0x63,0x63,0x61,0x73,0x65,0x66,0x6f,0x6c,0x64, +0x65,0x64,0x91,0x18,0x69,0x74,0x6c,0x65,0x63,0x61,0x73,0x65,0x64,0x8b,0x13,0x6d, +0x70,0x65,0x78,0x33,0x61,0x2e,0x63,0xa2,0x48,0x66,0xd9,0x40,2,1,0x6e,0x72, +0x73,0x10,0x65,3,0x64,0x83,0x66,0x3a,0x69,0x4a,0x73,0x17,0x65,0x6e,0x73,0x69, +0x74,0x69,0x76,0x65,0x65,0x15,0x6f,0x6c,0x64,0x69,0x6e,0x67,0xd9,0x40,2,0x17, +0x67,0x6e,0x6f,0x72,0x61,0x62,0x6c,0x65,0x85,0x13,0x6f,0x6e,0x69,0x63,0x1f,0x61, +0x6c,0x63,0x6f,0x6d,0x62,0x69,0x6e,0x69,0x6e,0x67,0x63,0x6c,0x61,0x73,0x73,0xc3, +2,0x10,0x63,0xc3,2,3,0x61,0x30,0x65,0x34,0x69,0xa2,0x41,0x74,0xc3,3, +0x11,0x73,0x68,0x29,2,0x63,0x3a,0x66,0x58,0x70,0x2c,0x16,0x72,0x65,0x63,0x61, +0x74,0x65,0x64,0x2d,0x1d,0x6f,0x6d,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x74, +0x79,0x70,0x65,0xc3,3,0x15,0x61,0x75,0x6c,0x74,0x69,0x67,0x1f,0x6e,0x6f,0x72, +0x61,0x62,0x6c,0x65,0x63,0x6f,0x64,0x65,0x70,0x6f,0x69,0x6e,0x74,0x2b,0x2a,0x10, +0x61,0x2e,0x15,0x63,0x72,0x69,0x74,0x69,0x63,0x2f,3,0x66,0x34,0x6e,0x3e,0x74, +0x42,0x79,0x22,0x11,0x65,0x73,0x23,0x20,0x13,0x61,0x6c,0x73,0x65,0x21,0x20,0x10, +0x6f,0x21,0x22,0x12,0x72,0x75,0x65,0x23,0xb,0x6b,0x5b,0x6f,0x23,0x6f,0x3c,0x72, +0x4c,0x76,1,0x69,0x24,0x72,0x33,0x13,0x72,0x61,0x6d,0x61,0x33,0x10,0x76,0x22, +0x14,0x65,0x72,0x6c,0x61,0x79,0x23,0xa2,0xe2,0x13,0x69,0x67,0x68,0x74,0xa3,0xe2, +0x6b,0x58,0x6c,0x74,0x6e,3,0x6b,0x2f,0x6f,0x30,0x72,0x21,0x75,0x12,0x6b,0x74, +0x61,0x2f,0x19,0x74,0x72,0x65,0x6f,0x72,0x64,0x65,0x72,0x65,0x64,0x21,1,0x61, +0x24,0x76,0x31,0x18,0x6e,0x61,0x76,0x6f,0x69,0x63,0x69,0x6e,0x67,0x31,0xa2,0xe0, +0x12,0x65,0x66,0x74,0xa3,0xe0,0x64,0x45,0x64,0x4e,0x68,0x88,0x69,1,0x6f,0x26, +0x73,0xa3,0xf0,0x1a,0x74,0x61,0x73,0x75,0x62,0x73,0x63,0x72,0x69,0x70,0x74,0xa3, +0xf0,2,0x61,0xa3,0xea,0x62,0xa3,0xe9,0x6f,0x13,0x75,0x62,0x6c,0x65,1,0x61, +0x30,0x62,0x13,0x65,0x6c,0x6f,0x77,0xa3,0xe9,0x13,0x62,0x6f,0x76,0x65,0xa3,0xea, +0x12,0x61,0x6e,0x72,0x2c,0x15,0x65,0x61,0x64,0x69,0x6e,0x67,0x2d,0x61,0xa2,0x7b, +0x62,0xa2,0xd4,0x63,0x11,0x63,0x63,4,0x31,0x3c,0x32,0xa2,0x42,0x33,0xa2,0x56, +0x38,0xa2,0x64,0x39,0x10,0x31,0xa3,0x5b,9,0x35,0xa,0x35,0x3f,0x36,0x41,0x37, +0x43,0x38,0x45,0x39,0x47,0x30,0x30,0x31,0x3c,0x32,0x42,0x33,0x4e,0x34,0x3d,0x34, +1,0x33,0xa3,0x67,0x37,0xa3,0x6b,0x36,0x10,0x38,0xa3,0x76,0x38,1,0x32,0xa3, +0x7a,0x39,0xa3,0x81,0x3a,2,0x30,0xa3,0x82,0x32,0xa3,0x84,0x33,0xa3,0x85,9, +0x35,0xa,0x35,0x53,0x36,0x55,0x37,0x57,0x38,0x59,0x39,0x5b,0x30,0x49,0x31,0x4b, +0x32,0x4d,0x33,0x4f,0x34,0x51,6,0x33,8,0x33,0x63,0x34,0x65,0x35,0x67,0x36, +0x69,0x30,0x5d,0x31,0x5f,0x32,0x61,0x10,0x34,0xa3,0x54,0xa2,0xe6,3,0x62,0xa0, +0x6c,0xa3,0xe4,0x72,0xa3,0xe8,0x74,2,0x61,0x74,0x62,0x7c,0x74,0x14,0x61,0x63, +0x68,0x65,0x64,1,0x61,0x3e,0x62,0x13,0x65,0x6c,0x6f,0x77,0xa2,0xca,0x13,0x6c, +0x65,0x66,0x74,0xa3,0xc8,0x13,0x62,0x6f,0x76,0x65,0xa2,0xd6,0x14,0x72,0x69,0x67, +0x68,0x74,0xa3,0xd8,0xa2,0xd6,0x10,0x72,0xa3,0xd8,0xa2,0xca,0x10,0x6c,0xa3,0xc8, +0x12,0x6f,0x76,0x65,0xa2,0xe6,1,0x6c,0x30,0x72,0x13,0x69,0x67,0x68,0x74,0xa3, +0xe8,0x12,0x65,0x66,0x74,0xa3,0xe4,0xa2,0xdc,2,0x65,0x2c,0x6c,0xa3,0xda,0x72, +0xa3,0xde,0x12,0x6c,0x6f,0x77,0xa2,0xdc,1,0x6c,0x30,0x72,0x13,0x69,0x67,0x68, +0x74,0xa3,0xde,0x12,0x65,0x66,0x74,0xa3,0xda,0xb,0x6e,0xc0,0xca,0x72,0x5f,0x72, +0x46,0x73,0xa2,0x48,0x77,1,0x68,0x24,0x73,0x33,0x17,0x69,0x74,0x65,0x73,0x70, +0x61,0x63,0x65,0x33,0x22,1,0x69,0x30,0x6c,2,0x65,0x3d,0x69,0x4b,0x6f,0x3f, +0x18,0x67,0x68,0x74,0x74,0x6f,0x6c,0x65,0x66,0x74,0x22,2,0x65,0x38,0x69,0x48, +0x6f,0x16,0x76,0x65,0x72,0x72,0x69,0x64,0x65,0x3f,0x17,0x6d,0x62,0x65,0x64,0x64, +0x69,0x6e,0x67,0x3d,0x15,0x73,0x6f,0x6c,0x61,0x74,0x65,0x4b,0x30,0x1e,0x65,0x67, +0x6d,0x65,0x6e,0x74,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x31,0x6e,0xa2, +0x41,0x6f,0xa2,0x53,0x70,2,0x61,0x66,0x64,0x86,0x6f,0x1b,0x70,0x64,0x69,0x72, +0x65,0x63,0x74,0x69,0x6f,0x6e,0x61,0x6c,1,0x66,0x32,0x69,0x15,0x73,0x6f,0x6c, +0x61,0x74,0x65,0x4d,0x14,0x6f,0x72,0x6d,0x61,0x74,0x41,0x1f,0x72,0x61,0x67,0x72, +0x61,0x70,0x68,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x2f,1,0x66,0x41, +0x69,0x4d,1,0x6f,0x28,0x73,0x10,0x6d,0x43,0x1b,0x6e,0x73,0x70,0x61,0x63,0x69, +0x6e,0x67,0x6d,0x61,0x72,0x6b,0x43,1,0x6e,0x35,0x74,0x19,0x68,0x65,0x72,0x6e, +0x65,0x75,0x74,0x72,0x61,0x6c,0x35,0x65,0x88,0x65,0x98,0x66,0xa2,0x6a,0x6c,0x20, +1,0x65,0x30,0x72,2,0x65,0x37,0x69,0x49,0x6f,0x39,0x18,0x66,0x74,0x74,0x6f, +0x72,0x69,0x67,0x68,0x74,0x20,2,0x65,0x38,0x69,0x48,0x6f,0x16,0x76,0x65,0x72, +0x72,0x69,0x64,0x65,0x39,0x17,0x6d,0x62,0x65,0x64,0x64,0x69,0x6e,0x67,0x37,0x15, +0x73,0x6f,0x6c,0x61,0x74,0x65,0x49,3,0x6e,0x25,0x73,0x27,0x74,0x29,0x75,0x15, +0x72,0x6f,0x70,0x65,0x61,0x6e,2,0x6e,0x3c,0x73,0x46,0x74,0x18,0x65,0x72,0x6d, +0x69,0x6e,0x61,0x74,0x6f,0x72,0x29,0x14,0x75,0x6d,0x62,0x65,0x72,0x25,0x17,0x65, +0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x27,1,0x69,0x28,0x73,0x10,0x69,0x47,0x1f, +0x72,0x73,0x74,0x73,0x74,0x72,0x6f,0x6e,0x67,0x69,0x73,0x6f,0x6c,0x61,0x74,0x65, +0x47,0x61,0x4e,0x62,0x84,0x63,1,0x6f,0x24,0x73,0x2d,0x1c,0x6d,0x6d,0x6f,0x6e, +0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x2d,2,0x6c,0x3b,0x6e,0x2b,0x72, +0x13,0x61,0x62,0x69,0x63,1,0x6c,0x30,0x6e,0x14,0x75,0x6d,0x62,0x65,0x72,0x2b, +0x14,0x65,0x74,0x74,0x65,0x72,0x3b,0x2e,1,0x6e,0x45,0x6f,0x1c,0x75,0x6e,0x64, +0x61,0x72,0x79,0x6e,0x65,0x75,0x74,0x72,0x61,0x6c,0x45,0,0x16,0x6d,0xc9,0x20, +0x74,0xc2,0x30,0x77,0x89,0x77,0x86,0x79,0xa2,0x46,0x7a,1,0x61,0x58,0x6e,0x1a, +0x61,0x6d,0x65,0x6e,0x6e,0x79,0x6d,0x75,0x73,0x69,0x63,0xa4,0x40,0x19,0x61,0x6c, +0x6e,0x6f,0x74,0x61,0x74,0x69,0x6f,0x6e,0xa5,0x40,0x1c,0x6e,0x61,0x62,0x61,0x7a, +0x61,0x72,0x73,0x71,0x75,0x61,0x72,0x65,0xa5,0x18,0x10,0x61,1,0x6e,0x36,0x72, +0x16,0x61,0x6e,0x67,0x63,0x69,0x74,0x69,0xa3,0xfc,0x12,0x63,0x68,0x6f,0xa5,0x2c, +1,0x65,0x88,0x69,2,0x6a,0x3c,0x72,0x68,0x73,0x17,0x79,0x6c,0x6c,0x61,0x62, +0x6c,0x65,0x73,0xa3,0x48,0x12,0x69,0x6e,0x67,0xa2,0x74,0x1e,0x68,0x65,0x78,0x61, +0x67,0x72,0x61,0x6d,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x74,0x16,0x61,0x64, +0x69,0x63,0x61,0x6c,0x73,0xa3,0x49,0x13,0x7a,0x69,0x64,0x69,0xa5,0x34,0x74,0xa2, +0x65,0x75,0xa4,0x4f,0x76,3,0x61,0x3c,0x65,0x80,0x69,0xa2,0x50,0x73,0xa2,0x6c, +0x12,0x73,0x75,0x70,0xa3,0x7d,1,0x69,0xa3,0x9f,0x72,0x1e,0x69,0x61,0x74,0x69, +0x6f,0x6e,0x73,0x65,0x6c,0x65,0x63,0x74,0x6f,0x72,0x73,0xa2,0x6c,0x19,0x73,0x75, +0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x7d,1,0x64,0x3c,0x72,0x19,0x74, +0x69,0x63,0x61,0x6c,0x66,0x6f,0x72,0x6d,0x73,0xa3,0x91,0x14,0x69,0x63,0x65,0x78, +0x74,0xa2,0xaf,0x16,0x65,0x6e,0x73,0x69,0x6f,0x6e,0x73,0xa3,0xaf,0x15,0x74,0x68, +0x6b,0x75,0x71,0x69,0xa5,0x3f,5,0x69,0x3f,0x69,0x5a,0x6f,0x8c,0x72,0x1c,0x61, +0x6e,0x73,0x70,0x6f,0x72,0x74,0x61,0x6e,0x64,0x6d,0x61,0x70,0xa2,0xcf,0x16,0x73, +0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xcf,2,0x62,0x34,0x66,0x3c,0x72,0x13,0x68, +0x75,0x74,0x61,0xa3,0xfb,0x13,0x65,0x74,0x61,0x6e,0x57,0x14,0x69,0x6e,0x61,0x67, +0x68,0xa3,0x90,0x11,0x74,0x6f,0xa5,0x3d,0x61,0x3e,0x65,0xa2,0xa0,0x68,0x10,0x61, +1,0x61,0x24,0x69,0x53,0x11,0x6e,0x61,0x3d,4,0x67,0x8e,0x69,0xa2,0x49,0x6b, +0xa2,0x72,0x6d,0xa2,0x74,0x6e,0x10,0x67,1,0x73,0x68,0x75,0x10,0x74,0xa4,0x10, +1,0x63,0x40,0x73,0x11,0x75,0x70,0xa4,0x33,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e, +0x74,0xa5,0x33,0x18,0x6f,0x6d,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x73,0xa5,0x11,0x10, +0x61,0xa5,0x3c,2,0x61,0x2a,0x62,0x32,0x73,0xa3,0x60,0x12,0x6c,0x6f,0x67,0xa3, +0x62,0x13,0x61,0x6e,0x77,0x61,0xa3,0x65,3,0x6c,0x52,0x74,0x56,0x76,0x5e,0x78, +0x16,0x75,0x61,0x6e,0x6a,0x69,0x6e,0x67,0xa2,0x7c,0x16,0x73,0x79,0x6d,0x62,0x6f, +0x6c,0x73,0xa3,0x7c,0x10,0x65,0xa3,0x70,0x12,0x68,0x61,0x6d,0xa3,0xae,0x12,0x69, +0x65,0x74,0xa3,0xb7,0x11,0x72,0x69,0xa3,0xdc,0x11,0x69,0x6c,0x48,0x12,0x73,0x75, +0x70,0xa4,0x2b,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0x2b,0x13,0x6c,0x75, +0x67,0x75,0x4b,2,0x63,0x8c,0x67,0xa2,0x41,0x6e,0x1f,0x69,0x66,0x69,0x65,0x64, +0x63,0x61,0x6e,0x61,0x64,0x69,0x61,0x6e,0x61,0x62,0x6f,0x1f,0x72,0x69,0x67,0x69, +0x6e,0x61,0x6c,0x73,0x79,0x6c,0x6c,0x61,0x62,0x69,0x63,0x73,0x62,0x17,0x65,0x78, +0x74,0x65,0x6e,0x64,0x65,0x64,0xa2,0xad,0x10,0x61,0xa5,0x3e,0x11,0x61,0x73,0x62, +0x12,0x65,0x78,0x74,0xa2,0xad,0x10,0x61,0xa5,0x3e,0x15,0x61,0x72,0x69,0x74,0x69, +0x63,0xa3,0x78,0x70,0xc3,0x4b,0x70,0xa6,0x61,0x72,0xa8,0x1d,0x73,7,0x6f,0xc1, +0xbe,0x6f,0xa2,0x69,0x70,0xa2,0x85,0x75,0xa2,0xa4,0x79,2,0x6c,0x50,0x6d,0x62, +0x72,0x12,0x69,0x61,0x63,0x3a,0x12,0x73,0x75,0x70,0xa4,0x17,0x16,0x70,0x6c,0x65, +0x6d,0x65,0x6e,0x74,0xa5,0x17,0x17,0x6f,0x74,0x69,0x6e,0x61,0x67,0x72,0x69,0xa3, +0x8f,0x13,0x62,0x6f,0x6c,0x73,1,0x61,0x4c,0x66,0x10,0x6f,0x1f,0x72,0x6c,0x65, +0x67,0x61,0x63,0x79,0x63,0x6f,0x6d,0x70,0x75,0x74,0x69,0x6e,0x67,0xa5,0x32,0x1f, +0x6e,0x64,0x70,0x69,0x63,0x74,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x78,0x74, +1,0x61,0xa5,0x2a,0x65,0x14,0x6e,0x64,0x65,0x64,0x61,0xa5,0x2a,2,0x67,0x34, +0x72,0x3e,0x79,0x13,0x6f,0x6d,0x62,0x6f,0xa5,0x16,0x13,0x64,0x69,0x61,0x6e,0xa5, +0x23,0x17,0x61,0x73,0x6f,0x6d,0x70,0x65,0x6e,0x67,0xa3,0xda,1,0x61,0x32,0x65, +0x14,0x63,0x69,0x61,0x6c,0x73,0xa3,0x56,0x12,0x63,0x69,0x6e,0x1f,0x67,0x6d,0x6f, +0x64,0x69,0x66,0x69,0x65,0x72,0x6c,0x65,0x74,0x74,0x65,0x72,0x73,0x2d,2,0x6e, +0x48,0x70,0x76,0x74,0x1d,0x74,0x6f,0x6e,0x73,0x69,0x67,0x6e,0x77,0x72,0x69,0x74, +0x69,0x6e,0x67,0xa5,6,0x15,0x64,0x61,0x6e,0x65,0x73,0x65,0xa2,0x9b,0x12,0x73, +0x75,0x70,0xa2,0xdb,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xdb,4,0x61, +0xa2,0xa8,0x65,0x5c,0x6d,0x9e,0x70,0xa2,0x4b,0x73,0x13,0x79,0x6d,0x62,0x6f,0x1f, +0x6c,0x73,0x61,0x6e,0x64,0x70,0x69,0x63,0x74,0x6f,0x67,0x72,0x61,0x70,0x68,0x73, +0xa5,5,0x10,0x72,1,0x61,0x4e,0x73,0x12,0x63,0x72,0x69,0x1f,0x70,0x74,0x73, +0x61,0x6e,0x64,0x73,0x75,0x62,0x73,0x63,0x72,0x69,0x70,0x74,0x73,0x73,0x14,0x6e, +0x64,0x73,0x75,0x62,0x73,0x1b,0x61,0x74,0x68,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f, +0x72,0x73,0xa3,0x6a,1,0x6c,0x40,0x75,1,0x61,0x6e,0x6e,0x17,0x63,0x74,0x75, +0x61,0x74,0x69,0x6f,0x6e,0xa3,0x8e,0x15,0x65,0x6d,0x65,0x6e,0x74,0x61,1,0x6c, +0x50,0x72,0x1e,0x79,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0x61,0x72, +0x65,0x61,1,0x61,0xa3,0x6d,0x62,0xa3,0x6e,3,0x61,0x5c,0x6d,0x78,0x70,0xa2, +0x41,0x73,0x13,0x79,0x6d,0x62,0x6f,0x1f,0x6c,0x73,0x61,0x6e,0x64,0x70,0x69,0x63, +0x74,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa5,5,0x14,0x72,0x72,0x6f,0x77,0x73, +2,0x61,0xa3,0x67,0x62,0xa3,0x68,0x63,0xa3,0xfa,0x13,0x61,0x74,0x68,0x65,0x1f, +0x6d,0x61,0x74,0x69,0x63,0x61,0x6c,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73, +0xa3,0x6a,0x19,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xa3,0x8e,0x61, +0x88,0x68,0xa2,0x48,0x69,0xa2,0x71,0x6d,0x12,0x61,0x6c,0x6c,1,0x66,0x46,0x6b, +0x15,0x61,0x6e,0x61,0x65,0x78,0x74,0xa4,0x29,0x15,0x65,0x6e,0x73,0x69,0x6f,0x6e, +0xa5,0x29,0x12,0x6f,0x72,0x6d,1,0x73,0xa3,0x54,0x76,0x16,0x61,0x72,0x69,0x61, +0x6e,0x74,0x73,0xa3,0x54,1,0x6d,0x36,0x75,0x16,0x72,0x61,0x73,0x68,0x74,0x72, +0x61,0xa3,0xa1,0x15,0x61,0x72,0x69,0x74,0x61,0x6e,0xa3,0xac,1,0x61,0x52,0x6f, +0x13,0x72,0x74,0x68,0x61,0x1f,0x6e,0x64,0x66,0x6f,0x72,0x6d,0x61,0x74,0x63,0x6f, +0x6e,0x74,0x72,0x6f,0x6c,0x73,0xa3,0xf7,1,0x72,0x2e,0x76,0x12,0x69,0x61,0x6e, +0xa3,0x79,0x12,0x61,0x64,0x61,0xa3,0xd9,1,0x64,0x50,0x6e,0x13,0x68,0x61,0x6c, +0x61,0x50,0x1d,0x61,0x72,0x63,0x68,0x61,0x69,0x63,0x6e,0x75,0x6d,0x62,0x65,0x72, +0x73,0xa3,0xf9,0x13,0x64,0x68,0x61,0x6d,0xa3,0xf8,5,0x72,0x35,0x72,0x44,0x73, +0x64,0x75,1,0x61,0xa3,0x4e,0x6e,0x17,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e, +0x71,0x17,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0xa2,0x4e,0x13,0x61,0x72,0x65, +0x61,0xa3,0x4e,0x1b,0x61,0x6c,0x74,0x65,0x72,0x70,0x61,0x68,0x6c,0x61,0x76,0x69, +0xa3,0xf6,0x61,0x40,0x68,0x82,0x6c,0x19,0x61,0x79,0x69,0x6e,0x67,0x63,0x61,0x72, +0x64,0x73,0xa3,0xcc,2,0x68,0x38,0x6c,0x4a,0x75,0x15,0x63,0x69,0x6e,0x68,0x61, +0x75,0xa3,0xf5,0x17,0x61,0x77,0x68,0x68,0x6d,0x6f,0x6e,0x67,0xa3,0xf3,0x15,0x6d, +0x79,0x72,0x65,0x6e,0x65,0xa3,0xf4,1,0x61,0x8e,0x6f,1,0x65,0x74,0x6e,0x16, +0x65,0x74,0x69,0x63,0x65,0x78,0x74,0xa2,0x72,1,0x65,0x2c,0x73,0x11,0x75,0x70, +0xa3,0x8d,0x15,0x6e,0x73,0x69,0x6f,0x6e,0x73,0xa2,0x72,0x19,0x73,0x75,0x70,0x70, +0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x8d,0x15,0x6e,0x69,0x63,0x69,0x61,0x6e,0xa3, +0x97,1,0x67,0x3e,0x69,0x13,0x73,0x74,0x6f,0x73,0xa2,0xa6,0x13,0x64,0x69,0x73, +0x63,0xa3,0xa6,0x12,0x73,0x70,0x61,0xa3,0x96,1,0x65,0x5c,0x75,1,0x6d,0x2a, +0x6e,0x11,0x69,0x63,0x67,0x10,0x69,0xa2,0xc0,0x1d,0x6e,0x75,0x6d,0x65,0x72,0x61, +0x6c,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xc0,0x13,0x6a,0x61,0x6e,0x67,0xa3, +0xa3,0x6d,0xa2,0xf0,0x6e,0xa8,0x23,0x6f,6,0x70,0x63,0x70,0x56,0x72,0x8a,0x73, +0xa2,0x4c,0x74,0x10,0x74,0x1f,0x6f,0x6d,0x61,0x6e,0x73,0x69,0x79,0x61,0x71,0x6e, +0x75,0x6d,0x62,0x65,0x72,0x73,0xa5,0x28,0x18,0x74,0x69,0x63,0x61,0x6c,0x63,0x68, +0x61,0x72,0x1f,0x61,0x63,0x74,0x65,0x72,0x72,0x65,0x63,0x6f,0x67,0x6e,0x69,0x74, +0x69,0x6f,0x6e,0x85,1,0x69,0x46,0x6e,0x1e,0x61,0x6d,0x65,0x6e,0x74,0x61,0x6c, +0x64,0x69,0x6e,0x67,0x62,0x61,0x74,0x73,0xa3,0xf2,0x11,0x79,0x61,0x47,1,0x61, +0x30,0x6d,0x13,0x61,0x6e,0x79,0x61,0xa3,0x7a,0x11,0x67,0x65,0xa5,0xf,0x63,0xa2, +0x7b,0x67,0xa2,0x7b,0x6c,1,0x63,0xa2,0x6c,0x64,6,0x70,0x42,0x70,0x3a,0x73, +0x5a,0x74,0x88,0x75,0x14,0x79,0x67,0x68,0x75,0x72,0xa5,0x3b,0x11,0x65,0x72,1, +0x6d,0x2e,0x73,0x12,0x69,0x61,0x6e,0xa3,0x8c,0x11,0x69,0x63,0xa3,0xf1,0x10,0x6f, +1,0x67,0x3a,0x75,0x18,0x74,0x68,0x61,0x72,0x61,0x62,0x69,0x61,0x6e,0xa3,0xbb, +0x13,0x64,0x69,0x61,0x6e,0xa5,0x22,0x14,0x75,0x72,0x6b,0x69,0x63,0xa3,0xbf,0x68, +0x42,0x69,0x54,0x6e,0x1a,0x6f,0x72,0x74,0x68,0x61,0x72,0x61,0x62,0x69,0x61,0x6e, +0xa3,0xf0,0x17,0x75,0x6e,0x67,0x61,0x72,0x69,0x61,0x6e,0xa5,4,0x14,0x74,0x61, +0x6c,0x69,0x63,0xa3,0x58,0x13,0x68,0x69,0x6b,0x69,0xa3,0x9d,0x10,0x72,0x85,0x12, +0x68,0x61,0x6d,0x65,6,0x6f,0x86,0x6f,0x6c,0x72,0xa2,0x61,0x75,0xa2,0x62,0x79, +0x14,0x61,0x6e,0x6d,0x61,0x72,0x58,0x12,0x65,0x78,0x74,2,0x61,0xa3,0xb6,0x62, +0xa3,0xee,0x65,0x13,0x6e,0x64,0x65,0x64,1,0x61,0xa3,0xb6,0x62,0xa3,0xee,1, +0x64,0x52,0x6e,0x15,0x67,0x6f,0x6c,0x69,0x61,0x6e,0x6a,0x12,0x73,0x75,0x70,0xa4, +0xd,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0xd,0x10,0x69,0xa2,0xec,0x13, +0x66,0x69,0x65,0x72,1,0x6c,0x3c,0x74,0x19,0x6f,0x6e,0x65,0x6c,0x65,0x74,0x74, +0x65,0x72,0x73,0xa3,0x8a,0x15,0x65,0x74,0x74,0x65,0x72,0x73,0x2d,0x10,0x6f,0xa3, +0xed,1,0x6c,0x44,0x73,0x11,0x69,0x63,0xa2,0x5c,0x18,0x61,0x6c,0x73,0x79,0x6d, +0x62,0x6f,0x6c,0x73,0xa3,0x5c,0x13,0x74,0x61,0x6e,0x69,0xa5,3,0x61,0xa2,0x9b, +0x65,0xa4,0x4c,0x69,1,0x61,0xa2,0x8f,0x73,0x10,0x63,5,0x70,0x18,0x70,0xa2, +0x71,0x73,0x36,0x74,0x17,0x65,0x63,0x68,0x6e,0x69,0x63,0x61,0x6c,0x81,0x15,0x79, +0x6d,0x62,0x6f,0x6c,0x73,0x8f,0x61,0xa2,0x66,0x65,0x46,0x6d,0x19,0x61,0x74,0x68, +0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,1,0x61,0xa3,0x66,0x62,0xa3,0x69,0x17,0x6c, +0x6c,0x61,0x6e,0x65,0x6f,0x75,0x73,2,0x6d,0x3a,0x73,0x6c,0x74,0x17,0x65,0x63, +0x68,0x6e,0x69,0x63,0x61,0x6c,0x81,0x11,0x61,0x74,0x1f,0x68,0x65,0x6d,0x61,0x74, +0x69,0x63,0x61,0x6c,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,1,0x61,0xa3,0x66,0x62, +0xa3,0x69,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x8e,0x12,0x61,0x6e,0x64,1,0x61, +0x3c,0x70,0x19,0x69,0x63,0x74,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa3,0xcd,0x14, +0x72,0x72,0x6f,0x77,0x73,0xa3,0x73,0x10,0x6f,0xa3,0xd8,7,0x72,0x6f,0x72,0x44, +0x73,0x4e,0x74,0x62,0x79,0x19,0x61,0x6e,0x6e,0x75,0x6d,0x65,0x72,0x61,0x6c,0x73, +0xa5,0x20,0x13,0x63,0x68,0x65,0x6e,0xa5,0xc,0x18,0x61,0x72,0x61,0x6d,0x67,0x6f, +0x6e,0x64,0x69,0xa5,0x14,0x10,0x68,2,0x61,0x3a,0x65,0x4a,0x6f,0x17,0x70,0x65, +0x72,0x61,0x74,0x6f,0x72,0x73,0x7f,0x16,0x6c,0x70,0x68,0x61,0x6e,0x75,0x6d,0xa3, +0x5d,0x16,0x6d,0x61,0x74,0x69,0x63,0x61,0x6c,1,0x61,0x36,0x6f,0x17,0x70,0x65, +0x72,0x61,0x74,0x6f,0x72,0x73,0x7f,0x11,0x6c,0x70,0x1f,0x68,0x61,0x6e,0x75,0x6d, +0x65,0x72,0x69,0x63,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x5d,0x68,0x50,0x6b, +0x7e,0x6c,0x88,0x6e,1,0x64,0x34,0x69,0x15,0x63,0x68,0x61,0x65,0x61,0x6e,0xa3, +0xea,0x12,0x61,0x69,0x63,0xa3,0xc6,1,0x61,0x3e,0x6a,0x12,0x6f,0x6e,0x67,0xa2, +0xaa,0x14,0x74,0x69,0x6c,0x65,0x73,0xa3,0xaa,0x13,0x6a,0x61,0x6e,0x69,0xa3,0xe9, +0x13,0x61,0x73,0x61,0x72,0xa5,0x1f,0x15,0x61,0x79,0x61,0x6c,0x61,0x6d,0x4f,3, +0x64,0x6c,0x65,0x7e,0x6e,0xa2,0x47,0x72,0x14,0x6f,0x69,0x74,0x69,0x63,1,0x63, +0x3c,0x68,0x19,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0xd7,0x15, +0x75,0x72,0x73,0x69,0x76,0x65,0xa3,0xd6,0x17,0x65,0x66,0x61,0x69,0x64,0x72,0x69, +0x6e,0xa5,0x21,0x17,0x74,0x65,0x69,0x6d,0x61,0x79,0x65,0x6b,0xa2,0xb8,0x12,0x65, +0x78,0x74,0xa2,0xd5,0x16,0x65,0x6e,0x73,0x69,0x6f,0x6e,0x73,0xa3,0xd5,0x18,0x64, +0x65,0x6b,0x69,0x6b,0x61,0x6b,0x75,0x69,0xa3,0xeb,6,0x6b,0x3b,0x6b,0x56,0x6f, +0x5a,0x75,0x64,0x79,0x11,0x69,0x61,0x1f,0x6b,0x65,0x6e,0x67,0x70,0x75,0x61,0x63, +0x68,0x75,0x65,0x68,0x6d,0x6f,0x6e,0x67,0xa5,0x27,0x10,0x6f,0xa3,0x92,0x14,0x62, +0x6c,0x6f,0x63,0x6b,0x21,1,0x6d,0x2c,0x73,0x11,0x68,0x75,0xa5,0x15,0x17,0x62, +0x65,0x72,0x66,0x6f,0x72,0x6d,0x73,0x7b,0x61,0x44,0x62,0x21,0x65,0x10,0x77,1, +0x61,0xa5,0xe,0x74,0x14,0x61,0x69,0x6c,0x75,0x65,0xa3,0x8b,2,0x62,0x3c,0x67, +0x4a,0x6e,0x17,0x64,0x69,0x6e,0x61,0x67,0x61,0x72,0x69,0xa5,0x26,0x15,0x61,0x74, +0x61,0x65,0x61,0x6e,0xa3,0xef,0x16,0x6d,0x75,0x6e,0x64,0x61,0x72,0x69,0xa5,0x47, +0x67,0xc4,0x5d,0x6a,0xc1,0xe4,0x6a,0xa2,0xdf,0x6b,0xa2,0xf8,0x6c,4,0x61,0x54, +0x65,0xa2,0x6b,0x69,0xa2,0x82,0x6f,0xa2,0xc1,0x79,1,0x63,0x2e,0x64,0x12,0x69, +0x61,0x6e,0xa3,0xa9,0x12,0x69,0x61,0x6e,0xa3,0xa7,1,0x6f,0x55,0x74,0x11,0x69, +0x6e,1,0x31,0x96,0x65,0x11,0x78,0x74,6,0x64,0x21,0x64,0xa3,0x95,0x65,0x2c, +0x66,0xa5,0x39,0x67,0xa5,0x3a,0xa2,0xe7,0x13,0x6e,0x64,0x65,0x64,6,0x64,0xc, +0x64,0xa3,0x95,0x65,0xa3,0xe7,0x66,0xa5,0x39,0x67,0xa5,0x3a,0x61,0x2a,0x62,0x29, +0x63,0xa3,0x94,0x26,0x18,0x64,0x64,0x69,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x6d,0x24, +0x12,0x73,0x75,0x70,0x24,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x25,1,0x70, +0x42,0x74,0x1d,0x74,0x65,0x72,0x6c,0x69,0x6b,0x65,0x73,0x79,0x6d,0x62,0x6f,0x6c, +0x73,0x79,0x12,0x63,0x68,0x61,0xa3,0x9c,2,0x6d,0x4e,0x6e,0x54,0x73,0x10,0x75, +0xa2,0xb0,0x12,0x73,0x75,0x70,0xa4,0x31,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74, +0xa5,0x31,0x11,0x62,0x75,0xa3,0x6f,0x12,0x65,0x61,0x72,1,0x61,0xa3,0xe8,0x62, +1,0x69,0x38,0x73,0x17,0x79,0x6c,0x6c,0x61,0x62,0x61,0x72,0x79,0xa3,0x75,0x17, +0x64,0x65,0x6f,0x67,0x72,0x61,0x6d,0x73,0xa3,0x76,0x1a,0x77,0x73,0x75,0x72,0x72, +0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4d,0x10,0x61,1,0x6d,0x32,0x76,0x14,0x61, +0x6e,0x65,0x73,0x65,0xa3,0xb5,0x10,0x6f,0x5c,0x12,0x65,0x78,0x74,1,0x61,0xa3, +0xb4,0x62,0xa3,0xb9,1,0x61,0xa2,0x43,0x68,4,0x61,0x40,0x69,0x50,0x6d,0x6e, +0x6f,0x86,0x75,0x15,0x64,0x61,0x77,0x61,0x64,0x69,0xa3,0xe6,0x16,0x72,0x6f,0x73, +0x68,0x74,0x68,0x69,0xa3,0x89,0x1d,0x74,0x61,0x6e,0x73,0x6d,0x61,0x6c,0x6c,0x73, +0x63,0x72,0x69,0x70,0x74,0xa5,0x30,0x11,0x65,0x72,0x68,0x16,0x73,0x79,0x6d,0x62, +0x6f,0x6c,0x73,0xa3,0x71,0x12,0x6a,0x6b,0x69,0xa3,0xe5,5,0x74,0x35,0x74,0x34, +0x77,0x7a,0x79,0x13,0x61,0x68,0x6c,0x69,0xa3,0xa2,0x14,0x61,0x6b,0x61,0x6e,0x61, +0x9e,1,0x65,0x4c,0x70,0x10,0x68,0x1f,0x6f,0x6e,0x65,0x74,0x69,0x63,0x65,0x78, +0x74,0x65,0x6e,0x73,0x69,0x6f,0x6e,0x73,0xa3,0x6b,0x11,0x78,0x74,0xa3,0x6b,0x10, +0x69,0xa5,0x46,0x69,0xa2,0x4e,0x6b,0xa2,0x51,0x6e,3,0x61,0x34,0x62,0x84,0x67, +0x8a,0x6e,0x12,0x61,0x64,0x61,0x4d,1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2,0xcb, +0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xcb,0x11,0x78,0x74,2,0x61,0xa5, +0x13,0x62,0xa5,0x38,0x65,0x13,0x6e,0x64,0x65,0x64,1,0x61,0xa5,0x13,0x62,0xa5, +0x38,0x11,0x75,0x6e,0xa3,0x42,0x11,0x78,0x69,0x96,0x17,0x72,0x61,0x64,0x69,0x63, +0x61,0x6c,0x73,0x97,0x12,0x74,0x68,0x69,0xa3,0xc1,0x1c,0x74,0x6f,0x76,0x69,0x6b, +0x6e,0x75,0x6d,0x65,0x72,0x61,0x6c,0x73,0xa5,0x45,0x67,0xa2,0xb5,0x68,0xa4,0x84, +0x69,3,0x64,0x4c,0x6d,0xa2,0x55,0x6e,0xa2,0x62,0x70,0x13,0x61,0x65,0x78,0x74, +0x2a,0x16,0x65,0x6e,0x73,0x69,0x6f,0x6e,0x73,0x2b,1,0x63,0x99,0x65,0x17,0x6f, +0x67,0x72,0x61,0x70,0x68,0x69,0x63,1,0x64,0x56,0x73,0x15,0x79,0x6d,0x62,0x6f, +0x6c,0x73,0xa4,0xb,0x1d,0x61,0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74, +0x69,0x6f,0x6e,0xa5,0xb,0x13,0x65,0x73,0x63,0x72,0x1f,0x69,0x70,0x74,0x69,0x6f, +0x6e,0x63,0x68,0x61,0x72,0x61,0x63,0x74,0x65,0x72,0x73,0x99,0x1c,0x70,0x65,0x72, +0x69,0x61,0x6c,0x61,0x72,0x61,0x6d,0x61,0x69,0x63,0xa3,0xba,1,0x64,0x62,0x73, +0x1b,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x70,0x61,1,0x68,0x32, +0x72,0x14,0x74,0x68,0x69,0x61,0x6e,0xa3,0xbd,0x13,0x6c,0x61,0x76,0x69,0xa3,0xbe, +0x11,0x69,0x63,1,0x6e,0x3e,0x73,0x1a,0x69,0x79,0x61,0x71,0x6e,0x75,0x6d,0x62, +0x65,0x72,0x73,0xa5,0x1e,0x19,0x75,0x6d,0x62,0x65,0x72,0x66,0x6f,0x72,0x6d,0x73, +0xa3,0xb2,4,0x65,0x74,0x6c,0xa2,0x82,0x6f,0xa2,0x9a,0x72,0xa2,0x9e,0x75,2, +0x6a,0x34,0x6e,0x3e,0x72,0x14,0x6d,0x75,0x6b,0x68,0x69,0x43,0x14,0x61,0x72,0x61, +0x74,0x69,0x45,0x18,0x6a,0x61,0x6c,0x61,0x67,0x6f,0x6e,0x64,0x69,0xa5,0x1c,1, +0x6e,0xa2,0x46,0x6f,1,0x6d,0x6e,0x72,0x13,0x67,0x69,0x61,0x6e,0x5a,1,0x65, +0x40,0x73,0x11,0x75,0x70,0xa2,0x87,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3, +0x87,0x11,0x78,0x74,0xa4,0x1b,0x14,0x65,0x6e,0x64,0x65,0x64,0xa5,0x1b,0x1a,0x65, +0x74,0x72,0x69,0x63,0x73,0x68,0x61,0x70,0x65,0x73,0x8c,0x12,0x65,0x78,0x74,0xa2, +0xe3,0x14,0x65,0x6e,0x64,0x65,0x64,0xa3,0xe3,0x1e,0x65,0x72,0x61,0x6c,0x70,0x75, +0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x71,0x17,0x61,0x67,0x6f,0x6c,0x69, +0x74,0x69,0x63,0xa2,0x88,0x12,0x73,0x75,0x70,0xa4,0xa,0x16,0x70,0x6c,0x65,0x6d, +0x65,0x6e,0x74,0xa5,0xa,0x13,0x74,0x68,0x69,0x63,0xa3,0x59,1,0x61,0x5c,0x65, +0x11,0x65,0x6b,0x30,1,0x61,0x38,0x65,0x11,0x78,0x74,0x6e,0x14,0x65,0x6e,0x64, +0x65,0x64,0x6f,0x17,0x6e,0x64,0x63,0x6f,0x70,0x74,0x69,0x63,0x31,0x13,0x6e,0x74, +0x68,0x61,0xa3,0xe4,2,0x61,0xa2,0x48,0x65,0xa2,0xdf,0x69,1,0x67,0x30,0x72, +0x14,0x61,0x67,0x61,0x6e,0x61,0x9d,0x10,0x68,1,0x70,0x3a,0x73,0x18,0x75,0x72, +0x72,0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4b,1,0x72,0x3c,0x75,0x19,0x73,0x75, +0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4c,0x11,0x69,0x76,0x1f,0x61,0x74, +0x65,0x75,0x73,0x65,0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4c, +2,0x6c,0x32,0x6e,0x9a,0x74,0x12,0x72,0x61,0x6e,0xa5,2,0x10,0x66,2,0x61, +0x58,0x6d,0x70,0x77,0x14,0x69,0x64,0x74,0x68,0x61,0x1f,0x6e,0x64,0x66,0x75,0x6c, +0x6c,0x77,0x69,0x64,0x74,0x68,0x66,0x6f,0x72,0x6d,0x73,0xa3,0x57,0x1a,0x6e,0x64, +0x66,0x75,0x6c,0x6c,0x66,0x6f,0x72,0x6d,0x73,0xa3,0x57,0x13,0x61,0x72,0x6b,0x73, +0xa3,0x52,2,0x67,0x34,0x69,0xa2,0x45,0x75,0x12,0x6e,0x6f,0x6f,0xa3,0x63,0x11, +0x75,0x6c,0xa2,0x4a,2,0x63,0x3c,0x6a,0x5e,0x73,0x17,0x79,0x6c,0x6c,0x61,0x62, +0x6c,0x65,0x73,0xa3,0x4a,0x1f,0x6f,0x6d,0x70,0x61,0x74,0x69,0x62,0x69,0x6c,0x69, +0x74,0x79,0x6a,0x61,0x6d,0x6f,0xa3,0x41,0x12,0x61,0x6d,0x6f,0x5c,0x17,0x65,0x78, +0x74,0x65,0x6e,0x64,0x65,0x64,1,0x61,0xa3,0xb4,0x62,0xa3,0xb9,0x19,0x66,0x69, +0x72,0x6f,0x68,0x69,0x6e,0x67,0x79,0x61,0xa5,0x1d,0x13,0x62,0x72,0x65,0x77,0x37, +0x61,0xa4,0xc,0x62,0xa6,0x59,0x63,0xa8,0x2e,0x64,0xac,0xe9,0x65,5,0x6d,0xa9, +0x6d,0x94,0x6e,0xa2,0x41,0x74,0x15,0x68,0x69,0x6f,0x70,0x69,0x63,0x5e,1,0x65, +0x40,0x73,0x11,0x75,0x70,0xa2,0x86,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3, +0x86,0x11,0x78,0x74,0xa2,0x85,2,0x61,0xa3,0xc8,0x62,0xa5,0x37,0x65,0x13,0x6e, +0x64,0x65,0x64,0xa2,0x85,1,0x61,0xa3,0xc8,0x62,0xa5,0x37,0x16,0x6f,0x74,0x69, +0x63,0x6f,0x6e,0x73,0xa3,0xce,0x15,0x63,0x6c,0x6f,0x73,0x65,0x64,2,0x61,0x5a, +0x63,0x9e,0x69,0x1c,0x64,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x73,0x75, +0x70,0xa2,0xc4,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xc4,0x16,0x6c,0x70, +0x68,0x61,0x6e,0x75,0x6d,0x86,1,0x65,0x2c,0x73,0x11,0x75,0x70,0xa3,0xc3,0x13, +0x72,0x69,0x63,0x73,0x86,0x18,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3, +0xc3,0x11,0x6a,0x6b,0xa2,0x44,0x1f,0x6c,0x65,0x74,0x74,0x65,0x72,0x73,0x61,0x6e, +0x64,0x6d,0x6f,0x6e,0x74,0x68,0x73,0xa3,0x44,0x61,0x4a,0x67,0x76,0x6c,1,0x62, +0x30,0x79,0x13,0x6d,0x61,0x69,0x63,0xa5,0x25,0x13,0x61,0x73,0x61,0x6e,0xa3,0xe2, +0x13,0x72,0x6c,0x79,0x64,0x1f,0x79,0x6e,0x61,0x73,0x74,0x69,0x63,0x63,0x75,0x6e, +0x65,0x69,0x66,0x6f,0x72,0x6d,0xa5,1,0x1f,0x79,0x70,0x74,0x69,0x61,0x6e,0x68, +0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,1,0x66,0x26,0x73,0xa3,0xc2,0x1c, +0x6f,0x72,0x6d,0x61,0x74,0x63,0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x73,0xa5,0x24,7, +0x6e,0xc0,0xf2,0x6e,0x3e,0x72,0xa2,0x5d,0x73,0xa2,0xe5,0x76,0x14,0x65,0x73,0x74, +0x61,0x6e,0xa3,0xbc,1,0x61,0x92,0x63,0x13,0x69,0x65,0x6e,0x74,1,0x67,0x34, +0x73,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xa5,0x13,0x72,0x65,0x65,0x6b,1, +0x6d,0x34,0x6e,0x15,0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0x7f,0x13,0x75,0x73,0x69, +0x63,0xa2,0x7e,0x19,0x61,0x6c,0x6e,0x6f,0x74,0x61,0x74,0x69,0x6f,0x6e,0xa3,0x7e, +0x10,0x74,0x1f,0x6f,0x6c,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79, +0x70,0x68,0x73,0xa3,0xfe,2,0x61,0x32,0x6d,0xa2,0x7e,0x72,0x12,0x6f,0x77,0x73, +0x7d,0x12,0x62,0x69,0x63,0x38,3,0x65,0x4a,0x6d,0x80,0x70,0xa2,0x50,0x73,0x11, +0x75,0x70,0xa2,0x80,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x80,0x11,0x78, +0x74,3,0x61,0xa3,0xd2,0x62,0xa5,0x35,0x63,0xa5,0x41,0x65,0x13,0x6e,0x64,0x65, +0x64,2,0x61,0xa3,0xd2,0x62,0xa5,0x35,0x63,0xa5,0x41,0x12,0x61,0x74,0x68,0xa2, +0xd3,0x18,0x65,0x6d,0x61,0x74,0x69,0x63,0x61,0x6c,0x61,0x1f,0x6c,0x70,0x68,0x61, +0x62,0x65,0x74,0x69,0x63,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xd3,1,0x66, +0x42,0x72,0x1e,0x65,0x73,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x66,0x6f,0x72, +0x6d,0x73,1,0x61,0xa3,0x51,0x62,0xa3,0x55,0x14,0x65,0x6e,0x69,0x61,0x6e,0x35, +0x12,0x63,0x69,0x69,0x23,0x64,0x9e,0x65,0xa2,0x42,0x68,0xa2,0x4d,0x6c,1,0x63, +0x62,0x70,0x17,0x68,0x61,0x62,0x65,0x74,0x69,0x63,0x70,1,0x66,0xa3,0x50,0x72, +0x1e,0x65,0x73,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x66,0x6f,0x72,0x6d,0x73, +0xa3,0x50,0x16,0x68,0x65,0x6d,0x69,0x63,0x61,0x6c,0xa2,0xd0,0x16,0x73,0x79,0x6d, +0x62,0x6f,0x6c,0x73,0xa3,0xd0,0x12,0x6c,0x61,0x6d,0xa5,7,0x1a,0x67,0x65,0x61, +0x6e,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0x77,0x11,0x6f,0x6d,0xa3,0xfd,7, +0x6f,0x71,0x6f,0x64,0x72,0xa2,0x41,0x75,0xa2,0x58,0x79,0x1b,0x7a,0x61,0x6e,0x74, +0x69,0x6e,0x65,0x6d,0x75,0x73,0x69,0x63,0xa2,0x5b,0x18,0x61,0x6c,0x73,0x79,0x6d, +0x62,0x6f,0x6c,0x73,0xa3,0x5b,1,0x70,0x34,0x78,0x16,0x64,0x72,0x61,0x77,0x69, +0x6e,0x67,0x89,0x14,0x6f,0x6d,0x6f,0x66,0x6f,0xa0,0x12,0x65,0x78,0x74,0xa2,0x43, +0x14,0x65,0x6e,0x64,0x65,0x64,0xa3,0x43,0x10,0x61,1,0x68,0x40,0x69,0x12,0x6c, +0x6c,0x65,0x92,0x17,0x70,0x61,0x74,0x74,0x65,0x72,0x6e,0x73,0x93,0x11,0x6d,0x69, +0xa3,0xc9,1,0x67,0x2c,0x68,0x11,0x69,0x64,0xa3,0x64,0x14,0x69,0x6e,0x65,0x73, +0x65,0xa3,0x81,0x61,0x48,0x65,0xa2,0x4e,0x68,0xa2,0x52,0x6c,0x1a,0x6f,0x63,0x6b, +0x65,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x73,0x8b,3,0x6c,0x34,0x6d,0x40,0x73,0x66, +0x74,0x11,0x61,0x6b,0xa3,0xc7,0x14,0x69,0x6e,0x65,0x73,0x65,0xa3,0x93,0x11,0x75, +0x6d,0xa2,0xb1,0x12,0x73,0x75,0x70,0xa2,0xca,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e, +0x74,0xa3,0xca,1,0x69,0x30,0x73,0x13,0x61,0x76,0x61,0x68,0xa3,0xdd,0x15,0x63, +0x6c,0x61,0x74,0x69,0x6e,0x23,0x14,0x6e,0x67,0x61,0x6c,0x69,0x41,0x16,0x61,0x69, +0x6b,0x73,0x75,0x6b,0x69,0xa5,8,5,0x6f,0xc1,0x60,0x6f,0xa2,0x69,0x75,0xa4, +0x24,0x79,1,0x70,0xa2,0x44,0x72,0x14,0x69,0x6c,0x6c,0x69,0x63,0x32,1,0x65, +0x4c,0x73,0x11,0x75,0x70,0xa2,0x61,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa2, +0x61,0x12,0x61,0x72,0x79,0xa3,0x61,0x11,0x78,0x74,4,0x61,0xa3,0x9e,0x62,0xa3, +0xa0,0x63,0xa5,9,0x64,0xa5,0x43,0x65,0x13,0x6e,0x64,0x65,0x64,3,0x61,0xa3, +0x9e,0x62,0xa3,0xa0,0x63,0xa5,9,0x64,0xa5,0x43,0x10,0x72,1,0x69,0x34,0x6f, +0x15,0x6d,0x69,0x6e,0x6f,0x61,0x6e,0xa5,0x36,0x1a,0x6f,0x74,0x73,0x79,0x6c,0x6c, +0x61,0x62,0x61,0x72,0x79,0xa3,0x7b,3,0x6d,0x5a,0x6e,0xa2,0x95,0x70,0xa2,0xa0, +0x75,0x17,0x6e,0x74,0x69,0x6e,0x67,0x72,0x6f,0x64,0xa2,0x9a,0x17,0x6e,0x75,0x6d, +0x65,0x72,0x61,0x6c,0x73,0xa3,0x9a,2,0x62,0x3a,0x6d,0xa2,0x5f,0x70,0x15,0x61, +0x74,0x6a,0x61,0x6d,0x6f,0xa3,0x41,0x14,0x69,0x6e,0x69,0x6e,0x67,2,0x64,0x46, +0x68,0x9e,0x6d,0x1d,0x61,0x72,0x6b,0x73,0x66,0x6f,0x72,0x73,0x79,0x6d,0x62,0x6f, +0x6c,0x73,0x77,0x1e,0x69,0x61,0x63,0x72,0x69,0x74,0x69,0x63,0x61,0x6c,0x6d,0x61, +0x72,0x6b,0x73,0x2e,2,0x65,0x40,0x66,0xa6,0x52,0x73,0x18,0x75,0x70,0x70,0x6c, +0x65,0x6d,0x65,0x6e,0x74,0xa3,0x83,0x16,0x78,0x74,0x65,0x6e,0x64,0x65,0x64,0xa3, +0xe0,0x17,0x61,0x6c,0x66,0x6d,0x61,0x72,0x6b,0x73,0xa3,0x52,0x11,0x6f,0x6e,0x1f, +0x69,0x6e,0x64,0x69,0x63,0x6e,0x75,0x6d,0x62,0x65,0x72,0x66,0x6f,0x72,0x6d,0x73, +0xa3,0xb2,0x1b,0x74,0x72,0x6f,0x6c,0x70,0x69,0x63,0x74,0x75,0x72,0x65,0x73,0x83, +0x12,0x74,0x69,0x63,0xa2,0x84,0x1b,0x65,0x70,0x61,0x63,0x74,0x6e,0x75,0x6d,0x62, +0x65,0x72,0x73,0xa3,0xdf,1,0x6e,0x3e,0x72,0x1b,0x72,0x65,0x6e,0x63,0x79,0x73, +0x79,0x6d,0x62,0x6f,0x6c,0x73,0x75,0x15,0x65,0x69,0x66,0x6f,0x72,0x6d,0xa2,0x98, +0x16,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa2,0x99,0x1d,0x61,0x6e,0x64,0x70,0x75, +0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xa3,0x99,0x61,0xa2,0xea,0x68,0xa4, +0x14,0x6a,0x10,0x6b,0xa2,0x47,4,0x63,0x92,0x65,0xa2,0x83,0x72,0xa2,0xa1,0x73, +0xa2,0xb3,0x75,0x1f,0x6e,0x69,0x66,0x69,0x65,0x64,0x69,0x64,0x65,0x6f,0x67,0x72, +0x61,0x70,0x68,0x73,0xa2,0x47,0x18,0x65,0x78,0x74,0x65,0x6e,0x73,0x69,0x6f,0x6e, +8,0x65,0x71,0x65,0xa5,0,0x66,0xa5,0x12,0x67,0xa5,0x2e,0x68,0xa5,0x42,0x69, +0xa5,0x48,0x14,0x6f,0x6d,0x70,0x61,0x74,0xa2,0x45,1,0x66,0x96,0x69,1,0x62, +0x44,0x64,0x17,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa2,0x4f,0x12,0x73,0x75, +0x70,0xa3,0x5f,0x14,0x69,0x6c,0x69,0x74,0x79,0xa2,0x45,1,0x66,0x54,0x69,0x18, +0x64,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa2,0x4f,0x19,0x73,0x75,0x70,0x70, +0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x5f,0x13,0x6f,0x72,0x6d,0x73,0xa3,0x53,0x11, +0x78,0x74,8,0x65,0xf,0x65,0xa5,0,0x66,0xa5,0x12,0x67,0xa5,0x2e,0x68,0xa5, +0x42,0x69,0xa5,0x48,0x61,0xa3,0x46,0x62,0xa3,0x5e,0x63,0xa3,0xc5,0x64,0xa3,0xd1, +0x19,0x61,0x64,0x69,0x63,0x61,0x6c,0x73,0x73,0x75,0x70,0x94,0x16,0x70,0x6c,0x65, +0x6d,0x65,0x6e,0x74,0x95,1,0x74,0x50,0x79,0x14,0x6d,0x62,0x6f,0x6c,0x73,0x9a, +0x1d,0x61,0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x9b, +0x14,0x72,0x6f,0x6b,0x65,0x73,0xa3,0x82,2,0x6e,0x48,0x72,0x64,0x75,0x1d,0x63, +0x61,0x73,0x69,0x61,0x6e,0x61,0x6c,0x62,0x61,0x6e,0x69,0x61,0x6e,0xa3,0xde,0x1d, +0x61,0x64,0x69,0x61,0x6e,0x73,0x79,0x6c,0x6c,0x61,0x62,0x69,0x63,0x73,0x63,0x12, +0x69,0x61,0x6e,0xa3,0xa8,2,0x61,0x3a,0x65,0x4c,0x6f,0x16,0x72,0x61,0x73,0x6d, +0x69,0x61,0x6e,0xa5,0x2d,1,0x6b,0x26,0x6d,0xa3,0xa4,0x11,0x6d,0x61,0xa3,0xd4, +1,0x72,0x38,0x73,0x17,0x73,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa5,0x19,0x13, +0x6f,0x6b,0x65,0x65,0x60,0x12,0x73,0x75,0x70,0xa2,0xff,0x16,0x70,0x6c,0x65,0x6d, +0x65,0x6e,0x74,0xa3,0xff,3,0x65,0x3e,0x69,0x8e,0x6f,0xa2,0x71,0x75,0x15,0x70, +0x6c,0x6f,0x79,0x61,0x6e,0xa3,0xe1,1,0x73,0x60,0x76,0x16,0x61,0x6e,0x61,0x67, +0x61,0x72,0x69,0x3e,0x12,0x65,0x78,0x74,0xa2,0xb3,1,0x61,0xa5,0x44,0x65,0x13, +0x6e,0x64,0x65,0x64,0xa2,0xb3,0x10,0x61,0xa5,0x44,0x13,0x65,0x72,0x65,0x74,0xa3, +0x5a,2,0x61,0x3a,0x6e,0x82,0x76,0x16,0x65,0x73,0x61,0x6b,0x75,0x72,0x75,0xa5, +0x2f,0x18,0x63,0x72,0x69,0x74,0x69,0x63,0x61,0x6c,0x73,0x2e,2,0x65,0x30,0x66, +0x36,0x73,0x11,0x75,0x70,0xa3,0x83,0x11,0x78,0x74,0xa3,0xe0,0x18,0x6f,0x72,0x73, +0x79,0x6d,0x62,0x6f,0x6c,0x73,0x77,0x14,0x67,0x62,0x61,0x74,0x73,0x91,1,0x67, +0x3e,0x6d,0x12,0x69,0x6e,0x6f,0xa2,0xab,0x14,0x74,0x69,0x6c,0x65,0x73,0xa3,0xab, +0x11,0x72,0x61,0xa5,0x1a,8,0x6d,0x5f,0x6d,0x3a,0x6e,0x48,0x73,0x7a,0x76,0xa2, +0x4b,0x77,0x12,0x69,0x64,0x65,0x43,0x11,0x65,0x64,0x32,0x12,0x69,0x61,0x6c,0x33, +2,0x61,0x40,0x62,0x37,0x6f,1,0x62,0x28,0x6e,0x10,0x65,0x21,0x13,0x72,0x65, +0x61,0x6b,0x37,0x10,0x72,0x34,0x12,0x72,0x6f,0x77,0x35,2,0x6d,0x38,0x71,0x46, +0x75,1,0x62,0x3d,0x70,0x3e,0x11,0x65,0x72,0x3f,1,0x61,0x24,0x6c,0x39,0x11, +0x6c,0x6c,0x39,1,0x72,0x3b,0x75,0x12,0x61,0x72,0x65,0x3b,0x12,0x65,0x72,0x74, +0x40,0x13,0x69,0x63,0x61,0x6c,0x41,0x63,0x58,0x65,0x92,0x66,0x96,0x69,1,0x6e, +0x36,0x73,0x10,0x6f,0x30,0x14,0x6c,0x61,0x74,0x65,0x64,0x31,0x11,0x69,0x74,0x2e, +0x12,0x69,0x61,0x6c,0x2f,2,0x61,0x36,0x69,0x48,0x6f,0x10,0x6d,0x24,0x12,0x70, +0x61,0x74,0x25,0x10,0x6e,0x22,0x15,0x6f,0x6e,0x69,0x63,0x61,0x6c,0x23,0x13,0x72, +0x63,0x6c,0x65,0x27,0x11,0x6e,0x63,0x27,2,0x69,0x3a,0x6f,0x44,0x72,0x10,0x61, +0x2c,0x14,0x63,0x74,0x69,0x6f,0x6e,0x2d,0x10,0x6e,0x28,0x11,0x61,0x6c,0x29,0x11, +0x6e,0x74,0x2b,4,0x61,0x3a,0x66,0x4c,0x68,0x5e,0x6e,0x70,0x77,0x2a,0x12,0x69, +0x64,0x65,0x2b,0x22,0x17,0x6d,0x62,0x69,0x67,0x75,0x6f,0x75,0x73,0x23,0x26,0x17, +0x75,0x6c,0x6c,0x77,0x69,0x64,0x74,0x68,0x27,0x24,0x17,0x61,0x6c,0x66,0x77,0x69, +0x64,0x74,0x68,0x25,0x20,1,0x61,0x30,0x65,0x14,0x75,0x74,0x72,0x61,0x6c,0x21, +0x28,0x13,0x72,0x72,0x6f,0x77,0x29,0xd,0x6e,0xc0,0xfb,0x73,0x6d,0x73,0x3a,0x74, +0x98,0x75,0xa2,0x49,0x7a,2,0x6c,0x3b,0x70,0x3d,0x73,0x39,5,0x6f,0x28,0x6f, +0x57,0x70,0x34,0x75,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x45,0x11,0x61,0x63, +1,0x65,0x32,0x69,0x15,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x31,0x18,0x73,0x65,0x70, +0x61,0x72,0x61,0x74,0x6f,0x72,0x39,0x63,0x53,0x6b,0x55,0x6d,0x51,0x1d,0x69,0x74, +0x6c,0x65,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x27,1,0x6e,0x40, +0x70,0x1c,0x70,0x65,0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x23, +0x17,0x61,0x73,0x73,0x69,0x67,0x6e,0x65,0x64,0x21,0x6e,0x8a,0x6f,0xa2,0x47,0x70, +8,0x66,0x14,0x66,0x5b,0x69,0x59,0x6f,0x4f,0x72,0x24,0x73,0x49,0x17,0x69,0x76, +0x61,0x74,0x65,0x75,0x73,0x65,0x43,0x61,0x2c,0x63,0x4d,0x64,0x47,0x65,0x4b,0x1f, +0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72, +0x3d,2,0x64,0x33,0x6c,0x35,0x6f,0x36,0x1b,0x6e,0x73,0x70,0x61,0x63,0x69,0x6e, +0x67,0x6d,0x61,0x72,0x6b,0x2d,1,0x70,0x7c,0x74,0x12,0x68,0x65,0x72,3,0x6c, +0x38,0x6e,0x42,0x70,0x4c,0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c,0x57,0x14,0x65,0x74, +0x74,0x65,0x72,0x2b,0x14,0x75,0x6d,0x62,0x65,0x72,0x37,0x19,0x75,0x6e,0x63,0x74, +0x75,0x61,0x74,0x69,0x6f,0x6e,0x4f,0x1c,0x65,0x6e,0x70,0x75,0x6e,0x63,0x74,0x75, +0x61,0x74,0x69,0x6f,0x6e,0x49,0x66,0x9e,0x66,0x88,0x69,0xa2,0x4b,0x6c,0xa2,0x5c, +0x6d,4,0x61,0x60,0x63,0x31,0x65,0x2f,0x6e,0x2d,0x6f,0x15,0x64,0x69,0x66,0x69, +0x65,0x72,1,0x6c,0x30,0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c,0x55,0x14,0x65,0x74, +0x74,0x65,0x72,0x29,0x17,0x74,0x68,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x51,1,0x69, +0x2e,0x6f,0x13,0x72,0x6d,0x61,0x74,0x41,0x1d,0x6e,0x61,0x6c,0x70,0x75,0x6e,0x63, +0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x5b,0x10,0x6e,0x1f,0x69,0x74,0x69,0x61,0x6c, +0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x59,6,0x6d,0x18,0x6d, +0x29,0x6f,0x28,0x74,0x27,0x75,0x23,0x2a,0x1c,0x77,0x65,0x72,0x63,0x61,0x73,0x65, +0x6c,0x65,0x74,0x74,0x65,0x72,0x25,0x65,0x28,0x69,0x3c,0x6c,0x25,0x19,0x74,0x74, +0x65,0x72,0x6e,0x75,0x6d,0x62,0x65,0x72,0x35,0x1a,0x6e,0x65,0x73,0x65,0x70,0x61, +0x72,0x61,0x74,0x6f,0x72,0x3b,0x63,0x44,0x64,0xa2,0x60,0x65,0x1b,0x6e,0x63,0x6c, +0x6f,0x73,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x2f,6,0x6e,0x39,0x6e,0x46,0x6f, +0x4e,0x73,0x45,0x75,0x1b,0x72,0x72,0x65,0x6e,0x63,0x79,0x73,0x79,0x6d,0x62,0x6f, +0x6c,0x53,0x20,0x12,0x74,0x72,0x6c,0x3f,0x42,0x10,0x6e,1,0x6e,0x2c,0x74,0x12, +0x72,0x6f,0x6c,0x3f,0x1f,0x65,0x63,0x74,0x6f,0x72,0x70,0x75,0x6e,0x63,0x74,0x75, +0x61,0x74,0x69,0x6f,0x6e,0x4d,0x63,0x3f,0x66,0x41,0x6c,0x1d,0x6f,0x73,0x65,0x70, +0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x4b,2,0x61,0x30,0x65,0x4a, +0x69,0x12,0x67,0x69,0x74,0x33,0x1c,0x73,0x68,0x70,0x75,0x6e,0x63,0x74,0x75,0x61, +0x74,0x69,0x6f,0x6e,0x47,0x1a,0x63,0x69,0x6d,0x61,0x6c,0x6e,0x75,0x6d,0x62,0x65, +0x72,0x33,0,0x13,0x6e,0xc1,0xf,0x74,0x76,0x74,0x4c,0x76,0x9a,0x77,0xa2,0x48, +0x79,0xa2,0x49,0x7a,1,0x61,0x2c,0x68,0x12,0x61,0x69,0x6e,0x8b,0x11,0x69,0x6e, +0x85,2,0x61,0x36,0x65,0x3c,0x68,0x14,0x69,0x6e,0x79,0x65,0x68,0xa3,0x66,1, +0x68,0x71,0x77,0x73,1,0x68,0x28,0x74,0x10,0x68,0x77,0x16,0x6d,0x61,0x72,0x62, +0x75,0x74,0x61,0x74,0x13,0x67,0x6f,0x61,0x6c,0x3d,0x1a,0x65,0x72,0x74,0x69,0x63, +0x61,0x6c,0x74,0x61,0x69,0x6c,0xa3,0x67,0x11,0x61,0x77,0x79,1,0x65,0x32,0x75, +0x11,0x64,0x68,0x80,0x11,0x68,0x65,0x83,0x10,0x68,0x7a,1,0x62,0x34,0x77,0x16, +0x69,0x74,0x68,0x74,0x61,0x69,0x6c,0x7f,0x14,0x61,0x72,0x72,0x65,0x65,0x7d,0x6e, +0xa2,0x4c,0x70,0xa2,0x69,0x71,0xa2,0x69,0x72,0xa2,0x6f,0x73,5,0x74,0x22,0x74, +0x38,0x77,0x4c,0x79,0x16,0x72,0x69,0x61,0x63,0x77,0x61,0x77,0x6f,0x18,0x72,0x61, +0x69,0x67,0x68,0x74,0x77,0x61,0x77,0xa3,0x55,0x15,0x61,0x73,0x68,0x6b,0x61,0x66, +0x6d,0x61,0x2e,0x65,0x38,0x68,0x11,0x69,0x6e,0x6b,0x10,0x64,0x62,0x11,0x68,0x65, +0x65,1,0x65,0x2e,0x6d,0x13,0x6b,0x61,0x74,0x68,0x69,0x10,0x6e,0x67,2,0x6f, +0x2c,0x75,0x50,0x79,0x10,0x61,0x91,1,0x6a,0x28,0x6f,0x10,0x6e,0x55,0x1a,0x6f, +0x69,0x6e,0x69,0x6e,0x67,0x67,0x72,0x6f,0x75,0x70,0x21,0x10,0x6e,0x57,0x10,0x65, +0x59,0x10,0x61,1,0x66,0x5b,0x70,0x10,0x68,0x5d,1,0x65,0x38,0x6f,0x18,0x68, +0x69,0x6e,0x67,0x79,0x61,0x79,0x65,0x68,0x93,1,0x68,0x5f,0x76,0x16,0x65,0x72, +0x73,0x65,0x64,0x70,0x65,0x61,0x67,0xc1,0xc7,0x67,0xa4,0x52,0x68,0xa4,0x59,0x6b, +0xa4,0x99,0x6c,0xa4,0xb2,0x6d,2,0x61,0x2e,0x65,0xa4,0x3e,0x69,0x10,0x6d,0x53, +1,0x6c,0xa2,0xe7,0x6e,0x16,0x69,0x63,0x68,0x61,0x65,0x61,0x6e,0,0x12,0x6e, +0x76,0x73,0x51,0x73,0x3e,0x74,0x5c,0x77,0xa0,0x79,0xa2,0x42,0x7a,0x13,0x61,0x79, +0x69,0x6e,0xa3,0x54,0x10,0x61,1,0x64,0x2e,0x6d,0x12,0x65,0x6b,0x68,0xa3,0x4c, +0x11,0x68,0x65,0xa3,0x4b,3,0x61,0x38,0x65,0x3c,0x68,0x4a,0x77,0x13,0x65,0x6e, +0x74,0x79,0xa3,0x51,0x10,0x77,0xa3,0x4d,1,0x6e,0xa3,0x4e,0x74,0x10,0x68,0xa3, +0x4f,0x14,0x61,0x6d,0x65,0x64,0x68,0xa3,0x50,0x11,0x61,0x77,0xa3,0x52,0x12,0x6f, +0x64,0x68,0xa3,0x53,0x6e,0x3a,0x6f,0x40,0x70,0x46,0x71,0x4a,0x72,0x12,0x65,0x73, +0x68,0xa3,0x4a,0x11,0x75,0x6e,0xa3,0x46,0x11,0x6e,0x65,0xa3,0x47,0x10,0x65,0xa3, +0x48,0x12,0x6f,0x70,0x68,0xa3,0x49,0x67,0x33,0x67,0x38,0x68,0x40,0x6b,0x5e,0x6c, +0x66,0x6d,0x11,0x65,0x6d,0xa3,0x45,0x13,0x69,0x6d,0x65,0x6c,0xa1,1,0x65,0x32, +0x75,0x14,0x6e,0x64,0x72,0x65,0x64,0xa3,0x42,0x11,0x74,0x68,0xa3,0x41,0x12,0x61, +0x70,0x68,0xa3,0x43,0x14,0x61,0x6d,0x65,0x64,0x68,0xa3,0x44,0x61,0x34,0x62,0x4a, +0x64,0x50,0x66,0x12,0x69,0x76,0x65,0x9f,1,0x6c,0x2a,0x79,0x11,0x69,0x6e,0x97, +0x12,0x65,0x70,0x68,0x95,0x12,0x65,0x74,0x68,0x99,1,0x61,0x30,0x68,0x14,0x61, +0x6d,0x65,0x64,0x68,0x9d,0x13,0x6c,0x65,0x74,0x68,0x9b,0x15,0x61,0x79,0x61,0x6c, +0x61,0x6d,6,0x6e,0x2c,0x6e,0x34,0x72,0x5e,0x73,0x62,0x74,0x11,0x74,0x61,0xa3, +0x63,2,0x67,0x2e,0x6e,0x32,0x79,0x10,0x61,0xa3,0x60,0x10,0x61,0xa3,0x5d,1, +0x61,0xa3,0x5e,0x6e,0x10,0x61,0xa3,0x5f,0x10,0x61,0xa3,0x61,0x11,0x73,0x61,0xa3, +0x62,0x62,0x3c,0x6a,0x42,0x6c,0x10,0x6c,1,0x61,0xa3,0x5b,0x6c,0x10,0x61,0xa3, +0x5c,0x11,0x68,0x61,0xa3,0x59,0x10,0x61,0xa3,0x5a,0x11,0x65,0x6d,0x51,0x10,0x61, +1,0x66,0x37,0x6d,0x11,0x61,0x6c,0x39,1,0x61,0x40,0x65,0x3e,1,0x68,0x28, +0x74,0x10,0x68,0x45,0x40,0x13,0x67,0x6f,0x61,0x6c,0x43,2,0x68,0x3b,0x6d,0x5c, +0x6e,0x1a,0x69,0x66,0x69,0x72,0x6f,0x68,0x69,0x6e,0x67,0x79,0x61,1,0x6b,0x2a, +0x70,0x10,0x61,0xa3,0x65,0x15,0x69,0x6e,0x6e,0x61,0x79,0x61,0xa3,0x64,0x1a,0x7a, +0x61,0x6f,0x6e,0x68,0x65,0x68,0x67,0x6f,0x61,0x6c,0x3d,2,0x61,0x3a,0x68,0x44, +0x6e,0x17,0x6f,0x74,0x74,0x65,0x64,0x68,0x65,0x68,0x4b,1,0x66,0x47,0x70,0x10, +0x68,0x49,0x12,0x61,0x70,0x68,0x89,0x11,0x61,0x6d,0x4c,0x12,0x61,0x64,0x68,0x4f, +0x61,0x6e,0x62,0xa2,0x54,0x64,0xa2,0x70,0x65,0x31,0x66,2,0x61,0x3e,0x65,0x4a, +0x69,0x19,0x6e,0x61,0x6c,0x73,0x65,0x6d,0x6b,0x61,0x74,0x68,0x35,0x15,0x72,0x73, +0x69,0x79,0x65,0x68,0x8f,0x86,0x10,0x68,0x33,2,0x66,0x3c,0x69,0x70,0x6c,1, +0x61,0x28,0x65,0x10,0x66,0x27,0x11,0x70,0x68,0x25,0x14,0x72,0x69,0x63,0x61,0x6e, +2,0x66,0x30,0x6e,0x36,0x71,0x11,0x61,0x66,0xa3,0x58,0x11,0x65,0x68,0xa3,0x56, +0x12,0x6f,0x6f,0x6e,0xa3,0x57,0x10,0x6e,0x23,1,0x65,0x4a,0x75,0x10,0x72,0x1f, +0x75,0x73,0x68,0x61,0x73,0x6b,0x69,0x79,0x65,0x68,0x62,0x61,0x72,0x72,0x65,0x65, +0x8d,1,0x68,0x29,0x74,0x10,0x68,0x2b,0x11,0x61,0x6c,0x2c,0x16,0x61,0x74,0x68, +0x72,0x69,0x73,0x68,0x2f,7,0x6e,0x2e,0x6e,0x2c,0x72,0x3e,0x74,0x56,0x75,0x21, +0x18,0x6f,0x6e,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x21,0x28,0x1a,0x69,0x67,0x68, +0x74,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x29,0x2a,0x19,0x72,0x61,0x6e,0x73,0x70, +0x61,0x72,0x65,0x6e,0x74,0x2b,0x63,0x23,0x64,0x40,0x6a,0x56,0x6c,0x26,0x19,0x65, +0x66,0x74,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x27,0x24,0x19,0x75,0x61,0x6c,0x6a, +0x6f,0x69,0x6e,0x69,0x6e,0x67,0x25,0x19,0x6f,0x69,0x6e,0x63,0x61,0x75,0x73,0x69, +0x6e,0x67,0x23,0,0x14,0x6e,0xc0,0xe5,0x73,0x5e,0x77,0x23,0x77,0x40,0x78,0x58, +0x7a,0x10,0x77,0x58,1,0x6a,0x75,0x73,0x13,0x70,0x61,0x63,0x65,0x59,1,0x6a, +0x5d,0x6f,0x17,0x72,0x64,0x6a,0x6f,0x69,0x6e,0x65,0x72,0x5d,0x10,0x78,0x21,0x73, +0x4a,0x75,0x7a,0x76,1,0x66,0x7d,0x69,0x7e,0x13,0x72,0x61,0x6d,0x61,0x7e,0x14, +0x66,0x69,0x6e,0x61,0x6c,0x7d,4,0x61,0x51,0x67,0x53,0x70,0x28,0x75,0x30,0x79, +0x57,0x54,0x12,0x61,0x63,0x65,0x55,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x53, +0x15,0x6e,0x6b,0x6e,0x6f,0x77,0x6e,0x21,0x6e,0x60,0x6f,0xa2,0x41,0x70,0xa2,0x50, +0x71,0xa2,0x6e,0x72,1,0x65,0x24,0x69,0x6f,0x1e,0x67,0x69,0x6f,0x6e,0x61,0x6c, +0x69,0x6e,0x64,0x69,0x63,0x61,0x74,0x6f,0x72,0x6f,4,0x65,0x3e,0x6c,0x5b,0x6f, +0x46,0x73,0x45,0x75,0x46,0x14,0x6d,0x65,0x72,0x69,0x63,0x47,0x15,0x78,0x74,0x6c, +0x69,0x6e,0x65,0x5b,0x17,0x6e,0x73,0x74,0x61,0x72,0x74,0x65,0x72,0x45,0x10,0x70, +0x48,0x1c,0x65,0x6e,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x49, +1,0x6f,0x3e,0x72,0x4c,0x1a,0x65,0x66,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,0x69, +0x63,0x4d,0x4a,0x1b,0x73,0x74,0x66,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,0x69,0x63, +0x4b,0x10,0x75,0x4e,0x16,0x6f,0x74,0x61,0x74,0x69,0x6f,0x6e,0x4f,0x68,0x7b,0x68, +0x50,0x69,0x86,0x6a,0xa2,0x61,0x6c,0xa2,0x65,0x6d,0x1c,0x61,0x6e,0x64,0x61,0x74, +0x6f,0x72,0x79,0x62,0x72,0x65,0x61,0x6b,0x2d,4,0x32,0x5f,0x33,0x61,0x65,0x34, +0x6c,0x6d,0x79,0x3a,0x13,0x70,0x68,0x65,0x6e,0x3b,0x19,0x62,0x72,0x65,0x77,0x6c, +0x65,0x74,0x74,0x65,0x72,0x6d,2,0x64,0x28,0x6e,0x3c,0x73,0x41,0x3c,0x18,0x65, +0x6f,0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x3d,0x3e,1,0x66,0x3e,0x73,0x11,0x65, +0x70,1,0x61,0x22,0x65,0x14,0x72,0x61,0x62,0x6c,0x65,0x3f,0x18,0x69,0x78,0x6e, +0x75,0x6d,0x65,0x72,0x69,0x63,0x41,2,0x6c,0x63,0x74,0x65,0x76,0x67,1,0x66, +0x43,0x69,0x15,0x6e,0x65,0x66,0x65,0x65,0x64,0x43,0x61,0x42,0x62,0xa2,0x49,0x63, +0xa2,0x76,0x65,0xa2,0xfc,0x67,0x10,0x6c,0x38,0x11,0x75,0x65,0x39,5,0x6d,0xf, +0x6d,0x28,0x70,0x79,0x73,0x7b,0x16,0x62,0x69,0x67,0x75,0x6f,0x75,0x73,0x23,0x69, +0x23,0x6b,0x38,0x6c,0x24,0x17,0x70,0x68,0x61,0x62,0x65,0x74,0x69,0x63,0x25,0x76, +0x13,0x73,0x61,0x72,0x61,0x76,1,0x70,0x2e,0x73,0x13,0x74,0x61,0x72,0x74,0x7b, +0x15,0x72,0x65,0x62,0x61,0x73,0x65,0x79,4,0x32,0x27,0x61,0x29,0x62,0x2b,0x6b, +0x2d,0x72,0x12,0x65,0x61,0x6b,2,0x61,0x36,0x62,0x3e,0x73,0x15,0x79,0x6d,0x62, +0x6f,0x6c,0x73,0x57,0x13,0x66,0x74,0x65,0x72,0x29,1,0x65,0x2a,0x6f,0x11,0x74, +0x68,0x27,0x13,0x66,0x6f,0x72,0x65,0x2b,7,0x6d,0x51,0x6d,0x33,0x6f,0x28,0x70, +0x69,0x72,0x35,1,0x6d,0x76,0x6e,1,0x64,0x3c,0x74,0x1a,0x69,0x6e,0x67,0x65, +0x6e,0x74,0x62,0x72,0x65,0x61,0x6b,0x2f,0x15,0x69,0x74,0x69,0x6f,0x6e,0x61,0x1f, +0x6c,0x6a,0x61,0x70,0x61,0x6e,0x65,0x73,0x65,0x73,0x74,0x61,0x72,0x74,0x65,0x72, +0x6b,1,0x62,0x3a,0x70,0x19,0x6c,0x65,0x78,0x63,0x6f,0x6e,0x74,0x65,0x78,0x74, +0x51,0x18,0x69,0x6e,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x33,0x61,0x6a,0x62,0x2f, +0x6a,0x6b,0x6c,0x30,0x13,0x6f,0x73,0x65,0x70,1,0x61,0x38,0x75,0x18,0x6e,0x63, +0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x31,0x18,0x72,0x65,0x6e,0x74,0x68,0x65,0x73, +0x69,0x73,0x69,0x1b,0x72,0x72,0x69,0x61,0x67,0x65,0x72,0x65,0x74,0x75,0x72,0x6e, +0x35,2,0x62,0x3e,0x6d,0x46,0x78,0x36,0x18,0x63,0x6c,0x61,0x6d,0x61,0x74,0x69, +0x6f,0x6e,0x37,0x70,0x12,0x61,0x73,0x65,0x71,0x72,0x16,0x6f,0x64,0x69,0x66,0x69, +0x65,0x72,0x73,1,0x64,0x42,0x6e,1,0x6f,0x32,0x75,0x26,0x14,0x6d,0x65,0x72, +0x69,0x63,0x27,0x11,0x6e,0x65,0x21,1,0x65,0x2e,0x69,0x24,0x12,0x67,0x69,0x74, +0x25,0x22,0x14,0x63,0x69,0x6d,0x61,0x6c,0x23,0,0x18,0x6e,0xc4,0x6f,0x74,0xc1, +0x91,0x77,0x96,0x77,0xa2,0x4c,0x78,0xa2,0x70,0x79,0xa2,0x7a,0x7a,6,0x73,0x1e, +0x73,0x34,0x78,0x42,0x79,0x48,0x7a,0x11,0x7a,0x7a,0xa3,0x67,0x10,0x79,1,0x65, +0xa3,0xae,0x6d,0xa3,0x81,0x11,0x78,0x78,0xa3,0x66,0x11,0x79,0x79,0x21,0x61,0x30, +0x69,0x58,0x6d,0x11,0x74,0x68,0xa3,0x80,0x10,0x6e,1,0x61,0x26,0x62,0xa3,0xb1, +0x1a,0x62,0x61,0x7a,0x61,0x72,0x73,0x71,0x75,0x61,0x72,0x65,0xa3,0xb1,0x11,0x6e, +0x68,0x23,2,0x61,0x30,0x63,0x5a,0x6f,0x11,0x6c,0x65,0xa3,0x9b,1,0x6e,0x3c, +0x72,0x10,0x61,0xa2,0x92,0x15,0x6e,0x67,0x63,0x69,0x74,0x69,0xa3,0x92,0x12,0x63, +0x68,0x6f,0xa3,0xbc,0x11,0x68,0x6f,0xa3,0xbc,1,0x70,0x2c,0x73,0x11,0x75,0x78, +0xa3,0x65,0x11,0x65,0x6f,0x9b,1,0x65,0x2c,0x69,0x72,0x11,0x69,0x69,0x73,0x11, +0x7a,0x69,0xa2,0xc0,0x11,0x64,0x69,0xa3,0xc0,0x74,0x66,0x75,0xa2,0xde,0x76,1, +0x61,0x48,0x69,1,0x73,0x38,0x74,0x10,0x68,0xa2,0xc5,0x13,0x6b,0x75,0x71,0x69, +0xa3,0xc5,0x10,0x70,0xa3,0x64,0x10,0x69,0xa2,0x63,0x10,0x69,0xa3,0x63,7,0x68, +0x3e,0x68,0x34,0x69,0x48,0x6e,0x86,0x6f,0x11,0x74,0x6f,0xa3,0xc4,0x10,0x61,1, +0x61,0x24,0x69,0x6d,0x6a,0x11,0x6e,0x61,0x6b,2,0x62,0x3a,0x66,0x4a,0x72,0x10, +0x68,0xa2,0x9e,0x12,0x75,0x74,0x61,0xa3,0x9e,1,0x65,0x24,0x74,0x6f,0x12,0x74, +0x61,0x6e,0x6f,0x14,0x69,0x6e,0x61,0x67,0x68,0x99,0x11,0x73,0x61,0xa3,0xc3,0x61, +0x36,0x65,0xa2,0x65,0x66,0xa2,0x71,0x67,0x11,0x6c,0x67,0x75,6,0x6c,0x28,0x6c, +0x32,0x6d,0x38,0x6e,0x44,0x76,0x10,0x74,0xa3,0x7f,1,0x65,0x89,0x75,0x97,1, +0x69,0x24,0x6c,0x67,0x10,0x6c,0x67,0x10,0x67,0xa2,0x9a,1,0x73,0x2a,0x75,0x10, +0x74,0xa3,0x9a,0x10,0x61,0xa3,0xc3,0x67,0x36,0x69,0x52,0x6b,0x10,0x72,0xa2,0x99, +0x10,0x69,0xa3,0x99,1,0x61,0x30,0x62,0x7a,0x13,0x61,0x6e,0x77,0x61,0x7b,0x12, +0x6c,0x6f,0x67,0x75,2,0x6c,0x32,0x74,0x34,0x76,0x12,0x69,0x65,0x74,0xa3,0x7f, +0x10,0x65,0x89,0x12,0x68,0x61,0x6d,0xa3,0x6a,1,0x6c,0x2a,0x6e,0x10,0x67,0xa3, +0x62,0x10,0x75,0x68,0x11,0x67,0x75,0x69,0x11,0x6e,0x67,0x99,1,0x67,0x32,0x6e, +0x14,0x6b,0x6e,0x6f,0x77,0x6e,0xa3,0x67,0x11,0x61,0x72,0x8a,0x13,0x69,0x74,0x69, +0x63,0x8b,0x71,0xc1,0x13,0x71,0xa2,0xde,0x72,0xa2,0xe3,0x73,6,0x69,0x8a,0x69, +0x72,0x6f,0xa2,0x4c,0x75,0xa2,0x75,0x79,1,0x6c,0x46,0x72,4,0x63,0x65,0x65, +0xa3,0x5f,0x69,0x2c,0x6a,0xa3,0x60,0x6e,0xa3,0x61,0x11,0x61,0x63,0x65,0x10,0x6f, +0x94,0x16,0x74,0x69,0x6e,0x61,0x67,0x72,0x69,0x95,2,0x64,0x3c,0x67,0x4c,0x6e, +1,0x64,0xa3,0x91,0x68,0x62,0x12,0x61,0x6c,0x61,0x63,0x10,0x64,0xa2,0xa6,0x12, +0x68,0x61,0x6d,0xa3,0xa6,0x17,0x6e,0x77,0x72,0x69,0x74,0x69,0x6e,0x67,0xa3,0x70, +2,0x67,0x3a,0x72,0x52,0x79,0x10,0x6f,0xa2,0xb0,0x12,0x6d,0x62,0x6f,0xa3,0xb0, +1,0x64,0x26,0x6f,0xa3,0xb8,0xa2,0xb7,0x12,0x69,0x61,0x6e,0xa3,0xb7,0x10,0x61, +0xa2,0x98,0x16,0x73,0x6f,0x6d,0x70,0x65,0x6e,0x67,0xa3,0x98,0x11,0x6e,0x64,0xa2, +0x71,0x14,0x61,0x6e,0x65,0x73,0x65,0xa3,0x71,0x61,0x5c,0x67,0xa2,0x43,0x68,1, +0x61,0x2a,0x72,0x10,0x64,0xa3,0x97,2,0x72,0x28,0x76,0x30,0x77,0x87,0x12,0x61, +0x64,0x61,0xa3,0x97,0x12,0x69,0x61,0x6e,0x87,2,0x6d,0x40,0x72,0x58,0x75,0x10, +0x72,0xa2,0x6f,0x15,0x61,0x73,0x68,0x74,0x72,0x61,0xa3,0x6f,1,0x61,0x26,0x72, +0xa3,0x7e,0x14,0x72,0x69,0x74,0x61,0x6e,0xa3,0x7e,1,0x61,0xa3,0x5e,0x62,0xa3, +0x85,0x11,0x6e,0x77,0xa3,0x70,0x11,0x61,0x61,1,0x63,0x2f,0x69,0x23,3,0x65, +0x3e,0x6a,0x48,0x6f,0x4e,0x75,0x10,0x6e,1,0x69,0x24,0x72,0x61,0x10,0x63,0x61, +0x13,0x6a,0x61,0x6e,0x67,0xa3,0x6e,0x11,0x6e,0x67,0xa3,0x6e,1,0x68,0x2a,0x72, +0x10,0x6f,0xa3,0x5d,0x10,0x67,0xa3,0xb6,0x6e,0xa2,0x83,0x6f,0xa4,1,0x70,5, +0x6c,0x1e,0x6c,0x44,0x72,0x4a,0x73,0x1b,0x61,0x6c,0x74,0x65,0x72,0x70,0x61,0x68, +0x6c,0x61,0x76,0x69,0xa3,0x7b,0x11,0x72,0x64,0xa3,0x5c,0x11,0x74,0x69,0xa3,0x7d, +0x61,0x7c,0x65,0xa2,0x54,0x68,3,0x61,0x3e,0x6c,0x4e,0x6e,0x5e,0x6f,0x16,0x65, +0x6e,0x69,0x63,0x69,0x61,0x6e,0xa3,0x5b,0x10,0x67,0xa2,0x5a,0x12,0x73,0x70,0x61, +0xa3,0x5a,2,0x69,0xa3,0x7a,0x70,0xa3,0x7b,0x76,0xa3,0x7c,0x10,0x78,0xa3,0x5b, +2,0x68,0x3e,0x6c,0x50,0x75,0x10,0x63,0xa2,0xa5,0x14,0x69,0x6e,0x68,0x61,0x75, +0xa3,0xa5,0x17,0x61,0x77,0x68,0x68,0x6d,0x6f,0x6e,0x67,0xa3,0x4b,0x10,0x6d,0xa2, +0x90,0x14,0x79,0x72,0x65,0x6e,0x65,0xa3,0x90,0x11,0x72,0x6d,0xa3,0x59,6,0x6b, +0x36,0x6b,0x56,0x73,0x6e,0x75,0x74,0x79,0x11,0x69,0x61,0x1f,0x6b,0x65,0x6e,0x67, +0x70,0x75,0x61,0x63,0x68,0x75,0x65,0x68,0x6d,0x6f,0x6e,0x67,0xa3,0xba,1,0x67, +0x2e,0x6f,0xa2,0x57,0x10,0x6f,0xa3,0x57,0x10,0x62,0xa3,0x84,0x11,0x68,0x75,0xa3, +0x96,0x12,0x73,0x68,0x75,0xa3,0x96,0x61,0x42,0x62,0x9e,0x65,0x10,0x77,1,0x61, +0xa3,0xaa,0x74,0x14,0x61,0x69,0x6c,0x75,0x65,0x97,3,0x62,0x32,0x67,0x40,0x6e, +0x56,0x72,0x10,0x62,0xa3,0x8e,0x15,0x61,0x74,0x61,0x65,0x61,0x6e,0xa3,0x8f,0x10, +0x6d,0xa2,0xc7,0x15,0x75,0x6e,0x64,0x61,0x72,0x69,0xa3,0xc7,0x10,0x64,0xa2,0xbb, +0x16,0x69,0x6e,0x61,0x67,0x61,0x72,0x69,0xa3,0xbb,0x11,0x61,0x74,0xa3,0x8f,4, +0x67,0x3c,0x6c,0x4e,0x72,0xa2,0x8e,0x73,0xa2,0x9c,0x75,0x11,0x67,0x72,0xa3,0xc2, +1,0x61,0x2a,0x68,0x11,0x61,0x6d,0x5b,0x10,0x6d,0x5b,1,0x63,0xa2,0x6a,0x64, +6,0x70,0x41,0x70,0x3a,0x73,0x58,0x74,0x86,0x75,0x14,0x79,0x67,0x68,0x75,0x72, +0xa3,0xc2,0x11,0x65,0x72,1,0x6d,0x2c,0x73,0x12,0x69,0x61,0x6e,0x9b,0x11,0x69, +0x63,0xa3,0x59,0x10,0x6f,1,0x67,0x3a,0x75,0x18,0x74,0x68,0x61,0x72,0x61,0x62, +0x69,0x61,0x6e,0xa3,0x85,0x13,0x64,0x69,0x61,0x6e,0xa3,0xb8,0x14,0x75,0x72,0x6b, +0x69,0x63,0xa3,0x58,0x68,0x42,0x69,0x54,0x6e,0x1a,0x6f,0x72,0x74,0x68,0x61,0x72, +0x61,0x62,0x69,0x61,0x6e,0xa3,0x8e,0x17,0x75,0x6e,0x67,0x61,0x72,0x69,0x61,0x6e, +0xa3,0x4c,0x14,0x74,0x61,0x6c,0x69,0x63,0x5d,1,0x68,0x26,0x6b,0xa3,0x6d,0x12, +0x69,0x6b,0x69,0xa3,0x6d,2,0x69,0x2c,0x6b,0x30,0x79,0x10,0x61,0x5f,0x11,0x79, +0x61,0x5f,0x10,0x68,0xa3,0x58,2,0x61,0x36,0x67,0x3c,0x6d,0x10,0x61,0x84,0x12, +0x6e,0x79,0x61,0x85,0x11,0x67,0x65,0xa3,0xab,0x10,0x65,0xa3,0xab,0x68,0xc3,0x15, +0x6b,0xc2,0x2c,0x6b,0xa4,0x17,0x6c,0xa4,0xba,0x6d,8,0x6f,0x46,0x6f,0x48,0x72, +0x74,0x74,0x80,0x75,0x86,0x79,1,0x61,0x28,0x6d,0x10,0x72,0x59,0x13,0x6e,0x6d, +0x61,0x72,0x59,2,0x64,0x2e,0x6e,0x32,0x6f,0x10,0x6e,0xa3,0x72,0x10,0x69,0xa3, +0xa3,0x10,0x67,0x56,0x14,0x6f,0x6c,0x69,0x61,0x6e,0x57,0x10,0x6f,0xa2,0x95,0x10, +0x6f,0xa3,0x95,0x11,0x65,0x69,0xa3,0x73,0x11,0x6c,0x74,0xa2,0xa4,0x12,0x61,0x6e, +0x69,0xa3,0xa4,0x61,0x36,0x65,0xa2,0x67,0x69,0xa2,0xbd,0x6c,0x11,0x79,0x6d,0x55, +6,0x6e,0x38,0x6e,0x32,0x72,0x5c,0x73,0x6c,0x79,0x10,0x61,0xa3,0x55,1,0x64, +0x38,0x69,0xa2,0x79,0x15,0x63,0x68,0x61,0x65,0x61,0x6e,0xa3,0x79,0xa2,0x54,0x12, +0x61,0x69,0x63,0xa3,0x54,0x10,0x63,0xa2,0xa9,0x12,0x68,0x65,0x6e,0xa3,0xa9,0x18, +0x61,0x72,0x61,0x6d,0x67,0x6f,0x6e,0x64,0x69,0xa3,0xaf,0x68,0x36,0x6b,0x4c,0x6c, +0x15,0x61,0x79,0x61,0x6c,0x61,0x6d,0x55,1,0x61,0x26,0x6a,0xa3,0xa0,0x13,0x6a, +0x61,0x6e,0x69,0xa3,0xa0,0x10,0x61,0xa2,0xb4,0x12,0x73,0x61,0x72,0xa3,0xb4,3, +0x64,0x78,0x65,0x94,0x6e,0xa2,0x42,0x72,1,0x63,0xa3,0x8d,0x6f,0xa2,0x56,0x13, +0x69,0x74,0x69,0x63,1,0x63,0x3c,0x68,0x19,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79, +0x70,0x68,0x73,0xa3,0x56,0x15,0x75,0x72,0x73,0x69,0x76,0x65,0xa3,0x8d,1,0x65, +0x26,0x66,0xa3,0xb5,0x16,0x66,0x61,0x69,0x64,0x72,0x69,0x6e,0xa3,0xb5,0x17,0x74, +0x65,0x69,0x6d,0x61,0x79,0x65,0x6b,0xa3,0x73,0x10,0x64,0xa2,0x8c,0x17,0x65,0x6b, +0x69,0x6b,0x61,0x6b,0x75,0x69,0xa3,0x8c,0x11,0x61,0x6f,0xa3,0x5c,6,0x6e,0x1a, +0x6e,0x34,0x6f,0x38,0x70,0x3e,0x74,0x11,0x68,0x69,0xa3,0x78,0x11,0x64,0x61,0x4b, +0x11,0x72,0x65,0xa3,0x77,0x11,0x65,0x6c,0xa3,0x8a,0x61,0x32,0x68,0xa2,0x44,0x69, +0x11,0x74,0x73,0xa3,0xbf,5,0x74,0x23,0x74,0x34,0x77,0x56,0x79,0x13,0x61,0x68, +0x6c,0x69,0xa3,0x4f,0x14,0x61,0x6b,0x61,0x6e,0x61,0x4c,0x19,0x6f,0x72,0x68,0x69, +0x72,0x61,0x67,0x61,0x6e,0x61,0x8d,0x10,0x69,0xa3,0xc6,0x69,0x38,0x6c,0x40,0x6e, +1,0x61,0x4d,0x6e,0x12,0x61,0x64,0x61,0x4b,0x12,0x74,0x68,0x69,0xa3,0x78,0x10, +0x69,0xa3,0x4f,4,0x61,0x40,0x69,0x52,0x6d,0x70,0x6f,0x7c,0x75,0x15,0x64,0x61, +0x77,0x61,0x64,0x69,0xa3,0x91,0x10,0x72,0x92,0x15,0x6f,0x73,0x68,0x74,0x68,0x69, +0x93,0x1d,0x74,0x61,0x6e,0x73,0x6d,0x61,0x6c,0x6c,0x73,0x63,0x72,0x69,0x70,0x74, +0xa3,0xbf,1,0x65,0x24,0x72,0x4f,0x10,0x72,0x4f,0x10,0x6a,0xa2,0x9d,0x11,0x6b, +0x69,0xa3,0x9d,4,0x61,0x5c,0x65,0x90,0x69,0xa0,0x6f,0xa2,0x5d,0x79,1,0x63, +0x34,0x64,0x10,0x69,0xa2,0x6c,0x11,0x61,0x6e,0xa3,0x6c,0x10,0x69,0xa2,0x6b,0x11, +0x61,0x6e,0xa3,0x6b,2,0x6e,0x42,0x6f,0x46,0x74,3,0x66,0xa3,0x50,0x67,0xa3, +0x51,0x69,0x24,0x6e,0x53,0x10,0x6e,0x53,0x10,0x61,0xa3,0x6a,0x50,0x10,0x6f,0x51, +0x11,0x70,0x63,0xa2,0x52,0x11,0x68,0x61,0xa3,0x52,2,0x6d,0x2e,0x6e,0x36,0x73, +0x10,0x75,0xa3,0x83,0x10,0x62,0x80,0x10,0x75,0x81,2,0x61,0xa3,0x53,0x62,0x83, +0x65,0x11,0x61,0x72,1,0x61,0xa3,0x53,0x62,0x83,0x11,0x6d,0x61,0xa3,0x8b,0x68, +0x6e,0x69,0xa2,0x95,0x6a,2,0x61,0x30,0x70,0x52,0x75,0x11,0x72,0x63,0xa3,0x94, +1,0x6d,0x38,0x76,0x10,0x61,0xa2,0x4e,0x13,0x6e,0x65,0x73,0x65,0xa3,0x4e,0x10, +0x6f,0xa3,0xad,0x11,0x61,0x6e,0xa3,0x69,6,0x6c,0x1e,0x6c,0x34,0x6d,0x3a,0x72, +0x48,0x75,0x11,0x6e,0x67,0xa3,0x4c,0x11,0x75,0x77,0xa3,0x9c,0x10,0x6e,1,0x67, +0xa3,0x4b,0x70,0xa3,0xba,0x11,0x6b,0x74,0x8d,0x61,0x3c,0x65,0xa2,0x43,0x69,0x11, +0x72,0x61,0x48,0x13,0x67,0x61,0x6e,0x61,0x49,1,0x6e,0x34,0x74,0x10,0x72,0xa2, +0xa2,0x11,0x61,0x6e,0xa3,0xa2,0x42,6,0x6f,0xe,0x6f,0x77,0x73,0xa3,0x49,0x74, +0xa3,0x4a,0x75,0x12,0x6e,0x6f,0x6f,0x77,0x62,0xa3,0xac,0x67,0x3e,0x69,0x42,0x19, +0x66,0x69,0x72,0x6f,0x68,0x69,0x6e,0x67,0x79,0x61,0xa3,0xb6,0x44,0x11,0x75,0x6c, +0x45,0x11,0x62,0x72,0x46,0x11,0x65,0x77,0x47,2,0x6d,0x2e,0x6e,0x4a,0x74,0x11, +0x61,0x6c,0x5d,0x1c,0x70,0x65,0x72,0x69,0x61,0x6c,0x61,0x72,0x61,0x6d,0x61,0x69, +0x63,0xa3,0x74,2,0x64,0x66,0x68,0x6a,0x73,0x1b,0x63,0x72,0x69,0x70,0x74,0x69, +0x6f,0x6e,0x61,0x6c,0x70,0x61,1,0x68,0x32,0x72,0x14,0x74,0x68,0x69,0x61,0x6e, +0xa3,0x7d,0x13,0x6c,0x61,0x76,0x69,0xa3,0x7a,0x10,0x73,0xa3,0x4d,0x15,0x65,0x72, +0x69,0x74,0x65,0x64,0x23,0x64,0xc1,0xd,0x64,0xa2,0x7a,0x65,0xa2,0xc1,0x67,4, +0x65,0x82,0x6c,0x9a,0x6f,0xa2,0x46,0x72,0xa2,0x55,0x75,2,0x6a,0x3c,0x6e,0x4e, +0x72,1,0x6d,0x24,0x75,0x41,0x13,0x75,0x6b,0x68,0x69,0x41,1,0x61,0x24,0x72, +0x3f,0x13,0x72,0x61,0x74,0x69,0x3f,0x18,0x6a,0x61,0x6c,0x61,0x67,0x6f,0x6e,0x64, +0x69,0xa3,0xb3,0x10,0x6f,1,0x6b,0xa3,0x48,0x72,0x38,0x13,0x67,0x69,0x61,0x6e, +0x39,0x11,0x61,0x67,0x90,0x15,0x6f,0x6c,0x69,0x74,0x69,0x63,0x91,1,0x6e,0x30, +0x74,0x10,0x68,0x3a,0x11,0x69,0x63,0x3b,1,0x67,0xa3,0xb3,0x6d,0xa3,0xaf,1, +0x61,0x32,0x65,1,0x65,0x24,0x6b,0x3d,0x10,0x6b,0x3d,0x10,0x6e,0xa2,0x89,0x12, +0x74,0x68,0x61,0xa3,0x89,4,0x65,0x46,0x69,0x6c,0x6f,0x8c,0x73,0x9a,0x75,0x11, +0x70,0x6c,0xa2,0x87,0x13,0x6f,0x79,0x61,0x6e,0xa3,0x87,1,0x73,0x38,0x76,0x10, +0x61,0x34,0x15,0x6e,0x61,0x67,0x61,0x72,0x69,0x35,0x13,0x65,0x72,0x65,0x74,0x33, +1,0x61,0x36,0x76,0x16,0x65,0x73,0x61,0x6b,0x75,0x72,0x75,0xa3,0xbe,0x10,0x6b, +0xa3,0xbe,0x11,0x67,0x72,0xa2,0xb2,0x10,0x61,0xa3,0xb2,0x11,0x72,0x74,0x33,2, +0x67,0x3a,0x6c,0x72,0x74,0x11,0x68,0x69,0x36,0x13,0x6f,0x70,0x69,0x63,0x37,0x10, +0x79,2,0x64,0xa3,0x45,0x68,0xa3,0x46,0x70,0xa2,0x47,0x1e,0x74,0x69,0x61,0x6e, +0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0x47,1,0x62,0x36, +0x79,0x10,0x6d,0xa2,0xb9,0x12,0x61,0x69,0x63,0xa3,0xb9,0x10,0x61,0xa2,0x88,0x12, +0x73,0x61,0x6e,0xa3,0x88,0x61,0xa2,0xc9,0x62,0xa4,0x2e,0x63,6,0x6f,0x52,0x6f, +0x76,0x70,0x92,0x75,0xa2,0x41,0x79,1,0x70,0x3e,0x72,2,0x69,0x2a,0x6c,0x31, +0x73,0xa3,0x44,0x13,0x6c,0x6c,0x69,0x63,0x31,0x10,0x72,1,0x69,0x34,0x6f,0x15, +0x6d,0x69,0x6e,0x6f,0x61,0x6e,0xa3,0xc1,0x11,0x6f,0x74,0x7f,1,0x6d,0x30,0x70, +0x10,0x74,0x2e,0x11,0x69,0x63,0x2f,0x12,0x6d,0x6f,0x6e,0x21,1,0x6d,0x28,0x72, +0x10,0x74,0x7f,0x10,0x6e,0xa3,0xc1,0x16,0x6e,0x65,0x69,0x66,0x6f,0x72,0x6d,0xa3, +0x65,0x61,0x32,0x68,0xa2,0x41,0x69,0x11,0x72,0x74,0xa3,0x43,3,0x6b,0x4c,0x6e, +0x50,0x72,0x76,0x75,0x1d,0x63,0x61,0x73,0x69,0x61,0x6e,0x61,0x6c,0x62,0x61,0x6e, +0x69,0x61,0x6e,0xa3,0x9f,0x10,0x6d,0xa3,0x76,1,0x61,0x24,0x73,0x71,0x1d,0x64, +0x69,0x61,0x6e,0x61,0x62,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x71,0x10,0x69, +0xa2,0x68,0x11,0x61,0x6e,0xa3,0x68,3,0x61,0x32,0x65,0x44,0x6f,0x52,0x72,0x10, +0x73,0xa3,0xbd,1,0x6b,0x26,0x6d,0xa3,0x42,0x11,0x6d,0x61,0xa3,0x76,0x10,0x72, +0x2c,0x13,0x6f,0x6b,0x65,0x65,0x2d,0x16,0x72,0x61,0x73,0x6d,0x69,0x61,0x6e,0xa3, +0xbd,6,0x68,0x4a,0x68,0x48,0x6e,0x4e,0x72,0x76,0x76,1,0x65,0x2a,0x73,0x10, +0x74,0xa3,0x75,0x13,0x73,0x74,0x61,0x6e,0xa3,0x75,0x11,0x6f,0x6d,0xa3,0xa1,0x11, +0x61,0x74,0x1f,0x6f,0x6c,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79, +0x70,0x68,0x73,0xa3,0x9c,1,0x61,0x3e,0x6d,2,0x65,0x2a,0x69,0xa3,0x74,0x6e, +0x27,0x13,0x6e,0x69,0x61,0x6e,0x27,0x10,0x62,0x24,0x11,0x69,0x63,0x25,0x64,0x30, +0x66,0x44,0x67,0x11,0x68,0x62,0xa3,0x9f,0x10,0x6c,1,0x61,0x26,0x6d,0xa3,0xa7, +0x10,0x6d,0xa3,0xa7,0x11,0x61,0x6b,0xa3,0x93,6,0x6c,0x3c,0x6c,0x52,0x6f,0x56, +0x72,0x66,0x75,1,0x67,0x30,0x68,1,0x64,0x79,0x69,0x10,0x64,0x79,0x10,0x69, +0x8e,0x13,0x6e,0x65,0x73,0x65,0x8f,0x11,0x69,0x73,0xa1,0x11,0x70,0x6f,0x2a,0x13, +0x6d,0x6f,0x66,0x6f,0x2b,0x10,0x61,1,0x68,0x2e,0x69,0x7c,0x12,0x6c,0x6c,0x65, +0x7d,0xa2,0x41,0x11,0x6d,0x69,0xa3,0x41,0x61,0x48,0x65,0x9c,0x68,1,0x61,0x2a, +0x6b,0x10,0x73,0xa3,0xa8,0x15,0x69,0x6b,0x73,0x75,0x6b,0x69,0xa3,0xa8,3,0x6c, +0x3a,0x6d,0x48,0x73,0x54,0x74,1,0x61,0x24,0x6b,0x9f,0x10,0x6b,0x9f,0x10,0x69, +0x9c,0x13,0x6e,0x65,0x73,0x65,0x9d,0x10,0x75,0xa2,0x82,0x10,0x6d,0xa3,0x82,0x10, +0x73,0xa2,0x86,0x13,0x61,0x76,0x61,0x68,0xa3,0x86,0x11,0x6e,0x67,0x28,0x12,0x61, +0x6c,0x69,0x29,3,0x6c,0x42,0x6e,0x90,0x74,0xa2,0x46,0x76,0x24,0x17,0x6f,0x77, +0x65,0x6c,0x6a,0x61,0x6d,0x6f,0x25,0x22,1,0x65,0x54,0x76,0x28,1,0x73,0x38, +0x74,0x2a,0x17,0x73,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x2b,0x16,0x79,0x6c,0x6c, +0x61,0x62,0x6c,0x65,0x29,0x18,0x61,0x64,0x69,0x6e,0x67,0x6a,0x61,0x6d,0x6f,0x23, +1,0x61,0x21,0x6f,0x1a,0x74,0x61,0x70,0x70,0x6c,0x69,0x63,0x61,0x62,0x6c,0x65, +0x21,0x26,0x1a,0x72,0x61,0x69,0x6c,0x69,0x6e,0x67,0x6a,0x61,0x6d,0x6f,0x27,1, +0x6e,0x2c,0x79,0x22,0x11,0x65,0x73,0x23,0x20,0x10,0x6f,0x21,1,0x6e,0x2c,0x79, +0x22,0x11,0x65,0x73,0x23,0x20,0x10,0x6f,0x21,2,0x6d,0x30,0x6e,0x3a,0x79,0x22, +0x11,0x65,0x73,0x23,0x24,0x13,0x61,0x79,0x62,0x65,0x25,0x20,0x10,0x6f,0x21,2, +0x6d,0x30,0x6e,0x3a,0x79,0x22,0x11,0x65,0x73,0x23,0x24,0x13,0x61,0x79,0x62,0x65, +0x25,0x20,0x10,0x6f,0x21,0xb,0x72,0x39,0x76,0xc,0x76,0x33,0x78,0x2a,0x7a,0x11, +0x77,0x6a,0x43,0x10,0x78,0x21,0x72,0x28,0x73,0x50,0x74,0x31,1,0x65,0x24,0x69, +0x39,0x1e,0x67,0x69,0x6f,0x6e,0x61,0x6c,0x69,0x6e,0x64,0x69,0x63,0x61,0x74,0x6f, +0x72,0x39,1,0x6d,0x35,0x70,0x18,0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b, +0x35,0x6c,0x1f,0x6c,0x3c,0x6f,0x4a,0x70,1,0x70,0x37,0x72,0x14,0x65,0x70,0x65, +0x6e,0x64,0x37,0x28,1,0x66,0x2b,0x76,0x2c,0x10,0x74,0x2f,0x13,0x74,0x68,0x65, +0x72,0x21,0x63,0x4c,0x65,0x64,0x67,1,0x61,0x3a,0x6c,0x19,0x75,0x65,0x61,0x66, +0x74,0x65,0x72,0x7a,0x77,0x6a,0x41,0x10,0x7a,0x41,2,0x6e,0x23,0x6f,0x24,0x72, +0x25,0x14,0x6e,0x74,0x72,0x6f,0x6c,0x23,2,0x62,0x34,0x6d,0x4e,0x78,0x26,0x13, +0x74,0x65,0x6e,0x64,0x27,0x3a,1,0x61,0x24,0x67,0x3d,0x11,0x73,0x65,0x3a,0x12, +0x67,0x61,0x7a,0x3d,0x3e,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,0x72,0x3f,9,0x6e, +0x4a,0x6e,0x34,0x6f,0x44,0x73,0x60,0x75,0x94,0x78,0x10,0x78,0x21,0x10,0x75,0x2a, +0x14,0x6d,0x65,0x72,0x69,0x63,0x2b,1,0x6c,0x2c,0x74,0x12,0x68,0x65,0x72,0x21, +0x14,0x65,0x74,0x74,0x65,0x72,0x2d,3,0x63,0x36,0x65,0x46,0x70,0x31,0x74,0x32, +0x12,0x65,0x72,0x6d,0x33,0x3c,0x16,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3d,0x2e, +0x10,0x70,0x2f,0x10,0x70,0x34,0x12,0x70,0x65,0x72,0x35,0x61,0x46,0x63,0x52,0x65, +0x64,0x66,0x72,0x6c,2,0x65,0x2d,0x66,0x3b,0x6f,0x28,0x12,0x77,0x65,0x72,0x29, +0x10,0x74,0x22,0x12,0x65,0x72,0x6d,0x23,1,0x6c,0x24,0x72,0x37,0x24,0x12,0x6f, +0x73,0x65,0x25,0x10,0x78,0x38,0x13,0x74,0x65,0x6e,0x64,0x39,0x10,0x6f,0x26,0x13, +0x72,0x6d,0x61,0x74,0x27,0,0x10,0x6c,0x88,0x72,0x40,0x72,0x36,0x73,0x5e,0x77, +0x7a,0x78,0x8a,0x7a,0x11,0x77,0x6a,0x4b,1,0x65,0x24,0x69,0x3b,0x1e,0x67,0x69, +0x6f,0x6e,0x61,0x6c,0x69,0x6e,0x64,0x69,0x63,0x61,0x74,0x6f,0x72,0x3b,1,0x69, +0x24,0x71,0x3f,0x18,0x6e,0x67,0x6c,0x65,0x71,0x75,0x6f,0x74,0x65,0x3f,0x17,0x73, +0x65,0x67,0x73,0x70,0x61,0x63,0x65,0x4d,0x10,0x78,0x21,0x6c,0x36,0x6d,0x3c,0x6e, +0x76,0x6f,0x13,0x74,0x68,0x65,0x72,0x21,1,0x65,0x23,0x66,0x35,3,0x62,0x37, +0x69,0x28,0x6c,0x29,0x6e,0x2b,0x10,0x64,1,0x6c,0x34,0x6e,0x11,0x75,0x6d,0x2a, +0x12,0x6c,0x65,0x74,0x37,0x14,0x65,0x74,0x74,0x65,0x72,0x29,2,0x65,0x36,0x6c, +0x39,0x75,0x2c,0x14,0x6d,0x65,0x72,0x69,0x63,0x2d,0x14,0x77,0x6c,0x69,0x6e,0x65, +0x39,0x66,0x3f,0x66,0x40,0x67,0x4e,0x68,0x70,0x6b,0x10,0x61,0x26,0x15,0x74,0x61, +0x6b,0x61,0x6e,0x61,0x27,0x10,0x6f,0x24,0x13,0x72,0x6d,0x61,0x74,0x25,1,0x61, +0x3a,0x6c,0x19,0x75,0x65,0x61,0x66,0x74,0x65,0x72,0x7a,0x77,0x6a,0x49,0x10,0x7a, +0x49,1,0x65,0x24,0x6c,0x3d,0x19,0x62,0x72,0x65,0x77,0x6c,0x65,0x74,0x74,0x65, +0x72,0x3d,0x61,0x86,0x63,0x92,0x64,0x94,0x65,2,0x62,0x44,0x6d,0x5e,0x78,0x2e, +0x13,0x74,0x65,0x6e,0x64,0x32,0x15,0x6e,0x75,0x6d,0x6c,0x65,0x74,0x2f,0x42,1, +0x61,0x24,0x67,0x45,0x11,0x73,0x65,0x42,0x12,0x67,0x61,0x7a,0x45,0x46,0x16,0x6f, +0x64,0x69,0x66,0x69,0x65,0x72,0x47,0x15,0x6c,0x65,0x74,0x74,0x65,0x72,0x23,0x10, +0x72,0x31,1,0x6f,0x24,0x71,0x41,0x18,0x75,0x62,0x6c,0x65,0x71,0x75,0x6f,0x74, +0x65,0x41,2,0x63,0x32,0x6e,0x3c,0x6f,0x22,0x12,0x70,0x65,0x6e,0x23,0x24,0x13, +0x6c,0x6f,0x73,0x65,0x25,0x20,0x12,0x6f,0x6e,0x65,0x21,6,0x6f,0x65,0x6f,0x4a, +0x72,0x5c,0x74,0x64,0x76,0x1d,0x69,0x73,0x75,0x61,0x6c,0x6f,0x72,0x64,0x65,0x72, +0x6c,0x65,0x66,0x74,0x3d,0x18,0x76,0x65,0x72,0x73,0x74,0x72,0x75,0x63,0x6b,0x2d, +0x13,0x69,0x67,0x68,0x74,0x2f,0x11,0x6f,0x70,0x30,0x12,0x61,0x6e,0x64,2,0x62, +0x32,0x6c,0x62,0x72,0x13,0x69,0x67,0x68,0x74,0x3b,0x14,0x6f,0x74,0x74,0x6f,0x6d, +0x32,0x12,0x61,0x6e,0x64,1,0x6c,0x2e,0x72,0x13,0x69,0x67,0x68,0x74,0x35,0x12, +0x65,0x66,0x74,0x3f,0x12,0x65,0x66,0x74,0x36,0x17,0x61,0x6e,0x64,0x72,0x69,0x67, +0x68,0x74,0x39,0x62,0x2c,0x6c,0x5c,0x6e,0x10,0x61,0x21,0x14,0x6f,0x74,0x74,0x6f, +0x6d,0x22,0x12,0x61,0x6e,0x64,1,0x6c,0x2e,0x72,0x13,0x69,0x67,0x68,0x74,0x27, +0x12,0x65,0x66,0x74,0x25,0x12,0x65,0x66,0x74,0x28,0x17,0x61,0x6e,0x64,0x72,0x69, +0x67,0x68,0x74,0x2b,0xd,0x6e,0xaa,0x72,0x70,0x72,0x92,0x73,0xa2,0x46,0x74,0xa2, +0x54,0x76,1,0x69,0x60,0x6f,0x12,0x77,0x65,0x6c,0x62,1,0x64,0x3a,0x69,0x19, +0x6e,0x64,0x65,0x70,0x65,0x6e,0x64,0x65,0x6e,0x74,0x67,0x17,0x65,0x70,0x65,0x6e, +0x64,0x65,0x6e,0x74,0x65,1,0x72,0x2e,0x73,0x13,0x61,0x72,0x67,0x61,0x61,0x12, +0x61,0x6d,0x61,0x5f,0x1d,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x68,0x69,0x66, +0x74,0x65,0x72,0x57,0x1e,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x6d,0x6f,0x64,0x69, +0x66,0x69,0x65,0x72,0x59,0x12,0x6f,0x6e,0x65,1,0x6c,0x2c,0x6d,0x12,0x61,0x72, +0x6b,0x5d,0x14,0x65,0x74,0x74,0x65,0x72,0x5b,0x6e,0x3c,0x6f,0x7c,0x70,0x18,0x75, +0x72,0x65,0x6b,0x69,0x6c,0x6c,0x65,0x72,0x55,1,0x6f,0x4c,0x75,1,0x6b,0x3c, +0x6d,0x12,0x62,0x65,0x72,0x50,0x15,0x6a,0x6f,0x69,0x6e,0x65,0x72,0x53,0x11,0x74, +0x61,0x4f,0x16,0x6e,0x6a,0x6f,0x69,0x6e,0x65,0x72,0x4d,0x13,0x74,0x68,0x65,0x72, +0x21,0x67,0x3e,0x67,0x4a,0x69,0x64,0x6a,0x82,0x6d,0x1d,0x6f,0x64,0x69,0x66,0x79, +0x69,0x6e,0x67,0x6c,0x65,0x74,0x74,0x65,0x72,0x4b,0x1c,0x65,0x6d,0x69,0x6e,0x61, +0x74,0x69,0x6f,0x6e,0x6d,0x61,0x72,0x6b,0x45,0x1e,0x6e,0x76,0x69,0x73,0x69,0x62, +0x6c,0x65,0x73,0x74,0x61,0x63,0x6b,0x65,0x72,0x47,0x14,0x6f,0x69,0x6e,0x65,0x72, +0x49,0x61,0xa2,0xba,0x62,0xa2,0xc0,0x63,1,0x61,0xa2,0xa2,0x6f,0x16,0x6e,0x73, +0x6f,0x6e,0x61,0x6e,0x74,0x2a,8,0x6b,0x67,0x6b,0x48,0x6d,0x52,0x70,0x5c,0x73, +0xa2,0x42,0x77,0x19,0x69,0x74,0x68,0x73,0x74,0x61,0x63,0x6b,0x65,0x72,0x43,0x14, +0x69,0x6c,0x6c,0x65,0x72,0x35,0x14,0x65,0x64,0x69,0x61,0x6c,0x37,1,0x6c,0x52, +0x72,0x10,0x65,1,0x63,0x2e,0x66,0x13,0x69,0x78,0x65,0x64,0x3d,0x19,0x65,0x64, +0x69,0x6e,0x67,0x72,0x65,0x70,0x68,0x61,0x3b,0x18,0x61,0x63,0x65,0x68,0x6f,0x6c, +0x64,0x65,0x72,0x39,0x10,0x75,1,0x62,0x3e,0x63,0x1b,0x63,0x65,0x65,0x64,0x69, +0x6e,0x67,0x72,0x65,0x70,0x68,0x61,0x41,0x15,0x6a,0x6f,0x69,0x6e,0x65,0x64,0x3f, +0x64,0x4c,0x66,0x52,0x68,0x5a,0x69,0x1e,0x6e,0x69,0x74,0x69,0x61,0x6c,0x70,0x6f, +0x73,0x74,0x66,0x69,0x78,0x65,0x64,0x33,0x12,0x65,0x61,0x64,0x2d,0x13,0x69,0x6e, +0x61,0x6c,0x2f,0x18,0x65,0x61,0x64,0x6c,0x65,0x74,0x74,0x65,0x72,0x31,0x1d,0x6e, +0x74,0x69,0x6c,0x6c,0x61,0x74,0x69,0x6f,0x6e,0x6d,0x61,0x72,0x6b,0x29,0x16,0x76, +0x61,0x67,0x72,0x61,0x68,0x61,0x23,1,0x69,0x4a,0x72,0x10,0x61,0x1f,0x68,0x6d, +0x69,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x6e,0x75,0x6d,0x62,0x65,0x72,0x27,0x12, +0x6e,0x64,0x75,0x25,2,0x72,0x38,0x74,0x46,0x75,0x26,0x15,0x70,0x72,0x69,0x67, +0x68,0x74,0x27,0x20,0x15,0x6f,0x74,0x61,0x74,0x65,0x64,0x21,1,0x72,0x24,0x75, +0x25,0x22,0x18,0x61,0x6e,0x73,0x66,0x6f,0x72,0x6d,0x65,0x64,1,0x72,0x32,0x75, +0x15,0x70,0x72,0x69,0x67,0x68,0x74,0x25,0x15,0x6f,0x74,0x61,0x74,0x65,0x64,0x23, +0xd,0x6e,0xc1,0x86,0x73,0xa8,0x73,0x4c,0x74,0xa2,0x76,0x75,0xa2,0x83,0x7a,0xd8, +0x70,0,2,0x6c,0xd9,0x20,0,0x70,0xd9,0x40,0,0x73,0xc3,0,0xfe,0xf, +0,0,0,7,0x6f,0x3c,0x6f,0xff,8,0,0,0,0x70,0x3a,0x75,0x6e, +0x79,0x13,0x6d,0x62,0x6f,0x6c,0xff,0xf,0,0,0,0x11,0x61,0x63,1,0x65, +0x34,0x69,0x15,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa5,0,0x18,0x73,0x65,0x70,0x61, +0x72,0x61,0x74,0x6f,0x72,0xc3,0,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0xe1, +0,0,0x63,0xff,2,0,0,0,0x65,0x38,0x6b,0xff,4,0,0,0, +0x6d,0xff,1,0,0,0,0x16,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,0x70, +0,0x1d,0x69,0x74,0x6c,0x65,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72, +0x31,1,0x6e,0x40,0x70,0x1c,0x70,0x65,0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74, +0x74,0x65,0x72,0x25,0x17,0x61,0x73,0x73,0x69,0x67,0x6e,0x65,0x64,0x23,0x6e,0xa2, +0x69,0x6f,0xa2,0x89,0x70,0xfe,0x30,0xf8,0,0,9,0x69,0x33,0x69,0xff,0x10, +0,0,0,0x6f,0xfd,0x80,0,0,0x72,0x54,0x73,0xf9,0,0,0x75,0x12, +0x6e,0x63,0x74,0xfe,0x30,0xf8,0,0,0x15,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff, +0x30,0xf8,0,0,0x17,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0xdd,0,0, +0x61,0x48,0x63,0xfd,0x40,0,0,0x64,0xe9,0,0,0x65,0xfd,0x20,0,0, +0x66,0xff,0x20,0,0,0,0x1f,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x65, +0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,0x40,0,0xbe,0,3,0x64,0xa7,0, +0x6c,0xab,0,0x6f,0x30,0x75,0x13,0x6d,0x62,0x65,0x72,0xbf,0,0xb2,0,0x1b, +0x6e,0x73,0x70,0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa1,1,0x70,0x92, +0x74,0x12,0x68,0x65,0x72,0xe6,0x80,1,3,0x6c,0x40,0x6e,0x4a,0x70,0x56,0x73, +0x14,0x79,0x6d,0x62,0x6f,0x6c,0xff,8,0,0,0,0x14,0x65,0x74,0x74,0x65, +0x72,0x61,0x14,0x75,0x6d,0x62,0x65,0x72,0xb3,0,0x19,0x75,0x6e,0x63,0x74,0x75, +0x61,0x74,0x69,0x6f,0x6e,0xfd,0x80,0,0,0x1c,0x65,0x6e,0x70,0x75,0x6e,0x63, +0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xf9,0,0,0x66,0xc0,0xc4,0x66,0xa2,0x47, +0x69,0xa2,0x64,0x6c,0xa2,0x79,0x6d,0xa4,0xc0,4,0x61,0x6c,0x63,0xa5,0,0x65, +0xa3,0x80,0x6e,0xa1,0x6f,0x15,0x64,0x69,0x66,0x69,0x65,0x72,1,0x6c,0x38,0x73, +0x14,0x79,0x6d,0x62,0x6f,0x6c,0xff,4,0,0,0,0x14,0x65,0x74,0x74,0x65, +0x72,0x41,1,0x72,0x3c,0x74,0x16,0x68,0x73,0x79,0x6d,0x62,0x6f,0x6c,0xff,1, +0,0,0,0x10,0x6b,0xa5,0xc0,1,0x69,0x32,0x6f,0x13,0x72,0x6d,0x61,0x74, +0xdb,0,0,0x1d,0x6e,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69, +0x6f,0x6e,0xff,0x20,0,0,0,0x10,0x6e,0x1f,0x69,0x74,0x69,0x61,0x6c,0x70, +0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff,0x10,0,0,0,0x9c, +7,0x6d,0x18,0x6d,0x41,0x6f,0x28,0x74,0x31,0x75,0x25,0x60,0x1c,0x77,0x65,0x72, +0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x29,0x63,0x3d,0x65,0x28,0x69, +0x42,0x6c,0x29,0x13,0x74,0x74,0x65,0x72,0x9c,0x15,0x6e,0x75,0x6d,0x62,0x65,0x72, +0xab,0,0x1a,0x6e,0x65,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,0x20, +0,0x63,0x46,0x64,0xa2,0x96,0x65,0x1b,0x6e,0x63,0x6c,0x6f,0x73,0x69,0x6e,0x67, +0x6d,0x61,0x72,0x6b,0xa3,0x80,0xe6,0x80,1,7,0x6e,0x57,0x6e,0x52,0x6f,0x5e, +0x73,0xe1,0,0,0x75,0x1b,0x72,0x72,0x65,0x6e,0x63,0x79,0x73,0x79,0x6d,0x62, +0x6f,0x6c,0xff,2,0,0,0,0x22,0x12,0x74,0x72,0x6c,0xd9,0x80,0,0xdc, +0,0,1,0x6d,0x62,0x6e,1,0x6e,0x30,0x74,0x12,0x72,0x6f,0x6c,0xd9,0x80, +0,0x1f,0x65,0x63,0x74,0x6f,0x72,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69, +0x6f,0x6e,0xfd,0x40,0,0,0x19,0x62,0x69,0x6e,0x69,0x6e,0x67,0x6d,0x61,0x72, +0x6b,0xa5,0xc0,0x61,0x58,0x63,0xd9,0x80,0,0x66,0xdb,0,0,0x6c,0x1d,0x6f, +0x73,0x65,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xfd,0x20,0, +0,0x18,0x73,0x65,0x64,0x6c,0x65,0x74,0x74,0x65,0x72,0x3d,2,0x61,0x32,0x65, +0x50,0x69,0x12,0x67,0x69,0x74,0xa7,0,0x1c,0x73,0x68,0x70,0x75,0x6e,0x63,0x74, +0x75,0x61,0x74,0x69,0x6f,0x6e,0xe9,0,0,0x1a,0x63,0x69,0x6d,0x61,0x6c,0x6e, +0x75,0x6d,0x62,0x65,0x72,0xa7,0 }; -const char PropNameData::nameGroups[23100]={ +const char PropNameData::nameGroups[23338]={ 2,'A','l','p','h','a',0,'A','l','p','h','a','b','e','t','i','c',0, 4,'N',0,'N','o',0,'F',0,'F','a','l','s','e',0,4,'Y',0,'Y','e','s',0,'T',0,'T','r','u','e',0, 2,'N','R',0,'N','o','t','_','R','e','o','r','d','e','r','e','d',0, @@ -1176,6 +1184,10 @@ const char PropNameData::nameGroups[23100]={ 2,'R','G','I','_','E','m','o','j','i','_','Z','W','J','_','S','e','q','u','e','n','c','e',0, 'R','G','I','_','E','m','o','j','i','_','Z','W','J','_','S','e','q','u','e','n','c','e',0, 2,'R','G','I','_','E','m','o','j','i',0,'R','G','I','_','E','m','o','j','i',0, +2,'I','D','S','U',0,'I','D','S','_','U','n','a','r','y','_','O','p','e','r','a','t','o','r',0, +2,'I','D','_','C','o','m','p','a','t','_','M','a','t','h','_','S','t','a','r','t',0,'I','D','_','C','o','m','p','a','t','_', +'M','a','t','h','_','S','t','a','r','t',0,2,'I','D','_','C','o','m','p','a','t','_','M','a','t','h','_','C','o','n','t','i', +'n','u','e',0,'I','D','_','C','o','m','p','a','t','_','M','a','t','h','_','C','o','n','t','i','n','u','e',0, 2,'b','c',0,'B','i','d','i','_','C','l','a','s','s',0,2,'L',0,'L','e','f','t','_','T','o','_','R','i','g','h','t',0, 2,'R',0,'R','i','g','h','t','_','T','o','_','L','e','f','t',0, 2,'E','N',0,'E','u','r','o','p','e','a','n','_','N','u','m','b','e','r',0, @@ -1568,9 +1580,11 @@ const char PropNameData::nameGroups[23100]={ 'e','n','d','e','d','_','A',0,2,'K','a','k','t','o','v','i','k','_','N','u','m','e','r','a','l','s',0, 'K','a','k','t','o','v','i','k','_','N','u','m','e','r','a','l','s',0, 2,'K','a','w','i',0,'K','a','w','i',0,2,'N','a','g','_','M','u','n','d','a','r','i',0, -'N','a','g','_','M','u','n','d','a','r','i',0,2,'c','c','c',0,'C','a','n','o','n','i','c','a','l','_','C','o','m','b','i', -'n','i','n','g','_','C','l','a','s','s',0,2,'d','t',0,'D','e','c','o','m','p','o','s','i','t','i','o','n','_','T','y','p', -'e',0,3,'N','o','n','e',0,'N','o','n','e',0,'n','o','n','e',0, +'N','a','g','_','M','u','n','d','a','r','i',0,2,'C','J','K','_','E','x','t','_','I',0,'C','J','K','_','U','n','i','f','i', +'e','d','_','I','d','e','o','g','r','a','p','h','s','_','E','x','t','e','n','s','i','o','n','_','I',0, +2,'c','c','c',0,'C','a','n','o','n','i','c','a','l','_','C','o','m','b','i','n','i','n','g','_','C','l','a','s','s',0, +2,'d','t',0,'D','e','c','o','m','p','o','s','i','t','i','o','n','_','T','y','p','e',0, +3,'N','o','n','e',0,'N','o','n','e',0,'n','o','n','e',0, 3,'C','a','n',0,'C','a','n','o','n','i','c','a','l',0,'c','a','n',0, 3,'C','o','m',0,'C','o','m','p','a','t',0,'c','o','m',0, 3,'E','n','c',0,'C','i','r','c','l','e',0,'e','n','c',0, @@ -1739,7 +1753,11 @@ const char PropNameData::nameGroups[23100]={ 's','i','s',0,2,'C','J',0,'C','o','n','d','i','t','i','o','n','a','l','_','J','a','p','a','n','e','s','e','_','S','t','a', 'r','t','e','r',0,2,'H','L',0,'H','e','b','r','e','w','_','L','e','t','t','e','r',0, 2,'E','B',0,'E','_','B','a','s','e',0,2,'E','M',0,'E','_','M','o','d','i','f','i','e','r',0, -2,'Z','W','J',0,'Z','W','J',0,2,'n','t',0,'N','u','m','e','r','i','c','_','T','y','p','e',0, +2,'Z','W','J',0,'Z','W','J',0,2,'A','K',0,'A','k','s','a','r','a',0, +2,'A','P',0,'A','k','s','a','r','a','_','P','r','e','b','a','s','e',0, +2,'A','S',0,'A','k','s','a','r','a','_','S','t','a','r','t',0, +2,'V','F',0,'V','i','r','a','m','a','_','F','i','n','a','l',0, +2,'V','I',0,'V','i','r','a','m','a',0,2,'n','t',0,'N','u','m','e','r','i','c','_','T','y','p','e',0, 2,'N','o','n','e',0,'N','o','n','e',0,2,'D','e',0,'D','e','c','i','m','a','l',0, 2,'D','i',0,'D','i','g','i','t',0,2,'N','u',0,'N','u','m','e','r','i','c',0, 2,'s','c',0,'S','c','r','i','p','t',0,2,'Z','y','y','y',0,'C','o','m','m','o','n',0, diff --git a/thirdparty/icu4c/common/putil.cpp b/thirdparty/icu4c/common/putil.cpp index ab904af20a..ab25f3b996 100644 --- a/thirdparty/icu4c/common/putil.cpp +++ b/thirdparty/icu4c/common/putil.cpp @@ -1175,6 +1175,21 @@ uprv_tzname(int n) if (ret != nullptr && uprv_strcmp(TZDEFAULT, gTimeZoneBuffer) != 0) { int32_t tzZoneInfoTailLen = uprv_strlen(TZZONEINFOTAIL); const char *tzZoneInfoTailPtr = uprv_strstr(gTimeZoneBuffer, TZZONEINFOTAIL); + // MacOS14 has the realpath as something like + // /usr/share/zoneinfo.default/Australia/Melbourne + // which will not have "/zoneinfo/" in the path. + // Therefore if we fail, we fall back to read the link which is + // /var/db/timezone/zoneinfo/Australia/Melbourne + // We also fall back to reading the link if the realpath leads to something like + // /usr/share/zoneinfo/posixrules + if (tzZoneInfoTailPtr == nullptr || + uprv_strcmp(tzZoneInfoTailPtr + tzZoneInfoTailLen, "posixrules") == 0) { + ssize_t size = readlink(TZDEFAULT, gTimeZoneBuffer, sizeof(gTimeZoneBuffer)-1); + if (size > 0) { + gTimeZoneBuffer[size] = 0; + tzZoneInfoTailPtr = uprv_strstr(gTimeZoneBuffer, TZZONEINFOTAIL); + } + } if (tzZoneInfoTailPtr != nullptr) { tzZoneInfoTailPtr += tzZoneInfoTailLen; skipZoneIDPrefix(&tzZoneInfoTailPtr); diff --git a/thirdparty/icu4c/common/rbbi.cpp b/thirdparty/icu4c/common/rbbi.cpp index 73716ab406..599279fb72 100644 --- a/thirdparty/icu4c/common/rbbi.cpp +++ b/thirdparty/icu4c/common/rbbi.cpp @@ -1125,6 +1125,7 @@ static icu::UStack *gLanguageBreakFactories = nullptr; static const icu::UnicodeString *gEmptyString = nullptr; static icu::UInitOnce gLanguageBreakFactoriesInitOnce {}; static icu::UInitOnce gRBBIInitOnce {}; +static icu::ICULanguageBreakFactory *gICULanguageBreakFactory = nullptr; /** * Release all static memory held by breakiterator. @@ -1153,37 +1154,41 @@ static void U_CALLCONV rbbiInit() { ucln_common_registerCleanup(UCLN_COMMON_RBBI, rbbi_cleanup); } -static void U_CALLCONV initLanguageFactories() { - UErrorCode status = U_ZERO_ERROR; +static void U_CALLCONV initLanguageFactories(UErrorCode& status) { U_ASSERT(gLanguageBreakFactories == nullptr); gLanguageBreakFactories = new UStack(_deleteFactory, nullptr, status); if (gLanguageBreakFactories != nullptr && U_SUCCESS(status)) { - ICULanguageBreakFactory *builtIn = new ICULanguageBreakFactory(status); - gLanguageBreakFactories->push(builtIn, status); + LocalPointer<ICULanguageBreakFactory> factory(new ICULanguageBreakFactory(status), status); + if (U_SUCCESS(status)) { + gICULanguageBreakFactory = factory.orphan(); + gLanguageBreakFactories->push(gICULanguageBreakFactory, status); #ifdef U_LOCAL_SERVICE_HOOK - LanguageBreakFactory *extra = (LanguageBreakFactory *)uprv_svc_hook("languageBreakFactory", &status); - if (extra != nullptr) { - gLanguageBreakFactories->push(extra, status); - } + LanguageBreakFactory *extra = (LanguageBreakFactory *)uprv_svc_hook("languageBreakFactory", &status); + if (extra != nullptr) { + gLanguageBreakFactories->push(extra, status); + } #endif + } } ucln_common_registerCleanup(UCLN_COMMON_RBBI, rbbi_cleanup); } +void ensureLanguageFactories(UErrorCode& status) { + umtx_initOnce(gLanguageBreakFactoriesInitOnce, &initLanguageFactories, status); +} static const LanguageBreakEngine* -getLanguageBreakEngineFromFactory(UChar32 c) +getLanguageBreakEngineFromFactory(UChar32 c, const char* locale) { - umtx_initOnce(gLanguageBreakFactoriesInitOnce, &initLanguageFactories); - if (gLanguageBreakFactories == nullptr) { - return nullptr; - } + UErrorCode status = U_ZERO_ERROR; + ensureLanguageFactories(status); + if (U_FAILURE(status)) return nullptr; int32_t i = gLanguageBreakFactories->size(); const LanguageBreakEngine *lbe = nullptr; while (--i >= 0) { LanguageBreakFactory *factory = (LanguageBreakFactory *)(gLanguageBreakFactories->elementAt(i)); - lbe = factory->getEngineFor(c); + lbe = factory->getEngineFor(c, locale); if (lbe != nullptr) { break; } @@ -1199,7 +1204,7 @@ getLanguageBreakEngineFromFactory(UChar32 c) // //------------------------------------------------------------------------------- const LanguageBreakEngine * -RuleBasedBreakIterator::getLanguageBreakEngine(UChar32 c) { +RuleBasedBreakIterator::getLanguageBreakEngine(UChar32 c, const char* locale) { const LanguageBreakEngine *lbe = nullptr; UErrorCode status = U_ZERO_ERROR; @@ -1215,14 +1220,14 @@ RuleBasedBreakIterator::getLanguageBreakEngine(UChar32 c) { int32_t i = fLanguageBreakEngines->size(); while (--i >= 0) { lbe = (const LanguageBreakEngine *)(fLanguageBreakEngines->elementAt(i)); - if (lbe->handles(c)) { + if (lbe->handles(c, locale)) { return lbe; } } // No existing dictionary took the character. See if a factory wants to // give us a new LanguageBreakEngine for this character. - lbe = getLanguageBreakEngineFromFactory(c); + lbe = getLanguageBreakEngineFromFactory(c, locale); // If we got one, use it and push it on our stack. if (lbe != nullptr) { @@ -1259,6 +1264,18 @@ RuleBasedBreakIterator::getLanguageBreakEngine(UChar32 c) { return fUnhandledBreakEngine; } +#ifndef U_HIDE_DRAFT_API +void U_EXPORT2 RuleBasedBreakIterator::registerExternalBreakEngine( + ExternalBreakEngine* toAdopt, UErrorCode& status) { + LocalPointer<ExternalBreakEngine> engine(toAdopt, status); + if (U_FAILURE(status)) return; + ensureLanguageFactories(status); + if (U_FAILURE(status)) return; + gICULanguageBreakFactory->addExternalEngine(engine.orphan(), status); +} +#endif /* U_HIDE_DRAFT_API */ + + void RuleBasedBreakIterator::dumpCache() { fBreakCache->dumpCache(); } diff --git a/thirdparty/icu4c/common/rbbi_cache.cpp b/thirdparty/icu4c/common/rbbi_cache.cpp index 02ca555a89..f7a283f69e 100644 --- a/thirdparty/icu4c/common/rbbi_cache.cpp +++ b/thirdparty/icu4c/common/rbbi_cache.cpp @@ -158,12 +158,13 @@ void RuleBasedBreakIterator::DictionaryCache::populateDictionary(int32_t startPo // We now have a dictionary character. Get the appropriate language object // to deal with it. - const LanguageBreakEngine *lbe = fBI->getLanguageBreakEngine(c); + const LanguageBreakEngine *lbe = fBI->getLanguageBreakEngine( + c, fBI->getLocaleID(ULOC_REQUESTED_LOCALE, status)); // Ask the language object if there are any breaks. It will add them to the cache and // leave the text pointer on the other side of its range, ready to search for the next one. if (lbe != nullptr) { - foundBreakCount += lbe->findBreaks(text, rangeStart, rangeEnd, fBreaks, fBI->fIsPhraseBreaking, status); + foundBreakCount += lbe->findBreaks(text, current, rangeEnd, fBreaks, fBI->fIsPhraseBreaking, status); } // Reload the loop variables for the next go-round diff --git a/thirdparty/icu4c/common/rbbirb.cpp b/thirdparty/icu4c/common/rbbirb.cpp index 7177254ec4..92cccc1a33 100644 --- a/thirdparty/icu4c/common/rbbirb.cpp +++ b/thirdparty/icu4c/common/rbbirb.cpp @@ -66,7 +66,6 @@ RBBIRuleBuilder::RBBIRuleBuilder(const UnicodeString &rules, fForwardTable = nullptr; fRuleStatusVals = nullptr; fChainRules = false; - fLBCMNoChain = false; fLookAheadHardBreak = false; fUSetNodes = nullptr; fRuleStatusVals = nullptr; diff --git a/thirdparty/icu4c/common/rbbirb.h b/thirdparty/icu4c/common/rbbirb.h index d983a184b6..96d3aa643d 100644 --- a/thirdparty/icu4c/common/rbbirb.h +++ b/thirdparty/icu4c/common/rbbirb.h @@ -159,9 +159,6 @@ public: UBool fChainRules; // True for chained Unicode TR style rules. // False for traditional regexp rules. - UBool fLBCMNoChain; // True: suppress chaining of rules on - // chars with LineBreak property == CM. - UBool fLookAheadHardBreak; // True: Look ahead matches cause an // immediate break, no continuing for the // longest match. diff --git a/thirdparty/icu4c/common/rbbiscan.cpp b/thirdparty/icu4c/common/rbbiscan.cpp index 455ace78b8..844b063909 100644 --- a/thirdparty/icu4c/common/rbbiscan.cpp +++ b/thirdparty/icu4c/common/rbbiscan.cpp @@ -547,8 +547,6 @@ UBool RBBIRuleScanner::doParseActions(int32_t action) UnicodeString opt(fRB->fRules, fOptionStart, fScanIndex-fOptionStart); if (opt == UNICODE_STRING("chain", 5)) { fRB->fChainRules = true; - } else if (opt == UNICODE_STRING("LBCMNoChain", 11)) { - fRB->fLBCMNoChain = true; } else if (opt == UNICODE_STRING("forward", 7)) { fRB->fDefaultTree = &fRB->fForwardTree; } else if (opt == UNICODE_STRING("reverse", 7)) { diff --git a/thirdparty/icu4c/common/rbbitblb.cpp b/thirdparty/icu4c/common/rbbitblb.cpp index 0c2bcff4e5..8b40136fc7 100644 --- a/thirdparty/icu4c/common/rbbitblb.cpp +++ b/thirdparty/icu4c/common/rbbitblb.cpp @@ -458,21 +458,6 @@ void RBBITableBuilder::calcChainedFollowPos(RBBINode *tree, RBBINode *endMarkNod // We've got a node that can end a match. - // !!LBCMNoChain implementation: If this node's val correspond to - // the Line Break $CM char class, don't chain from it. - // TODO: Remove this. !!LBCMNoChain is deprecated, and is not used - // by any of the standard ICU rules. - if (fRB->fLBCMNoChain) { - UChar32 c = this->fRB->fSetBuilder->getFirstChar(endNode->fVal); - if (c != -1) { - // c == -1 occurs with sets containing only the {eof} marker string. - ULineBreak cLBProp = (ULineBreak)u_getIntPropertyValue(c, UCHAR_LINE_BREAK); - if (cLBProp == U_LB_COMBINING_MARK) { - continue; - } - } - } - // Now iterate over the nodes that can start a match, looking for ones // with the same char class as our ending node. RBBINode *startNode; diff --git a/thirdparty/icu4c/common/ubidi_props_data.h b/thirdparty/icu4c/common/ubidi_props_data.h index 5dcd1d7c78..f85dc09675 100644 --- a/thirdparty/icu4c/common/ubidi_props_data.h +++ b/thirdparty/icu4c/common/ubidi_props_data.h @@ -9,11 +9,11 @@ #ifdef INCLUDED_FROM_UBIDI_PROPS_C -static const UVersionInfo ubidi_props_dataVersion={0xf,0,0,0}; +static const UVersionInfo ubidi_props_dataVersion={0xf,1,0,0}; -static const int32_t ubidi_props_indexes[UBIDI_IX_TOP]={0x10,0x6bc0,0x65d0,0x28,0x620,0x8cc,0x10ac0,0x10d24,0,0,0,0,0,0,0,0x6702b6}; +static const int32_t ubidi_props_indexes[UBIDI_IX_TOP]={0x10,0x6ba0,0x65b0,0x28,0x620,0x8cc,0x10ac0,0x10d24,0,0,0,0,0,0,0,0x6702b6}; -static const uint16_t ubidi_props_trieIndex[13024]={ +static const uint16_t ubidi_props_trieIndex[13008]={ 0x387,0x38f,0x397,0x39f,0x3b7,0x3bf,0x3c7,0x3cf,0x3a7,0x3af,0x3a7,0x3af,0x3a7,0x3af,0x3a7,0x3af, 0x3a7,0x3af,0x3a7,0x3af,0x3d5,0x3dd,0x3e5,0x3ed,0x3f5,0x3fd,0x3f9,0x401,0x409,0x411,0x40c,0x414, 0x3a7,0x3af,0x3a7,0x3af,0x41c,0x424,0x3a7,0x3af,0x3a7,0x3af,0x3a7,0x3af,0x42a,0x432,0x43a,0x442, @@ -38,8 +38,8 @@ static const uint16_t ubidi_props_trieIndex[13024]={ 0x7e8,0x7f0,0x7f8,0x7ff,0x806,0x80e,0x812,0x7e0,0x67c,0x67c,0x67c,0x81a,0x820,0x67c,0x67c,0x826, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x82e,0x3a7,0x3a7,0x3a7,0x836,0x3a7,0x3a7,0x3a7,0x3f5, 0x83e,0x846,0x849,0x3a7,0x851,0x67c,0x67c,0x67f,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x858,0x85e, -0x86e,0x866,0x3a7,0x3a7,0x876,0x61f,0x3a7,0x3ce,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x67c,0x835, -0x3dc,0x3a7,0x87e,0x886,0x3a7,0x88e,0x896,0x3a7,0x3a7,0x3a7,0x3a7,0x89a,0x3a7,0x3a7,0x674,0x3cd, +0x86e,0x866,0x3a7,0x3a7,0x876,0x61f,0x3a7,0x3ce,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x67c,0x87e, +0x3dc,0x3a7,0x85e,0x882,0x3a7,0x88a,0x892,0x3a7,0x3a7,0x3a7,0x3a7,0x896,0x3a7,0x3a7,0x674,0x3cd, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, @@ -96,10 +96,10 @@ static const uint16_t ubidi_props_trieIndex[13024]={ 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0x87e,0x67c,0x595,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x8a1,0x3a7,0x3a7,0x8a6,0x8ae,0x3a7,0x3a7,0x5cb,0x67c,0x673,0x3a7,0x3a7,0x8b6,0x3a7,0x3a7,0x3a7, -0x8be,0x8c5,0x645,0x8cd,0x3a7,0x3a7,0x5a1,0x8d5,0x3a7,0x8dd,0x8e4,0x3a7,0x501,0x8e9,0x3a7,0x51a, -0x3a7,0x8f1,0x8f9,0x51c,0x3a7,0x8fd,0x51b,0x905,0x3a7,0x3a7,0x3a7,0x90b,0x3a7,0x3a7,0x3a7,0x912, +0x3a7,0x3a7,0x3a7,0x3a7,0x85e,0x67c,0x595,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0x89d,0x3a7,0x3a7,0x8a2,0x8aa,0x3a7,0x3a7,0x5cb,0x67c,0x673,0x3a7,0x3a7,0x8b2,0x3a7,0x3a7,0x3a7, +0x8ba,0x8c1,0x645,0x8c9,0x3a7,0x3a7,0x5a1,0x8d1,0x3a7,0x8d9,0x8e0,0x3a7,0x501,0x8e5,0x3a7,0x51a, +0x3a7,0x8ed,0x8f5,0x51c,0x3a7,0x8f9,0x51b,0x901,0x3a7,0x3a7,0x3a7,0x907,0x3a7,0x3a7,0x3a7,0x90e, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, @@ -139,9 +139,9 @@ static const uint16_t ubidi_props_trieIndex[13024]={ 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x926,0x91a,0x91e,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6, -0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x92e,0x936,0x4a6,0x4a6,0x4a6,0x93b,0x93f, -0x947,0x94f,0x953,0x95b,0x4a6,0x4a6,0x4a6,0x95f,0x967,0x397,0x96f,0x977,0x3a7,0x3a7,0x3a7,0x97f, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x922,0x916,0x91a,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6, +0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x92a,0x932,0x4a6,0x4a6,0x4a6,0x937,0x93b, +0x943,0x94b,0x94f,0x957,0x4a6,0x4a6,0x4a6,0x95b,0x963,0x397,0x96b,0x973,0x3a7,0x3a7,0x3a7,0x97b, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0xe9c,0xe9c,0xedc,0xf1c,0xe9c,0xe9c,0xe9c,0xe9c,0xe9c,0xe9c,0xf54,0xf94,0xfd4,0xfe4,0x1024,0x1030, @@ -178,68 +178,68 @@ static const uint16_t ubidi_props_trieIndex[13024]={ 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd89, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd89, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x987,0x3a7,0x67c,0x67c,0x98f,0x61f,0x3a7,0x514, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x997,0x3a7,0x3a7,0x3a7,0x99e,0x3a7,0x3a7,0x3a7,0x3a7, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x983,0x3a7,0x67c,0x67c,0x98b,0x61f,0x3a7,0x514, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x993,0x3a7,0x3a7,0x3a7,0x99a,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x9a6,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c, -0x9ae,0x9b2,0x43c,0x43c,0x43c,0x43c,0x9c2,0x9ba,0x43c,0x9ca,0x43c,0x43c,0x9d2,0x9d8,0x43c,0x43c, -0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x9e8,0x9e0,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c, -0x43c,0x43c,0x43c,0x9f0,0x43c,0x9f8,0x4a6,0xa00,0x43c,0xa08,0xa0f,0xa15,0xa1d,0xa21,0xa29,0x43c, -0x51b,0xa31,0xa38,0xa3f,0x41e,0xa47,0x569,0x3a7,0x501,0xa4e,0x3a7,0xa54,0x41e,0xa59,0xa61,0x3a7, -0x3a7,0xa66,0x51b,0x3a7,0x3a7,0x3a7,0x836,0xa6e,0x41e,0x5a3,0x57e,0xa75,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0xa31,0xa7d,0x3a7,0x3a7,0xa85,0xa8d,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xa91,0xa99,0x3a7, -0x3a7,0xaa1,0x57e,0xaa9,0x3a7,0xaaf,0x3a7,0x3a7,0x60f,0xab7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0xabc,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xac3,0xacb,0x3a7,0x3a7,0x3a7,0xace,0x57e,0xad6, -0xada,0xae2,0x3a7,0xae9,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0xaf0,0x3a7,0x3a7,0xafe,0xaf8,0x3a7,0x3a7,0x3a7,0xb06,0xb0e,0x3a7,0xb12,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x5a5,0x41e,0x99e,0xb1a,0x3a7,0x3a7,0x3a7,0xb27,0xb22,0x3a7, +0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x9a2,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c, +0x9aa,0x9ae,0x43c,0x43c,0x43c,0x43c,0x9be,0x9b6,0x43c,0x9c6,0x43c,0x43c,0x9ce,0x9d4,0x43c,0x43c, +0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x9e4,0x9dc,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c, +0x43c,0x43c,0x43c,0x9ec,0x43c,0x9f4,0x4a6,0x9fc,0x43c,0xa04,0xa0b,0xa11,0xa19,0xa1d,0xa25,0x43c, +0x51b,0xa2d,0xa34,0xa3b,0x41e,0xa43,0x569,0x3a7,0x501,0xa4a,0x3a7,0xa50,0x41e,0xa55,0xa5d,0x3a7, +0x3a7,0xa62,0x51b,0x3a7,0x3a7,0x3a7,0x836,0xa6a,0x41e,0x5a3,0x57e,0xa71,0x3a7,0x3a7,0x3a7,0x3a7, +0x3a7,0xa2d,0xa79,0x3a7,0x3a7,0xa81,0xa89,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xa8d,0xa95,0x3a7, +0x3a7,0xa9d,0x57e,0xaa5,0x3a7,0xaab,0x3a7,0x3a7,0x60f,0xab3,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0xab8,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xabf,0xac7,0x3a7,0x3a7,0x3a7,0xaca,0x57e,0xad2, +0xad6,0xade,0x3a7,0xae5,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0xaec,0x3a7,0x3a7,0xafa,0xaf4,0x3a7,0x3a7,0x3a7,0xb02,0xb0a,0x3a7,0xb0e,0x3a7,0x3a7,0x3a7,0x3a7, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x5a5,0x41e,0x99a,0xb16,0x3a7,0x3a7,0x3a7,0xb23,0xb1e,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0xb2f,0xb37,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xb3d, -0x3a7,0xb43,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0xb2b,0xb33,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xb39, +0x3a7,0xb3f,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0xa55,0x3a7,0xb49,0x3a7,0x3a7,0xb51,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0x3a7,0x3a7,0xa51,0x3a7,0xb45,0x3a7,0x3a7,0xb4d,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x535,0xb59,0x3a7,0x3a7, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x535,0xb55,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3f5,0xb61,0x500,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0xb69,0xb71,0xb77,0x3a7,0xb7d,0x67c,0x67c,0xb85,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x67c,0x67c,0xb8d,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xb93, -0x3a7,0xb9a,0x3a7,0xb96,0x3a7,0xb9d,0x3a7,0xba5,0xba9,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3f5,0xbb1,0x3f5,0xbb8,0xbbf,0xbc7,0x3a7, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3f5,0xb5d,0x500,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0x3a7,0x3a7,0x3a7,0x3a7,0xb65,0xb6d,0xb73,0x3a7,0xb79,0x67c,0x67c,0xb81,0x3a7,0x3a7,0x3a7,0x3a7, +0x3a7,0x67c,0x67c,0xb89,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xb8f, +0x3a7,0xb96,0x3a7,0xb92,0x3a7,0xb99,0x3a7,0xba1,0xba5,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3f5,0xbad,0x3f5,0xbb4,0xbbb,0xbc3,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xbcf,0xbd7,0x3a7,0x3a7,0xa55,0x3a7,0x3a7, -0x3a7,0x3a7,0xb43,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xa81,0x3a7, -0xbdc,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0xbe4,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0xbec, -0x43c,0xbf4,0xbf4,0xbfb,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c, -0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x91e,0x4a6,0x4a6,0x43c, -0x43c,0x4a6,0x4a6,0xc03,0x43c,0x43c,0x43c,0x43c,0x43c,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6, -0xc0b,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x67c,0xc13,0x67c,0x67c,0x67f,0xc18,0xc1c, -0x858,0xc24,0x3c9,0x3a7,0xc2a,0x3a7,0xc2f,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x783,0x3a7,0x3a7,0x3a7, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xbcb,0xbd3,0x3a7,0x3a7,0xa51,0x3a7,0x3a7, +0x3a7,0x3a7,0xb3f,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xa7d,0x3a7, +0xbd8,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0xbe0,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0xbe8, +0x43c,0xbf0,0xbf0,0xbf7,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c, +0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x91a,0x4a6,0x4a6,0x43c, +0x43c,0x4a6,0x4a6,0xbff,0x43c,0x43c,0x43c,0x43c,0x43c,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6, +0xc07,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x67c,0xc0f,0x67c,0x67c,0x67f,0xc14,0xc18, +0x858,0xc20,0x3c9,0x3a7,0xc26,0x3a7,0xc2b,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x783,0x3a7,0x3a7,0x3a7, 0x3a7,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c, -0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0xc37, -0x98f,0x67c,0x67c,0x67c,0xc3e,0x67c,0x67c,0xc45,0xc4d,0xc13,0x67c,0xc55,0x67c,0xc5d,0xc62,0x3a7, -0x3a7,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67f,0xc6a,0xc73,0xc77,0xc7f, -0xc6f,0x67c,0x67c,0x67c,0x67c,0xc87,0x67c,0x792,0xc8f,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0xc33, +0x98b,0x67c,0x67c,0x67c,0xc3a,0x67c,0x67c,0xc41,0xc49,0xc0f,0x67c,0xc51,0x67c,0xc59,0xc5e,0x3a7, +0x3a7,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67f,0xc66,0xc6f,0xc73,0xc7b, +0xc6b,0x67c,0x67c,0x67c,0x67c,0xc83,0x67c,0x792,0xc8b,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xc96,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xc92,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, 0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7, -0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xc96,0xca6,0xc9e,0xc9e,0xc9e,0xca7,0xca7,0xca7, -0xca7,0x3f5,0x3f5,0x3f5,0x3f5,0x3f5,0x3f5,0x3f5,0xcaf,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7, -0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7, -0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7, -0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7, -0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0x386,0x386,0x386,0x12,0x12,0x12,0x12, +0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xc92,0xca2,0xc9a,0xc9a,0xc9a,0xca3,0xca3,0xca3, +0xca3,0x3f5,0x3f5,0x3f5,0x3f5,0x3f5,0x3f5,0x3f5,0xcab,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3, +0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3, +0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3, +0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3, +0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0xca3,0x386,0x386,0x386,0x12,0x12,0x12,0x12, 0x12,0x12,0x12,0x12,0x12,8,7,8,9,7,0x12,0x12,0x12,0x12,0x12,0x12, 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,7,7,7,8,9,0xa,0xa,4, 4,4,0xa,0xa,0x310a,0xf20a,0xa,3,6,3,6,6,2,2,2,2, @@ -551,15 +551,14 @@ static const uint16_t ubidi_props_trieIndex[13024]={ 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, 0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0,0,0,0,0xa,0,0,0,0,0,0,0, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0, 0,0,0xb1,0xb1,0xb1,0xb1,0,0,0xa,0,0,0,0,0,0xa,0xa, 0,0,0,0,0,0xa,0xa,0xa,9,0xa,0xa,0xa,0xa,0,0,0, 0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0xa,0xa,0x310a,0xf20a,0x310a,0xf20a, 0x310a,0xf20a,0x310a,0xf20a,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0xb1,0xb1,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0, +0,0xb1,0xb1,0xa,0xa,0,0,0,0xa,0xa,0xa,0xa,0,0,0,0, +0,0,0,0,0,0,0,0xa,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa, @@ -935,13 +934,13 @@ static const UBiDiProps ubidi_props_singleton={ ubidi_props_trieIndex+3612, nullptr, 3612, - 9412, + 9396, 0x1a0, 0xe9c, 0x0, 0x0, 0x110000, - 0x32dc, + 0x32cc, nullptr, 0, false, false, 0, nullptr }, { 2,2,0,0 } diff --git a/thirdparty/icu4c/common/ucase.cpp b/thirdparty/icu4c/common/ucase.cpp index 392e1266ae..4fd23fc935 100644 --- a/thirdparty/icu4c/common/ucase.cpp +++ b/thirdparty/icu4c/common/ucase.cpp @@ -317,43 +317,6 @@ ucase_addCaseClosure(UChar32 c, const USetAdder *sa) { } } -namespace { - -/** - * Add the simple case closure mapping, - * except if there is not actually an scf relationship between the two characters. - * TODO: Unicode should probably add the corresponding scf mappings. - * See https://crbug.com/v8/13377 and Unicode-internal PAG issue #23. - * If & when those scf mappings are added, we should be able to remove all of these exceptions. - */ -void addOneSimpleCaseClosure(UChar32 c, UChar32 t, const USetAdder *sa) { - switch (c) { - case 0x0390: - if (t == 0x1FD3) { return; } - break; - case 0x03B0: - if (t == 0x1FE3) { return; } - break; - case 0x1FD3: - if (t == 0x0390) { return; } - break; - case 0x1FE3: - if (t == 0x03B0) { return; } - break; - case 0xFB05: - if (t == 0xFB06) { return; } - break; - case 0xFB06: - if (t == 0xFB05) { return; } - break; - default: - break; - } - sa->add(sa->set, t); -} - -} // namespace - U_CFUNC void U_EXPORT2 ucase_addSimpleCaseClosure(UChar32 c, const USetAdder *sa) { uint16_t props=UTRIE2_GET16(&ucase_props_singleton.trie, c); @@ -397,7 +360,7 @@ ucase_addSimpleCaseClosure(UChar32 c, const USetAdder *sa) { pe=pe0; UChar32 mapping; GET_SLOT_VALUE(excWord, idx, pe, mapping); - addOneSimpleCaseClosure(c, mapping, sa); + sa->add(sa->set, mapping); } } if(HAS_SLOT(excWord, UCASE_EXC_DELTA)) { @@ -405,7 +368,7 @@ ucase_addSimpleCaseClosure(UChar32 c, const USetAdder *sa) { int32_t delta; GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); UChar32 mapping = (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; - addOneSimpleCaseClosure(c, mapping, sa); + sa->add(sa->set, mapping); } /* get the closure string pointer & length */ @@ -448,7 +411,7 @@ ucase_addSimpleCaseClosure(UChar32 c, const USetAdder *sa) { for(int32_t idx=0; idx<closureLength;) { UChar32 mapping; U16_NEXT_UNSAFE(closure, idx, mapping); - addOneSimpleCaseClosure(c, mapping, sa); + sa->add(sa->set, mapping); } } } diff --git a/thirdparty/icu4c/common/ucase_props_data.h b/thirdparty/icu4c/common/ucase_props_data.h index 7e6de63fb7..92b59520cc 100644 --- a/thirdparty/icu4c/common/ucase_props_data.h +++ b/thirdparty/icu4c/common/ucase_props_data.h @@ -9,9 +9,9 @@ #ifdef INCLUDED_FROM_UCASE_CPP -static const UVersionInfo ucase_props_dataVersion={0xf,0,0,0}; +static const UVersionInfo ucase_props_dataVersion={0xf,1,0,0}; -static const int32_t ucase_props_indexes[UCASE_IX_TOP]={0x10,0x76f2,0x66c8,0x683,0x172,0,0,0,0,0,0,0,0,0,0,3}; +static const int32_t ucase_props_indexes[UCASE_IX_TOP]={0x10,0x76ec,0x66c8,0x680,0x172,0,0,0,0,0,0,0,0,0,0,3}; static const uint16_t ucase_props_trieIndex[13148]={ 0x355,0x35d,0x365,0x36d,0x37b,0x383,0x38b,0x393,0x39b,0x3a3,0x3aa,0x3b2,0x3ba,0x3c2,0x3ca,0x3d2, @@ -509,9 +509,9 @@ static const uint16_t ucase_props_trieIndex[13148]={ 0x39b9,0x3a29,0x3a99,0x3b09,0x3b7b,0x3beb,0x3c5b,0x3ccb,0x3d3b,0x3dab,0x3e1b,0x3e8b,0x411,0x411,0x3ef9,0x3f79, 0x3fe9,0,0x4069,0x40e9,0xfc12,0xfc12,0xdb12,0xdb12,0x419b,4,0x4209,4,4,4,0x4259,0x42d9, 0x4349,0,0x43c9,0x4449,0xd512,0xd512,0xd512,0xd512,0x44fb,4,4,4,0x411,0x411,0x4569,0x4619, -0,0,0x46e9,0x4769,0xfc12,0xfc12,0xce12,0xce12,0,4,4,4,0x411,0x411,0x4819,0x48c9, -0x4999,0x391,0x4a19,0x4a99,0xfc12,0xfc12,0xc812,0xc812,0xfc92,4,4,4,0,0,0x4b49,0x4bc9, -0x4c39,0,0x4cb9,0x4d39,0xc012,0xc012,0xc112,0xc112,0x4deb,4,4,0,0,0,0,0, +0,0,0x46d9,0x4759,0xfc12,0xfc12,0xce12,0xce12,0,4,4,4,0x411,0x411,0x4809,0x48b9, +0x4979,0x391,0x49f9,0x4a79,0xfc12,0xfc12,0xc812,0xc812,0xfc92,4,4,4,0,0,0x4b29,0x4ba9, +0x4c19,0,0x4c99,0x4d19,0xc012,0xc012,0xc112,0xc112,0x4dcb,4,4,0,0,0,0,0, 0,0,0,0,0,0,0,4,4,4,4,4,0,0,0,0, 0,0,0,0,4,4,0,0,0,0,0,0,4,0,0,4, 0,0,4,4,4,4,4,0,0,0,0,0,0,0,0,0, @@ -525,8 +525,8 @@ static const uint16_t ucase_props_trieIndex[13148]={ 0x64,0x44,0x64,0x64,0x64,0x64,0x64,0x64,0x44,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,2, 0,0,1,2,2,2,1,1,2,2,2,1,0,2,0,0, -0,2,2,2,2,2,0,0,0,0,0,0,2,0,0x4e5a,0, -2,0,0x4e9a,0x4eda,2,2,0,1,2,2,0xe12,2,1,0,0,0, +0,2,2,2,2,2,0,0,0,0,0,0,2,0,0x4e3a,0, +2,0,0x4e7a,0x4eba,2,2,0,1,2,2,0xe12,2,1,0,0,0, 0,1,0,0,1,1,2,2,0,0,0,0,0,2,1,1, 0x21,0x21,0,0,0,0,0xf211,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0x812,0x812,0x812,0x812,0x812,0x812,0x812,0x812, @@ -541,13 +541,13 @@ static const uint16_t ucase_props_trieIndex[13148]={ 0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812, 0x1812,0x1812,0x1812,0x1812,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811, 0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811, -0xe811,0xe811,0xe811,0xe811,0x92,0xff91,0x4f1a,0x4f3a,0x4f5a,0x4f79,0x4f99,0x92,0xff91,0x92,0xff91,0x92, -0xff91,0x4fba,0x4fda,0x4ffa,0x501a,1,0x92,0xff91,1,0x92,0xff91,1,1,1,1,1, -0x25,5,0x503a,0x503a,0x92,0xff91,0x92,0xff91,1,0,0,0,0,0,0,0x92, +0xe811,0xe811,0xe811,0xe811,0x92,0xff91,0x4efa,0x4f1a,0x4f3a,0x4f59,0x4f79,0x92,0xff91,0x92,0xff91,0x92, +0xff91,0x4f9a,0x4fba,0x4fda,0x4ffa,1,0x92,0xff91,1,0x92,0xff91,1,1,1,1,1, +0x25,5,0x501a,0x501a,0x92,0xff91,0x92,0xff91,1,0,0,0,0,0,0,0x92, 0xff91,0x92,0xff91,0x44,0x44,0x44,0x92,0xff91,0,0,0,0,0,0,0,0, -0,0,0,0,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059, -0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059, -0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0,0x5059,0,0,0,0,0,0x5059,0,0, +0,0,0,0,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039, +0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0x5039, +0x5039,0x5039,0x5039,0x5039,0x5039,0x5039,0,0x5039,0,0,0,0,0,0x5039,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0x64,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, @@ -562,7 +562,7 @@ static const uint16_t ucase_props_trieIndex[13148]={ 0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,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,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91, -0x92,0xff91,0x507a,0x50b9,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91, +0x92,0xff91,0x505a,0x5099,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91, 0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0,0x44,4,4,4,0, 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,4,0x92,0xff91,0x92,0xff91, 0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91, @@ -573,11 +573,11 @@ static const uint16_t ucase_props_trieIndex[13148]={ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,0x92,0xff91, 0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,1,1,0x92,0xff91, 0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91, -5,1,1,1,1,1,1,1,1,0x92,0xff91,0x92,0xff91,0x50fa,0x92,0xff91, -0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,4,4,4,0x92,0xff91,0x511a,1,0, +5,1,1,1,1,1,1,1,1,0x92,0xff91,0x92,0xff91,0x50da,0x92,0xff91, +0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,4,4,4,0x92,0xff91,0x50fa,1,0, 0x92,0xff91,0x92,0xff91,0x1811,1,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91, -0x92,0xff91,0x513a,0x515a,0x517a,0x519a,0x513a,1,0x51ba,0x51da,0x51fa,0x521a,0x92,0xff91,0x92,0xff91, -0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0xe812,0x523a,0x525a,0x92,0xff91,0x92,0xff91,0, +0x92,0xff91,0x511a,0x513a,0x515a,0x517a,0x511a,1,0x519a,0x51ba,0x51da,0x51fa,0x92,0xff91,0x92,0xff91, +0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0xe812,0x521a,0x523a,0x92,0xff91,0x92,0xff91,0, 0,0,0,0,0x92,0xff91,0,1,0,1,0x92,0xff91,0x92,0xff91,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,5,5,5,0x92,0xff91,0,5,5,1,0,0,0,0,0, @@ -607,17 +607,17 @@ static const uint16_t ucase_props_trieIndex[13148]={ 0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0, 0,0,0,4,4,0,0x64,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,0x5279,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,0x5259,1,1,1,1, 1,1,1,4,5,5,5,5,1,1,1,1,1,1,1,1, -1,5,4,4,0,0,0,0,0x5299,0x52c9,0x52f9,0x5329,0x5359,0x5389,0x53b9,0x53e9, -0x5419,0x5449,0x5479,0x54a9,0x54d9,0x5509,0x5539,0x5569,0x5b99,0x5bc9,0x5bf9,0x5c29,0x5c59,0x5c89,0x5cb9,0x5ce9, -0x5d19,0x5d49,0x5d79,0x5da9,0x5dd9,0x5e09,0x5e39,0x5e69,0x5e99,0x5ec9,0x5ef9,0x5f29,0x5f59,0x5f89,0x5fb9,0x5fe9, -0x6019,0x6049,0x6079,0x60a9,0x60d9,0x6109,0x6139,0x6169,0x5599,0x55c9,0x55f9,0x5629,0x5659,0x5689,0x56b9,0x56e9, -0x5719,0x5749,0x5779,0x57a9,0x57d9,0x5809,0x5839,0x5869,0x5899,0x58c9,0x58f9,0x5929,0x5959,0x5989,0x59b9,0x59e9, -0x5a19,0x5a49,0x5a79,0x5aa9,0x5ad9,0x5b09,0x5b39,0x5b69,0,0,0,0,0,4,0,0, +1,5,4,4,0,0,0,0,0x5279,0x52a9,0x52d9,0x5309,0x5339,0x5369,0x5399,0x53c9, +0x53f9,0x5429,0x5459,0x5489,0x54b9,0x54e9,0x5519,0x5549,0x5b79,0x5ba9,0x5bd9,0x5c09,0x5c39,0x5c69,0x5c99,0x5cc9, +0x5cf9,0x5d29,0x5d59,0x5d89,0x5db9,0x5de9,0x5e19,0x5e49,0x5e79,0x5ea9,0x5ed9,0x5f09,0x5f39,0x5f69,0x5f99,0x5fc9, +0x5ff9,0x6029,0x6059,0x6089,0x60b9,0x60e9,0x6119,0x6149,0x5579,0x55a9,0x55d9,0x5609,0x5639,0x5669,0x5699,0x56c9, +0x56f9,0x5729,0x5759,0x5789,0x57b9,0x57e9,0x5819,0x5849,0x5879,0x58a9,0x58d9,0x5909,0x5939,0x5969,0x5999,0x59c9, +0x59f9,0x5a29,0x5a59,0x5a89,0x5ab9,0x5ae9,0x5b19,0x5b49,0,0,0,0,0,4,0,0, 4,0,0,0,0,0x64,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0x6199,0x6219,0x6299,0x6319,0x63c9,0x6479,0x6519,0, -0,0,0,0,0,0,0,0,0,0,0,0x65b9,0x6639,0x66b9,0x6739,0x67b9, +0,0,0,0,0,0,0,0,0x6179,0x61f9,0x6279,0x62f9,0x63a9,0x6459,0x64e9,0, +0,0,0,0,0,0,0,0,0,0,0,0x6589,0x6609,0x6689,0x6709,0x6789, 0,0,0,0,0,0,0x64,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,4, @@ -838,7 +838,7 @@ static const uint16_t ucase_props_trieIndex[13148]={ 0,0,0,0,0,0,0,0,0,0,0,0 }; -static const uint16_t ucase_props_exceptions[1667]={ +static const uint16_t ucase_props_exceptions[1664]={ 0xc850,0x20,2,0x130,0x131,0x4810,0x20,0x841,0x6b,1,0x212a,0x841,0x73,1,0x17f,0x5c50, 0x20,2,0x130,0x131,0x844,0x4b,1,0x212a,0x844,0x53,1,0x17f,0x806,0x3bc,0x39c,0x841, 0xe5,1,0x212b,0x8c0,1,0x2220,0x73,0x73,0x53,0x53,0x53,0x73,0x1e9e,0x844,0xc5,1, @@ -909,41 +909,40 @@ static const uint16_t ucase_props_exceptions[1667]={ 0x3b7,0x3b9,0x397,0x399,0x880,0x2220,0x3ae,0x3b9,0x389,0x399,0x389,0x345,0x880,0x2220,0x3b7,0x342, 0x397,0x342,0x397,0x342,0x880,0x3330,0x3b7,0x342,0x3b9,0x397,0x342,0x399,0x397,0x342,0x345,0xc90, 9,0x220,0x3b7,0x3b9,0x397,0x399,0x880,0x3330,0x3b9,0x308,0x300,0x399,0x308,0x300,0x399,0x308, -0x300,0x8c0,1,0x3330,0x3b9,0x308,0x301,0x399,0x308,0x301,0x399,0x308,0x301,0x390,0x880,0x2220, -0x3b9,0x342,0x399,0x342,0x399,0x342,0x880,0x3330,0x3b9,0x308,0x342,0x399,0x308,0x342,0x399,0x308, -0x342,0x880,0x3330,0x3c5,0x308,0x300,0x3a5,0x308,0x300,0x3a5,0x308,0x300,0x8c0,1,0x3330,0x3c5, -0x308,0x301,0x3a5,0x308,0x301,0x3a5,0x308,0x301,0x3b0,0x880,0x2220,0x3c1,0x313,0x3a1,0x313,0x3a1, -0x313,0x880,0x2220,0x3c5,0x342,0x3a5,0x342,0x3a5,0x342,0x880,0x3330,0x3c5,0x308,0x342,0x3a5,0x308, -0x342,0x3a5,0x308,0x342,0x880,0x2220,0x1f7c,0x3b9,0x1ffa,0x399,0x1ffa,0x345,0x890,9,0x220,0x3c9, -0x3b9,0x3a9,0x399,0x880,0x2220,0x3ce,0x3b9,0x38f,0x399,0x38f,0x345,0x880,0x2220,0x3c9,0x342,0x3a9, -0x342,0x3a9,0x342,0x880,0x3330,0x3c9,0x342,0x3b9,0x3a9,0x342,0x399,0x3a9,0x342,0x345,0xc90,9, -0x220,0x3c9,0x3b9,0x3a9,0x399,0xc50,0x1d5d,1,0x3a9,0xc50,0x20bf,1,0x4b,0xc50,0x2046,1, -0xc5,0xc10,0x29f7,0xc10,0xee6,0xc10,0x29e7,0xc10,0x2a2b,0xc10,0x2a28,0xc10,0x2a1c,0xc10,0x29fd,0xc10, -0x2a1f,0xc10,0x2a1e,0xc10,0x2a3f,0xc10,0x1c60,0x841,0xa64b,1,0x1c88,0x844,0xa64a,1,0x1c88,0xc10, -0x8a04,0xc10,0xa528,0xc10,0xa544,0xc10,0xa54f,0xc10,0xa54b,0xc10,0xa541,0xc10,0xa512,0xc10,0xa52a,0xc10, -0xa515,0x810,0x3a0,0xc10,0xa543,0xc10,0x8a38,0xc10,0x3a0,0x806,0x13a0,0x13a0,0x806,0x13a1,0x13a1,0x806, -0x13a2,0x13a2,0x806,0x13a3,0x13a3,0x806,0x13a4,0x13a4,0x806,0x13a5,0x13a5,0x806,0x13a6,0x13a6,0x806,0x13a7, -0x13a7,0x806,0x13a8,0x13a8,0x806,0x13a9,0x13a9,0x806,0x13aa,0x13aa,0x806,0x13ab,0x13ab,0x806,0x13ac,0x13ac, -0x806,0x13ad,0x13ad,0x806,0x13ae,0x13ae,0x806,0x13af,0x13af,0x806,0x13b0,0x13b0,0x806,0x13b1,0x13b1,0x806, -0x13b2,0x13b2,0x806,0x13b3,0x13b3,0x806,0x13b4,0x13b4,0x806,0x13b5,0x13b5,0x806,0x13b6,0x13b6,0x806,0x13b7, -0x13b7,0x806,0x13b8,0x13b8,0x806,0x13b9,0x13b9,0x806,0x13ba,0x13ba,0x806,0x13bb,0x13bb,0x806,0x13bc,0x13bc, -0x806,0x13bd,0x13bd,0x806,0x13be,0x13be,0x806,0x13bf,0x13bf,0x806,0x13c0,0x13c0,0x806,0x13c1,0x13c1,0x806, -0x13c2,0x13c2,0x806,0x13c3,0x13c3,0x806,0x13c4,0x13c4,0x806,0x13c5,0x13c5,0x806,0x13c6,0x13c6,0x806,0x13c7, -0x13c7,0x806,0x13c8,0x13c8,0x806,0x13c9,0x13c9,0x806,0x13ca,0x13ca,0x806,0x13cb,0x13cb,0x806,0x13cc,0x13cc, -0x806,0x13cd,0x13cd,0x806,0x13ce,0x13ce,0x806,0x13cf,0x13cf,0x806,0x13d0,0x13d0,0x806,0x13d1,0x13d1,0x806, -0x13d2,0x13d2,0x806,0x13d3,0x13d3,0x806,0x13d4,0x13d4,0x806,0x13d5,0x13d5,0x806,0x13d6,0x13d6,0x806,0x13d7, -0x13d7,0x806,0x13d8,0x13d8,0x806,0x13d9,0x13d9,0x806,0x13da,0x13da,0x806,0x13db,0x13db,0x806,0x13dc,0x13dc, -0x806,0x13dd,0x13dd,0x806,0x13de,0x13de,0x806,0x13df,0x13df,0x806,0x13e0,0x13e0,0x806,0x13e1,0x13e1,0x806, -0x13e2,0x13e2,0x806,0x13e3,0x13e3,0x806,0x13e4,0x13e4,0x806,0x13e5,0x13e5,0x806,0x13e6,0x13e6,0x806,0x13e7, -0x13e7,0x806,0x13e8,0x13e8,0x806,0x13e9,0x13e9,0x806,0x13ea,0x13ea,0x806,0x13eb,0x13eb,0x806,0x13ec,0x13ec, -0x806,0x13ed,0x13ed,0x806,0x13ee,0x13ee,0x806,0x13ef,0x13ef,0x880,0x2220,0x66,0x66,0x46,0x46,0x46, -0x66,0x880,0x2220,0x66,0x69,0x46,0x49,0x46,0x69,0x880,0x2220,0x66,0x6c,0x46,0x4c,0x46, -0x6c,0x880,0x3330,0x66,0x66,0x69,0x46,0x46,0x49,0x46,0x66,0x69,0x880,0x3330,0x66,0x66, -0x6c,0x46,0x46,0x4c,0x46,0x66,0x6c,0x8c0,1,0x2220,0x73,0x74,0x53,0x54,0x53,0x74, -0xfb06,0x8c0,1,0x2220,0x73,0x74,0x53,0x54,0x53,0x74,0xfb05,0x880,0x2220,0x574,0x576,0x544, -0x546,0x544,0x576,0x880,0x2220,0x574,0x565,0x544,0x535,0x544,0x565,0x880,0x2220,0x574,0x56b,0x544, -0x53b,0x544,0x56b,0x880,0x2220,0x57e,0x576,0x54e,0x546,0x54e,0x576,0x880,0x2220,0x574,0x56d,0x544, -0x53d,0x544,0x56d +0x300,0x882,0x390,0x3330,0x3b9,0x308,0x301,0x399,0x308,0x301,0x399,0x308,0x301,0x880,0x2220,0x3b9, +0x342,0x399,0x342,0x399,0x342,0x880,0x3330,0x3b9,0x308,0x342,0x399,0x308,0x342,0x399,0x308,0x342, +0x880,0x3330,0x3c5,0x308,0x300,0x3a5,0x308,0x300,0x3a5,0x308,0x300,0x882,0x3b0,0x3330,0x3c5,0x308, +0x301,0x3a5,0x308,0x301,0x3a5,0x308,0x301,0x880,0x2220,0x3c1,0x313,0x3a1,0x313,0x3a1,0x313,0x880, +0x2220,0x3c5,0x342,0x3a5,0x342,0x3a5,0x342,0x880,0x3330,0x3c5,0x308,0x342,0x3a5,0x308,0x342,0x3a5, +0x308,0x342,0x880,0x2220,0x1f7c,0x3b9,0x1ffa,0x399,0x1ffa,0x345,0x890,9,0x220,0x3c9,0x3b9,0x3a9, +0x399,0x880,0x2220,0x3ce,0x3b9,0x38f,0x399,0x38f,0x345,0x880,0x2220,0x3c9,0x342,0x3a9,0x342,0x3a9, +0x342,0x880,0x3330,0x3c9,0x342,0x3b9,0x3a9,0x342,0x399,0x3a9,0x342,0x345,0xc90,9,0x220,0x3c9, +0x3b9,0x3a9,0x399,0xc50,0x1d5d,1,0x3a9,0xc50,0x20bf,1,0x4b,0xc50,0x2046,1,0xc5,0xc10, +0x29f7,0xc10,0xee6,0xc10,0x29e7,0xc10,0x2a2b,0xc10,0x2a28,0xc10,0x2a1c,0xc10,0x29fd,0xc10,0x2a1f,0xc10, +0x2a1e,0xc10,0x2a3f,0xc10,0x1c60,0x841,0xa64b,1,0x1c88,0x844,0xa64a,1,0x1c88,0xc10,0x8a04,0xc10, +0xa528,0xc10,0xa544,0xc10,0xa54f,0xc10,0xa54b,0xc10,0xa541,0xc10,0xa512,0xc10,0xa52a,0xc10,0xa515,0x810, +0x3a0,0xc10,0xa543,0xc10,0x8a38,0xc10,0x3a0,0x806,0x13a0,0x13a0,0x806,0x13a1,0x13a1,0x806,0x13a2,0x13a2, +0x806,0x13a3,0x13a3,0x806,0x13a4,0x13a4,0x806,0x13a5,0x13a5,0x806,0x13a6,0x13a6,0x806,0x13a7,0x13a7,0x806, +0x13a8,0x13a8,0x806,0x13a9,0x13a9,0x806,0x13aa,0x13aa,0x806,0x13ab,0x13ab,0x806,0x13ac,0x13ac,0x806,0x13ad, +0x13ad,0x806,0x13ae,0x13ae,0x806,0x13af,0x13af,0x806,0x13b0,0x13b0,0x806,0x13b1,0x13b1,0x806,0x13b2,0x13b2, +0x806,0x13b3,0x13b3,0x806,0x13b4,0x13b4,0x806,0x13b5,0x13b5,0x806,0x13b6,0x13b6,0x806,0x13b7,0x13b7,0x806, +0x13b8,0x13b8,0x806,0x13b9,0x13b9,0x806,0x13ba,0x13ba,0x806,0x13bb,0x13bb,0x806,0x13bc,0x13bc,0x806,0x13bd, +0x13bd,0x806,0x13be,0x13be,0x806,0x13bf,0x13bf,0x806,0x13c0,0x13c0,0x806,0x13c1,0x13c1,0x806,0x13c2,0x13c2, +0x806,0x13c3,0x13c3,0x806,0x13c4,0x13c4,0x806,0x13c5,0x13c5,0x806,0x13c6,0x13c6,0x806,0x13c7,0x13c7,0x806, +0x13c8,0x13c8,0x806,0x13c9,0x13c9,0x806,0x13ca,0x13ca,0x806,0x13cb,0x13cb,0x806,0x13cc,0x13cc,0x806,0x13cd, +0x13cd,0x806,0x13ce,0x13ce,0x806,0x13cf,0x13cf,0x806,0x13d0,0x13d0,0x806,0x13d1,0x13d1,0x806,0x13d2,0x13d2, +0x806,0x13d3,0x13d3,0x806,0x13d4,0x13d4,0x806,0x13d5,0x13d5,0x806,0x13d6,0x13d6,0x806,0x13d7,0x13d7,0x806, +0x13d8,0x13d8,0x806,0x13d9,0x13d9,0x806,0x13da,0x13da,0x806,0x13db,0x13db,0x806,0x13dc,0x13dc,0x806,0x13dd, +0x13dd,0x806,0x13de,0x13de,0x806,0x13df,0x13df,0x806,0x13e0,0x13e0,0x806,0x13e1,0x13e1,0x806,0x13e2,0x13e2, +0x806,0x13e3,0x13e3,0x806,0x13e4,0x13e4,0x806,0x13e5,0x13e5,0x806,0x13e6,0x13e6,0x806,0x13e7,0x13e7,0x806, +0x13e8,0x13e8,0x806,0x13e9,0x13e9,0x806,0x13ea,0x13ea,0x806,0x13eb,0x13eb,0x806,0x13ec,0x13ec,0x806,0x13ed, +0x13ed,0x806,0x13ee,0x13ee,0x806,0x13ef,0x13ef,0x880,0x2220,0x66,0x66,0x46,0x46,0x46,0x66,0x880, +0x2220,0x66,0x69,0x46,0x49,0x46,0x69,0x880,0x2220,0x66,0x6c,0x46,0x4c,0x46,0x6c,0x880, +0x3330,0x66,0x66,0x69,0x46,0x46,0x49,0x46,0x66,0x69,0x880,0x3330,0x66,0x66,0x6c,0x46, +0x46,0x4c,0x46,0x66,0x6c,0x882,0xfb06,0x2220,0x73,0x74,0x53,0x54,0x53,0x74,0x8c0,1, +0x2220,0x73,0x74,0x53,0x54,0x53,0x74,0xfb05,0x880,0x2220,0x574,0x576,0x544,0x546,0x544,0x576, +0x880,0x2220,0x574,0x565,0x544,0x535,0x544,0x565,0x880,0x2220,0x574,0x56b,0x544,0x53b,0x544,0x56b, +0x880,0x2220,0x57e,0x576,0x54e,0x546,0x54e,0x576,0x880,0x2220,0x574,0x56d,0x544,0x53d,0x544,0x56d }; static const uint16_t ucase_props_unfold[370]={ diff --git a/thirdparty/icu4c/common/ucasemap.cpp b/thirdparty/icu4c/common/ucasemap.cpp index 1d8a8b6c2f..f6a0106aec 100644 --- a/thirdparty/icu4c/common/ucasemap.cpp +++ b/thirdparty/icu4c/common/ucasemap.cpp @@ -679,14 +679,18 @@ void toUpper(uint32_t options, // Adding one only to the final vowel in a longer sequence // (which does not occur in normal writing) would require lookahead. // Set the same flag as for preserving an existing dialytika. - if ((data & HAS_VOWEL) != 0 && (state & AFTER_VOWEL_WITH_ACCENT) != 0 && - (upper == 0x399 || upper == 0x3A5)) { - data |= HAS_DIALYTIKA; + if ((data & HAS_VOWEL) != 0 && + (state & (AFTER_VOWEL_WITH_PRECOMPOSED_ACCENT | AFTER_VOWEL_WITH_COMBINING_ACCENT)) != + 0 && + (upper == 0x399 || upper == 0x3A5)) { + data |= (state & AFTER_VOWEL_WITH_PRECOMPOSED_ACCENT) != 0 ? HAS_DIALYTIKA + : HAS_COMBINING_DIALYTIKA; } int32_t numYpogegrammeni = 0; // Map each one to a trailing, spacing, capital iota. if ((data & HAS_YPOGEGRAMMENI) != 0) { numYpogegrammeni = 1; } + const UBool hasPrecomposedAccent = (data & HAS_ACCENT) != 0; // Skip combining diacritics after this Greek letter. int32_t nextNextIndex = nextIndex; while (nextIndex < srcLength) { @@ -704,7 +708,8 @@ void toUpper(uint32_t options, } } if ((data & HAS_VOWEL_AND_ACCENT_AND_DIALYTIKA) == HAS_VOWEL_AND_ACCENT) { - nextState |= AFTER_VOWEL_WITH_ACCENT; + nextState |= hasPrecomposedAccent ? AFTER_VOWEL_WITH_PRECOMPOSED_ACCENT + : AFTER_VOWEL_WITH_COMBINING_ACCENT; } // Map according to Greek rules. UBool addTonos = false; @@ -715,7 +720,7 @@ void toUpper(uint32_t options, !isFollowedByCasedLetter(src, nextIndex, srcLength)) { // Keep disjunctive "or" with (only) a tonos. // We use the same "word boundary" conditions as for the Final_Sigma test. - if (i == nextIndex) { + if (hasPrecomposedAccent) { upper = 0x389; // Preserve the precomposed form. } else { addTonos = true; diff --git a/thirdparty/icu4c/common/ucasemap_imp.h b/thirdparty/icu4c/common/ucasemap_imp.h index 71d0e9033f..bc83c6bd78 100644 --- a/thirdparty/icu4c/common/ucasemap_imp.h +++ b/thirdparty/icu4c/common/ucasemap_imp.h @@ -263,7 +263,8 @@ static const uint32_t HAS_EITHER_DIALYTIKA = HAS_DIALYTIKA | HAS_COMBINING_DIALY // State bits. static const uint32_t AFTER_CASED = 1; -static const uint32_t AFTER_VOWEL_WITH_ACCENT = 2; +static const uint32_t AFTER_VOWEL_WITH_COMBINING_ACCENT = 2; +static const uint32_t AFTER_VOWEL_WITH_PRECOMPOSED_ACCENT = 4; uint32_t getLetterData(UChar32 c); diff --git a/thirdparty/icu4c/common/uchar_props_data.h b/thirdparty/icu4c/common/uchar_props_data.h index f4d3932574..0324223975 100644 --- a/thirdparty/icu4c/common/uchar_props_data.h +++ b/thirdparty/icu4c/common/uchar_props_data.h @@ -9,9 +9,9 @@ #ifdef INCLUDED_FROM_UCHAR_C -static const UVersionInfo dataVersion={0xf,0,0,0}; +static const UVersionInfo dataVersion={0xf,1,0,0}; -static const uint16_t propsTrie_index[23016]={ +static const uint16_t propsTrie_index[23156]={ 0x495,0x49d,0x4a5,0x4ad,0x4c5,0x4cd,0x4d5,0x4dd,0x4e5,0x4ed,0x4f3,0x4fb,0x503,0x50b,0x513,0x51b, 0x521,0x529,0x531,0x539,0x53c,0x544,0x54c,0x554,0x55c,0x564,0x560,0x568,0x570,0x578,0x57d,0x585, 0x58d,0x595,0x599,0x5a1,0x5a9,0x5b1,0x5b9,0x5c1,0x5bd,0x5c5,0x5ca,0x5d2,0x5d8,0x5e0,0x5e8,0x5f0, @@ -51,53 +51,57 @@ static const uint16_t propsTrie_index[23016]={ 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x934,0x934, -0xc2e,0x600,0xc31,0x600,0xc39,0xc3f,0xc47,0xc4f,0xc54,0x600,0x600,0xc58,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xc5f,0x600,0xc66,0xc6c,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xc74,0x600,0x600,0x600,0xc7c,0x600, +0xc2e,0xc35,0xc37,0x600,0xc3f,0xc45,0xc4d,0xc55,0xc5a,0x600,0x600,0xc5e,0x600,0x600,0x600,0xc64, +0xc6b,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xc72,0x600,0xc79,0xc7f,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xc87,0x600,0x600,0x600,0xc8f,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0xc7e,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xc85,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0xc91,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xc98,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0xc8c,0x600,0x600,0x600,0xc93,0xc9b,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0xc9f,0x600,0x600,0x600,0xca6,0xcae,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xca0,0x600,0x600,0xca8,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0xcb3,0xcb8,0x600,0x600,0xcc0,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xcac,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xcc4,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xcc9,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xcc7,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xcaf,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xcd1,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xcb2,0x600,0x600,0x600, +0x600,0x600,0x600,0xcd7,0xcdf,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xce5, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0xcb8,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0xcec,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0xcf1,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0xcc0,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0xcc5,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0xcf6,0x600,0x600,0x600,0xc32,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0xcca,0x600,0x600,0x600,0xccf,0x600,0x600,0x600,0x600,0x600,0x600, +0xcd3,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0xcfc,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0xd04,0xd0b,0xd0f,0x600,0x600,0x600,0xccb,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0xcd7,0xcde,0xce2,0x600,0x600,0x600,0xce9,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0xd1e,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0xd16,0x934,0xd26,0x9ad,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0xd2b,0xd33,0x4e5,0xd43,0xd3b,0x600,0x600,0xd4b,0xd53,0xd63,0x4e5,0xd68,0xd70,0xd76,0xd7d,0xd5b, +0xd85,0xd8d,0x600,0xd95,0xda5,0xda8,0xd9d,0xdb0,0x655,0xdb8,0xdbf,0x8f6,0x6a3,0xdcf,0xdc7,0xdd7, +0x600,0xddf,0xde7,0xdef,0x600,0xdf7,0xdff,0xe07,0xe0f,0xe17,0xe1b,0xe23,0x535,0x535,0x600,0xe2b, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0xcf7,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0xcef,0x934,0xcff,0x9ad,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0xd04,0xd0c,0x4e5,0xd1c,0xd14,0x600,0x600,0xd24,0xd2c,0xd3c,0x4e5,0xd41,0xd49,0xd4f,0xd56,0xd34, -0xd5e,0xd66,0x600,0xd6e,0xd7e,0xd81,0xd76,0xd89,0x655,0xd91,0xd98,0x8f6,0x6a3,0xda8,0xda0,0xdb0, -0x600,0xdb8,0xdc0,0xdc8,0x600,0xdd0,0xdd8,0xde0,0xde8,0xdf0,0xdf4,0xdfc,0x535,0x535,0x600,0xe04, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, @@ -115,33 +119,29 @@ static const uint16_t propsTrie_index[23016]={ 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xe0c,0xe18,0xe10, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xe33,0xe3f,0xe37, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20, -0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0x600,0x600,0x600,0xe30,0x600,0xcea,0xe37,0xe3c, -0x600,0x600,0x600,0xe44,0x600,0x600,0x901,0x4b5,0xe5a,0xe4a,0xe52,0x600,0x600,0xe62,0xe6a,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xe6f,0x938,0x600,0xe77,0x600,0xe7d,0xe81, -0xe89,0xe91,0xe98,0xea0,0x600,0x600,0x600,0xea6,0xebe,0x4a5,0xec6,0xece,0xed3,0x916,0xeae,0xeb6, -0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20, -0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20, +0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47, +0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0x600,0x600,0x600,0xe57,0x600,0xccc,0xe5e,0xe63, +0x600,0x600,0x600,0xe6b,0x600,0x600,0x901,0x4b5,0xe81,0xe71,0xe79,0x600,0x600,0xe89,0xe91,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xe96,0x938,0x600,0xe9e,0x600,0xea4,0xea8, +0xeb0,0xeb8,0xebf,0xec7,0x600,0x600,0x600,0xecd,0xee5,0x4a5,0xeed,0xef5,0xefa,0x916,0xed5,0xedd, +0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47, +0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47,0xe47, 0x12d4,0x12d4,0x1314,0x1354,0x1394,0x13cc,0x140c,0x144c,0x1484,0x14c4,0x14f0,0x1530,0x1570,0x1580,0x15c0,0x15f4, 0x1634,0x1664,0x16a4,0x16e4,0x16f4,0x1728,0x1760,0x17a0,0x17e0,0x1820,0x1854,0x1880,0x18c0,0x18f8,0x1914,0x1954, 0xa80,0xac0,0xb00,0xb40,0xb80,0xbab,0xbeb,0xa40,0xc0e,0xa40,0xa40,0xa40,0xa40,0xc4e,0x1db,0x1db, @@ -180,132 +180,132 @@ static const uint16_t propsTrie_index[23016]={ 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0xedb,0xee2,0xeea,0x4b5,0x600,0x600,0x600,0xef2,0xf02,0xefa,0xf19,0xf0a,0xf11,0xf21,0xf25,0xf29, -0x4b5,0x4b5,0x4b5,0x4b5,0x8f6,0x600,0xf31,0xf39,0x600,0xf41,0xf49,0xf4d,0xf55,0x600,0xf5d,0x4b5, -0x58d,0x597,0xf65,0x600,0xf69,0xf71,0xf81,0xf79,0x600,0xf89,0x600,0xf90,0xfa0,0xf98,0x4b5,0x4b5, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xb88,0x902,0xfa8,0xfb8,0xfb0,0x4b5,0x4b5, -0xfc8,0xfc0,0xfcb,0xfd3,0x916,0xfdb,0x4b5,0xfe3,0xfeb,0xff3,0x4b5,0x4b5,0x600,0x1003,0x100b,0xffb, -0x101b,0x1022,0x1013,0x102a,0x1032,0x4b5,0x1042,0x103a,0x600,0x1045,0x104d,0x1055,0x105d,0x1065,0x4b5,0x4b5, -0x600,0x600,0x106d,0x4b5,0x58d,0x1075,0x535,0x107d,0x600,0x1085,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0x4b5,0x4b5,0x108d,0x600,0x1095,0x4b5,0x109a,0x10a2,0x10aa,0x10b1,0xfdf,0x10b9,0xfdf,0x10c1,0xb88, -0x10d1,0x636,0x10d9,0x10c9,0x98f,0x10e1,0x10e9,0x10ef,0x1107,0x10f7,0x10ff,0x110b,0x98f,0x111b,0x1113,0x1123, -0x113b,0x112b,0x1133,0x4b5,0x1142,0x114a,0x658,0x1152,0x1162,0x1168,0x1170,0x115a,0x4b5,0x4b5,0x4b5,0x4b5, -0x600,0x1178,0x1180,0x1099,0x600,0x1188,0x1190,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x1198,0x11a0,0x4b5, -0x600,0x11a8,0x11b0,0x11b8,0x600,0x11c8,0x11c0,0x4b5,0x870,0x11d0,0x11d8,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x600,0x11e0,0x4b5,0x4b5,0x4b5,0x58d,0x535,0x11e8,0x11f8,0x11fe,0x11f0,0x4b5,0x4b5,0x120e,0x1212,0x1206, -0x122a,0x121a,0x1222,0x600,0x1238,0x1232,0x600,0x8f7,0x1248,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x1256,0x125b,0x1240,0x1250,0x126b,0x1263,0x4b5,0x4b5,0x127a,0x127e,0x1272,0x128e,0x1286,0x11c0,0x4b5,0x4b5, -0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x1292,0x12a2,0x12a7,0x129a,0x4b5,0x4b5,0x12af,0x12bf,0x12b7, +0xf02,0xf09,0xf11,0x4b5,0x600,0x600,0x600,0xf19,0xf29,0xf21,0xf40,0xf31,0xf38,0xf48,0xbbd,0xf50, +0x4b5,0x4b5,0x4b5,0x4b5,0x8f6,0x600,0xf58,0xf60,0x600,0xf68,0xf70,0xf74,0xf7c,0x600,0xf84,0x4b5, +0x58d,0x597,0xf8c,0x600,0xf90,0xf98,0xfa8,0xfa0,0x600,0xfb0,0x600,0xfb7,0xfc7,0xfbf,0x4b5,0x4b5, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xb88,0x902,0xfcf,0xfdf,0xfd7,0x4b5,0x4b5, +0xfef,0xfe7,0xff2,0xffa,0x916,0x1002,0x4b5,0x100a,0x1012,0x101a,0x4b5,0x4b5,0x600,0x102a,0x1032,0x1022, +0x1042,0x1049,0x103a,0x1051,0x1059,0x4b5,0x1069,0x1061,0x600,0x106c,0x1074,0x107c,0x1084,0x108c,0x4b5,0x4b5, +0x600,0x600,0x1094,0x4b5,0x58d,0x109c,0x535,0x10a4,0x600,0x10ac,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, +0x4b5,0x4b5,0x4b5,0x10b4,0x600,0x10bc,0x4b5,0x10c1,0x10c9,0x10d1,0x10d8,0x1006,0x10e0,0x1006,0x10e8,0xb88, +0x10f8,0x636,0x1100,0x10f0,0x98f,0x1108,0x1110,0x1116,0x112e,0x111e,0x1126,0x1132,0x98f,0x1142,0x113a,0x114a, +0x1162,0x1152,0x115a,0x4b5,0x1169,0x1171,0x658,0x1179,0x1189,0x118f,0x1197,0x1181,0x4b5,0x4b5,0x4b5,0x4b5, +0x600,0x119f,0x11a7,0x10c0,0x600,0x11af,0x11b7,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x11bf,0x11c7,0x4b5, +0x600,0x11cf,0x11d7,0x11df,0x600,0x11ef,0x11e7,0x4b5,0x870,0x11f7,0x11ff,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, +0x600,0x1207,0x4b5,0x4b5,0x4b5,0x58d,0x535,0x120f,0x121f,0x1225,0x1217,0x4b5,0x4b5,0x1235,0x1239,0x122d, +0x1251,0x1241,0x1249,0x600,0x125f,0x1259,0x600,0x8f7,0x126f,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, +0x127d,0x1282,0x1267,0x1277,0x1292,0x128a,0x4b5,0x4b5,0x12a1,0x12a5,0x1299,0x12b5,0x12ad,0x11e7,0x4b5,0x4b5, +0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x12b9,0x12c9,0x12ce,0x12c1,0x4b5,0x4b5,0x12d6,0x12e6,0x12de, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x901,0x4b5,0x4b5,0x4b5, -0x12cf,0x12d7,0x12df,0x12c7,0x600,0x600,0x600,0x600,0x600,0x600,0x12e7,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, +0x12f6,0x12fe,0x1306,0x12ee,0x600,0x600,0x600,0x600,0x600,0x600,0x130e,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0xfdf,0x600,0x600,0x12ef,0x600,0x600,0x600,0x600,0x600, +0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x1006,0x600,0x600,0x1316,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x12f7,0x12ff,0x4b5,0x4b5, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x131e,0x1326,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x11d8,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600, +0x11ff,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x8f7, -0x916,0xda4,0x600,0x916,0x1307,0x130c,0x600,0x131c,0x1324,0x132c,0x1314,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, +0x916,0xdcb,0x600,0x916,0x132e,0x1333,0x600,0x1343,0x134b,0x1353,0x133b,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x58d,0x535,0x1334,0x4b5,0x4b5,0x4b5,0x600,0x600,0x133c,0x1341,0x1347,0x4b5,0x4b5,0x134f,0x600,0x600, +0x58d,0x535,0x135b,0x4b5,0x4b5,0x4b5,0x600,0x600,0x1363,0x1368,0x136e,0x4b5,0x4b5,0x1376,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1357,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x137e,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x902,0x4b5,0x106d,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, +0x600,0x600,0x600,0x600,0x902,0x4b5,0x1094,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x135d,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x1365,0x136a,0x1371,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xe10,0x4b5, +0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x1384,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x138c,0x1391,0x1398,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xe37,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600,0x600,0x1377,0x137c,0x1384,0x4b5,0x4b5,0x4b5, +0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600,0x600,0x139e,0x13a3,0x13ab,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x55c,0x1394,0x139b,0x934,0x934,0x934,0x138c,0x4b5,0x934,0x934,0x934, -0x934,0x934,0x934,0x934,0xbb7,0x934,0x13a2,0x934,0x13a9,0x13b1,0x13b7,0x934,0xade,0x934,0x934,0x13bf, -0x4b5,0x4b5,0x4b5,0x13c7,0x13c7,0x934,0x934,0xadb,0x13cf,0x4b5,0x4b5,0x4b5,0x4b5,0x13df,0x13e6,0x13eb, -0x13f1,0x13f9,0x1401,0x1409,0x13e3,0x1411,0x1419,0x1421,0x1426,0x13f8,0x13df,0x13e6,0x13e2,0x13f1,0x142e,0x13e0, -0x1431,0x13e3,0x1439,0x1441,0x1449,0x1450,0x143c,0x1444,0x144c,0x1453,0x143f,0x145b,0x13d7,0x934,0x934,0x934, -0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x55c,0x146b,0x55c, -0x1472,0x1479,0x1463,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, +0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x55c,0x13bb,0x13c2,0x934,0x934,0x934,0x13b3,0x4b5,0x934,0x934,0x934, +0x934,0x934,0x934,0x934,0xbb7,0x934,0x13c9,0x934,0x13d0,0x13d8,0x13de,0x934,0xade,0x934,0x934,0x13e6, +0x4b5,0x4b5,0x4b5,0x13ee,0x13ee,0x934,0x934,0xadb,0x13f6,0x4b5,0x4b5,0x4b5,0x4b5,0x1406,0x140d,0x1412, +0x1418,0x1420,0x1428,0x1430,0x140a,0x1438,0x1440,0x1448,0x144d,0x141f,0x1406,0x140d,0x1409,0x1418,0x1455,0x1407, +0x1458,0x140a,0x1460,0x1468,0x1470,0x1477,0x1463,0x146b,0x1473,0x147a,0x1466,0x1482,0x13fe,0x934,0x934,0x934, +0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x55c,0x1492,0x55c, +0x1499,0x14a0,0x148a,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x1488,0x1490,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x1480,0x1498,0x9d4, -0x14a8,0x14a0,0x4b5,0x4b5,0x4b5,0x600,0x14b8,0x14b0,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0xfdf,0x14c0,0x600,0x14c8,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0x4b5,0x4b5,0xfdf,0x14d0,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x14d8,0x600,0x600,0x600, -0x600,0x600,0x600,0x14e0,0x4b5,0x58d,0x14f0,0x14e8,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, +0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x14af,0x14b7,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x14a7,0x14bf,0x9d4, +0x14cf,0x14c7,0x4b5,0x4b5,0x4b5,0x600,0x14df,0x14d7,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, +0x4b5,0x1006,0x14e7,0x600,0x14ef,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, +0x4b5,0x4b5,0x4b5,0x1006,0x14f7,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, +0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x14ff,0x600,0x600,0x600, +0x600,0x600,0x600,0x1507,0x4b5,0x58d,0x1517,0x150f,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x14f8,0x1508,0x1500,0x4b5,0x4b5,0x1518,0x1510,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x1528,0x1530,0x1538, -0x1540,0x1548,0x1550,0x4b5,0x1520,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x934,0x1558,0x934, -0x934,0xbaf,0x13a0,0x1560,0xbb7,0x1568,0x934,0x934,0x934,0x934,0xbb9,0x4b5,0x1570,0x1578,0x157c,0x1584, -0x158c,0x4b5,0x4b5,0x4b5,0x4b5,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x1594,0x934,0x934,0x934, +0x151f,0x152f,0x1527,0x4b5,0x4b5,0x153f,0x1537,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x154f,0x1557,0x155f, +0x1567,0x156f,0x1577,0x4b5,0x1547,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x934,0x157f,0x934, +0x934,0xbaf,0x13c7,0x1587,0xbb7,0x158f,0x934,0x934,0x934,0x934,0xbb9,0x4b5,0x1597,0x159f,0x15a3,0x15ab, +0x15b3,0x4b5,0x4b5,0x4b5,0x4b5,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x15bb,0x934,0x934,0x934, 0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934, -0x934,0x934,0x934,0x157d,0x159c,0x934,0x934,0x934,0x15a4,0x934,0x934,0x15ab,0x15b3,0x1558,0x934,0x15bb, -0x934,0x15c3,0x15c8,0x4b5,0x4b5,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0xbaf, -0x15d0,0x15d9,0x15dd,0x15e5,0x15d5,0x934,0x934,0x934,0x934,0x15ed,0x934,0xade,0x11bc,0x4b5,0x4b5,0x4b5, +0x934,0x934,0x934,0x15a4,0x15c3,0x934,0x934,0x934,0x15cb,0x934,0x934,0x15d2,0x15da,0x157f,0x934,0x15e2, +0x934,0x15ea,0x15ef,0x4b5,0x4b5,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0xbaf, +0x15f7,0x1600,0x1604,0x160c,0x15fc,0x934,0x934,0x934,0x934,0x1614,0x934,0xade,0x11e3,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x15f5,0x600,0x600, -0x15fc,0x600,0x600,0x600,0x1604,0x600,0x160c,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x161c,0x600,0x600, +0x1623,0x600,0x600,0x600,0x162b,0x600,0x1633,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xc90,0x600,0x600, -0x1614,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x161c,0x1624,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xca3,0x600,0x600, +0x163b,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1643,0x164b,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0xccf,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0xc32,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x162b,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1652,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1632,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1659,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x1639,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0x600,0x600,0x600,0x600,0x1660,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x4b5,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x901,0x600,0x600,0x600,0x600,0x600,0x600,0xf69,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x901,0x600,0x600,0x600,0x600,0x600,0x600,0xf90,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1641,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1668,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1649,0x4b5,0x4b5, -0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600, -0x600,0x600,0x1651,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xf69,0x4b5, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1670,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, +0xf90,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600, +0x600,0x600,0x1674,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xf90,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x67d,0x600,0x600,0x600,0x600,0x600,0x600,0x600, 0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1314,0x4b5, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x133b,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0x1661,0x1659,0x1659,0x1659,0x4b5,0x4b5,0x4b5,0x4b5,0x55c,0x55c,0x55c,0x55c,0x55c,0x55c,0x55c, -0x1669,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, +0x4b5,0x1684,0x167c,0x167c,0x167c,0x4b5,0x4b5,0x4b5,0x4b5,0x55c,0x55c,0x55c,0x55c,0x55c,0x55c,0x55c, +0x168c,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, -0x4b5,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0x1671,0x494,0x494,0x494,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, +0x4b5,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0x1694,0x494,0x494,0x494,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, 0xf,0xf,0xf,0xf,0xc,0x17,0x17,0x17,0x19,0x17,0x17,0x17,0x14,0x15,0x17,0x18, 0x17,0x13,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17, @@ -765,7 +765,7 @@ static const uint16_t propsTrie_index[23016]={ 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, 0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0,0,0,0,0x1b,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,6,6, +0x1b,0x1b,0x1b,0x1b,0x1b,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,6,6, 6,6,8,8,0x13,4,4,4,4,4,0x1b,0x1b,0x7ca,0xa4a,0xcca,4, 5,0x17,0x1b,0x1b,0xc,0x17,0x17,0x17,0x1b,4,5,0x54a,0x14,0x15,0x14,0x15, 0x14,0x15,0x14,0x15,0x14,0x15,0x1b,0x1b,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15, @@ -778,7 +778,7 @@ static const uint16_t propsTrie_index[23016]={ 5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,0,0x1b,0x1b,0x58b,0x5cb,0x60b,0x64b,0x1b,0x1b, 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0, -0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, +0,0,0,0x1b,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0x1b,0x1b, 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, 0x1b,0x1b,0x1b,0x1b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1b,0xa8b,0xacb,0xb0b, @@ -793,664 +793,673 @@ static const uint16_t propsTrie_index[23016]={ 5,5,5,5,5,0x705,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,0x585,5,5,0x705,5,5,5,0x7885, 5,0x605,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,0x5c5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,0x785,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -0x5c5,5,5,5,5,5,5,5,0x685,5,0x645,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,0x785,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,0x5c5,5,5,5,5,5,5,5, +0x685,5,0x645,5,5,5,5,5,5,5,5,5,5,5,5,5, +0x7b85,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,0x7985,0x7c5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,0x7985,0x7c5,5,5,5, +5,5,5,0x7845,5,5,5,5,5,5,5,5,0x605,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,0x7845,5,5,5,5, -5,5,5,5,0x605,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,0x685,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -0x1e45,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -0x7985,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x7a85,5, +5,5,5,5,5,0x685,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,0x1e45,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,0x5c5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,0x5c5,5,0x745,5,0x6c5,5,5, +5,5,0x5c5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,0x7985,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,0x7c5,5,0x7845,0xa45,0xcc5,5,5,5,5,5,5,0xf45,5,5,5, +5,5,5,5,5,5,5,5,5,5,0x7905,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,0x605,0x605,0x605,0x605,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,0x5c5,5,0x745,5,0x6c5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,0x7c5,5,0x7845, +0xa45,0xcc5,5,5,5,5,5,5,0xf45,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,0x605,0x605,0x605, +0x605,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x645, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,0x645,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,0x585,5,5,5,5,5,5,5,0x585,5,5, +5,0x585,5,5,5,5,5,5,5,0x585,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,0x585,5,5,5,5,5, +5,5,5,5,5,5,0x585,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,0x785,0xa45,5,5,5,5, -5,5,5,5,5,5,5,5,0x585,0x5c5,0x605,5,0x5c5,5,5,5, +5,5,5,5,5,5,0x785,0xa45,5,5,5,5,5,5,5,5, +5,5,5,5,0x585,0x5c5,0x605,5,0x5c5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,0x705,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x7c5,5, 5,5,5,5,5,5,5,5,5,5,5,5,0x745,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,0x705,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x785,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x1e45,5, +5,5,0x545,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,0x785,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,0x1e45,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,0x8005,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,0x79c5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,0x645,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 0x7885,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,0x5c5,5,5,5,5,0x5c5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,0x5c5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,0x7845,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x6c5,5, -5,5,5,5,0x1e45,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,0x785,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -0x6c5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,0x545,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,0,0,0,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,5,5,5,5, +5,0x7845,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,4,5,5,5,5,5,5,5,5,5,5,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,4,0x17,0x17,0x17, +5,5,0x6c5,5,5,5,5,5,0x1e45,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +5,5,5,5,0x6c5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,4,5,5, +5,5,5,5,5,5,5,5,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0, +0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,4,0x17,0x17,0x17,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,2, 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, -1,2,1,2,1,2,1,2,1,2,1,2,4,4,6,6, -1,2,1,2,1,2,1,2,1,2,1,2,1,2,5,6, -7,7,7,0x17,6,6,6,6,6,6,6,6,6,6,0x17,4, -5,5,5,5,5,5,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x54a, -6,6,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0, +1,2,1,2,1,2,1,2,4,4,6,6,1,2,1,2, +1,2,1,2,1,2,1,2,1,2,5,6,7,7,7,0x17, +6,6,6,6,6,6,6,6,6,6,0x17,4,5,5,5,5, +5,5,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x54a,6,6,0x17,0x17, +0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0x1a,0x1a,0x1a,0x1a, 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, -0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,4,4,4,4,4,4,4,4, +0x1a,0x1a,0x1a,4,4,4,4,4,4,4,4,4,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4, +4,1,2,5,4,4,2,5,5,5,5,5,0x1a,0x1a,1,2, +1,2,1,2,1,2,1,2,1,2,1,2,2,2,1,2, +1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, +4,2,2,2,2,2,2,2,2,1,2,1,2,1,1,2, +1,2,1,2,1,2,1,2,4,0x1a,0x1a,1,2,1,2,5, +1,2,1,2,2,2,1,2,1,2,1,2,1,2,1,2, +1,2,1,1,1,1,1,2,1,1,1,1,1,2,1,2, +1,2,1,2,1,2,1,2,1,1,1,1,2,1,2,0, +0,0,0,0,1,2,0,2,0,2,1,2,1,2,0,0, +0,0,0,0,5,5,6,5,5,5,6,5,5,5,5,6, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,8,8,6,6,8,0x1b,0x1b,0x1b,0x1b, +6,0,0,0,0x34cb,0x344b,0x3ccb,0x37cb,0x35cb,0x3fcb,0x1b,0x1b,0x19,0x1b,0,0, +0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,0x17,0x17,0x17,0x17,0,0,0,0, +0,0,0,0,8,8,8,8,6,6,0,0,0,0,0,0, +0,0,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0, +0,0,0,0,8,8,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,8,8,8,8,8,8,8,8,8,8,8,8, +6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, +6,6,5,5,5,5,5,5,0x17,0x17,0x17,5,0x17,5,5,6, +5,5,5,5,5,5,6,6,6,6,6,6,6,6,0x17,0x17, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,6,6,6,6,6,6,6,6,6,6,6,8,8, +0,0,0,0,0,0,0,0,0,0,0,0x17,8,0x17,0x17,0x17, +0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,4,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0x17,0x17,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6, +8,8,6,6,6,6,8,8,6,6,8,8,5,5,5,5, +5,6,4,5,5,5,5,5,5,5,5,5,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,5,5,5,0,5,5,5,5, +5,5,5,5,5,6,6,6,6,6,6,8,8,6,6,8, +8,6,6,0,0,0,0,0,0,0,0,0,5,5,5,6, +5,5,5,5,5,5,5,5,6,8,0,0,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0x17,0x17,0x17,0x17,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,4,5,5,5, +5,5,5,0x1b,0x1b,0x1b,5,8,6,8,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,6,5,6,6, +6,5,5,6,6,5,5,5,5,5,6,6,5,6,5,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,4,4,4,1,2,5,4,4,2,5,5,5,5,5, -0x1a,0x1a,1,2,1,2,1,2,1,2,1,2,1,2,1,2, -2,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, -1,2,1,2,4,2,2,2,2,2,2,2,2,1,2,1, -2,1,1,2,1,2,1,2,1,2,1,2,4,0x1a,0x1a,1, -2,1,2,5,1,2,1,2,2,2,1,2,1,2,1,2, -1,2,1,2,1,2,1,1,1,1,1,2,1,1,1,1, -1,2,1,2,1,2,1,2,1,2,1,2,1,1,1,1, -2,1,2,0,0,0,0,0,1,2,0,2,0,2,1,2, -1,2,0,0,0,0,0,0,5,5,6,5,5,5,6,5, -5,5,5,6,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,8,8,6,6,8, -0x1b,0x1b,0x1b,0x1b,6,0,0,0,0x34cb,0x344b,0x3ccb,0x37cb,0x35cb,0x3fcb,0x1b,0x1b, -0x19,0x1b,0,0,0,0,0,0,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,0x17,0x17,0x17,0x17, -0,0,0,0,0,0,0,0,8,8,8,8,6,6,0,0, -0,0,0,0,0,0,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209, -0x249,0x289,0,0,0,0,0,0,8,8,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,8,8,8,8,8,8,8,8, -8,8,8,8,6,6,6,6,6,6,6,6,6,6,6,6, -6,6,6,6,6,6,5,5,5,5,5,5,0x17,0x17,0x17,5, -0x17,5,5,6,5,5,5,5,5,5,6,6,6,6,6,6, -6,6,0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6, -6,6,8,8,0,0,0,0,0,0,0,0,0,0,0,0x17, -8,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,4, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0x17,0x17, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,6,8,8,6,6,6,6,8,8,6,6,8,8, -5,5,5,5,5,6,4,5,5,5,5,5,5,5,5,5, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,5,5,5,0, -5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,8, -8,6,6,8,8,6,6,0,0,0,0,0,0,0,0,0, -5,5,5,6,5,5,5,5,5,5,5,5,6,8,0,0, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0x17,0x17,0x17,0x17, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -4,5,5,5,5,5,5,0x1b,0x1b,0x1b,5,8,6,8,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -6,5,6,6,6,5,5,6,6,5,5,5,5,5,6,6, -5,6,5,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,5,4,0x17,0x17, -5,5,5,5,5,5,5,5,5,5,5,8,6,6,8,8, -0x17,0x17,5,4,4,8,6,0,0,0,0,0,0,0,0,0, -0,5,5,5,5,5,5,0,0,5,5,5,5,5,5,0, -0,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0, -5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,0, +0,0,0,0,0,0,0,5,5,4,0x17,0x17,5,5,5,5, +5,5,5,5,5,5,5,8,6,6,8,8,0x17,0x17,5,4, +4,8,6,0,0,0,0,0,0,0,0,0,0,5,5,5, +5,5,5,0,0,5,5,5,5,5,5,0,0,5,5,5, +5,5,5,0,0,0,0,0,0,0,0,0,5,5,5,5, +5,5,5,0,5,5,5,5,5,5,5,0,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,2,2,2,2,2,2,2,0x1a,4,4,4,4, -2,2,2,2,2,2,2,2,2,4,0x1a,0x1a,0,0,0,0, -2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -5,5,5,8,8,6,8,8,6,8,8,0x17,8,6,0,0, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0, -5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0, -5,5,5,5,5,5,5,0,0,0,0,5,5,5,5,5, +2,2,2,2,2,2,2,0x1a,4,4,4,4,2,2,2,2, +2,2,2,2,2,4,0x1a,0x1a,0,0,0,0,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,8, +8,6,8,8,6,8,8,0x17,8,6,0,0,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,5,5,5,5, +0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,0,0,0,0,5,5,5,5, +5,5,5,0,0,0,0,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,0x12,0x12,0x12,0x12, 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, -0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, +0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x11,0x11,0x11, 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, -0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, -5,5,5,5,5,5,5,5,5,5,5,0x605,5,5,5,5, -5,5,5,0x7c5,5,5,5,5,0x5c5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,0x6c5,5,0x6c5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,0x7c5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,0x18,5,5,5,5,5,5,5,5,5,5,5,5,5,0, -5,5,5,5,5,0,5,0,5,5,0,5,5,0,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,2,2,2,2,2,2,2,0, -0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2, -0,0,0,0,0,5,6,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, -0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,0x15,0x14,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,0,0,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0, -0,0,0,0x1b,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, -0x19,0x1b,0x1b,0x1b,6,6,6,6,6,6,6,6,6,6,6,6, -6,6,6,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x14,0x15,0x17,0,0, -0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,6, -6,6,6,6,0x17,0x13,0x13,0x16,0x16,0x14,0x15,0x14,0x15,0x14,0x15,0x14, -0x15,0x14,0x15,0x14,0x15,0x17,0x17,0x14,0x15,0x17,0x17,0x17,0x17,0x16,0x16,0x16, -0x17,0x17,0x17,0,0x17,0x17,0x17,0x17,0x13,0x14,0x15,0x14,0x15,0x14,0x15,0x17, -0x17,0x17,0x18,0x13,0x18,0x18,0x18,0,0x17,0x19,0x17,0x17,0,0,0,0, -5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5, +0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,5,5,5,5, +5,5,5,5,5,5,5,0x605,5,5,5,5,5,5,5,0x7c5, +5,5,5,5,0x5c5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,0x6c5,5,0x6c5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,0x7c5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,0x18,5,5, +5,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5, +5,0,5,0,5,5,0,5,5,0,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,2,2,2,2,2,2,2,0,0,0,0,0, +0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0, +0,5,6,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, +0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,0x15,0x14,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0x1b, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +5,5,5,5,5,5,5,5,5,5,5,5,0x19,0x1b,0x1b,0x1b, +6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, +0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x14,0x15,0x17,0,0,0,0,0,0, +6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, +0x17,0x13,0x13,0x16,0x16,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14, +0x15,0x17,0x17,0x14,0x15,0x17,0x17,0x17,0x17,0x16,0x16,0x16,0x17,0x17,0x17,0, +0x17,0x17,0x17,0x17,0x13,0x14,0x15,0x14,0x15,0x14,0x15,0x17,0x17,0x17,0x18,0x13, +0x18,0x18,0x18,0,0x17,0x19,0x17,0x17,0,0,0,0,5,5,5,5, +5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,0,0,0x10,0,0,5,5,5,5,5,5, -0,0,5,5,5,5,5,5,0,0,5,5,5,5,5,5, -0,0,5,5,5,0,0,0,0x19,0x19,0x18,0x1a,0x1b,0x19,0x19,0, -0x1b,0x18,0x18,0x18,0x18,0x1b,0x1b,0,0,0,0,0,0,0,0,0, -0,0x10,0x10,0x10,0x1b,0x1b,0,0,0,0x17,0x17,0x17,0x19,0x17,0x17,0x17, -0x14,0x15,0x17,0x18,0x17,0x13,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209, -0x249,0x289,0x17,0x17,0x18,0x18,0x18,0x17,0x1a,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,0x14,0x18,0x15,0x18,0x14,0x15,0x17,0x14,0x15,0x17,0x17,5,5, -5,5,5,5,5,5,5,5,4,5,5,5,5,5,5,5, +5,0,0,0x10,0,0,5,5,5,5,5,5,0,0,5,5, +5,5,5,5,0,0,5,5,5,5,5,5,0,0,5,5, +5,0,0,0,0x19,0x19,0x18,0x1a,0x1b,0x19,0x19,0,0x1b,0x18,0x18,0x18, +0x18,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0x10,0x10,0x10, +0x1b,0x1b,0,0,0,0x17,0x17,0x17,0x19,0x17,0x17,0x17,0x14,0x15,0x17,0x18, +0x17,0x13,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17, +0x18,0x18,0x18,0x17,0x1a,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,0x14, +0x18,0x15,0x18,0x14,0x15,0x17,0x14,0x15,0x17,0x17,5,5,5,5,5,5, +5,5,5,5,4,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,4,4,5,5,5,5, -5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5, +5,5,5,5,5,5,4,4,5,5,5,5,5,5,5,5, +5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,0,5,5,0,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,0,0,0,0,0,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0x984b,0xa04b, -0xa84b,0xb04b,0xb84b,0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0,0,0,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x17,0x17,0x17,0,0,0,0,0x58b, -0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b, -0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0xcca,0x11ca,0x11ca, -0x11ca,0x11ca,0x1e4a,0x880a,0x980a,0x980a,0x980a,0x980a,0x980a,0x784a,0x984a,0x68a,0x11ca,0x344b,0x344b,0x388b, -0x3ccb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x54b,0x34cb, -0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0,0,0,0x34ca,0x344a,0x58a,0x68a,0x11ca,0x980a,0x984a,0x988a,0x68a,0x7ca,0x11ca,0x1e4a, -0x980a,0x784a,0x984a,0x68a,0x7ca,0x11ca,0x1e4a,0x980a,0x784a,0x788a,0x988a,0x7ca,0x58a,0x58a,0x58a,0x5ca, -0x5ca,0x5ca,0x5ca,0x68a,0x1b,0,0,0,0,0,0,0,0,0,0,0, +5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,0,0,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,0,0,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, +0,0,0,0,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0x984b,0xa04b,0xa84b,0xb04b,0xb84b,0x788b, +0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x17,0x17,0x17,0,0,0,0,0x58b,0x5cb,0x60b,0x64b,0x68b, +0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b, +0x900b,0x980b,0xa00b,0xa80b,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0xcca,0x11ca,0x11ca,0x11ca,0x11ca,0x1e4a,0x880a, +0x980a,0x980a,0x980a,0x980a,0x980a,0x784a,0x984a,0x68a,0x11ca,0x344b,0x344b,0x388b,0x3ccb,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x54b,0x34cb,0x1b,0x1b,0x1b,0, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0, +0x34ca,0x344a,0x58a,0x68a,0x11ca,0x980a,0x984a,0x988a,0x68a,0x7ca,0x11ca,0x1e4a,0x980a,0x784a,0x984a,0x68a, +0x7ca,0x11ca,0x1e4a,0x980a,0x784a,0x788a,0x988a,0x7ca,0x58a,0x58a,0x58a,0x5ca,0x5ca,0x5ca,0x5ca,0x68a, +0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,6,0,0,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,6,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b, -0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b, -0,0,0,0,0x58b,0x68b,0x7cb,0x11cb,0,0,0,0,0,0,0,0, -0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,0x1bca,5,5,5,5,5,5,5,5,0xb80a,0, -0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,0, -0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0,0, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,0,0x17,5,5,5,5,0,0,0,0,5,5,5,5, -5,5,5,5,0x17,0x58a,0x5ca,0x7ca,0xa4a,0x1e4a,0,0,0,0,0,0, -0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5, +5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +6,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b, +0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0,0,0,0, +0x58b,0x68b,0x7cb,0x11cb,0,0,0,0,0,0,0,0,0,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0, -0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0,0,0,0,2,2,2,2, -2,2,2,2,5,5,5,5,5,5,5,5,0,0,0,0, -0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0x17, -1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1, -2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,0,2,2,2,2,2,2,2,0,2,2,0,0,0, -1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1, -1,1,1,0,1,1,0,2,2,2,2,2,2,2,2,2, -5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, -4,0,4,4,4,4,4,4,4,4,4,0,0,0,0,0, -4,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4, -4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +5,0x1bca,5,5,5,5,5,5,5,5,0xb80a,0,0,0,0,0, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,0,5,5,0,0,0,5,0,0,5, -5,5,5,5,5,5,0,0,5,0,5,5,5,5,5,5, +5,5,5,5,5,5,6,6,6,6,6,0,0,0,0,0, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,0,0x17,0x58b,0x5cb,0x60b,0x7cb,0xa4b,0x1e4b,0x784b,0x788b,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0x17, +5,5,5,5,0,0,0,0,5,5,5,5,5,5,5,5, +0x17,0x58a,0x5ca,0x7ca,0xa4a,0x1e4a,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,0x1b,0x1b,0x58b,0x5cb,0x60b,0x64b,0x68b,0x7cb,0xa4b,0,0,0,0, -0,0,0,0x58b,0x5cb,0x60b,0x64b,0x64b,0x68b,0x7cb,0xa4b,0x1e4b,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, -5,5,0,0,0,0,0,0x58b,0x68b,0x7cb,0xa4b,0x1e4b,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0, +0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,0,0,0,0,2,2,2,2,2,2,2,2, +5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,0x58b,0x7cb,0xa4b,0x1e4b,0x5cb,0x60b,0,0,0,0x17,5,5,5,5, +0,0,0,0,0,0,0,0,0,0,0,0x17,1,1,1,1, +1,1,1,1,1,1,1,0,1,1,1,1,2,2,0,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2, +2,2,2,2,2,2,0,2,2,0,0,0,1,1,1,1, +1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0, +1,1,0,2,2,2,2,2,2,2,2,2,5,5,5,5, +5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4, +4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,4, +4,4,4,4,4,4,4,0,0,0,0,0,4,4,4,4, +4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4, +4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,0,5,5,0,0,0,5,0,0,5,5,5,5,5, +5,5,0,0,5,0,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0x17, +0x58b,0x5cb,0x60b,0x7cb,0xa4b,0x1e4b,0x784b,0x788b,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x1b, +0x1b,0x58b,0x5cb,0x60b,0x64b,0x68b,0x7cb,0xa4b,0,0,0,0,0,0,0,0x58b, +0x5cb,0x60b,0x64b,0x64b,0x68b,0x7cb,0xa4b,0x1e4b,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,0,5,5,0,0, +0,0,0,0x58b,0x68b,0x7cb,0xa4b,0x1e4b,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x58b,0x7cb, +0xa4b,0x1e4b,0x5cb,0x60b,0,0,0,0x17,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,0,0,0,0,0,0x17,0xa04b,0xa84b,0xb04b,0xb84b,0x788b,0x808b,0x888b,0x908b, +0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0x78cb,0x80cb,0x88cb,0x90cb,0x98cb,0xa0cb,0xa8cb,0xb0cb,0xb8cb,0x36cb,0x354b, +0x34cb,0x348b,0x46cb,0x344b,0x4ecb,0x388b,0x3ccb,0x454b,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +0,0,0,0,0x5ecb,0x344b,5,5,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b, +0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0,0,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b, +0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0x984b,0x30b,0x34b,0x38b,0x3cb,0x7cb,0xa4b,0x1e4b,0x784b, +0x344b,0,0,0,0,0,0,0,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, +0x17,0,0,0,0,0,0,0,5,6,6,6,0,6,6,0, +0,0,0,0,6,6,6,6,5,5,5,5,0,5,5,5, +0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,0,0,6,6,6,0, +0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,0,0,0,0,0,0x17,0xa04b,0xa84b,0xb04b,0xb84b, -0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0x78cb,0x80cb,0x88cb,0x90cb,0x98cb,0xa0cb,0xa8cb, -0xb0cb,0xb8cb,0x36cb,0x354b,0x34cb,0x348b,0x46cb,0x344b,0x4ecb,0x388b,0x3ccb,0x454b,5,5,5,5, +5,0x58b,0x11cb,0x17,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,0,0,0,0,0x5ecb,0x344b,5,5,0x58b,0x5cb,0x60b,0x64b, -0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0,0,0x1e4b,0x800b, -0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0x984b,0x30b,0x34b,0x38b,0x3cb, -0x7cb,0xa4b,0x1e4b,0x784b,0x344b,0,0,0,0,0,0,0,0x17,0x17,0x17,0x17, -0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,5,6,6,6, -0,6,6,0,0,0,0,0,6,6,6,6,5,5,5,5, -0,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0, -6,6,6,0,0,0,0,6,5,5,5,5,5,5,5,5, +5,0x58b,0x7cb,0xa4b,5,5,5,5,5,6,6,0,0,0,0,0x58b, +0x68b,0x7cb,0xa4b,0x1e4b,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0, +0,0,0,0,5,5,5,5,5,5,5,5,0x1b,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,0x58b,0x11cb,0x17,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,0,0,0,0x17,0x17,0x17,0x17,0x17,0x17,0x17, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,0x58b,0x7cb,0xa4b,5,5,5,5,5,6,6,0, -0,0,0,0x58b,0x68b,0x7cb,0xa4b,0x1e4b,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0, -0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, -0x1b,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,0,0,0,0x17,0x17,0x17, -0x17,0x17,0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,0,0,0x58b,0x5cb,0x60b,0x64b, -0x7cb,0xa4b,0x1e4b,0x784b,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,0,0,0,0,0,0x58b,0x5cb,0x60b,0x64b, -0x7cb,0xa4b,0x1e4b,0x784b,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,0,0,0,0,0,0,0,0x17,0x17,0x17, -0x17,0,0,0,0,0,0,0,0,0,0,0,0,0x58b,0x5cb,0x60b, -0x64b,0x7cb,0xa4b,0x1e4b,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,5,5,5,5,5,5,5,5,5,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0, -0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,2,2,2,0,0,0,0,0,0,0,0x58b,0x68b, -0x7cb,0x11cb,0x1e4b,0x784b,5,5,5,5,6,6,6,6,0,0,0,0, -0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0, -0,0,0,0,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0xa4b,0xccb, -0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x344b, -0x34cb,0x348b,0x388b,0,5,5,5,5,5,5,5,5,5,5,0,6, -6,0x13,0,0,5,5,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,6,6,6,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,0,0,0x58b,0x5cb,0x60b,0x64b,0x7cb,0xa4b,0x1e4b,0x784b, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,0x58b,0x5cb,0x60b,0x64b,0x68b,0x7cb,0xa4b,0xccb,0x1e4b,0x344b,5, -0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6, -6,6,6,6,6,0x58b,0x7cb,0xa4b,0x1e4b,0x17,0x17,0x17,0x17,0x17,0,0, -0,0,0,0,5,5,6,6,6,6,0x17,0x17,0x17,0x17,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,5,5,5,5,5,0x58b,0x5cb,0x60b,0x64b,0x7cb,0xa4b,0x1e4b, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x784b,0x49,0x89,0xc9,0x109,0x149,0x189, -0x1c9,0x209,0x249,0x289,6,5,5,6,6,5,0,0,0,0,0,0, -0,0,0,6,8,6,8,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,6,6,6,6,6,6,6,0x17,0x17,0x17,0x17,0x17, -0x17,0x17,0,0,0,0,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb, -0xa4b,0xccb,0xf4b,0x11cb,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,8,8,8,6,6,6,6,8,8,6,6,0x17, -0x17,0x10,0x17,0x17,0x17,0x17,6,0,0,0,0,0,0,0,0,0, -0,0x10,0,0,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109, -0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,5,5,5,5, -5,5,5,6,6,6,6,6,8,6,6,6,6,6,6,6, -6,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0x17,0x17, -5,8,8,5,0,0,0,0,0,0,0,0,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,5, +5,5,5,0,0,0,0,0,0x58b,0x5cb,0x60b,0x64b,0x7cb,0xa4b,0x1e4b,0x784b, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6, -0x17,0x17,5,0,0,0,0,0,0,0,0,0,8,5,5,5, -5,0x17,0x17,0x17,0x17,6,6,6,6,0x17,8,6,0x49,0x89,0xc9,0x109, -0x149,0x189,0x1c9,0x209,0x249,0x289,5,0x17,5,0x17,0x17,0x17,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,8, -8,8,6,6,6,6,6,6,6,6,6,8,0,0x58b,0x5cb,0x60b, -0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b, -0x784b,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5, -5,5,5,5,5,5,5,5,8,8,8,6,6,6,8,8, -6,8,6,6,0x17,0x17,0x17,0x17,0x17,0x17,6,5,5,6,0,0, +5,5,0,0,0,0,0,0,0,0x17,0x17,0x17,0x17,0,0,0, +0,0,0,0,0,0,0,0,0,0x58b,0x5cb,0x60b,0x64b,0x7cb,0xa4b,0x1e4b, 0,0,0,0,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,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, -5,0,5,5,5,5,0,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5, -5,0x17,0,0,0,0,0,0,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,8,8,8,6,6,6,6,6, -6,6,6,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209, -0x249,0x289,0,0,0,0,0,0,5,5,8,8,0,0,6,6, -6,6,6,6,6,0,0,0,6,6,6,6,6,0,0,0, -0,0,0,0,0,0,0,0,6,6,8,8,0,5,5,5, -5,5,5,5,5,0,0,5,5,0,0,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5, -5,0,5,5,0,5,5,5,5,5,0,6,6,5,8,8, -6,8,8,8,8,0,0,8,8,0,0,8,8,8,0,0, -5,0,0,0,0,0,0,8,0,0,0,0,0,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,8,8,8,6,6,6,6,6,6,6,6, -8,8,6,6,6,8,6,5,5,5,5,0x17,0x17,0x17,0x17,0x17, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0,0x17,6,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -8,8,8,6,6,6,6,6,6,8,6,8,8,8,8,6, -6,8,6,6,5,5,0x17,5,0,0,0,0,0,0,0,0, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,8, -8,8,6,6,6,6,0,0,8,8,8,8,6,6,8,6, -6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, -0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,5,5,5,5,6,6,0,0, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -8,8,8,6,6,6,6,6,6,6,6,8,8,6,8,6, -6,0x17,0x17,0x17,5,0,0,0,0,0,0,0,0,0,0,0, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0, -0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0, +5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,0,0,0,0,0,0,0,0x58b,0x68b,0x7cb,0x11cb,0x1e4b,0x784b, +5,5,5,5,6,6,6,6,0,0,0,0,0,0,0,0, 0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0, +0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb, +0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x344b,0x34cb,0x348b,0x388b,0, +5,5,5,5,5,5,5,5,5,5,0,6,6,0x13,0,0, +5,5,0,0,0,0,0,0,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,5,5,5,5,5,5,5,5,5,5,6,8,6,8,8, -6,6,6,6,6,6,8,6,5,0x17,0,0,0,0,0,0, -8,8,6,6,6,6,8,6,6,6,6,6,0,0,0,0, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x7cb,0xa4b,0x17,0x17,0x17,0x1b, -5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0, +0,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,0x58b,0x5cb,0x60b,0x64b,0x68b,0x7cb,0xa4b,0xccb,0x1e4b,0x344b,5,0,0,0,0, +0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6, +6,0x58b,0x7cb,0xa4b,0x1e4b,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0, +5,5,6,6,6,6,0x17,0x17,0x17,0x17,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -5,5,5,5,5,5,5,5,5,5,5,5,8,8,8,6, -6,6,6,6,6,6,6,6,8,6,6,0x17,0,0,0,0, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b, -0x16cb,0x194b,0x1bcb,0,0,0,0,0,0,0,0,0,0,0,0,5, -8,5,8,6,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0, -5,5,5,5,5,5,5,0,0,5,0,0,5,5,5,5, -5,5,5,5,0,5,5,0,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,8,8,8,8,8,8,0,8, -8,0,0,6,6,8,6,5,6,5,0x17,5,8,0,0,0, +5,5,5,5,5,0x58b,0x5cb,0x60b,0x64b,0x7cb,0xa4b,0x1e4b,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x784b,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289, +6,5,5,6,6,5,0,0,0,0,0,0,0,0,0,6, +8,6,8,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +6,6,6,6,6,6,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0, +0,0,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +8,8,8,6,6,6,6,8,8,6,6,0x17,0x17,0x10,0x17,0x17, +0x17,0x17,6,0,0,0,0,0,0,0,0,0,0,0x10,0,0, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209, +0x249,0x289,0,0,0,0,0,0,5,5,5,5,5,5,5,6, +6,6,6,6,8,6,6,6,6,6,6,6,6,0,0x49,0x89, +0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0x17,0x17,5,8,8,5, 0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, -0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,8,8,8,6,6,6,6, -0,0,6,6,8,8,8,8,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6, -6,8,5,6,6,6,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,6, -0,0,0,0,0,0,0,0,5,6,6,6,6,6,6,8, -8,6,6,6,5,5,5,5,5,6,6,6,6,6,6,6, -6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,0x17,0x17,0x17,0,0,0,0,0, +5,5,5,5,5,5,5,5,6,6,6,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,6,0x17,0x17,5,0, +0,0,0,0,0,0,0,0,8,5,5,5,5,0x17,0x17,0x17, +0x17,6,6,6,6,0x17,8,6,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209, +0x249,0x289,5,0x17,5,0x17,0x17,0x17,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,8,8,8,6,6, +6,6,6,6,6,6,6,8,0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b, +0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x784b,0,0,0, 0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6, -6,6,6,6,6,6,6,8,6,6,0x17,0x17,0x17,5,0x17,0x17, -5,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0,0, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb, -0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0, +5,5,5,5,8,8,8,6,6,6,8,8,6,8,6,6, +0x17,0x17,0x17,0x17,0x17,0x17,6,5,5,6,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0,0,0, -0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,8,6,6,6,6, -6,6,6,0,6,6,6,6,6,6,8,6,6,6,6,6, -6,6,6,6,0,8,6,6,6,6,6,6,6,8,6,6, -8,6,6,0,0,0,0,0,0,0,0,0,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,0,0,6,6, -6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,6, -0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209, -0x249,0x289,0,0,0,0,0,0,5,5,5,5,5,5,5,0, +0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,0,5,0,5,5, 5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,0, -0,0,6,0,6,6,0,6,5,5,5,5,5,5,5,5, -5,5,8,8,8,8,8,0,6,6,0,8,8,6,8,6, -5,0,0,0,0,0,0,0,5,5,5,5,5,5,0,5, -5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,6,6,8,8,0x17, -0x17,0,0,0,0,0,0,0,6,8,6,0x17,0x17,0x17,0x17,0x17, -0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209, -0x249,0x289,0,0,0,0,0,0,6,6,5,8,5,5,5,5, -5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -8,8,6,6,6,6,6,0,0,0,8,8,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0x19,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0, -0,0,0,0,0,0,0,0,0,0,0,0x17,0xcd0b,0xcc0b,0xcb0b,0xd00b, -0xca0b,0xcf0b,0xcb4b,0xd04b,0xc90b,0x37cb,0x37cb,0x364b,0x35cb,0xc94b,0x3fcb,0x350b,0x34cb,0x344b,0x344b,0x3ccb, -0xcd0b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x19,0x19,0x34ca,0x354a,0x34ca,0x34ca, -0x344a,0x348a,0x388a,0xf4a,0x11ca,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0,0x17,0x17,0x17,0x17, -0x17,0,0,0,0,0,0,0,0,0,0,0,0x5ca,0x60a,0x64a,0x68a, -0x6ca,0x70a,0x74a,0x78a,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x64a,0x68a,0x6ca,0x70a,0x74a, -0x78a,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x58a,0x5ca,0x60a,0x64a,0x68a,0x5ca, -0x60a,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x58a,0x5ca,0x60a,0x60a,0x64a,0x68a,0xc08a,0xc18a, -0x58a,0x5ca,0x60a,0x60a,0x64a,0x68a,0x60a,0x60a,0x64a,0x64a,0x64a,0x64a,0x6ca,0x70a,0x70a,0x70a, -0x74a,0x74a,0x78a,0x78a,0x78a,0x78a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x58a,0x5ca,0x60a,0x64a,0x64a, -0x68a,0x68a,0x5ca,0x60a,0x58a,0x5ca,0x348a,0x388a,0x454a,0x348a,0x388a,0x35ca,5,5,5,5, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +5,5,0,5,5,5,5,5,5,5,5,5,5,0x17,0,0, +0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,8,8,8,6,6,6,6,6,6,6,6,0, +0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0, +0,0,0,0,5,5,8,8,0,0,6,6,6,6,6,6, +6,0,0,0,6,6,6,6,6,0,0,0,0,0,0,0, +0,0,0,0,6,6,8,8,0,5,5,5,5,5,5,5, +5,0,0,5,5,0,0,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,0,5,5,5,5,5,5,5,0,5,5, +0,5,5,5,5,5,0,6,6,5,8,8,6,8,8,8, +8,0,0,8,8,0,0,8,8,8,0,0,5,0,0,0, +0,0,0,8,0,0,0,0,0,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,8,8,8,6,6,6,6,6,6,6,6,8,8,6,6, +6,8,6,5,5,5,5,0x17,0x17,0x17,0x17,0x17,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0,0x17,6,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,8,8,8,6, +6,6,6,6,6,8,6,8,8,8,8,6,6,8,6,6, +5,5,0x17,5,0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,8,8,8,6,6, +6,6,0,0,8,8,8,8,6,6,8,6,6,0x17,0x17,0x17, +0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, +0x17,0x17,0x17,0x17,5,5,5,5,6,6,0,0,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,8,8,8,6, +6,6,6,6,6,6,6,8,8,6,8,6,6,0x17,0x17,0x17, +5,0,0,0,0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,0x17,0x17,0x17,0x17, +0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,0x17,0x17,0, +5,5,5,5,5,5,5,6,8,6,8,8,6,6,6,6, +6,6,8,6,5,0x17,0,0,0,0,0,0,8,8,6,6, +6,6,8,6,6,6,6,6,0,0,0,0,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0x7cb,0xa4b,0x17,0x17,0x17,0x1b,5,5,5,5, +5,5,5,0,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,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,0x10,0x10,0x10,0x10, -0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,6,5,5,5, -5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6, -6,6,0,0,0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109, +5,5,5,5,5,5,5,5,8,8,8,6,6,6,6,6, +6,6,6,6,8,6,6,0x17,0,0,0,0,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0, +0,0,0,0,0,0,0,0,0,0,0,5,8,5,8,6, +0x17,0x17,0x17,0,0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109, 0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0, -6,6,6,6,6,0x17,0,0,0,0,0,0,0,0,0,0, +5,5,5,0,0,5,0,0,5,5,5,5,5,5,5,5, +0,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,8,8,8,8,8,8,0,8,8,0,0,6, +6,8,6,5,6,5,0x17,5,8,0,0,0,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,5,5,5,5,5,5,5,0,0,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,8,8,8,6,6,6,6,0,0,6,6, +8,8,8,8,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,6,6,6,6,6,6,8,5,6, +6,6,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,6,0,0,0,0, +0,0,0,0,5,6,6,6,6,6,6,8,8,6,6,6, +5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0, +0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6, +6,6,6,8,6,6,0x17,0x17,0x17,5,0x17,0x17,5,0x17,0x17,0x17, +0x17,0x17,0,0,0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x17,0x17,0x17,0x17, +0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0x70b,0x74b,0x78b,0x7cb, +0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0,0,0,0x17,0x17,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,8,6,6,6,6,6,6,6,0, +6,6,6,6,6,6,8,6,6,6,6,6,6,6,6,6, +0,8,6,6,6,6,6,6,6,8,6,6,8,6,6,0, +0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,0,0,6,6,6,6,6,6, +6,6,6,6,6,6,6,6,6,6,5,6,0,0,0,0, +0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0, +0,0,0,0,5,5,5,5,5,5,5,0,5,5,0,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,6,6,6,6,6,6,0,0,0,6,0, +6,6,0,6,5,5,5,5,5,5,5,5,5,5,8,8, +8,8,8,0,6,6,0,8,8,6,8,6,5,0,0,0, +0,0,0,0,5,5,5,5,5,5,0,5,5,0,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,6,6,8,8,0x17,0x17,0,0,0, +0,0,0,0,6,8,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, +0x17,0x17,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0, +0,0,0,0,6,6,5,8,5,5,5,5,5,5,5,5, +5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,8,8,6,6, +6,6,6,0,0,0,8,8,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x19,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0, +0,0,0,0,0,0,0,0x17,0xcd0b,0xcc0b,0xcb0b,0xd00b,0xca0b,0xcf0b,0xcb4b,0xd04b, +0xc90b,0x37cb,0x37cb,0x364b,0x35cb,0xc94b,0x3fcb,0x350b,0x34cb,0x344b,0x344b,0x3ccb,0xcd0b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x19,0x19,0x34ca,0x354a,0x34ca,0x34ca,0x344a,0x348a,0x388a,0xf4a, +0x11ca,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0,0x17,0x17,0x17,0x17,0x17,0,0,0, +0,0,0,0,0,0,0,0,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a, +0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x58a,0x5ca,0x60a, +0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x58a,0x5ca,0x60a,0x64a,0x68a,0x5ca,0x60a,0x60a,0x64a,0x68a, +0x6ca,0x70a,0x74a,0x78a,0x58a,0x5ca,0x60a,0x60a,0x64a,0x68a,0xc08a,0xc18a,0x58a,0x5ca,0x60a,0x60a, +0x64a,0x68a,0x60a,0x60a,0x64a,0x64a,0x64a,0x64a,0x6ca,0x70a,0x70a,0x70a,0x74a,0x74a,0x78a,0x78a, +0x78a,0x78a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x58a,0x5ca,0x60a,0x64a,0x64a,0x68a,0x68a,0x5ca,0x60a, +0x58a,0x5ca,0x348a,0x388a,0x454a,0x348a,0x388a,0x35ca,5,5,5,5,0,0,0,0, 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,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,0x17,0x17,0,0,0,0,0, +0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,6,5,5,5,5,5,5,6, +6,6,6,6,6,6,6,6,6,6,6,6,6,6,0,0, +0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209, +0x249,0x289,0,0,0,0,0,0,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,0,0,6,6,6,6, +6,0x17,0,0,0,0,0,0,0,0,0,0,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6, +6,6,6,0x17,0x17,0x17,0x17,0x17,0x1b,0x1b,0x1b,0x1b,4,4,4,4, +0x17,0x1b,0,0,0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0,0x7cb,0x1e4b,0x788b,0x790b,0x798b,0x7a0b,0x7a8b,0,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -6,6,6,6,6,6,6,0x17,0x17,0x17,0x17,0x17,0x1b,0x1b,0x1b,0x1b, -4,4,4,4,0x17,0x1b,0,0,0,0,0,0,0,0,0,0, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0x7cb,0x1e4b,0x788b,0x790b,0x798b, -0x7a0b,0x7a8b,0,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,0,0,0,0,0,5,5,5, -0x54b,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0x80b,0x84b,0x88b,0x8cb,0x90b, -0x94b,0x98b,0x9cb,0xa0b,0x58b,0x5cb,0x60b,0x17,0x17,0x17,0x17,0,0,0,0,0, -5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,6, -5,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +5,5,5,5,0,0,0,0,0,5,5,5,0x54b,0x58b,0x5cb,0x60b, +0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0x80b,0x84b,0x88b,0x8cb,0x90b,0x94b,0x98b,0x9cb,0xa0b, +0x58b,0x5cb,0x60b,0x17,0x17,0x17,0x17,0,0,0,0,0,5,5,5,5, +5,5,5,5,5,5,5,0,0,0,0,6,5,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, -8,8,8,8,0,0,0,0,0,0,0,6,6,6,6,4, -4,4,4,4,4,4,4,4,4,4,4,4,4,4,0x17,4, -6,0,0,0,0,0,0,0,0,0,0,0,8,8,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5, +8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +0,0,0,0,0,0,0,6,6,6,6,4,4,4,4,4, +4,4,4,4,4,4,4,4,4,4,0x17,4,6,0,0,0, +0,0,0,0,0,0,0,0,8,8,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,4,4,4,4,0,4,4,4,4,4,4,4, -0,4,4,0,5,5,5,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,5,5,5,0,0,5,0,0, -0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0, -0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,0,0,0,0,0,5,5,5,5, -5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0, -5,5,5,5,5,5,5,5,5,5,0,0,0x1b,6,6,0x17, -0x10,0x10,0x10,0x10,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0, +4,4,4,4,0,4,4,4,4,4,4,4,0,4,4,0, +5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,5,5,5,0,0,5,0,0,0,0,0,0, +0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,0,0,0,0,0,5,5,5,5,5,5,5,5, +5,5,5,5,5,0,0,0,0,0,0,0,5,5,5,5, +5,5,5,5,5,5,0,0,0x1b,6,6,0x17,0x10,0x10,0x10,0x10, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -6,6,6,6,6,6,6,6,6,6,6,6,6,6,0,0, -6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, -6,6,6,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0, -0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,8,8,6,6,6,0x1b,0x1b, -0x1b,8,8,8,8,8,8,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,6, -6,6,6,6,6,6,6,0x1b,0x1b,6,6,6,6,6,6,6, +0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6, +6,6,6,6,6,6,6,6,6,6,0,0,6,6,6,6, +6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0, +0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0x1b,0x1b,0x1b, 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,6, -6,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0x54b,0x58b,0x5cb,0x60b, -0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0x80b,0x84b,0x88b,0x8cb,0x90b,0x94b,0x98b,0x9cb,0xa0b, -0,0,0,0,0,0,0,0,0,0,0,0,0x58b,0x5cb,0x60b,0x64b, -0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x58b,0x5cb, -0x60b,0x64b,0x68b,0x58b,0x68b,0,0,0,0,0,0,0,0x249,0x289,0x49,0x89, -0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209, -0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,1,1,1,1, +0x1b,0x1b,0x1b,0x1b,0x1b,8,8,6,6,6,0x1b,0x1b,0x1b,8,8,8, +8,8,8,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,6,6,6,6,6, +6,6,6,0x1b,0x1b,6,6,6,6,6,6,6,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,6,6,0x1b,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x54b,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b, +0x74b,0x78b,0x7cb,0x80b,0x84b,0x88b,0x8cb,0x90b,0x94b,0x98b,0x9cb,0xa0b,0,0,0,0, +0,0,0,0,0,0,0,0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b, +0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x58b,0x5cb,0x60b,0x64b,0x68b,0x58b, +0x68b,0,0,0,0,0,0,0,0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189, +0x1c9,0x209,0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x49,0x89, +0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2, -2,0,2,2,2,2,2,2,2,2,2,2,1,1,1,1, +1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,2,2,2,2,2,2,2,0,2,2, +2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2, +1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,1,0,1,1, +0,0,1,0,0,1,1,0,0,1,1,1,1,0,1,1, +1,1,1,1,1,1,2,2,2,2,0,2,0,2,2,2, +2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +2,2,2,2,1,1,0,1,1,1,1,0,0,1,1,1, +1,1,1,1,1,0,1,1,1,1,1,1,1,0,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -1,0,1,1,0,0,1,0,0,1,1,0,0,1,1,1, -1,0,1,1,1,1,1,1,1,1,2,2,2,2,0,2, -0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2, -2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,2,2,2,2,1,1,0,1,1,1,1,0, -0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1, +2,2,2,2,2,2,2,2,1,1,0,1,1,1,1,0, +1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,1, 1,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,2,2,2,2,2,2,2,2,1,1,0,1, -1,1,1,0,1,1,1,1,1,0,1,0,0,0,1,1, -1,1,1,1,1,0,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,2,2,2,2,2,2,0,0,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,0x18,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,0x18, -2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x18, +2,2,2,2,2,2,0,0,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,0x18,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,0x18,2,2,2,2, +2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,0x18,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,0x18,2,2,2,2,2,2,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,0x18, -2,2,2,2,2,2,1,2,0,0,0x49,0x89,0xc9,0x109,0x149,0x189, -0x1c9,0x209,0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0,6,6,6, -6,6,6,6,6,6,6,6,6,6,6,6,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6, -6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, -6,6,6,0x1b,0x1b,0x1b,0x1b,6,6,6,6,6,6,6,6,6, -6,6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0x1b,0x1b,0x17,0x17,0x17,0x17,0x17, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6, -6,6,6,6,6,6,6,0,6,6,6,6,6,6,6,6, -6,6,6,6,6,6,6,6,6,0,0,6,6,6,6,6, -2,2,2,2,2,2,2,2,2,2,5,2,2,2,2,2, -2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, -0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -6,6,0,6,6,0,6,6,6,6,6,0,0,0,0,0, -4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,5,0x1b, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0, -6,6,6,6,6,6,6,4,4,4,4,4,4,4,0,0, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0x19, -5,5,5,5,5,5,5,5,5,5,5,4,6,6,6,6, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0, -5,5,5,5,5,5,5,0,5,5,5,5,0,5,5,0, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, -5,5,5,5,5,0,0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b, -6,6,6,6,6,6,6,0,0,0,0,0,0,0,0,0, -2,2,2,2,6,6,6,6,6,6,6,4,0,0,0,0, -0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0x17,0x17, -1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,0x18,2,2,2,2,2,2,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,2,2,2,0x18,2,2,2,2, +2,2,1,2,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289, +0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0,6,6,6,6,6,6,6, +6,6,6,6,6,6,6,6,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6, +6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0x1b, +0x1b,0x1b,0x1b,6,6,6,6,6,6,6,6,6,6,6,6,6, +6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,6,0x1b,0x1b,0x17,0x17,0x17,0x17,0x17,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6, +6,6,6,0,6,6,6,6,6,6,6,6,6,6,6,6, +6,6,6,6,6,0,0,6,6,6,6,6,2,2,2,2, +2,2,2,2,2,2,5,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0, +0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,6, +6,0,6,6,6,6,6,0,0,0,0,0,4,4,4,4, +4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4, +4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,5,0x1b,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5, +5,5,5,5,5,5,5,5,5,0,0,0,6,6,6,6, +6,6,6,4,4,4,4,4,4,4,0,0,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5, +5,5,5,5,5,5,5,5,6,6,6,6,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0x19,5,5,5,5, +5,5,5,5,5,5,5,4,6,6,6,6,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,5,5,5,5, +5,5,5,0,5,5,5,5,0,5,5,0,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5, +5,0,0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,6,6,6,6, +6,6,6,0,0,0,0,0,0,0,0,0,2,2,2,2, +6,6,6,6,6,6,6,4,0,0,0,0,0x49,0x89,0xc9,0x109, +0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0x17,0x17,1,1,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b, -0x78cb,0x794b,0x814b,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x1b,0x34cb,0x344b,0x3ccb, -0x19,0x58b,0x5cb,0x788b,0x78cb,0,0,0,0,0,0,0,0,0,0,0, -0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b, -0x984b,0xa04b,0xa84b,0xb04b,0xb84b,0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0x78cb,0x80cb, -0x984b,0xa04b,0xa84b,0xb04b,0xb84b,0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0x1b,0x5cb, -0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0x900b,0xa00b,0x804b,0x788b,0x344b,0x354b,0,0, -0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b, -0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0x18,0x18,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -0,5,5,0,5,0,0,5,0,5,5,5,5,5,5,5, -5,5,5,0,5,5,5,5,0,5,0,5,0,0,0,0, -0,0,5,0,0,0,0,5,0,5,0,5,0,5,5,5, -0,5,5,0,5,0,0,5,0,5,0,5,0,5,0,5, -0,5,5,0,5,0,0,5,5,5,5,0,5,5,5,5, -5,5,5,0,5,5,5,5,0,5,5,5,5,0,5,0, -5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0, -0,5,5,5,0,5,5,5,5,5,0,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0, +2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0x58b,0x5cb,0x60b, +0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x78cb,0x794b,0x814b,0x58b, +0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x1b,0x34cb,0x344b,0x3ccb,0x19,0x58b,0x5cb,0x788b, +0x78cb,0,0,0,0,0,0,0,0,0,0,0,0x16cb,0x194b,0x1bcb,0x1e4b, +0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0x984b,0xa04b,0xa84b,0xb04b, +0xb84b,0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0x78cb,0x80cb,0x984b,0xa04b,0xa84b,0xb04b, +0xb84b,0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0x1b,0x5cb,0x60b,0x64b,0x68b,0x6cb, +0x70b,0x74b,0x78b,0x7cb,0x900b,0xa00b,0x804b,0x788b,0x344b,0x354b,0,0,0,0x58b,0x5cb,0x60b, +0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b, +0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0x18,0x18,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5, +0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,0, +5,0,0,5,0,5,5,5,5,5,5,5,5,5,5,0, +5,5,5,5,0,5,0,5,0,0,0,0,0,0,5,0, +0,0,0,5,0,5,0,5,0,5,5,5,0,5,5,0, +5,0,0,5,0,5,0,5,0,5,0,5,0,5,5,0, +5,0,0,5,5,5,5,0,5,5,5,5,5,5,5,0, +5,5,5,5,0,5,5,5,5,0,5,0,5,5,5,5, +5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,0,0,0,0,0,5,5,5, +0,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,0,0,0,0,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x2cb,0x2cb,0x30b,0x34b, +0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x54b,0x54b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0, +0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0, +0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b, 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x2cb,0x2cb,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x54b,0x54b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0x1b,0x1b,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b, 0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b, 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x1a,0x1a,0x1a,0x1a, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x1a,0x1a,0x1a,0x1a,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0x1b,0x1b,0x1b,0x1b, 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0x1b,0,0,0, +0x1b,0x1b,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0,0,0,0,0x1b,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0x1b,0x1b,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0, -0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0, -0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0, -0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0, 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0, -0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x1b,0x1b,0x1b,5,0x705,5,5,5,5,5,5,5,5,5,5, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0, +0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, +5,0x705,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,0x645,5,5,5,5,5,5,5,5,5,5,5, +0x645,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x645,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,0x645,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,0x685,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,0x685,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0xcc5, +5,5,5,5,5,5,5,5,0xf45,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,0xf45,5,5,5,5,5,5,5, +5,5,5,5,5,5,0x6c5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,0x605,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,0xcc5,5,5,5,5,5,5,5,5,0xf45,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,0xf45,5,5,5, -5,5,5,5,5,5,5,5,5,5,0x6c5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,0x605,5,5, +5,5,5,5,5,0x605,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,0x605,5,5,5,5,5,5, +0x605,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x605, +5,5,5,5,5,5,5,5,5,5,5,5,5,0x645,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,0x605,5,5,5,5,5,5,5,5,5,5,5, +5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,0x605,5,5,5,5,5,5,5,5,5,5,5,5, -5,0x645,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,0,0,0,0,0,0,0,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,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,0x785,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +0x785,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, -0x10,0x10,0x10,0x10,0,0x10,0,0,0,0,0,0,0,0,0,0, +0,0x10,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,6, -6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, -0x11,0x11,0,0,0,0,0,0 +0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0,0, +0,0,0,0 }; static const UTrie2 propsTrie={ @@ -1458,155 +1467,155 @@ static const UTrie2 propsTrie={ propsTrie_index+4692, nullptr, 4692, - 18324, + 18464, 0xa40, 0x12d4, 0x0, 0x0, 0x110000, - 0x59e4, + 0x5a70, nullptr, 0, false, false, 0, nullptr }; -static const uint16_t propsVectorsTrie_index[32692]={ -0x539,0x541,0x549,0x551,0x569,0x571,0x579,0x581,0x589,0x591,0x599,0x5a1,0x5a9,0x5b1,0x5b9,0x5c1, -0x5c8,0x5d0,0x5d8,0x5e0,0x5e3,0x5eb,0x5f3,0x5fb,0x603,0x60b,0x613,0x61b,0x623,0x62b,0x633,0x63b, -0x643,0x64b,0x652,0x65a,0x662,0x66a,0x672,0x67a,0x682,0x68a,0x68f,0x697,0x69e,0x6a6,0x6ae,0x6b6, -0x6be,0x6c6,0x6ce,0x6d6,0x6dd,0x6e5,0x6ed,0x6f5,0x6fd,0x705,0x70d,0x715,0x71d,0x725,0x72d,0x735, -0x1b39,0xd8a,0xe56,0x118d,0x12cc,0x1d01,0x1ea0,0x1cf9,0x13e6,0x13f6,0x13de,0x13ee,0x80a,0x810,0x818,0x820, -0x828,0x82e,0x836,0x83e,0x846,0x84c,0x854,0x85c,0x864,0x86a,0x872,0x87a,0x882,0x88a,0x892,0x899, -0x8a1,0x8a7,0x8af,0x8b7,0x8bf,0x8c5,0x8cd,0x8d5,0x8dd,0x13fe,0x8e5,0x8ed,0x8f5,0x8fc,0x904,0x90c, -0x914,0x918,0x920,0x927,0x92f,0x937,0x93f,0x947,0x1719,0x1721,0x94f,0x957,0x95f,0x967,0x96f,0x976, -0x177f,0x176f,0x1777,0x1a74,0x1a7c,0x140e,0x97e,0x1406,0x1662,0x1662,0x1664,0x1422,0x1423,0x1416,0x1418,0x141a, -0x1787,0x1789,0x986,0x1789,0x98e,0x993,0x99b,0x178e,0x9a1,0x1789,0x9a7,0x9af,0xc6a,0x1796,0x1796,0x9b7, -0x17a6,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7, -0x17a7,0x17a7,0x17a7,0x179e,0x9bf,0x17af,0x17af,0x9c7,0xb92,0xb9a,0xba2,0xbaa,0x17bf,0x17b7,0x9cf,0x9d7, -0x9df,0x17c9,0x17d1,0x9e7,0x17c7,0x9ef,0x1b41,0xd92,0xbb2,0xbba,0xbc2,0xbc7,0x19da,0xc91,0xc98,0x1936, -0xc42,0x1b49,0xd9a,0xda2,0xdaa,0xdb2,0xf60,0xf64,0x1a3a,0x1a3f,0xcd0,0xcd8,0x1ab0,0x1ab8,0x1c19,0xe5e, -0x1ac0,0xd1e,0xd26,0x1ac8,0x1105,0x11b5,0xf38,0xdba,0x1956,0x193e,0x194e,0x1946,0x19f2,0x19ea,0x19a6,0x1a32, -0x142b,0x142b,0x142b,0x142b,0x142e,0x142b,0x142b,0x1436,0x9f7,0x143e,0x9fb,0xa03,0x143e,0xa0b,0xa13,0xa1b, -0x144e,0x1446,0x1456,0xa23,0xa2b,0x145e,0xa33,0xa3b,0x1466,0x146e,0x1476,0x147e,0xa43,0x1486,0x148d,0x1495, -0x149d,0x14a5,0x14ad,0x14b5,0x14bd,0x14c4,0x14cc,0x14d4,0x14dc,0x14e4,0x14e7,0x14e9,0x17d9,0x18cc,0x18d2,0x1a22, -0x14f1,0xa4b,0xa53,0x1617,0x161c,0x161f,0x1625,0x14f9,0x162d,0x162d,0x1509,0x1501,0x1511,0x1519,0x1521,0x1529, -0x1531,0x1539,0x1541,0x1549,0x18da,0x192e,0x1a84,0x1be1,0x1559,0x155f,0x1567,0x156f,0x1551,0x1577,0x18e2,0x18e9, -0x17e1,0x17e1,0x17e1,0x17e1,0x17e1,0x17e1,0x17e1,0x17e1,0x18f1,0x18f1,0x18f1,0x18f1,0x18f9,0x1900,0x1902,0x1909, -0x1911,0x1915,0x1915,0x1918,0x1915,0x1915,0x191e,0x1915,0x195e,0x1a2a,0x1a8c,0xbcf,0xbd5,0x1d45,0x1d4d,0x1e2b, -0x19ca,0x19be,0x19c2,0x1a47,0x19ae,0x19ae,0x19ae,0xc52,0x19b6,0xc72,0x1a0a,0xcc0,0xc5a,0xc62,0xc62,0x1ad0, -0x19fa,0x1a94,0xca8,0xcb0,0xa5b,0x17e9,0x17e9,0xa63,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0xa6b,0x73d, -0x164a,0x166c,0xa73,0x1674,0xa7b,0x167c,0x1684,0x168c,0xa83,0xa88,0x1694,0x169b,0xa8d,0x17f9,0x1a1a,0xc4a, -0xa95,0x16f6,0x16fd,0x16a3,0x1705,0x1709,0x16ab,0x16af,0x16c8,0x16c8,0x16ca,0x16b7,0x16bf,0x16bf,0x16c0,0x1711, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801, -0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1804,0x1966,0x1966, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2, -0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d9,0x1b31,0x1f0c, -0x180c,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812, -0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812, -0x1812,0x1812,0x1812,0x1812,0xa9d,0x181a,0xaa5,0x1b51,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc, -0x1ad8,0xd2e,0x1aec,0x1ae4,0x1aee,0x1b59,0x1b59,0xdc2,0x19d2,0x1a4f,0x1aa4,0x1aa8,0x1a9c,0x1c11,0xce0,0xce7, -0x1a02,0xcb8,0x1a57,0xcef,0x1af6,0x1af9,0xd36,0x1b61,0x1b09,0x1b01,0xd3e,0xdca,0x1b69,0x1b6d,0xdd2,0x100f, -0x1b11,0xd46,0xd4e,0x1b75,0x1b85,0x1b7d,0xdda,0xf08,0xe66,0xe6e,0x1d9b,0xfbf,0x1e48,0x1e48,0x1b8d,0xde2, -0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762, -0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764, -0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766, -0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761, -0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763, -0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765, -0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767, -0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762, -0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764, -0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766, -0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761, -0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763, -0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765, -0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767, -0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762, -0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764, -0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766, -0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761, -0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763, -0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765, -0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767, -0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0xaad,0xdea,0xded, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739, -0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, -0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x16e1,0x16e1,0x16e1,0x16e1,0x16e1,0x16e1,0x16e1,0x16e1, -0x16e6,0x16ee,0x1926,0x13a3,0x1a12,0x1a12,0x13a7,0x13ae,0xab5,0xabd,0xac5,0x1597,0x159e,0x15a6,0xacd,0x15ae, -0x15ec,0x15ec,0x157f,0x1587,0x15b6,0x15e3,0x15e4,0x15f4,0x15be,0x15c3,0x15cb,0x15d3,0xad5,0x15db,0xadd,0x158f, -0xcc8,0x15fc,0xae5,0xaed,0x1604,0x160a,0x160f,0xaf5,0xb05,0x1652,0x165a,0x163d,0x1642,0xb0d,0xb15,0xafd, -0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729, -0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1731,0x1731,0x1731,0x1731, -0x1564,0x1564,0x15a4,0x15e4,0x1624,0x1664,0x16a4,0x16e4,0x1720,0x1760,0x178c,0x17cc,0x180c,0x184c,0x188c,0x18cc, -0x190c,0x1948,0x1988,0x19c8,0x1a08,0x1a3c,0x1a78,0x1ab8,0x1af8,0x1b38,0x1b74,0x1bb4,0x1bf4,0x1c34,0x1c74,0x1cb4, -0xe59,0xa80,0xac0,0xb00,0xb40,0xb6b,0xf99,0xa40,0xed9,0xa40,0xa40,0xa40,0xa40,0xbab,0x13e2,0x13e2, +static const uint16_t propsVectorsTrie_index[32764]={ +0x53e,0x546,0x54e,0x556,0x56e,0x576,0x57e,0x586,0x58e,0x596,0x59e,0x5a6,0x5ae,0x5b6,0x5be,0x5c6, +0x5cd,0x5d5,0x5dd,0x5e5,0x5e8,0x5f0,0x5f8,0x600,0x608,0x610,0x618,0x620,0x628,0x630,0x638,0x640, +0x648,0x650,0x657,0x65f,0x667,0x66f,0x677,0x67f,0x687,0x68f,0x694,0x69c,0x6a3,0x6ab,0x6b3,0x6bb, +0x6c3,0x6cb,0x6d3,0x6db,0x6e2,0x6ea,0x6f2,0x6fa,0x702,0x70a,0x712,0x71a,0x722,0x72a,0x732,0x73a, +0x1b43,0xd8f,0xe5b,0x1192,0x12d1,0x1d0b,0x1eaa,0x1d03,0x13f0,0x1400,0x13e8,0x13f8,0x80f,0x815,0x81d,0x825, +0x82d,0x833,0x83b,0x843,0x84b,0x851,0x859,0x861,0x869,0x86f,0x877,0x87f,0x887,0x88f,0x897,0x89e, +0x8a6,0x8ac,0x8b4,0x8bc,0x8c4,0x8ca,0x8d2,0x8da,0x8e2,0x1408,0x8ea,0x8f2,0x8fa,0x901,0x909,0x911, +0x919,0x91d,0x925,0x92c,0x934,0x93c,0x944,0x94c,0x1723,0x172b,0x954,0x95c,0x964,0x96c,0x974,0x97b, +0x1789,0x1779,0x1781,0x1a7e,0x1a86,0x1418,0x983,0x1410,0x166c,0x166c,0x166e,0x142c,0x142d,0x1420,0x1422,0x1424, +0x1791,0x1793,0x98b,0x1793,0x993,0x998,0x9a0,0x1798,0x9a6,0x1793,0x9ac,0x9b4,0xc6f,0x17a0,0x17a0,0x9bc, +0x17b0,0x17b1,0x17b1,0x17b1,0x17b1,0x17b1,0x17b1,0x17b1,0x17b1,0x17b1,0x17b1,0x17b1,0x17b1,0x17b1,0x17b1,0x17b1, +0x17b1,0x17b1,0x17b1,0x17a8,0x9c4,0x17b9,0x17b9,0x9cc,0xb97,0xb9f,0xba7,0xbaf,0x17c9,0x17c1,0x9d4,0x9dc, +0x9e4,0x17d3,0x17db,0x9ec,0x17d1,0x9f4,0x1b4b,0xd97,0xbb7,0xbbf,0xbc7,0xbcc,0x19e4,0xc96,0xc9d,0x1940, +0xc47,0x1b53,0xd9f,0xda7,0xdaf,0xdb7,0xf65,0xf69,0x1a44,0x1a49,0xcd5,0xcdd,0x1aba,0x1ac2,0x1c23,0xe63, +0x1aca,0xd23,0xd2b,0x1ad2,0x110a,0x11ba,0xf3d,0xdbf,0x1960,0x1948,0x1958,0x1950,0x19fc,0x19f4,0x19b0,0x1a3c, +0x1435,0x1435,0x1435,0x1435,0x1438,0x1435,0x1435,0x1440,0x9fc,0x1448,0xa00,0xa08,0x1448,0xa10,0xa18,0xa20, +0x1458,0x1450,0x1460,0xa28,0xa30,0x1468,0xa38,0xa40,0x1470,0x1478,0x1480,0x1488,0xa48,0x1490,0x1497,0x149f, +0x14a7,0x14af,0x14b7,0x14bf,0x14c7,0x14ce,0x14d6,0x14de,0x14e6,0x14ee,0x14f1,0x14f3,0x17e3,0x18d6,0x18dc,0x1a2c, +0x14fb,0xa50,0xa58,0x1621,0x1626,0x1629,0x162f,0x1503,0x1637,0x1637,0x1513,0x150b,0x151b,0x1523,0x152b,0x1533, +0x153b,0x1543,0x154b,0x1553,0x18e4,0x1938,0x1a8e,0x1beb,0x1563,0x1569,0x1571,0x1579,0x155b,0x1581,0x18ec,0x18f3, +0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x18fb,0x18fb,0x18fb,0x18fb,0x1903,0x190a,0x190c,0x1913, +0x191b,0x191f,0x191f,0x1922,0x191f,0x191f,0x1928,0x191f,0x1968,0x1a34,0x1a96,0xbd4,0xbda,0x1d4f,0x1d57,0x1e35, +0x19d4,0x19c8,0x19cc,0x1a51,0x19b8,0x19b8,0x19b8,0xc57,0x19c0,0xc77,0x1a14,0xcc5,0xc5f,0xc67,0xc67,0x1ada, +0x1a04,0x1a9e,0xcad,0xcb5,0xa60,0x17f3,0x17f3,0xa68,0x17fb,0x17fb,0x17fb,0x17fb,0x17fb,0x17fb,0xa70,0x742, +0x1654,0x1676,0xa78,0x167e,0xa80,0x1686,0x168e,0x1696,0xa88,0xa8d,0x169e,0x16a5,0xa92,0x1803,0x1a24,0xc4f, +0xa9a,0x1700,0x1707,0x16ad,0x170f,0x1713,0x16b5,0x16b9,0x16d2,0x16d2,0x16d4,0x16c1,0x16c9,0x16c9,0x16ca,0x171b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b, +0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180b,0x180e,0x1970,0x1970, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc, +0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16dc,0x16e3,0x1b3b,0x1f16, +0x1816,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c, +0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c,0x181c, +0x181c,0x181c,0x181c,0x181c,0xaa2,0x1824,0xaaa,0x1b5b,0x1ae6,0x1ae6,0x1ae6,0x1ae6,0x1ae6,0x1ae6,0x1ae6,0x1ae6, +0x1ae2,0xd33,0x1af6,0x1aee,0x1af8,0x1b63,0x1b63,0xdc7,0x19dc,0x1a59,0x1aae,0x1ab2,0x1aa6,0x1c1b,0xce5,0xcec, +0x1a0c,0xcbd,0x1a61,0xcf4,0x1b00,0x1b03,0xd3b,0x1b6b,0x1b13,0x1b0b,0xd43,0xdcf,0x1b73,0x1b77,0xdd7,0x1014, +0x1b1b,0xd4b,0xd53,0x1b7f,0x1b8f,0x1b87,0xddf,0xf0d,0xe6b,0xe73,0x1da5,0xfc4,0x1e52,0x1e52,0x1b97,0xde7, +0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c, +0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e, +0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770, +0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b, +0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d, +0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f, +0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771, +0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c, +0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e, +0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770, +0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b, +0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d, +0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f, +0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771, +0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c, +0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e, +0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770, +0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b, +0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d, +0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f, +0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771, +0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0x1771,0x176b,0x176c,0x176d,0x176e,0x176f,0x1770,0xab2,0xdef,0xdf2, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743, +0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743,0x1743, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f, +0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x163f,0x16eb,0x16eb,0x16eb,0x16eb,0x16eb,0x16eb,0x16eb,0x16eb, +0x16f0,0x16f8,0x1930,0x139d,0x1a1c,0x1a1c,0x13a1,0x13a8,0xaba,0xac2,0xaca,0x15a1,0x15a8,0x15b0,0xad2,0x15b8, +0x15f6,0x15f6,0x1589,0x1591,0x15c0,0x15ed,0x15ee,0x15fe,0x15c8,0x15cd,0x15d5,0x15dd,0xada,0x15e5,0xae2,0x1599, +0xccd,0x1606,0xaea,0xaf2,0x160e,0x1614,0x1619,0xafa,0xb0a,0x165c,0x1664,0x1647,0x164c,0xb12,0xb1a,0xb02, +0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733, +0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x1733,0x173b,0x173b,0x173b,0x173b, +0x1578,0x1578,0x15b8,0x15f8,0x1638,0x1678,0x16b8,0x16f8,0x1734,0x1774,0x17a0,0x17e0,0x1820,0x1860,0x18a0,0x18e0, +0x1920,0x195c,0x199c,0x19dc,0x1a1c,0x1a50,0x1a8c,0x1acc,0x1b0c,0x1b4c,0x1b88,0x1bc8,0x1c08,0x1c48,0x1c88,0x1cc8, +0xe59,0xa80,0xac0,0xb00,0xb40,0xb6b,0xf99,0xa40,0xed9,0xa40,0xa40,0xa40,0xa40,0xbab,0x13f5,0x13f5, 0xf19,0xfd9,0xa40,0xa40,0xa40,0xbeb,0xf59,0xc2b,0xa40,0xc51,0xc91,0xcd1,0xd11,0xd51,0xe99,0xdc9, -0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322, -0x1322,0x1322,0x1322,0x1322,0x1019,0x1362,0x1157,0x1197,0x13a2,0x11a2,0x1422,0x1422,0x1422,0x1059,0x1079,0x10b9, -0x1462,0x1462,0x11e2,0x14a2,0x10f9,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079, -0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1117, +0x1335,0x1335,0x1335,0x1335,0x1335,0x1335,0x1335,0x1335,0x1335,0x1335,0x1335,0x1335,0x1335,0x1335,0x1335,0x1335, +0x1335,0x1335,0x1335,0x1335,0x1019,0x1375,0x116a,0x11aa,0x13b5,0x11b5,0x1435,0x1435,0x1435,0x1059,0x108c,0x10cc, +0x1475,0x1475,0x11f5,0x14b5,0x110c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c, +0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x108c,0x112a, 0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40, 0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xd89, 0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40, @@ -1629,1954 +1638,1958 @@ static const uint16_t propsVectorsTrie_index[32692]={ 0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xd89, 0xe09,0xe19,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40, 0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xd89, -0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2, -0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x1222, -0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2, -0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x1262, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0xc27,0xc2a,0xdf5,0x1deb,0x1017,0x745,0x559,0x10b1,0xcf7,0xd76,0x559,0x559,0x1d11,0xf10,0xf18,0x1e33, -0xc7a,0xc81,0xc89,0x1b95,0x1dcb,0x559,0x1dab,0xfe7,0x1b9d,0xdfd,0xe05,0xe0d,0x103f,0x74d,0x559,0x559, -0x1ba5,0x1ba5,0x755,0x559,0x1e60,0x10c9,0x1e58,0x10d1,0x1f4c,0x11cb,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0xe15,0x1fa4,0x12c4,0x1346,0x1347,0x1f6c,0x11f3,0x11fa,0x1201,0x1303,0x1307,0x127b,0x1211, -0x1c21,0x1c23,0xe76,0xe7d,0x1bad,0x1bb5,0xe1d,0xf30,0x1d09,0xef8,0xf00,0xfdf,0x1d29,0x1d2d,0x1d35,0x105f, -0xfaf,0x1d8b,0x75d,0x559,0x10b9,0x10c1,0x1d93,0xfb7,0xf91,0xf97,0xf9f,0xfa7,0x559,0x559,0x559,0x559, -0x1ed0,0x1ec8,0x113b,0x1143,0x1e13,0x1e0b,0x1087,0x559,0x559,0x559,0x559,0x559,0x1dfb,0x1047,0x104f,0x1057, -0x1dc3,0x1dbb,0xff7,0x1133,0x1d3d,0xf40,0x765,0x559,0x1097,0x109f,0x76d,0x559,0x559,0x559,0x559,0x559, -0x1f44,0x11ad,0x775,0x559,0x559,0x1e23,0x1e1b,0x108f,0x1283,0x1289,0x1291,0x559,0x559,0x1219,0x121d,0x1225, -0x1f04,0x1efc,0x1195,0x1ef4,0x1eec,0x1185,0x1df3,0x1037,0x1357,0x135a,0x135a,0x559,0x559,0x559,0x559,0x559, -0x10e9,0x10ee,0x10f6,0x10fd,0x1125,0x112b,0x559,0x559,0x1169,0x116d,0x1175,0x11bd,0x11c3,0x77d,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x11db,0x136a,0x136f,0x1377,0x559,0x559,0x781,0x1f8c,0x126b, -0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f, -0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a64,0xcff,0xd06,0xd06,0xd06, -0x1a6c,0x1a6c,0x1a6c,0xd0e,0x1e50,0x1e50,0x1e50,0x1e50,0x1e50,0x1e50,0x789,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x78d,0x1fbc,0x1fbc,0x12d4,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b, -0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0xe85,0xfff,0x1007,0x1fc4, -0x130f,0x1317,0xf48,0x1de3,0x1ddb,0x1027,0x102f,0x795,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1f64,0x1f5c,0x11eb, -0x559,0x559,0x559,0x1d21,0x1d21,0xf20,0x1d19,0xf28,0x559,0x559,0x111d,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x799,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1d73,0x1d73,0x1d73,0xf6c,0xf71, -0x7a1,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1fd4,0x1337,0x133e,0x1fcc,0x1fcc,0x1fcc,0x7a9, -0x559,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0xb2b,0x184f,0xb33,0x1850,0x1847,0x1858,0x185e,0x1866, -0xb3b,0x198e,0x198e,0x7b1,0x559,0x559,0x559,0x1362,0x11e3,0x197e,0x197e,0xc32,0xd16,0x559,0x559,0x559, -0x559,0x1897,0x189e,0xb43,0x18a1,0xb4b,0xb53,0xb5b,0x189b,0xb63,0xb6b,0xb73,0x18a0,0x18a8,0x1897,0x189e, -0x189a,0x18a1,0x18a9,0x1898,0x189f,0x189b,0xb7a,0x186e,0x1876,0x187d,0x1884,0x1871,0x1879,0x1880,0x1887,0xb82, -0x188f,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78, -0x1e78,0x1e68,0x1e6b,0x1e68,0x1e72,0x10d9,0x7b9,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x12f0,0x12f8,0x12fb,0x12fb,0x12fb,0x12fb,0x12fb, -0x12fb,0x110d,0x1115,0x1fdc,0x134f,0x7c1,0x559,0x559,0x559,0x1f84,0x122d,0x7c9,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x7cd,0x131f,0x1f94,0x1273,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x7d5,0x137f,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x12dc,0x1db3,0x1db3,0x1db3,0x1db3,0x1db3,0x1db3,0xfef,0x559,0x1ec0,0x1eb8,0x10e1,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x7dd,0x1f54,0x11d3,0x559,0x559,0x1235,0x1236,0x7e5,0x559,0x559,0x559,0x559, -0x559,0xebd,0xec5,0xecd,0xed5,0xedd,0xee5,0xeec,0xef0,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x7e9,0x1067,0x1e03,0x106d,0x1e03,0x1075,0x107a,0x107f, -0x107f,0x1e88,0x1ea8,0x1eb0,0x1f1c,0x1e90,0x1f74,0x1e98,0x1f24,0x1f7c,0x1f7c,0x119d,0x11a5,0x124d,0x1253,0x125b, -0x1263,0x1f9c,0x1f9c,0x1f9c,0x1f9c,0x12a7,0x1f9c,0x12ad,0x12b1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1, -0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1, -0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f2,0xb8a,0x18b1,0x18b1,0x18b1,0x7fa,0x7fa,0x7fa, -0x7fa,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x802,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa, -0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa, -0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa, -0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa, -0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0xbdd,0xbe4,0xbec,0xbf4,0x196e,0x196e,0x196e, -0xbfc,0xc04,0xc07,0x199e,0x1996,0xc3a,0xd56,0xd5a,0xd5e,0x559,0x559,0x559,0x559,0xd66,0x1b19,0xd6e, -0xf58,0x1822,0xb1d,0xb23,0x101f,0xc0f,0x19e2,0xca0,0x559,0x1837,0x182a,0x182f,0x1976,0xc17,0xc1f,0x114b, -0x1151,0x1d7b,0xf79,0x1d6b,0xf50,0x1327,0x132f,0x559,0x559,0x1da3,0x1da3,0x1da3,0x1da3,0x1da3,0x1da3,0x1da3, -0x1da3,0x1da3,0xfc7,0xfcf,0xfd7,0x12e4,0x12e8,0x559,0x559,0x1b21,0xd7e,0x1b29,0x1b29,0xd82,0xe8d,0xe95, -0xe9d,0x1bf1,0x1bd9,0x1bf9,0x1c01,0x1be9,0xe25,0xe29,0xe30,0xe38,0xe3c,0xe44,0xe4c,0xe4e,0xe4e,0xe4e, -0xe4e,0x1c62,0x1c6a,0x1c62,0x1c70,0x1c78,0x1c43,0x1c80,0x1c88,0x1c62,0x1c90,0x1c98,0x1c9f,0x1ca7,0x1c4b,0x1c62, -0x1cac,0x1c53,0x1c5a,0x1cb4,0x1cba,0x1d5c,0x1d63,0x1d55,0x1cc1,0x1cc9,0x1cd1,0x1cd9,0x1dd3,0x1ce1,0x1ce9,0xea5, -0xead,0x1c33,0x1c33,0x1c33,0xeb5,0x1d83,0x1d83,0xf81,0xf89,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e3b, -0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e40,0x1e3b,0x1e3b,0x1e3b,0x10a7,0x10a9,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8, -0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8, -0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8, -0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8, -0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1159,0x1c3b,0x1f14,0x1f14,0x1f14,0x1f14,0x1f14,0x1f14, -0x1f14,0x1f34,0x1161,0x123e,0x1245,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c, -0x117d,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd, -0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbf,0x1bbd,0x1bc7,0x1bbd,0x1bbd, -0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bca,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bd1,0x1209,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0, -0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0, -0x1ee4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1299, -0x129f,0x12b9,0x12bc,0x12bc,0x12bc,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559, -0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9, -0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9, -0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9, -0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18bc, -0x1387,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c, -0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c, -0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x138f,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387, -0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387, -0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387, -0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387, -0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4, -0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x13b6,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387, -0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387, -0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387, -0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1393,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4, -0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4, -0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x139b,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387, -0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387, -0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387, -0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387, -0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1393,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09, -0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09, -0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09, -0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09, -0x13be,0x1cf1,0x1cf1,0x1cf1,0x1cf1,0x1cf1,0x1cf1,0x13c6,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80, -0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80, -0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80, -0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80, -0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x13ce,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c, -0x1f2c,0x1f2c,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac, -0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x13d6,0x1fe4,0x1fe4,0x1fe4, -0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4, -0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4, -0x1fe4,0x1fe4,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751, -0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751, -0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751, -0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751, -0x1751,0x1741,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759, -0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759, -0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759, -0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759, -0x1759,0x1749,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751, -0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751, -0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751, -0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751, -0x1751,0x1751,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759, -0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759, -0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759, -0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759, -0x1759,0x1759,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9, -0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9, -0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9, -0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9, -0x18b9,0x18b9,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09, -0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09, -0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09, -0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09, -0x1c09,0x1c09,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80, -0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80, -0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80, -0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80, -0x1e80,0x1e80,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8, -0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8, -0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8, -0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8, -0x1ed8,0x1ed8,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c, -0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c, -0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c, -0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c, -0x1f2c,0x1f2c,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac, -0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac, -0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac, -0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac, -0x1fac,0x1fac,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4, -0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4, -0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4, -0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4, -0x1fe4,0x1fe4,0x538,0x538,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e5,0x2ee,0x2e8, -0x2e8,0x2eb,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2, -0x2e2,0x2e2,0x2e2,0x2e2,0x7da,0x7d4,0x7b9,0x79e,0x7aa,0x7a7,0x79e,0x7b6,0x7a4,0x7b0,0x79e,0x7cb, -0x7c2,0x7b3,0x7d7,0x7ad,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b,0x7bf,0x7bc, -0x7c5,0x7c5,0x7c5,0x7d4,0x79e,0x7e6,0x7e6,0x7e6,0x7e6,0x7e6,0x7e6,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0, -0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7a4, -0x7aa,0x7b0,0x7d1,0x798,0x7ce,0x7e3,0x7e3,0x7e3,0x7e3,0x7e3,0x7e3,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd, -0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7a4, -0x7c8,0x7a1,0x7c5,0x2e2,0,0,0,0,0,0,0,0,0,0,0,0, +0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5, +0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x12b5,0x1235, +0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5, +0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x12f5,0x1275, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0xc2c,0xc2f,0xdfa,0x1df5,0x101c,0x74a,0x55e,0x10b6,0xcfc,0xd7b,0x55e,0x55e,0x1d1b,0xf15,0xf1d,0x1e3d, +0xc7f,0xc86,0xc8e,0x1b9f,0x1dd5,0x55e,0x1db5,0xfec,0x1ba7,0xe02,0xe0a,0xe12,0x1044,0x752,0x55e,0x55e, +0x1baf,0x1baf,0x75a,0x55e,0x1e6a,0x10ce,0x1e62,0x10d6,0x1f56,0x11d0,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0xe1a,0x1fae,0x12c9,0x134b,0x134c,0x1f76,0x11f8,0x11ff,0x1206,0x1308,0x130c,0x1280,0x1216, +0x1c2b,0x1c2d,0xe7b,0xe82,0x1bb7,0x1bbf,0xe22,0xf35,0x1d13,0xefd,0xf05,0xfe4,0x1d33,0x1d37,0x1d3f,0x1064, +0xfb4,0x1d95,0x762,0x55e,0x10be,0x10c6,0x1d9d,0xfbc,0xf96,0xf9c,0xfa4,0xfac,0x55e,0x55e,0x55e,0x55e, +0x1eda,0x1ed2,0x1140,0x1148,0x1e1d,0x1e15,0x108c,0x55e,0x55e,0x55e,0x55e,0x55e,0x1e05,0x104c,0x1054,0x105c, +0x1dcd,0x1dc5,0xffc,0x1138,0x1d47,0xf45,0x76a,0x55e,0x109c,0x10a4,0x772,0x55e,0x55e,0x55e,0x55e,0x55e, +0x1f4e,0x11b2,0x77a,0x55e,0x55e,0x1e2d,0x1e25,0x1094,0x1288,0x128e,0x1296,0x55e,0x55e,0x121e,0x1222,0x122a, +0x1f0e,0x1f06,0x119a,0x1efe,0x1ef6,0x118a,0x1dfd,0x103c,0x135c,0x135f,0x135f,0x55e,0x55e,0x55e,0x55e,0x55e, +0x10ee,0x10f3,0x10fb,0x1102,0x112a,0x1130,0x55e,0x55e,0x116e,0x1172,0x117a,0x11c2,0x11c8,0x782,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x11e0,0x136f,0x1374,0x137c,0x55e,0x55e,0x786,0x1f96,0x1270, +0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69, +0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a69,0x1a6e,0xd04,0xd0b,0xd0b,0xd0b, +0x1a76,0x1a76,0x1a76,0xd13,0x1e5a,0x1e5a,0x1e5a,0x1e5a,0x1e5a,0x1e5a,0x78e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x792,0x1fc6,0x1fc6,0x12d9,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35, +0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0xe8a,0x1004,0x100c,0x1fce, +0x1314,0x131c,0xf4d,0x1ded,0x1de5,0x102c,0x1034,0x79a,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x1f6e,0x1f66,0x11f0, +0x55e,0x55e,0x55e,0x1d2b,0x1d2b,0xf25,0x1d23,0xf2d,0x55e,0x55e,0x1122,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x79e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x1d7d,0x1d7d,0x1d7d,0xf71,0xf76, +0x7a6,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x1fde,0x133c,0x1343,0x1fd6,0x1fd6,0x1fd6,0x7ae, +0x55e,0x1849,0x1849,0x1849,0x1849,0x1849,0x1849,0x1849,0xb30,0x1859,0xb38,0x185a,0x1851,0x1862,0x1868,0x1870, +0xb40,0x1998,0x1998,0x7b6,0x55e,0x55e,0x55e,0x1367,0x11e8,0x1988,0x1988,0xc37,0xd1b,0x55e,0x55e,0x55e, +0x55e,0x18a1,0x18a8,0xb48,0x18ab,0xb50,0xb58,0xb60,0x18a5,0xb68,0xb70,0xb78,0x18aa,0x18b2,0x18a1,0x18a8, +0x18a4,0x18ab,0x18b3,0x18a2,0x18a9,0x18a5,0xb7f,0x1878,0x1880,0x1887,0x188e,0x187b,0x1883,0x188a,0x1891,0xb87, +0x1899,0x1e82,0x1e82,0x1e82,0x1e82,0x1e82,0x1e82,0x1e82,0x1e82,0x1e82,0x1e82,0x1e82,0x1e82,0x1e82,0x1e82,0x1e82, +0x1e82,0x1e72,0x1e75,0x1e72,0x1e7c,0x10de,0x7be,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x12f5,0x12fd,0x1300,0x1300,0x1300,0x1300,0x1300, +0x1300,0x1112,0x111a,0x1fe6,0x1354,0x7c6,0x55e,0x55e,0x55e,0x1f8e,0x1232,0x7ce,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x7d2,0x1324,0x1f9e,0x1278,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x7da,0x1384,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x12e1,0x1dbd,0x1dbd,0x1dbd,0x1dbd,0x1dbd,0x1dbd,0xff4,0x55e,0x1eca,0x1ec2,0x10e6,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x7e2,0x1f5e,0x11d8,0x55e,0x55e,0x123a,0x123b,0x7ea,0x55e,0x55e,0x55e,0x55e, +0x55e,0xec2,0xeca,0xed2,0xeda,0xee2,0xeea,0xef1,0xef5,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x7ee,0x106c,0x1e0d,0x1072,0x1e0d,0x107a,0x107f,0x1084, +0x1084,0x1e92,0x1eb2,0x1eba,0x1f26,0x1e9a,0x1f7e,0x1ea2,0x1f2e,0x1f86,0x1f86,0x11a2,0x11aa,0x1252,0x1258,0x1260, +0x1268,0x1fa6,0x1fa6,0x1fa6,0x1fa6,0x12ac,0x1fa6,0x12b2,0x12b6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6, +0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6, +0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f6,0x7f7,0xb8f,0x18bb,0x18bb,0x18bb,0x7ff,0x7ff,0x7ff, +0x7ff,0x1990,0x1990,0x1990,0x1990,0x1990,0x1990,0x1990,0x807,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff, +0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff, +0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff, +0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff, +0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0x7ff,0xbe2,0xbe9,0xbf1,0xbf9,0x1978,0x1978,0x1978, +0xc01,0xc09,0xc0c,0x19a8,0x19a0,0xc3f,0xd5b,0xd5f,0xd63,0x55e,0x55e,0x55e,0x55e,0xd6b,0x1b23,0xd73, +0xf5d,0x182c,0xb22,0xb28,0x1024,0xc14,0x19ec,0xca5,0x55e,0x1841,0x1834,0x1839,0x1980,0xc1c,0xc24,0x1150, +0x1156,0x1d85,0xf7e,0x1d75,0xf55,0x132c,0x1334,0x55e,0x55e,0x1dad,0x1dad,0x1dad,0x1dad,0x1dad,0x1dad,0x1dad, +0x1dad,0x1dad,0xfcc,0xfd4,0xfdc,0x12e9,0x12ed,0x55e,0x55e,0x1b2b,0xd83,0x1b33,0x1b33,0xd87,0xe92,0xe9a, +0xea2,0x1bfb,0x1be3,0x1c03,0x1c0b,0x1bf3,0xe2a,0xe2e,0xe35,0xe3d,0xe41,0xe49,0xe51,0xe53,0xe53,0xe53, +0xe53,0x1c6c,0x1c74,0x1c6c,0x1c7a,0x1c82,0x1c4d,0x1c8a,0x1c92,0x1c6c,0x1c9a,0x1ca2,0x1ca9,0x1cb1,0x1c55,0x1c6c, +0x1cb6,0x1c5d,0x1c64,0x1cbe,0x1cc4,0x1d66,0x1d6d,0x1d5f,0x1ccb,0x1cd3,0x1cdb,0x1ce3,0x1ddd,0x1ceb,0x1cf3,0xeaa, +0xeb2,0x1c3d,0x1c3d,0x1c3d,0xeba,0x1d8d,0x1d8d,0xf86,0xf8e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x1e45,0x1e45,0x1e45,0x1e45,0x1e45,0x1e45,0x1e45, +0x1e45,0x1e45,0x1e45,0x1e45,0x1e45,0x1e45,0x1e45,0x1e4a,0x1e45,0x1e45,0x1e45,0x10ac,0x10ae,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2, +0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2, +0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2, +0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2, +0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x115e,0x1c45,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e, +0x1f1e,0x1f3e,0x1166,0x1243,0x124a,0x1f46,0x1f46,0x1f46,0x1f46,0x1f46,0x1f46,0x1f46,0x1f46,0x1f46,0x1f46,0x1f46, +0x1182,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bc7, +0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bc9,0x1bc7,0x1bd1,0x1bc7,0x1bc7, +0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bd4,0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bc7,0x1bdb,0x120e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea, +0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea,0x1eea, +0x1eee,0x1fbe,0x1fbe,0x1fbe,0x1fbe,0x1fbe,0x1fbe,0x1fbe,0x1fbe,0x1fbe,0x1fbe,0x1fbe,0x1fbe,0x1fbe,0x1fbe,0x129e, +0x12a4,0x12be,0x12c1,0x12c1,0x12c1,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e, +0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x55e,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3, +0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3, +0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3, +0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c6, +0x138c,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36, +0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36, +0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x13d0,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6, +0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x1ff6,0x13e0,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x18ce,0x18ce,0x18ce,0x18ce, +0x18ce,0x18ce,0x18ce,0x18ce,0x18ce,0x18ce,0x18ce,0x18ce,0x18ce,0x18ce,0x18ce,0x18ce,0x13b0,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138d,0x1fee,0x1fee,0x1fee,0x1fee, +0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee, +0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1395,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138d,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13, +0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13, +0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13, +0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13, +0x1c13,0x1c13,0x1c13,0x13b8,0x1cfb,0x1cfb,0x1cfb,0x1cfb,0x1cfb,0x1cfb,0x13c0,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a, +0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a, +0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a, +0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a, +0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x13c8,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36, +0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6, +0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x13d8, +0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee, +0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee, +0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b, +0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b, +0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b, +0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b, +0x175b,0x175b,0x175b,0x175b,0x174b,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763, +0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763, +0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763, +0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763, +0x1763,0x1763,0x1763,0x1763,0x1753,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b, +0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b, +0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b, +0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b, +0x175b,0x175b,0x175b,0x175b,0x175b,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763, +0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763, +0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763, +0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763,0x1763, +0x1763,0x1763,0x1763,0x1763,0x1763,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3, +0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3, +0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3, +0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3, +0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13, +0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13, +0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13, +0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1c13, +0x1c13,0x1c13,0x1c13,0x1c13,0x1c13,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a, +0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a, +0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a, +0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a, +0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1e8a,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2, +0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2, +0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2, +0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2, +0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1ee2,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36, +0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36, +0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36, +0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1f36, +0x1f36,0x1f36,0x1f36,0x1f36,0x1f36,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6, +0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6, +0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6, +0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6, +0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fb6,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee, +0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee, +0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee, +0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x1fee, +0x1fee,0x1fee,0x1fee,0x1fee,0x1fee,0x53d,0x53d,0x53d,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2, +0x2e2,0x2e5,0x2ee,0x2e8,0x2e8,0x2eb,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2, +0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x7da,0x7d4,0x7b9,0x79e,0x7aa,0x7a7,0x79e,0x7b6, +0x7a4,0x7b0,0x79e,0x7cb,0x7c2,0x7b3,0x7d7,0x7ad,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b, +0x79b,0x79b,0x7bf,0x7bc,0x7c5,0x7c5,0x7c5,0x7d4,0x79e,0x7e6,0x7e6,0x7e6,0x7e6,0x7e6,0x7e6,0x7e0, +0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0, +0x7e0,0x7e0,0x7e0,0x7a4,0x7aa,0x7b0,0x7d1,0x798,0x7ce,0x7e3,0x7e3,0x7e3,0x7e3,0x7e3,0x7e3,0x7dd, +0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd, +0x7dd,0x7dd,0x7dd,0x7a4,0x7c8,0x7a1,0x7c5,0x2e2,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x300,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1, +0,0,0,0,0,0,0,0,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x300,0x2f1,0x2f1, 0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1, -0x2f1,0x2f1,0x2f1,0x2f1,0x2f4,0x64b,0x7ef,0x7f2,0x651,0x7f2,0x7ec,0x645,0x63c,0x2fa,0x65a,0x2fd, -0x7f5,0x633,0x648,0x7e9,0x64e,0x657,0x639,0x639,0x63f,0x2f7,0x645,0x642,0x63c,0x639,0x65a,0x2fd, -0x636,0x636,0x636,0x64b,0x306,0x306,0x306,0x306,0x306,0x306,0x663,0x306,0x306,0x306,0x306,0x306, -0x306,0x306,0x306,0x306,0x663,0x306,0x306,0x306,0x306,0x306,0x306,0x654,0x663,0x306,0x306,0x306, -0x306,0x306,0x663,0x65d,0x660,0x660,0x303,0x303,0x303,0x303,0x65d,0x303,0x660,0x660,0x660,0x303, -0x660,0x660,0x303,0x303,0x65d,0x303,0x660,0x660,0x303,0x303,0x303,0x654,0x65d,0x660,0x660,0x303, -0x660,0x303,0x65d,0x303,0x312,0x669,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309, -0x312,0x309,0x312,0x309,0x30f,0x666,0x312,0x669,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x669, -0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x66f,0x666,0x312,0x309,0x312,0x669, -0x312,0x309,0x312,0x309,0x312,0x666,0x672,0x66c,0x312,0x309,0x312,0x309,0x666,0x312,0x309,0x312, -0x309,0x312,0x309,0x672,0x66c,0x66f,0x666,0x312,0x669,0x312,0x309,0x312,0x669,0x675,0x66f,0x666, -0x312,0x669,0x312,0x309,0x312,0x309,0x66f,0x666,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309, -0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x66f,0x666,0x312,0x309,0x312,0x669, -0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x312,0x309,0x312, -0x309,0x312,0x309,0x30c,0x315,0x321,0x321,0x315,0x321,0x315,0x321,0x321,0x315,0x321,0x321,0x321, -0x315,0x315,0x321,0x321,0x321,0x321,0x315,0x321,0x321,0x315,0x321,0x321,0x321,0x315,0x315,0x315, -0x321,0x321,0x315,0x321,0x324,0x318,0x321,0x315,0x321,0x315,0x321,0x321,0x315,0x321,0x315,0x315, -0x321,0x315,0x321,0x324,0x318,0x321,0x321,0x321,0x315,0x321,0x315,0x321,0x321,0x315,0x315,0x31e, -0x321,0x315,0x315,0x315,0x31e,0x31e,0x31e,0x31e,0x327,0x327,0x31b,0x327,0x327,0x31b,0x327,0x327, -0x31b,0x324,0x678,0x324,0x678,0x324,0x678,0x324,0x678,0x324,0x678,0x324,0x678,0x324,0x678,0x324, -0x678,0x315,0x324,0x318,0x324,0x318,0x324,0x318,0x321,0x315,0x324,0x318,0x324,0x318,0x324,0x318, -0x324,0x318,0x324,0x318,0x318,0x327,0x327,0x31b,0x324,0x318,0x9cf,0x9cf,0x9d2,0x9cc,0x324,0x318, -0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318, -0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x9d2,0x9cc,0x9d2,0x9cc,0x9cf,0x9c9,0x9d2,0x9cc, -0xb8b,0xc84,0x9cf,0x9c9,0x9cf,0x9c9,0x9d2,0x9cc,0x9d2,0x9cc,0x9d2,0x9cc,0x9d2,0x9cc,0x9d2,0x9cc, -0x9d2,0x9cc,0x9d2,0x9cc,0xc84,0xc84,0xc84,0xd7d,0xd7d,0xd7d,0xd80,0xd80,0xd7d,0xd80,0xd80,0xd7d, -0xd7d,0xd80,0xebe,0xec1,0xec1,0xec1,0xec1,0xebe,0xec1,0xebe,0xec1,0xebe,0xec1,0xebe,0xec1,0xebe, -0x32a,0x67b,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a, -0x32a,0x67b,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a, +0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f4,0x64b,0x7ef,0x7f2,0x651,0x7f2,0x7ec,0x645, +0x63c,0x2fa,0x65a,0x2fd,0x7f5,0x633,0x648,0x7e9,0x64e,0x657,0x639,0x639,0x63f,0x2f7,0x645,0x642, +0x63c,0x639,0x65a,0x2fd,0x636,0x636,0x636,0x64b,0x306,0x306,0x306,0x306,0x306,0x306,0x663,0x306, +0x306,0x306,0x306,0x306,0x306,0x306,0x306,0x306,0x663,0x306,0x306,0x306,0x306,0x306,0x306,0x654, +0x663,0x306,0x306,0x306,0x306,0x306,0x663,0x65d,0x660,0x660,0x303,0x303,0x303,0x303,0x65d,0x303, +0x660,0x660,0x660,0x303,0x660,0x660,0x303,0x303,0x65d,0x303,0x660,0x660,0x303,0x303,0x303,0x654, +0x65d,0x660,0x660,0x303,0x660,0x303,0x65d,0x303,0x312,0x669,0x312,0x309,0x312,0x309,0x312,0x309, +0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x30f,0x666,0x312,0x669,0x312,0x309,0x312,0x309, +0x312,0x309,0x312,0x669,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x66f,0x666, +0x312,0x309,0x312,0x669,0x312,0x309,0x312,0x309,0x312,0x666,0x672,0x66c,0x312,0x309,0x312,0x309, +0x666,0x312,0x309,0x312,0x309,0x312,0x309,0x672,0x66c,0x66f,0x666,0x312,0x669,0x312,0x309,0x312, +0x669,0x675,0x66f,0x666,0x312,0x669,0x312,0x309,0x312,0x309,0x66f,0x666,0x312,0x309,0x312,0x309, +0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x66f,0x666, +0x312,0x309,0x312,0x669,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309, +0x312,0x312,0x309,0x312,0x309,0x312,0x309,0x30c,0x315,0x321,0x321,0x315,0x321,0x315,0x321,0x321, +0x315,0x321,0x321,0x321,0x315,0x315,0x321,0x321,0x321,0x321,0x315,0x321,0x321,0x315,0x321,0x321, +0x321,0x315,0x315,0x315,0x321,0x321,0x315,0x321,0x324,0x318,0x321,0x315,0x321,0x315,0x321,0x321, +0x315,0x321,0x315,0x315,0x321,0x315,0x321,0x324,0x318,0x321,0x321,0x321,0x315,0x321,0x315,0x321, +0x321,0x315,0x315,0x31e,0x321,0x315,0x315,0x315,0x31e,0x31e,0x31e,0x31e,0x327,0x327,0x31b,0x327, +0x327,0x31b,0x327,0x327,0x31b,0x324,0x678,0x324,0x678,0x324,0x678,0x324,0x678,0x324,0x678,0x324, +0x678,0x324,0x678,0x324,0x678,0x315,0x324,0x318,0x324,0x318,0x324,0x318,0x321,0x315,0x324,0x318, +0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x318,0x327,0x327,0x31b,0x324,0x318,0x9cf,0x9cf, +0x9d2,0x9cc,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318, +0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x9d2,0x9cc,0x9d2,0x9cc, +0x9cf,0x9c9,0x9d2,0x9cc,0xb8e,0xc87,0x9cf,0x9c9,0x9cf,0x9c9,0x9d2,0x9cc,0x9d2,0x9cc,0x9d2,0x9cc, +0x9d2,0x9cc,0x9d2,0x9cc,0x9d2,0x9cc,0x9d2,0x9cc,0xc87,0xc87,0xc87,0xd80,0xd80,0xd80,0xd83,0xd83, +0xd80,0xd83,0xd83,0xd80,0xd80,0xd83,0xec1,0xec4,0xec4,0xec4,0xec4,0xec1,0xec4,0xec1,0xec4,0xec1, +0xec4,0xec1,0xec4,0xec1,0x32a,0x67b,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a, +0x32a,0x32a,0x32a,0x32a,0x32a,0x67b,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a, 0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a, -0x32d,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a, -0x32a,0x32a,0x32a,0x32a,0x32a,0x9d5,0x9d5,0x9d5,0x9d5,0x9d5,0xc87,0xc87,0x342,0x342,0x342,0x342, -0x342,0x342,0x342,0x342,0x342,0x339,0x339,0x339,0x339,0x339,0x339,0x339,0x336,0x336,0x333,0x333, -0x681,0x333,0x339,0x684,0x33c,0x684,0x684,0x684,0x33c,0x684,0x339,0x339,0x687,0x33f,0x333,0x333, -0x333,0x333,0x333,0x333,0x67e,0x67e,0x67e,0x67e,0x330,0x67e,0x333,0xb01,0x342,0x342,0x342,0x342, -0x342,0x333,0x333,0x333,0x333,0x333,0x9de,0x9de,0x9db,0x9d8,0x9db,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a, -0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0x68a,0x68a,0x68a,0x68a, +0x32a,0x32a,0x32a,0x32a,0x32d,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a, +0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x9d5,0x9d5,0x9d5,0x9d5,0x9d5,0xc8a,0xc8a, +0x342,0x342,0x342,0x342,0x342,0x342,0x342,0x342,0x342,0x339,0x339,0x339,0x339,0x339,0x339,0x339, +0x336,0x336,0x333,0x333,0x681,0x333,0x339,0x684,0x33c,0x684,0x684,0x684,0x33c,0x684,0x339,0x339, +0x687,0x33f,0x333,0x333,0x333,0x333,0x333,0x333,0x67e,0x67e,0x67e,0x67e,0x330,0x67e,0x333,0xb04, +0x342,0x342,0x342,0x342,0x342,0x333,0x333,0x333,0x333,0x333,0x9de,0x9de,0x9db,0x9d8,0x9db,0xc8d, +0xc8d,0xc8d,0xc8d,0xc8d,0xc8d,0xc8d,0xc8d,0xc8d,0xc8d,0xc8d,0xc8d,0xc8d,0xc8d,0xc8d,0xc8d,0xc8d, +0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a, 0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a, 0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a, 0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a, -0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68d,0x68d,0x92d,0x68d, -0x68d,0x930,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xc3c,0xd47,0xd47,0xd47,0xd47, -0xd47,0xd47,0xd47,0xd47,0xe82,0xe82,0xe82,0xe82,0xe85,0xd4a,0xd4a,0xd4a,0x690,0x690,0xb07,0xc81, -0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xf6c,0xf69,0xf6c,0xf69, -0x34e,0x357,0xf6c,0xf69,9,9,0x35d,0xec4,0xec4,0xec4,0x345,0x14af,9,9,9,9, -0x35a,0x348,0x36c,0x34b,0x36c,0x36c,0x36c,9,0x36c,9,0x36c,0x36c,0x363,0x696,0x696,0x696, -0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,9,0x696, -0x696,0x696,0x696,0x696,0x696,0x696,0x36c,0x36c,0x363,0x363,0x363,0x363,0x363,0x693,0x693,0x693, -0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x360,0x693, -0x693,0x693,0x693,0x693,0x693,0x693,0x363,0x363,0x363,0x363,0x363,0xf6c,0x36f,0x36f,0x372,0x36c, -0x36c,0x36f,0x366,0x9e1,0xb94,0xb91,0x369,0x9e1,0x369,0x9e1,0x369,0x9e1,0x369,0x9e1,0x354,0x351, -0x354,0x351,0x354,0x351,0x354,0x351,0x354,0x351,0x354,0x351,0x354,0x351,0x36f,0x36f,0x366,0x360, -0xb43,0xb40,0xb8e,0xc90,0xc8d,0xc93,0xc90,0xc8d,0xd83,0xd86,0xd86,0xd86,0x9f0,0x6a2,0x37e,0x381, -0x37e,0x37e,0x37e,0x381,0x37e,0x37e,0x37e,0x37e,0x381,0x9f0,0x381,0x37e,0x69f,0x69f,0x69f,0x69f, -0x69f,0x69f,0x69f,0x69f,0x69f,0x6a2,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f, -0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x699,0x699,0x699,0x699, -0x699,0x699,0x699,0x699,0x699,0x69c,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699, -0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x9ea,0x69c,0x378,0x37b,0x378,0x378,0x378,0x37b, -0x378,0x378,0x378,0x378,0x37b,0x9ea,0x37b,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378, -0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x381,0x37b, -0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x375,0x939,0x93c,0x91e,0x91e,0x1116, -0x9e4,0x9e4,0xb9a,0xb97,0x9ed,0x9e7,0x9ed,0x9e7,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378, +0x68d,0x68d,0x92d,0x68d,0x68d,0x930,0xb07,0xb07,0xb07,0xb07,0xb07,0xb07,0xb07,0xb07,0xb07,0xc3f, +0xd4a,0xd4a,0xd4a,0xd4a,0xd4a,0xd4a,0xd4a,0xd4a,0xe85,0xe85,0xe85,0xe85,0xe88,0xd4d,0xd4d,0xd4d, +0x690,0x690,0xb0a,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84, +0xf6f,0xf6c,0xf6f,0xf6c,0x34e,0x357,0xf6f,0xf6c,9,9,0x35d,0xec7,0xec7,0xec7,0x345,0x14b8, +9,9,9,9,0x35a,0x348,0x36c,0x34b,0x36c,0x36c,0x36c,9,0x36c,9,0x36c,0x36c, +0x363,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696, +0x696,0x696,9,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x36c,0x36c,0x363,0x363,0x363,0x363, +0x363,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693, +0x693,0x693,0x360,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x363,0x363,0x363,0x363,0x363,0xf6f, +0x36f,0x36f,0x372,0x36c,0x36c,0x36f,0x366,0x9e1,0xb97,0xb94,0x369,0x9e1,0x369,0x9e1,0x369,0x9e1, +0x369,0x9e1,0x354,0x351,0x354,0x351,0x354,0x351,0x354,0x351,0x354,0x351,0x354,0x351,0x354,0x351, +0x36f,0x36f,0x366,0x360,0xb46,0xb43,0xb91,0xc93,0xc90,0xc96,0xc93,0xc90,0xd86,0xd89,0xd89,0xd89, +0x9f0,0x6a2,0x37e,0x381,0x37e,0x37e,0x37e,0x381,0x37e,0x37e,0x37e,0x37e,0x381,0x9f0,0x381,0x37e, +0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x6a2,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f, +0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f, +0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x69c,0x699,0x699,0x699,0x699,0x699,0x699, +0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x9ea,0x69c,0x378,0x37b, +0x378,0x378,0x378,0x37b,0x378,0x378,0x378,0x378,0x37b,0x9ea,0x37b,0x378,0x37e,0x378,0x37e,0x378, 0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378, +0x37e,0x378,0x381,0x37b,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x375,0x939, +0x93c,0x91e,0x91e,0x111c,0x9e4,0x9e4,0xb9d,0xb9a,0x9ed,0x9e7,0x9ed,0x9e7,0x37e,0x378,0x37e,0x378, 0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378, -0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x381,0x37b,0x37e,0x378,0xb9a,0xb97,0x37e, -0x378,0xb9a,0xb97,0x37e,0x378,0xb9a,0xb97,0xec7,0x381,0x37b,0x381,0x37b,0x37e,0x378,0x381,0x37b, -0x37e,0x378,0x381,0x37b,0x381,0x37b,0x381,0x37b,0x37e,0x378,0x381,0x37b,0x381,0x37b,0x381,0x37b, -0x37e,0x378,0x381,0x37b,0x9f0,0x9ea,0x381,0x37b,0x381,0x37b,0x381,0x37b,0x381,0x37b,0xd8c,0xd89, -0x381,0x37b,0xeca,0xec7,0xeca,0xec7,0xeca,0xec7,0xc00,0xbfd,0xc00,0xbfd,0xc00,0xbfd,0xc00,0xbfd, -0xc00,0xbfd,0xc00,0xbfd,0xc00,0xbfd,0xc00,0xbfd,0xef7,0xef4,0xef7,0xef4,0xfe7,0xfe4,0xfe7,0xfe4, -0xfe7,0xfe4,0xfe7,0xfe4,0xfe7,0xfe4,0xfe7,0xfe4,0xfe7,0xfe4,0xfe7,0xfe4,0x114f,0x114c,0x1329,0x1326, -0x14e5,0x14e2,0x14e5,0x14e2,0x14e5,0x14e2,0x14e5,0x14e2,0xc,0x393,0x393,0x393,0x393,0x393,0x393,0x393, +0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378, +0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x381,0x37b,0x37e, +0x378,0xb9d,0xb9a,0x37e,0x378,0xb9d,0xb9a,0x37e,0x378,0xb9d,0xb9a,0xeca,0x381,0x37b,0x381,0x37b, +0x37e,0x378,0x381,0x37b,0x37e,0x378,0x381,0x37b,0x381,0x37b,0x381,0x37b,0x37e,0x378,0x381,0x37b, +0x381,0x37b,0x381,0x37b,0x37e,0x378,0x381,0x37b,0x9f0,0x9ea,0x381,0x37b,0x381,0x37b,0x381,0x37b, +0x381,0x37b,0xd8f,0xd8c,0x381,0x37b,0xecd,0xeca,0xecd,0xeca,0xecd,0xeca,0xc03,0xc00,0xc03,0xc00, +0xc03,0xc00,0xc03,0xc00,0xc03,0xc00,0xc03,0xc00,0xc03,0xc00,0xc03,0xc00,0xefa,0xef7,0xefa,0xef7, +0xfea,0xfe7,0xfea,0xfe7,0xfea,0xfe7,0xfea,0xfe7,0xfea,0xfe7,0xfea,0xfe7,0xfea,0xfe7,0xfea,0xfe7, +0x1155,0x1152,0x132f,0x132c,0x14ee,0x14eb,0x14ee,0x14eb,0x14ee,0x14eb,0x14ee,0x14eb,0xc,0x393,0x393,0x393, 0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393, -0x393,0x393,0x393,0xc,0xc,0x396,0x384,0x384,0x384,0x38a,0x384,0x387,0x18ea,0x38d,0x38d,0x38d, +0x393,0x393,0x393,0x393,0x393,0x393,0x393,0xc,0xc,0x396,0x384,0x384,0x384,0x38a,0x384,0x387, +0x18f9,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d, 0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d, -0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x390, -0x18ea,0x399,0x9f3,0xc,0xc,0x14b2,0x14b2,0x13ce,0xf,0x960,0x960,0x960,0x960,0x960,0x960,0x960, -0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0xd8f,0x960,0x960,0x960,0x960,0x960, -0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x39c,0x39c,0x39c,0x39c,0x39c,0x39c,0x39c,0x39c, -0x39c,0x39c,0xecd,0x39c,0x39c,0x39c,0x3a8,0x39c,0x39f,0x39c,0x39c,0x3ab,0x963,0xd92,0xd95,0xd92, -0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae, +0x38d,0x38d,0x38d,0x390,0x18f9,0x399,0x9f3,0xc,0xc,0x14bb,0x14bb,0x13d7,0xf,0x960,0x960,0x960, +0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0xd92,0x960, +0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x39c,0x39c,0x39c,0x39c, +0x39c,0x39c,0x39c,0x39c,0x39c,0x39c,0xed0,0x39c,0x39c,0x39c,0x3a8,0x39c,0x39f,0x39c,0x39c,0x3ab, +0x963,0xd95,0xd98,0xd95,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x3ae,0x3ae,0x3ae,0x3ae, 0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae, -0x3ae,0x3ae,0x3ae,0xf,0xf,0xf,0xf,0x18ed,0x3ae,0x3ae,0x3ae,0x3a5,0x3a2,0xf,0xf,0xf, -0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xca8,0xca8,0xca8,0xca8,0x13d1,0x14b5,0xf75,0xf75, -0xf75,0xf72,0xf72,0xd9b,0x8a6,0xca2,0xc9f,0xc9f,0xc96,0xc96,0xc96,0xc96,0xc96,0xc96,0xf6f,0xf6f, -0xf6f,0xf6f,0xf6f,0x8a3,0x14ac,0x1afd,0xd9e,0x8a9,0x12f0,0x3c9,0x3cc,0x3cc,0x3cc,0x3cc,0x3cc,0x3c9, +0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0xf,0xf,0xf,0xf,0x18fc,0x3ae,0x3ae,0x3ae,0x3a5, +0x3a2,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xcab,0xcab,0xcab,0xcab, +0x13da,0x14be,0xf78,0xf78,0xf78,0xf75,0xf75,0xd9e,0x8a6,0xca5,0xca2,0xca2,0xc99,0xc99,0xc99,0xc99, +0xc99,0xc99,0xf72,0xf72,0xf72,0xf72,0xf72,0x8a3,0x14b5,0x1b0f,0xda1,0x8a9,0x12f6,0x3c9,0x3cc,0x3cc, +0x3cc,0x3cc,0x3cc,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9, +0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0xf7b,0xf7b,0xf7b,0xf7b,0xf7b,0x8ac,0x3c9,0x3c9,0x3c9, +0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x924,0x924,0x924,0x924,0x924,0x924,0x924,0x924,0xb3d, +0xb3d,0xb3d,0xc99,0xc9f,0xc9c,0xd9b,0xd9b,0xd9b,0xd9b,0xd9b,0xd9b,0x12f3,0x93f,0x93f,0x93f,0x93f, +0x93f,0x93f,0x93f,0x93f,0x93f,0x93f,0x3c3,0x3c0,0x3bd,0x3ba,0xba0,0xba0,0x921,0x3c9,0x3c9,0x3d5, +0x3c9,0x3cf,0x3cf,0x3cf,0x3cf,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9, 0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9, -0x3c9,0x3c9,0x3c9,0xf78,0xf78,0xf78,0xf78,0xf78,0x8ac,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9, -0x3c9,0x3c9,0x3c9,0x924,0x924,0x924,0x924,0x924,0x924,0x924,0x924,0xb3a,0xb3a,0xb3a,0xc96,0xc9c, -0xc99,0xd98,0xd98,0xd98,0xd98,0xd98,0xd98,0x12ed,0x93f,0x93f,0x93f,0x93f,0x93f,0x93f,0x93f,0x93f, -0x93f,0x93f,0x3c3,0x3c0,0x3bd,0x3ba,0xb9d,0xb9d,0x921,0x3c9,0x3c9,0x3d5,0x3c9,0x3cf,0x3cf,0x3cf, -0x3cf,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9, 0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9, 0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9, -0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x9f9,0x9f9,0x3c9,0x3c9, -0x3c9,0x3c9,0x3c9,0x9f9,0x3cc,0x3c9,0x3cc,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9, -0x3c9,0x3c9,0x3c9,0x9f9,0x3c9,0x3c9,0x3c9,0x3cc,0x942,0x3c9,0x3b4,0x3b4,0x3b4,0x3b4,0x3b4,0x3b4, -0x3b4,0x3b1,0x3ba,0x3b7,0x3b7,0x3b4,0x3b4,0x3b4,0x3b4,0x3d2,0x3d2,0x3b4,0x3b4,0x3ba,0x3b7,0x3b7, -0x3b7,0x3b4,0xca5,0xca5,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x9f9,0x9f9, -0x9f9,0x9f6,0x9f6,0xca5,0xa0e,0xa0e,0xa0e,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa05, -0xa08,0xa05,0x12,0xa11,0xa0b,0x9fc,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b, +0x9f9,0x9f9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x9f9,0x3cc,0x3c9,0x3cc,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9, +0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x9f9,0x3c9,0x3c9,0x3c9,0x3cc,0x942,0x3c9,0x3b4,0x3b4, +0x3b4,0x3b4,0x3b4,0x3b4,0x3b4,0x3b1,0x3ba,0x3b7,0x3b7,0x3b4,0x3b4,0x3b4,0x3b4,0x3d2,0x3d2,0x3b4, +0x3b4,0x3ba,0x3b7,0x3b7,0x3b7,0x3b4,0xca8,0xca8,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6, +0x3c6,0x3c6,0x9f9,0x9f9,0x9f9,0x9f6,0x9f6,0xca8,0xa0e,0xa0e,0xa0e,0xa08,0xa08,0xa08,0xa08,0xa08, +0xa08,0xa08,0xa08,0xa05,0xa08,0xa05,0x12,0xa11,0xa0b,0x9fc,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b, 0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b, -0xa0b,0xcab,0xcab,0xcab,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02, -0xa02,0xa02,0xa02,0xa02,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x12, -0x12,0xcab,0xcab,0xcab,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb, -0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb, -0xdfb,0xdfb,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9, -0xff9,0xff9,0xff9,0xff9,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17, +0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xcae,0xcae,0xcae,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02, +0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff, +0x9ff,0x9ff,0x9ff,0x12,0x12,0xcae,0xcae,0xcae,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe, +0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe, +0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc, +0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17, 0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17, -0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14, -0xa14,0xa14,0xa14,0xa14,0xa14,0xba0,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, -0x15,0x15,0x15,0x15,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf12,0xf12, -0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12, -0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf06, -0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf15,0xf15,0xf09,0xf09,0xf0c,0xf1b,0xf18,0x102, -0x102,0x1911,0x1914,0x1914,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0xb13,0xb13,0xb16,0xb16,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13, -0x6f,0x6f,0x6f,0x6f,0x1e0,0x1e0,0x1e0,0x1e0,0x1e0,0x1e0,0x1e0,0x1617,0x1617,0x1617,0x1617,0x1617, -0x1617,0x1617,0x1617,0x1617,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1650,0x1650,0x1650, -0x1650,0x1650,0x1650,0x1650,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x16b,0x16b,0x16b, -0x16b,0x16b,0x16b,0x16b,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1bdb,0x1bd8,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2, -0x1c2,0x1c2,0x1c2,0x1c2,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1a7,0x1a7, -0x1a7,0x1a7,0x1a7,0x1a7,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x201,0x201,0x201,0x201,0x201, -0x201,0x201,0x201,0x201,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x249,0x249,0x249,0x249,0x249,0x249,0x249,0x249,0x249,0x249,0x249,0x249, -0x249,0x249,0x249,0x249,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x195f,0x195f,0x195f,0x195f,0x195f,0x195f,0x195f,0x195f,0x195f,0x195f,0x24f,0x24f, -0x24f,0x24f,0x24f,0x24f,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1ac1,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b, -0x28b,0x28b,0x28b,0x28b,0x1752,0x1752,0x1752,0x1752,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207, -0x207,0x207,0x207,0x207,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c, -0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e, -0x163e,0x163e,0x163e,0x163e,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1bc3,0x1bc3,0x1bc3,0x1bc3,0x2a0,0x1bc3,0x1bc3,0x1bc3,0x1bc3,0x1bc3,0x1bc3,0x1bc3, -0x2a0,0x1bc3,0x1bc3,0x2a0,0x16b6,0x16b6,0x16b6,0x16b6,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef, -0x1ef,0x1ef,0x1ef,0x1ef,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5, -0x2b5,0x2b5,0x2b5,0x2b5,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0xdf2,0xdf2,0xdef,0xdef,0xdef,0xdf2,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5, -0xd5,0xd5,0xd5,0xd5,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x213,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a, -0x176a,0x176a,0x176a,0x176a,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb, -0x2bb,0x2bb,0x2bb,0x1bf6,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1a13,0x1a13,0x1a13,0x1a13,0x1a13,0x1a13,0x1a13,0x1a13,0x1a13,0x1a13,0x270,0x270, -0x270,0x270,0x1a16,0x1a10,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93, -0x1b93,0x1b93,0x1b93,0x1b93,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26, -0x1c26,0x1c26,0x1c26,0x1c26,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0x255,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974, -0x1974,0x1974,0x1974,0x1974,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273, -0x273,0x273,0x273,0x273,0,0,0,0,0,0,0,0,0,0,0,0, +0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa14,0xa14, +0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xba3,0x15,0x15,0x15,0x15,0x15,0x15, +0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12, +0xf12,0xf12,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15, +0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15,0xf15, +0xf15,0xf15,0xf15,0xf09,0xf09,0xf09,0xf09,0xf09,0xf09,0xf09,0xf09,0xf09,0xf18,0xf18,0xf0c,0xf0c, +0xf0f,0xf1e,0xf1b,0xff,0xff,0x1920,0x1923,0x1923,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0xb16,0xb16,0xb19,0xb19,0xb16,0xb16,0xb16,0xb16, +0xb16,0xb16,0xb16,0xb16,0x1c53,0x1c53,0x1c50,0x1c50,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1626, +0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9, +0x1e9,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248, +0x1248,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1bed,0x1bea,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf, +0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491, +0x1491,0x1491,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1fe, +0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x246,0x246,0x246,0x246,0x246,0x246,0x246,0x246, +0x246,0x246,0x246,0x246,0x246,0x246,0x246,0x246,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e, +0x196e,0x196e,0x24c,0x24c,0x24c,0x24c,0x24c,0x24c,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1ad3,0x288,0x288,0x288,0x288,0x288,0x288,0x288, +0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x1761,0x1761,0x1761,0x1761,0x204,0x204,0x204,0x204, +0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e, +0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d, +0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1bd5,0x1bd5,0x1bd5,0x1bd5,0x29d,0x1bd5,0x1bd5,0x1bd5, +0x1bd5,0x1bd5,0x1bd5,0x1bd5,0x29d,0x1bd5,0x1bd5,0x29d,0x16c5,0x16c5,0x16c5,0x16c5,0x1ec,0x1ec,0x1ec,0x1ec, +0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x2b2,0x2b2,0x2b2,0x2b2, +0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0xdf5,0xdf5,0xdf2,0xdf2,0xdf2,0xdf5,0xd2,0xd2, +0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x210,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779, +0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8, +0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x1c08,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1a25,0x1a25,0x1a25,0x1a25,0x1a25,0x1a25,0x1a25,0x1a25, +0x1a25,0x1a25,0x26d,0x26d,0x26d,0x26d,0x1a28,0x1a22,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5, +0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38, +0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x252,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983, +0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x270, +0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x270,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0x95d,0x95d,3,3,3,3,3,3,3,3,3,3,3,3, +0,0,0,0,0,0,0x95d,0x95d,3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, -3,3,3,3,3,3,0x95d,0x95d,6,6,6,6,6,6,6,6, +3,3,3,3,3,3,3,3,3,3,0x95d,0x95d,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, -6,6,6,6,6,6,6,6,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50, -0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,6,6,6,6,6,6,6,6, -6,6,6,6,6,6,6,6,0x14bb,0x3f0,0x3ff,0x3ff,0x18,0x405,0x405,0x405, -0x405,0x405,0x405,0x405,0x405,0x18,0x18,0x405,0x405,0x18,0x18,0x405,0x405,0x405,0x405,0x405, -0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x18,0x405,0x405,0x405,0x405,0x405,0x405, -0x405,0x18,0x405,0x18,0x18,0x18,0x405,0x405,0x405,0x405,0x18,0x18,0x3f3,0xcb1,0x3f0,0x3ff, -0x3ff,0x3f0,0x3f0,0x3f0,0x3f0,0x18,0x18,0x3ff,0x3ff,0x18,0x18,0x402,0x402,0x3f6,0xda4,0x18, -0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3f0,0x18,0x18,0x18,0x18,0x408,0x408,0x18,0x408, -0x405,0x405,0x3f0,0x3f0,0x18,0x18,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948, -0x405,0x405,0x3fc,0x3fc,0x3f9,0x3f9,0x3f9,0x3f9,0x3f9,0x3fc,0x3f9,0x1125,0x184b,0x1848,0x18f0,0x18, -0x1b,0xcb4,0x40b,0xcb7,0x1b,0x417,0x417,0x417,0x417,0x417,0x417,0x1b,0x1b,0x1b,0x1b,0x417, -0x417,0x1b,0x1b,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417, -0x417,0x1b,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x1b,0x417,0x41a,0x1b,0x417,0x41a,0x1b, -0x417,0x417,0x1b,0x1b,0x40e,0x1b,0x414,0x414,0x414,0x40b,0x40b,0x1b,0x1b,0x1b,0x1b,0x40b, -0x40b,0x1b,0x1b,0x40b,0x40b,0x411,0x1b,0x1b,0x1b,0xf81,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, -0x1b,0x41a,0x41a,0x41a,0x417,0x1b,0x41a,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x94b,0x94b, -0x94b,0x94b,0x94b,0x94b,0x94b,0x94b,0x94b,0x94b,0x40b,0x40b,0x417,0x417,0x417,0xf81,0x18f3,0x1b, -0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1e,0x41d,0x41d,0x426,0x1e,0x429,0x429,0x429, -0x429,0x429,0x429,0x429,0xcc0,0x429,0x1e,0x429,0x429,0x429,0x1e,0x429,0x429,0x429,0x429,0x429, -0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x1e,0x429,0x429,0x429,0x429,0x429,0x429, -0x429,0x1e,0x429,0x429,0x1e,0x429,0x429,0x429,0x429,0x429,0x1e,0x1e,0x420,0x429,0x426,0x426, -0x426,0x41d,0x41d,0x41d,0x41d,0x41d,0x1e,0x41d,0x41d,0x426,0x1e,0x426,0x426,0x423,0x1e,0x1e, -0x429,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, -0x429,0xcc0,0xcba,0xcba,0x1e,0x1e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e, -0x13d4,0xcbd,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x16cb,0x184e,0x184e,0x184e,0x1851,0x1851,0x1851, -0x21,0x42c,0x43b,0x43b,0x21,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x21,0x21,0x441, -0x441,0x21,0x21,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441, -0x441,0x21,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x21,0x441,0x441,0x21,0xcc3,0x441,0x441, -0x441,0x441,0x21,0x21,0x42f,0x441,0x42c,0x42c,0x43b,0x42c,0x42c,0x42c,0xf84,0x21,0x21,0x43b, -0x43e,0x21,0x21,0x43e,0x43e,0x432,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x1a5b,0x42c,0x42c, -0x21,0x21,0x21,0x21,0x444,0x444,0x21,0x441,0x441,0x441,0xf84,0xf84,0x21,0x21,0x438,0x438, -0x438,0x438,0x438,0x438,0x438,0x438,0x438,0x438,0x435,0xcc3,0x12fc,0x12fc,0x12fc,0x12fc,0x12fc,0x12fc, -0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x24,0x24,0x447,0x453,0x24,0x453,0x453,0x453, -0x453,0x453,0x453,0x24,0x24,0x24,0x453,0x453,0x453,0x24,0x453,0x453,0x456,0x453,0x24,0x24, -0x24,0x453,0x453,0x24,0x453,0x24,0x453,0x453,0x24,0x24,0x24,0x453,0x453,0x24,0x24,0x24, -0x453,0x453,0x453,0x24,0x24,0x24,0x453,0x453,0x453,0x453,0x453,0x453,0x453,0x453,0xda7,0x453, -0x453,0x453,0x24,0x24,0x24,0x24,0x447,0x44d,0x447,0x44d,0x44d,0x24,0x24,0x24,0x44d,0x44d, -0x44d,0x24,0x450,0x450,0x450,0x44a,0x24,0x24,0xf87,0x24,0x24,0x24,0x24,0x24,0x24,0x447, -0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0xebb,0x954,0x954,0x954,0x954,0x954, -0x954,0x954,0x954,0x954,0x951,0x951,0x951,0xd77,0xcc6,0xcc6,0xcc6,0xcc6,0xcc6,0xcc9,0xcc6,0x24, -0x24,0x24,0x24,0x24,0x14be,0x465,0x465,0x465,0x18f6,0x468,0x468,0x468,0x468,0x468,0x468,0x468, -0x468,0x27,0x468,0x468,0x468,0x27,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468, -0x468,0x468,0x468,0x468,0x468,0x27,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468, -0x14c1,0x468,0x468,0x468,0x468,0x468,0x27,0x27,0x1b00,0xf90,0x459,0x459,0x459,0x465,0x465,0x465, -0x465,0x27,0x459,0x459,0x45c,0x27,0x459,0x459,0x459,0x45f,0x27,0x27,0x27,0x27,0x27,0x27, -0x27,0x459,0x459,0x27,0xf90,0xf90,0x16ce,0x27,0x27,0x1b03,0x27,0x27,0x468,0x468,0xf8a,0xf8a, -0x27,0x27,0x462,0x462,0x462,0x462,0x462,0x462,0x462,0x462,0x462,0x462,0x27,0x27,0x27,0x27, -0x27,0x27,0x27,0x19bf,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0x178e,0x14c4,0x471,0x471, -0x18f9,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x2a,0x477,0x477,0x477,0x2a,0x477,0x477, -0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x2a,0x477,0x477, -0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x2a,0x477,0x477,0x477,0x477,0x477,0x2a,0x2a, -0xccc,0xccf,0x471,0x46b,0x474,0x471,0x46b,0x471,0x471,0x2a,0x46b,0x474,0x474,0x2a,0x474,0x474, -0x46b,0x46e,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x46b,0x46b,0x2a,0x2a,0x2a,0x2a,0x2a, -0x2a,0x1b06,0x477,0x2a,0x477,0x477,0xed3,0xed3,0x2a,0x2a,0x957,0x957,0x957,0x957,0x957,0x957, -0x957,0x957,0x957,0x957,0x2a,0xed6,0xed6,0x1bc9,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a, -0x2a,0x2a,0x2a,0x2a,0x1854,0x14c7,0x483,0x483,0x1a5e,0x489,0x489,0x489,0x489,0x489,0x489,0x489, -0x489,0x2d,0x489,0x489,0x489,0x2d,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489, -0x489,0x489,0x489,0x489,0x483,0x47a,0x47a,0x47a,0xf93,0x2d,0x483,0x483,0x483,0x2d,0x486,0x486, -0x486,0x47d,0x1302,0x1791,0x2d,0x2d,0x2d,0x2d,0x1794,0x1794,0x1794,0x47a,0x1791,0x1791,0x1791,0x1791, -0x1791,0x1791,0x1791,0x16d1,0x489,0x489,0xf93,0xf93,0x2d,0x2d,0x480,0x480,0x480,0x480,0x480,0x480, -0x480,0x480,0x480,0x480,0xf96,0xf96,0xf96,0xf96,0xf96,0xf96,0x1791,0x1791,0x1791,0xf99,0xf9c,0xf9c, -0xf9c,0xf9c,0xf9c,0xf9c,0x30,0x1a61,0xa23,0xa23,0x30,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29, -0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0x30,0x30,0x30,0xa29,0xa29, -0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29, -0xa29,0xa29,0x30,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0x30,0xa29,0x30,0x30, -0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0x30,0x30,0x30,0xa1d,0x30,0x30,0x30,0x30,0xa1a, -0xa23,0xa23,0xa1a,0xa1a,0xa1a,0x30,0xa1a,0x30,0xa23,0xa23,0xa26,0xa23,0xa26,0xa26,0xa26,0xa1a, -0x30,0x30,0x30,0x30,0x30,0x30,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca, -0x30,0x30,0xa23,0xa23,0xa20,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, -0x33,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4, +6,6,6,6,6,6,6,6,6,6,6,6,0xd53,0xd53,0xd53,0xd53, +0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,6,6,6,6, +6,6,6,6,6,6,6,6,6,6,6,6,0x14c4,0x3f0,0x3ff,0x3ff, +0x18,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x18,0x18,0x405,0x405,0x18,0x18,0x405, +0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x18,0x405,0x405, +0x405,0x405,0x405,0x405,0x405,0x18,0x405,0x18,0x18,0x18,0x405,0x405,0x405,0x405,0x18,0x18, +0x3f3,0xcb4,0x3f0,0x3ff,0x3ff,0x3f0,0x3f0,0x3f0,0x3f0,0x18,0x18,0x3ff,0x3ff,0x18,0x18,0x402, +0x402,0x3f6,0xda7,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3f0,0x18,0x18,0x18,0x18, +0x408,0x408,0x18,0x408,0x405,0x405,0x3f0,0x3f0,0x18,0x18,0x948,0x948,0x948,0x948,0x948,0x948, +0x948,0x948,0x948,0x948,0x405,0x405,0x3fc,0x3fc,0x3f9,0x3f9,0x3f9,0x3f9,0x3f9,0x3fc,0x3f9,0x112b, +0x185a,0x1857,0x18ff,0x18,0x1b,0xcb7,0x40b,0xcba,0x1b,0x417,0x417,0x417,0x417,0x417,0x417,0x1b, +0x1b,0x1b,0x1b,0x417,0x417,0x1b,0x1b,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417, +0x417,0x417,0x417,0x417,0x417,0x1b,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x1b,0x417,0x41a, +0x1b,0x417,0x41a,0x1b,0x417,0x417,0x1b,0x1b,0x40e,0x1b,0x414,0x414,0x414,0x40b,0x40b,0x1b, +0x1b,0x1b,0x1b,0x40b,0x40b,0x1b,0x1b,0x40b,0x40b,0x411,0x1b,0x1b,0x1b,0xf84,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1b,0x1b,0x41a,0x41a,0x41a,0x417,0x1b,0x41a,0x1b,0x1b,0x1b,0x1b,0x1b, +0x1b,0x1b,0x94b,0x94b,0x94b,0x94b,0x94b,0x94b,0x94b,0x94b,0x94b,0x94b,0x40b,0x40b,0x417,0x417, +0x417,0xf84,0x1902,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1e,0x41d,0x41d,0x426, +0x1e,0x429,0x429,0x429,0x429,0x429,0x429,0x429,0xcc3,0x429,0x1e,0x429,0x429,0x429,0x1e,0x429, +0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x1e,0x429,0x429, +0x429,0x429,0x429,0x429,0x429,0x1e,0x429,0x429,0x1e,0x429,0x429,0x429,0x429,0x429,0x1e,0x1e, +0x420,0x429,0x426,0x426,0x426,0x41d,0x41d,0x41d,0x41d,0x41d,0x1e,0x41d,0x41d,0x426,0x1e,0x426, +0x426,0x423,0x1e,0x1e,0x429,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, +0x1e,0x1e,0x1e,0x1e,0x429,0xcc3,0xcbd,0xcbd,0x1e,0x1e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e, +0x94e,0x94e,0x94e,0x94e,0x13dd,0xcc0,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x16da,0x185d,0x185d, +0x185d,0x1860,0x1860,0x1860,0x21,0x42c,0x43b,0x43b,0x21,0x441,0x441,0x441,0x441,0x441,0x441,0x441, +0x441,0x21,0x21,0x441,0x441,0x21,0x21,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441, +0x441,0x441,0x441,0x441,0x441,0x21,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x21,0x441,0x441, +0x21,0xcc6,0x441,0x441,0x441,0x441,0x21,0x21,0x42f,0x441,0x42c,0x42c,0x43b,0x42c,0x42c,0x42c, +0xf87,0x21,0x21,0x43b,0x43e,0x21,0x21,0x43e,0x43e,0x432,0x21,0x21,0x21,0x21,0x21,0x21, +0x21,0x1a6d,0x42c,0x42c,0x21,0x21,0x21,0x21,0x444,0x444,0x21,0x441,0x441,0x441,0xf87,0xf87, +0x21,0x21,0x438,0x438,0x438,0x438,0x438,0x438,0x438,0x438,0x438,0x438,0x435,0xcc6,0x1302,0x1302, +0x1302,0x1302,0x1302,0x1302,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x24,0x24,0x447,0x453, +0x24,0x453,0x453,0x453,0x453,0x453,0x453,0x24,0x24,0x24,0x453,0x453,0x453,0x24,0x453,0x453, +0x456,0x453,0x24,0x24,0x24,0x453,0x453,0x24,0x453,0x24,0x453,0x453,0x24,0x24,0x24,0x453, +0x453,0x24,0x24,0x24,0x453,0x453,0x453,0x24,0x24,0x24,0x453,0x453,0x453,0x453,0x453,0x453, +0x453,0x453,0xdaa,0x453,0x453,0x453,0x24,0x24,0x24,0x24,0x447,0x44d,0x447,0x44d,0x44d,0x24, +0x24,0x24,0x44d,0x44d,0x44d,0x24,0x450,0x450,0x450,0x44a,0x24,0x24,0xf8a,0x24,0x24,0x24, +0x24,0x24,0x24,0x447,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0xebe,0x954, +0x954,0x954,0x954,0x954,0x954,0x954,0x954,0x954,0x951,0x951,0x951,0xd7a,0xcc9,0xcc9,0xcc9,0xcc9, +0xcc9,0xccc,0xcc9,0x24,0x24,0x24,0x24,0x24,0x14c7,0x465,0x465,0x465,0x1905,0x468,0x468,0x468, +0x468,0x468,0x468,0x468,0x468,0x27,0x468,0x468,0x468,0x27,0x468,0x468,0x468,0x468,0x468,0x468, +0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x27,0x468,0x468,0x468,0x468,0x468,0x468, +0x468,0x468,0x468,0x468,0x14ca,0x468,0x468,0x468,0x468,0x468,0x27,0x27,0x1b12,0xf93,0x459,0x459, +0x459,0x465,0x465,0x465,0x465,0x27,0x459,0x459,0x45c,0x27,0x459,0x459,0x459,0x45f,0x27,0x27, +0x27,0x27,0x27,0x27,0x27,0x459,0x459,0x27,0xf93,0xf93,0x16dd,0x27,0x27,0x1b15,0x27,0x27, +0x468,0x468,0xf8d,0xf8d,0x27,0x27,0x462,0x462,0x462,0x462,0x462,0x462,0x462,0x462,0x462,0x462, +0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x19d1,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90, +0x179d,0x14cd,0x471,0x471,0x1908,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x2a,0x477,0x477, +0x477,0x2a,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477, +0x477,0x2a,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x2a,0x477,0x477,0x477, +0x477,0x477,0x2a,0x2a,0xccf,0xcd2,0x471,0x46b,0x474,0x471,0x46b,0x471,0x471,0x2a,0x46b,0x474, +0x474,0x2a,0x474,0x474,0x46b,0x46e,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x46b,0x46b,0x2a, +0x2a,0x2a,0x2a,0x2a,0x2a,0x1b18,0x477,0x2a,0x477,0x477,0xed6,0xed6,0x2a,0x2a,0x957,0x957, +0x957,0x957,0x957,0x957,0x957,0x957,0x957,0x957,0x2a,0xed9,0xed9,0x1bdb,0x2a,0x2a,0x2a,0x2a, +0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x1863,0x14d0,0x483,0x483,0x1a70,0x489,0x489,0x489, +0x489,0x489,0x489,0x489,0x489,0x2d,0x489,0x489,0x489,0x2d,0x489,0x489,0x489,0x489,0x489,0x489, +0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x483,0x47a,0x47a,0x47a,0xf96,0x2d,0x483,0x483, +0x483,0x2d,0x486,0x486,0x486,0x47d,0x1308,0x17a0,0x2d,0x2d,0x2d,0x2d,0x17a3,0x17a3,0x17a3,0x47a, +0x17a0,0x17a0,0x17a0,0x17a0,0x17a0,0x17a0,0x17a0,0x16e0,0x489,0x489,0xf96,0xf96,0x2d,0x2d,0x480,0x480, +0x480,0x480,0x480,0x480,0x480,0x480,0x480,0x480,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0x17a0,0x17a0, +0x17a0,0xf9c,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0x30,0x1a73,0xa23,0xa23,0x30,0xa29,0xa29,0xa29, +0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0x30, +0x30,0x30,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29, +0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0x30,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29, +0x30,0xa29,0x30,0x30,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0x30,0x30,0x30,0xa1d,0x30, +0x30,0x30,0x30,0xa1a,0xa23,0xa23,0xa1a,0xa1a,0xa1a,0x30,0xa1a,0x30,0xa23,0xa23,0xa26,0xa23, +0xa26,0xa26,0xa26,0xa1a,0x30,0x30,0x30,0x30,0x30,0x30,0x14d3,0x14d3,0x14d3,0x14d3,0x14d3,0x14d3, +0x14d3,0x14d3,0x14d3,0x14d3,0x30,0x30,0xa23,0xa23,0xa20,0x30,0x30,0x30,0x30,0x30,0x30,0x30, +0x30,0x30,0x30,0x30,0x33,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4, 0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4, -0x4a4,0x48f,0x4a4,0x4a1,0x48f,0x48f,0x48f,0x48f,0x48f,0x48f,0x495,0x33,0x33,0x33,0x33,0x48c, -0x4aa,0x4aa,0x4aa,0x4aa,0x4aa,0x4a4,0x4a7,0x492,0x492,0x492,0x492,0x492,0x492,0x48f,0x492,0x498, -0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49b,0x49b,0x33,0x33,0x33,0x33, +0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x48f,0x4a4,0x4a1,0x48f,0x48f,0x48f,0x48f,0x48f,0x48f,0x495,0x33, +0x33,0x33,0x33,0x48c,0x4aa,0x4aa,0x4aa,0x4aa,0x4aa,0x4a4,0x4a7,0x492,0x492,0x492,0x492,0x492, +0x492,0x48f,0x492,0x498,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49b,0x49b, 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, -0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x4b9,0x4b9,0x36, -0x4b9,0x36,0x19c5,0x4b9,0x4b9,0x19c5,0x4b9,0x36,0x19c5,0x4b9,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5, -0x4b9,0x4b9,0x4b9,0x4b9,0x19c5,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x19c5,0x4b9,0x4b9,0x4b9, -0x36,0x4b9,0x36,0x4b9,0x19c5,0x19c5,0x4b9,0x4b9,0x19c5,0x4b9,0x4b9,0x4b9,0x4b9,0x4ad,0x4b9,0x4b6, -0x4ad,0x4ad,0x4ad,0x4ad,0x4ad,0x4ad,0x19c2,0x4ad,0x4ad,0x4b9,0x36,0x36,0x4c2,0x4c2,0x4c2,0x4c2, -0x4c2,0x36,0x4bf,0x36,0x4b0,0x4b0,0x4b0,0x4b0,0x4b0,0x4ad,0x1bcc,0x36,0x4b3,0x4b3,0x4b3,0x4b3, -0x4b3,0x4b3,0x4b3,0x4b3,0x4b3,0x4b3,0x36,0x36,0x4bc,0x4bc,0x13d7,0x13d7,0x36,0x36,0x36,0x36, +0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, +0x36,0x4b9,0x4b9,0x36,0x4b9,0x36,0x19d7,0x4b9,0x4b9,0x19d7,0x4b9,0x36,0x19d7,0x4b9,0x19d7,0x19d7, +0x19d7,0x19d7,0x19d7,0x19d7,0x4b9,0x4b9,0x4b9,0x4b9,0x19d7,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9, +0x19d7,0x4b9,0x4b9,0x4b9,0x36,0x4b9,0x36,0x4b9,0x19d7,0x19d7,0x4b9,0x4b9,0x19d7,0x4b9,0x4b9,0x4b9, +0x4b9,0x4ad,0x4b9,0x4b6,0x4ad,0x4ad,0x4ad,0x4ad,0x4ad,0x4ad,0x19d4,0x4ad,0x4ad,0x4b9,0x36,0x36, +0x4c2,0x4c2,0x4c2,0x4c2,0x4c2,0x36,0x4bf,0x36,0x4b0,0x4b0,0x4b0,0x4b0,0x4b0,0x4ad,0x1bde,0x36, +0x4b3,0x4b3,0x4b3,0x4b3,0x4b3,0x4b3,0x4b3,0x4b3,0x4b3,0x4b3,0x36,0x36,0x4bc,0x4bc,0x13e0,0x13e0, +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, -0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x99c,0x99c,0x99c,0x99f, -0x99c,0x99c,0x99c,0x99c,0x39,0x99c,0x99c,0x99c,0x99c,0x99f,0x99c,0x99c,0x99c,0x99c,0x99f,0x99c, -0x99c,0x99c,0x99c,0x99f,0x99c,0x99c,0x99c,0x99c,0x99f,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c, -0x99c,0x99c,0x99c,0x99c,0x99c,0x99f,0xa38,0xfa8,0xfa8,0x39,0x39,0x39,0x39,0x966,0x966,0x969, -0x966,0x969,0x969,0x975,0x969,0x975,0x966,0x966,0x966,0x966,0x966,0x996,0x966,0x969,0x96f,0x96f, -0x972,0x97b,0x96c,0x96c,0x99c,0x99c,0x99c,0x99c,0x130b,0x1305,0x1305,0x1305,0x966,0x966,0x966,0x969, -0x966,0x966,0xa2c,0x966,0x39,0x966,0x966,0x966,0x966,0x969,0x966,0x966,0x966,0x966,0x969,0x966, -0x966,0x966,0x966,0x969,0x966,0x966,0x966,0x966,0x969,0x966,0xa2c,0xa2c,0xa2c,0x966,0x966,0x966, -0x966,0x966,0x966,0x966,0xa2c,0x969,0xa2c,0xa2c,0xa2c,0x39,0xa35,0xa35,0xa32,0xa32,0xa32,0xa32, -0xa32,0xa32,0xa2f,0xa32,0xa32,0xa32,0xa32,0xa32,0xa32,0x39,0xf9f,0xa32,0xdaa,0xdaa,0xfa2,0xfa5, -0xf9f,0x1128,0x1128,0x1128,0x1128,0x1308,0x1308,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39, +0x99c,0x99c,0x99c,0x99f,0x99c,0x99c,0x99c,0x99c,0x39,0x99c,0x99c,0x99c,0x99c,0x99f,0x99c,0x99c, +0x99c,0x99c,0x99f,0x99c,0x99c,0x99c,0x99c,0x99f,0x99c,0x99c,0x99c,0x99c,0x99f,0x99c,0x99c,0x99c, +0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99f,0xa38,0xfab,0xfab,0x39,0x39,0x39, +0x39,0x966,0x966,0x969,0x966,0x969,0x969,0x975,0x969,0x975,0x966,0x966,0x966,0x966,0x966,0x996, +0x966,0x969,0x96f,0x96f,0x972,0x97b,0x96c,0x96c,0x99c,0x99c,0x99c,0x99c,0x1311,0x130b,0x130b,0x130b, +0x966,0x966,0x966,0x969,0x966,0x966,0xa2c,0x966,0x39,0x966,0x966,0x966,0x966,0x969,0x966,0x966, +0x966,0x966,0x969,0x966,0x966,0x966,0x966,0x969,0x966,0x966,0x966,0x966,0x969,0x966,0xa2c,0xa2c, +0xa2c,0x966,0x966,0x966,0x966,0x966,0x966,0x966,0xa2c,0x969,0xa2c,0xa2c,0xa2c,0x39,0xa35,0xa35, +0xa32,0xa32,0xa32,0xa32,0xa32,0xa32,0xa2f,0xa32,0xa32,0xa32,0xa32,0xa32,0xa32,0x39,0xfa2,0xa32, +0xdad,0xdad,0xfa5,0xfa8,0xfa2,0x112e,0x112e,0x112e,0x112e,0x130e,0x130e,0x39,0x39,0x39,0x39,0x39, 0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39, -0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x3c,0x13dd, -0x3c,0x3c,0x3c,0x3c,0x3c,0x13dd,0x3c,0x3c,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5, -0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdb9, +0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x4c8,0x4c8,0x4c8,0x4c8, +0x4c8,0x4c8,0x3c,0x13e6,0x3c,0x3c,0x3c,0x3c,0x3c,0x13e6,0x3c,0x3c,0x4c5,0x4c5,0x4c5,0x4c5, +0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0xa62,0xa62,0xa62,0xa62, +0xa62,0xa62,0xa62,0xdbc,0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62, +0xa62,0xa62,0xa62,0x3f,0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62, +0xa62,0xa62,0xa62,0xdbc,0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62, +0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdbc, 0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0x3f, -0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdb9, -0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62, -0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdb9,0xa62,0x3f,0xa62,0xa62, -0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0x3f,0xa62,0x3f,0xa62,0xa62, -0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdb9,0xa62,0xa62,0xa62,0xa62, -0xa62,0xa62,0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62, -0xa62,0xa62,0xa62,0xdb9,0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62, -0xa62,0xa62,0xa62,0xdb9,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62, -0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0x130e,0x130e,0xdb3,0xdb6,0xa5c,0xa65,0xa59, -0xa59,0xa59,0xa59,0xa65,0xa65,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f,0xa56,0xa56, -0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0x3f,0x3f,0x3f,0xa68,0xa68,0xa68,0xa68, +0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdbc, +0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62, +0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdbc,0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f, +0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdbc,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62, +0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0x1314,0x1314,0xdb6, +0xdb9,0xa5c,0xa65,0xa59,0xa59,0xa59,0xa59,0xa65,0xa65,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f, +0xa5f,0xa5f,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0x3f,0x3f,0x3f, 0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68, -0xa68,0x16d7,0x42,0x42,0x16d4,0x16d4,0x16d4,0x16d4,0x16d4,0x16d4,0x42,0x42,0xa7a,0xa7d,0xa7d,0xa7d, -0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d, -0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa77,0xa74,0x45,0x45,0x45,0xa83,0xa83,0xa83,0xa83, -0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa80,0xa80,0xa80,0xa83,0xa83,0xa83,0x14cd,0x14cd,0x14cd, -0x14cd,0x14cd,0x14cd,0x14cd,0x14cd,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0xaa4,0xaa4,0xaa4,0xaa4, -0xaa4,0xaa4,0xa86,0xaa4,0xaa4,0xa89,0xa89,0xa89,0xa89,0xa89,0xa89,0xa89,0xa89,0xa89,0xa8c,0xa89, -0xa9b,0xa9b,0xa9e,0xaa7,0xa95,0xa92,0xa9b,0xa98,0xaa7,0xcd2,0x4b,0x4b,0xaa1,0xaa1,0xaa1,0xaa1, -0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0xcd5,0xcd5,0xcd5,0xcd5, -0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0xab6,0xab6,0xb2e,0xb31, -0xabc,0xb2b,0xab9,0xab6,0xabf,0xace,0xac2,0xad1,0xad1,0xad1,0xaad,0x1b09,0xac5,0xac5,0xac5,0xac5, -0xac5,0xac5,0xac5,0xac5,0xac5,0xac5,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0xac8,0xac8,0xac8,0xac8, -0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8, -0xac8,0xac8,0xac8,0xac8,0x18fc,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0xac8,0xac8,0xac8,0xac8, -0xac8,0xac8,0xac8,0xac8,0xac8,0xab0,0xfc6,0x4e,0x4e,0x4e,0x4e,0x4e,0x117f,0x117f,0x117f,0x117f, -0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x4e6,0x4e6,0x4e6,0x4e6, -0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e6,0x4e6,0x4e6,0x4e6, -0x4e6,0x4e6,0x51,0x51,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x51,0x51,0x4e6,0x4e6,0x4e6,0x4e6, -0x4e6,0x4e6,0x4e6,0x4e6,0x51,0x4e9,0x51,0x4e9,0x51,0x4e9,0x51,0x4e9,0x4e6,0x4e6,0x4e6,0x4e6, -0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e6,0x4e6,0x4e6,0x4e6, -0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x51,0x51,0x4e6,0x4e6,0x4e6,0x4e6, -0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e6,0x4e6,0x4e6,0x4e6, -0x4e6,0x51,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e0,0x4e6,0x4e0,0x4e0,0x4dd,0x4e6,0x4e6, -0x4e6,0x51,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4dd,0x4dd,0x4dd,0x4e6,0x4e6,0x4e6,0x4e6, -0x51,0x51,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x51,0x4dd,0x4dd,0x4dd,0x4e6,0x4e6,0x4e6,0x4e6, -0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4dd,0x4dd,0x4dd,0x51,0x51,0x4e6,0x4e6, -0x4e6,0x51,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e3,0x4e0,0x51,0xba6,0xba9,0xba9,0xba9, -0xfcf,0x54,0x14a9,0x14a9,0x14a9,0x14a9,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x53d,0xbbb,0x57,0x57, -0x6d8,0x53d,0x53d,0x53d,0x53d,0x53d,0x543,0x555,0x543,0x54f,0x549,0x6db,0x53a,0x6d5,0x6d5,0x6d5, -0x6d5,0x53a,0x53a,0x53a,0x53a,0x53a,0x540,0x552,0x540,0x54c,0x546,0x57,0xdc2,0xdc2,0xdc2,0xdc2, -0xdc2,0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x57,0x57,0x57,0x1b0c,0x5a,0x5a,0x5a, -0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x564,0x564,0x564,0x564, -0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x561,0x561,0x561,0x561,0x564,0xadd,0xadd, -0xbc1,0xbc7,0xbc7,0xbc4,0xbc4,0xbc4,0xbc4,0xdc8,0xed9,0xed9,0xed9,0xed9,0x1113,0x5d,0x5d,0x5d, -0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x594,0x594,0x594,0xae6, -0xee2,0xfd5,0xfd5,0xfd5,0xfd5,0x126f,0x16dd,0x16dd,0x60,0x60,0x60,0x60,0x702,0x702,0x702,0x702, -0x702,0x702,0x702,0x702,0x702,0x702,0x5a0,0x5a0,0x59d,0x59d,0x59d,0x59d,0x5c1,0x5c1,0x5c1,0x5c1, -0x5c1,0xaef,0xaef,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, -0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x5c4,0x5c4,0x5c4,0x5c4, -0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, -0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0xb0a,0xb0a,0xb0a,0xb0a, -0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a, -0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0x69,0xb0a,0xb0a,0xb0a,0xb0a,0xb0d,0xb0a,0xb0a,0xb0a,0xb0a, -0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0d, -0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0xb10,0xb10,0xb10,0xb10, -0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10, -0xb10,0xb10,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x72,0x822,0x81c,0x822, -0x81c,0x822,0x81c,0x822,0x81c,0x822,0x81c,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c, -0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81c,0x81c,0x81c,0x822, -0x81c,0x822,0x81c,0x822,0x81c,0x81c,0x81c,0x81c,0x81c,0x81c,0x822,0x81c,0x81c,0x81c,0x81c,0x81c, -0x81f,0xc60,0xc60,0x72,0x72,0x936,0x936,0x8fd,0x8fd,0x825,0x828,0xc5d,0x75,0x75,0x75,0x75, -0x75,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a, -0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x1101,0x18c3,0x19aa, -0x78,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d, -0x83d,0x83d,0x83d,0x78,0x906,0x906,0x909,0x909,0x909,0x909,0x909,0x909,0x909,0x909,0x909,0x909, -0x909,0x909,0x909,0x909,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846, +0xa68,0xa68,0xa68,0xa68,0xa68,0x16e6,0x42,0x42,0x16e3,0x16e3,0x16e3,0x16e3,0x16e3,0x16e3,0x42,0x42, +0xa7a,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d, +0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa77,0xa74,0x45,0x45,0x45, +0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa80,0xa80,0xa80,0xa83,0xa83, +0xa83,0x14d6,0x14d6,0x14d6,0x14d6,0x14d6,0x14d6,0x14d6,0x14d6,0x48,0x48,0x48,0x48,0x48,0x48,0x48, +0xaa4,0xaa4,0xaa4,0xaa4,0xaa4,0xaa4,0xa86,0xaa4,0xaa4,0xa89,0xa89,0xa89,0xa89,0xa89,0xa89,0xa89, +0xa89,0xa89,0xa8c,0xa89,0xaad,0xaad,0xa9e,0xaa7,0xa95,0xa92,0xa9b,0xa98,0xaa7,0xcd5,0x4b,0x4b, +0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, +0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, +0xab9,0xab9,0xb31,0xb34,0xabf,0xb2e,0xabc,0xab9,0xac2,0xad1,0xac5,0xad4,0xad4,0xad4,0xab0,0x1b1b, +0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, +0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb, +0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0x190b,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, +0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xab3,0xfc9,0x4e,0x4e,0x4e,0x4e,0x4e, +0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185, +0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9, +0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x51,0x51,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x51,0x51, +0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x51,0x4e9,0x51,0x4e9,0x51,0x4e9,0x51,0x4e9, +0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9, +0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x51,0x51, +0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9, +0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x51,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e0,0x4e6,0x4e0, +0x4e0,0x4dd,0x4e6,0x4e6,0x4e6,0x51,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4dd,0x4dd,0x4dd, +0x4e6,0x4e6,0x4e6,0x4e6,0x51,0x51,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x51,0x4dd,0x4dd,0x4dd, +0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4dd,0x4dd,0x4dd, +0x51,0x51,0x4e6,0x4e6,0x4e6,0x51,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e3,0x4e0,0x51, +0xba9,0xbac,0xbac,0xbac,0xfd2,0x54,0x14b2,0x14b2,0x14b2,0x14b2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2, +0x53d,0xbbe,0x57,0x57,0x6d8,0x53d,0x53d,0x53d,0x53d,0x53d,0x543,0x555,0x543,0x54f,0x549,0x6db, +0x53a,0x6d5,0x6d5,0x6d5,0x6d5,0x53a,0x53a,0x53a,0x53a,0x53a,0x540,0x552,0x540,0x54c,0x546,0x57, +0xdc5,0xdc5,0xdc5,0xdc5,0xdc5,0x1317,0x1317,0x1317,0x1317,0x1317,0x1317,0x1317,0x1317,0x57,0x57,0x57, +0x1b1e,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a, +0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x561,0x561,0x561, +0x561,0x564,0xae0,0xae0,0xbc4,0xbca,0xbca,0xbc7,0xbc7,0xbc7,0xbc7,0xdcb,0xedc,0xedc,0xedc,0xedc, +0x1119,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d, +0x594,0x594,0x594,0xae9,0xee5,0xfd8,0xfd8,0xfd8,0xfd8,0x1275,0x16ec,0x16ec,0x60,0x60,0x60,0x60, +0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x5a0,0x5a0,0x59d,0x59d,0x59d,0x59d, +0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0xaf2,0xaf2,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, +0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, +0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x66,0x66,0x66,0x66,0x66, +0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, +0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d, +0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0x69,0xb0d,0xb0d,0xb0d,0xb0d,0xb10, +0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d, +0xb0d,0xb0d,0xb0d,0xb10,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69, +0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13, +0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c, +0x6f,0x822,0x81c,0x822,0x81c,0x822,0x81c,0x822,0x81c,0x822,0x81c,0x81c,0x81f,0x81c,0x81f,0x81c, +0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c, +0x81c,0x81c,0x81c,0x822,0x81c,0x822,0x81c,0x822,0x81c,0x81c,0x81c,0x81c,0x81c,0x81c,0x822,0x81c, +0x81c,0x81c,0x81c,0x81c,0x81f,0xc63,0xc63,0x6f,0x6f,0x936,0x936,0x8fd,0x8fd,0x825,0x828,0xc60, +0x72,0x72,0x72,0x72,0x72,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a, +0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a, +0x83a,0x1107,0x18d2,0x19bc,0x75,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d, +0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x75,0x906,0x906,0x909,0x909,0x909,0x909,0x909,0x909, +0x909,0x909,0x909,0x909,0x909,0x909,0x909,0x909,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846, 0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846, -0x846,0xd5c,0xd5c,0x7b,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22, -0xb22,0x7e,0x7e,0x7e,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28, -0xb28,0xb28,0xb28,0xb28,0xb28,0xc69,0xb28,0xb28,0xb28,0xc69,0xb28,0x81,0x81,0x81,0x81,0x81, -0x81,0x81,0x81,0x81,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6, -0x11a6,0x11a6,0x11a6,0x11a6,0x9c0,0x9c0,0x9c0,0x9c0,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, -0x84,0x84,0x84,0x84,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b, -0x121b,0x121b,0x121b,0x121b,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x87,0x87,0x87,0x87,0x87, -0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x87,0x87,0x87,0x87, -0x87,0xafb,0x5fa,0x600,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x5fd,0x600,0x600, -0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x87,0x600,0x600,0x600,0x600, -0x600,0x87,0x600,0x87,0x600,0x600,0x87,0x600,0x600,0x87,0x600,0x600,0x600,0x600,0x600,0x600, -0x600,0x600,0x600,0x603,0x615,0x60f,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f, -0x612,0x618,0x615,0x60f,0x1323,0x1323,0x1b0f,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a, -0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x615,0x60f,0x612,0x618,0x615,0x60f,0x615,0x60f,0x615, -0x60f,0x615,0x615,0x60f,0x60f,0x60f,0x60f,0x612,0x60f,0x60f,0x612,0x60f,0x612,0x612,0x612,0x60f, -0x612,0x612,0x612,0x612,0x8a,0x8a,0x612,0x612,0x612,0x612,0x60f,0x60f,0x612,0x60f,0x60f,0x60f, -0x60f,0x612,0x60f,0x60f,0x60f,0x60f,0x60f,0x612,0x612,0x612,0x60f,0x60f,0x8a,0x8a,0x8a,0x8a, -0x8a,0x8a,0x8a,0x1b0f,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46, -0xb46,0xb46,0xb46,0xb46,0x85e,0x870,0x86d,0x870,0x86d,0xc7e,0xc7e,0xd68,0xd65,0x861,0x861,0x861, -0x861,0x873,0x873,0x873,0x88b,0x88e,0x89d,0x8d,0x891,0x894,0x8a0,0x8a0,0x888,0x87f,0x879,0x87f, -0x879,0x87f,0x879,0x87c,0x87c,0x897,0x897,0x89a,0x897,0x897,0x897,0x8d,0x897,0x885,0x882,0x87c, -0x8d,0x8d,0x8d,0x8d,0x621,0x62d,0x621,0xbfa,0x621,0x90,0x621,0x62d,0x621,0x62d,0x621,0x62d, -0x621,0x62d,0x621,0x62d,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627, -0x62d,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x62a, -0x624,0x90,0x90,0x61e,0x75f,0x762,0x777,0x77a,0x759,0x762,0x762,0x96,0x741,0x744,0x744,0x744, -0x744,0x741,0x741,0x96,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0xafe,0xafe,0xafe, -0x9c3,0x73b,0x630,0x630,0x96,0x789,0x768,0x759,0x762,0x75f,0x759,0x76b,0x75c,0x756,0x759,0x777, -0x76e,0x765,0x786,0x759,0x783,0x783,0x783,0x783,0x783,0x783,0x783,0x783,0x783,0x783,0x774,0x771, -0x777,0x777,0x777,0x789,0x74a,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747, +0x846,0x846,0x846,0x846,0x846,0xd5f,0xd5f,0x78,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25, +0xb25,0xb25,0xb25,0xb25,0xb25,0x7b,0x7b,0x7b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b, +0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xc6c,0xb2b,0xb2b,0xb2b,0xc6c,0xb2b,0x7e, +0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac, +0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x9c0,0x9c0,0x9c0,0x9c0,0x81,0x81,0x81,0x81, +0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x1221,0x1221,0x1221,0x1221,0x1221,0x1221,0x1221,0x1221, +0x1221,0x1221,0x1221,0x1221,0x1221,0x1221,0x1221,0x1221,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x84, +0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7, +0x84,0x84,0x84,0x84,0x84,0xafe,0x5fa,0x600,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606, +0x606,0x5fd,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x84, +0x600,0x600,0x600,0x600,0x600,0x84,0x600,0x84,0x600,0x600,0x84,0x600,0x600,0x84,0x600,0x600, +0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x603,0x615,0x60f,0x615,0x60f,0x612,0x618,0x615,0x60f, +0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x1329,0x1329,0x1b21,0x87,0x87,0x87,0x87,0x87, +0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x615,0x60f,0x612,0x618,0x615, +0x60f,0x615,0x60f,0x615,0x60f,0x615,0x615,0x60f,0x60f,0x60f,0x60f,0x612,0x60f,0x60f,0x612,0x60f, +0x612,0x612,0x612,0x60f,0x612,0x612,0x612,0x612,0x87,0x87,0x612,0x612,0x612,0x612,0x60f,0x60f, +0x612,0x60f,0x60f,0x60f,0x60f,0x612,0x60f,0x60f,0x60f,0x60f,0x60f,0x612,0x612,0x612,0x60f,0x60f, +0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x1b21,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49, +0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0x85e,0x870,0x86d,0x870,0x86d,0xc81,0xc81,0xd6b, +0xd68,0x861,0x861,0x861,0x861,0x873,0x873,0x873,0x88b,0x88e,0x89d,0x8a,0x891,0x894,0x8a0,0x8a0, +0x888,0x87f,0x879,0x87f,0x879,0x87f,0x879,0x87c,0x87c,0x897,0x897,0x89a,0x897,0x897,0x897,0x8a, +0x897,0x885,0x882,0x87c,0x8a,0x8a,0x8a,0x8a,0x621,0x62d,0x621,0xbfd,0x621,0x8d,0x621,0x62d, +0x621,0x62d,0x621,0x62d,0x621,0x62d,0x621,0x62d,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627, +0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x62a, +0x624,0x62a,0x624,0x62a,0x624,0x8d,0x8d,0x61e,0x75f,0x762,0x777,0x77a,0x759,0x762,0x762,0x93, +0x741,0x744,0x744,0x744,0x744,0x741,0x741,0x93,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, +0x90,0xb01,0xb01,0xb01,0x9c3,0x73b,0x630,0x630,0x93,0x789,0x768,0x759,0x762,0x75f,0x759,0x76b, +0x75c,0x756,0x759,0x777,0x76e,0x765,0x786,0x759,0x783,0x783,0x783,0x783,0x783,0x783,0x783,0x783, +0x783,0x783,0x774,0x771,0x777,0x777,0x777,0x789,0x74a,0x747,0x747,0x747,0x747,0x747,0x747,0x747, 0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747, -0x747,0x747,0x747,0x96,0x96,0x96,0x747,0x747,0x747,0x747,0x747,0x747,0x96,0x96,0x747,0x747, -0x747,0x747,0x747,0x747,0x96,0x96,0x747,0x747,0x747,0x747,0x747,0x747,0x96,0x96,0x747,0x747, -0x747,0x96,0x96,0x96,0xb49,0xb49,0xb49,0xb49,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, -0x99,0x1860,0x1860,0x1860,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f, -0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0x9c,0x9c,0x9c,0x9c,0x9c,0x1626,0x1626,0x1626,0x1626, -0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0xb58,0xb58,0xb58,0xb58, -0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58, -0xb58,0xb58,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0xb64,0xb64,0xb64,0xb64, -0xb64,0xb64,0xb64,0xa2,0xa2,0xfe1,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64, -0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0x16e3,0x16e3,0x16e3,0x16e3, -0x16e3,0x16e3,0x16e3,0x16e3,0x16e3,0x1b12,0x1b12,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2, -0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xb7c,0xb7c,0xb7c,0xb7c, -0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, -0xb79,0xa5,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb7c,0xb7c,0xb79,0xb79, -0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, -0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb7c,0xa5,0xb7c,0xb7c,0xa5,0xa5,0xb7c,0xa5, -0xa5,0xb7c,0xb7c,0xa5,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, -0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb79,0xa5,0xb79,0xa5,0xb79,0xb79,0xb79,0xb79,0xcf0,0xb79,0xb79, -0xa5,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb7c,0xb7c,0xb7c,0xb7c, -0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb79, -0xb7c,0xb7c,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xa5,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, -0xb7c,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xa5,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, -0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, -0xb79,0xb79,0xb79,0xb79,0xb7c,0xb7c,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xa5,0xb7c,0xb7c,0xb7c,0xb7c, -0xb7c,0xa5,0xb7c,0xa5,0xa5,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xa5,0xb79,0xb79, -0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xdda,0xdda,0xa5,0xa5, +0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x93,0x93,0x93,0x747,0x747,0x747,0x747,0x747,0x747, +0x93,0x93,0x747,0x747,0x747,0x747,0x747,0x747,0x93,0x93,0x747,0x747,0x747,0x747,0x747,0x747, +0x93,0x93,0x747,0x747,0x747,0x93,0x93,0x93,0xb4c,0xb4c,0xb4c,0xb4c,0x96,0x96,0x96,0x96, +0x96,0x96,0x96,0x96,0x96,0x186f,0x186f,0x186f,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52, +0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0x99,0x99,0x99,0x99,0x99, +0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, +0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b, +0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c, +0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0x9f,0x9f,0xfe4,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67, +0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67, +0x16f2,0x16f2,0x16f2,0x16f2,0x16f2,0x16f2,0x16f2,0x16f2,0x16f2,0x1b24,0x1b24,0x9f,0x9f,0x9f,0x9f,0x9f, +0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f, +0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7c,0xb7c, +0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xa2,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, +0xb7f,0xb7f,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, +0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7f,0xa2,0xb7f,0xb7f, +0xa2,0xa2,0xb7f,0xa2,0xa2,0xb7f,0xb7f,0xa2,0xa2,0xb7f,0xb7f,0xb7f,0xb7f,0xa2,0xb7f,0xb7f, +0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7c,0xb7c,0xb7c,0xb7c,0xa2,0xb7c,0xa2,0xb7c,0xb7c,0xb7c, +0xb7c,0xcf3,0xb7c,0xb7c,0xa2,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, +0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f, +0xb7c,0xb7c,0xb7c,0xb7c,0xb7f,0xb7f,0xa2,0xb7f,0xb7f,0xb7f,0xb7f,0xa2,0xa2,0xb7f,0xb7f,0xb7f, +0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xa2,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xa2,0xb7c,0xb7c, 0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, -0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb73,0xb79,0xb79,0xb79,0xb79, -0xb79,0xb79,0xef1,0xeee,0xa5,0xa5,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76, -0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xa8,0xb82,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8, -0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8, -0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xc09,0xc09,0xc09,0xc09,0xc09,0xc09,0xc09,0xc09, -0xc09,0xc09,0xc09,0xc09,0xc09,0x1b18,0xc09,0xc09,0xc09,0xc09,0xc03,0xc03,0xc06,0x1b15,0xab,0xab, -0xab,0xab,0xab,0xab,0xab,0xab,0xab,0x1b18,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12, -0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc0c,0xc0c,0xc0f,0xc72,0xc72,0xae, -0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18, -0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc15,0xc15,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xc1e,0xc1e,0xc1e,0xc1e,0xc1e,0xc1e,0xc1e,0xc1e, -0xc1e,0xc1e,0xc1e,0xc1e,0xc1e,0xb4,0xc1e,0xc1e,0xc1e,0xb4,0xc1b,0xc1b,0xb4,0xb4,0xb4,0xb4, -0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02, -0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02, -0xd02,0xd02,0xd02,0xd02,0xd02,0x14e8,0x14e8,0xb7,0xcf3,0xcf3,0xcf3,0xcff,0xcff,0xcff,0xcff,0xcf3, -0xcf3,0xcff,0xcff,0xcff,0xb7,0xb7,0xb7,0xb7,0xcff,0xcff,0xcf3,0xcff,0xcff,0xcff,0xcff,0xcff, -0xcff,0xcf6,0xcf6,0xcf6,0xb7,0xb7,0xb7,0xb7,0xcf9,0xb7,0xb7,0xb7,0xd05,0xd05,0xcfc,0xcfc, -0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08, -0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xba,0xba,0xd08,0xd08,0xd08,0xd08, -0xd08,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0x14eb,0x14eb,0x14eb,0x14eb, -0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb, -0xbd,0xbd,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb, -0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0xbd,0x1a64,0x14eb,0x14eb,0x14eb,0x14eb, -0x14eb,0x14eb,0x14eb,0x14eb,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c, -0xc0,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c, -0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xc0,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c, -0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xc0,0xd2c,0xd2c,0xc0,0xd2c, -0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xc0,0xc0, -0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xc0,0xc0, -0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, -0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, -0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f, -0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xc3,0xc3,0xc3,0xc3,0xc3, -0xd6e,0xd6e,0xd74,0xc6,0xc6,0xc6,0xc6,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b, -0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b, -0xc6,0xc6,0xc6,0xd71,0xd71,0xd71,0xd71,0xd71,0xd71,0xd71,0xd71,0xd71,0xd35,0xd35,0xd35,0xd35, -0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35, -0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xc9,0xd32,0xd3e,0xd3e,0xd3e,0xd3e, -0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e, -0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xcc,0xcc,0xd3b,0xd3b,0xd3b,0xd3b, -0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x1824,0x1824,0x1824,0x1824, -0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0xd41,0xd41,0xd41,0xd41, -0xd41,0xd41,0xcf,0xcf,0xd41,0xcf,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41, -0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xcf,0xd41, -0xd41,0xcf,0xcf,0xcf,0xd41,0xcf,0xcf,0xd41,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44, -0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd2, -0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5, -0xdf5,0xdf5,0xdf5,0x14ee,0x14ee,0x179a,0x179a,0xd8,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0, -0x10e0,0x10e0,0x10e0,0x10e0,0x1a73,0x129,0x129,0x129,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07, -0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xdfe, -0xdfe,0xe04,0xe04,0xdfe,0xdb,0xdb,0xe01,0xe01,0x1110,0x1110,0x1110,0x1110,0xde,0xde,0xde,0xde, -0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f, -0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xe19,0xe16,0xe19,0xe16,0xe16,0xe0d,0xe0d,0xe0d, -0xe0d,0xe0d,0xe0d,0x115b,0x1158,0x115b,0x1158,0x1155,0x1155,0x1155,0x13e6,0x13e3,0xe1,0xe1,0xe1,0xe1, -0xe1,0xe13,0xe10,0xe10,0xe10,0xe0d,0xe13,0xe10,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c, -0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe4, -0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe4, -0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe4,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe4, -0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe4,0xe22,0xe22,0xe22,0xe22,0xe22,0xe22,0xe22,0xe22, -0xe22,0xe22,0xe22,0xe22,0xe22,0xe22,0xe22,0xe22,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f, -0xe1f,0xe1f,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xea,0x13e9, -0xea,0xea,0xea,0xea,0xea,0x13e9,0xea,0xea,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c, -0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe3d,0xe31,0xe31,0xe31,0xed,0xe31,0xe31,0xed, -0xed,0xed,0xed,0xed,0xe31,0xe31,0xe31,0xe31,0xe3d,0xe3d,0xe3d,0xe3d,0xed,0xe3d,0xe3d,0xe3d, -0xed,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d, -0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0x1905,0x1905,0xed,0xed,0xe2e,0xe2e,0xe2e,0xed, -0xed,0xed,0xed,0xe34,0xe37,0xe37,0xe37,0xe37,0xe37,0xe37,0xe37,0xe37,0x1902,0xed,0xed,0xed, -0xed,0xed,0xed,0xed,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe40,0xe40,0xe37,0xed,0xed,0xed, -0xed,0xed,0xed,0xed,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0x1161,0x1161, -0xf0,0xf0,0xf0,0xf0,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4f,0xe4f,0xe4f,0xe4c,0xe4c,0xe4f,0xe4c, -0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, -0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0x115e,0xf0,0xf0,0xf0,0xe46,0xe46, -0xe55,0xe55,0xe55,0xe55,0xf3,0xf3,0xf3,0xf3,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55, -0xe52,0xe55,0xe55,0xe55,0xe55,0xe55,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3, -0x14fd,0x1503,0x1500,0x1845,0x17a0,0x1869,0x1869,0x1869,0x1869,0x1869,0x190b,0x1908,0x190e,0x1908,0x190e,0x19cb, -0x1a67,0x1a67,0x1a67,0x1b2a,0x1b2a,0x1b24,0x1b21,0x1b24,0x1b21,0x1b24,0x1b21,0x1b24,0x1b21,0x1b27,0xf6,0xf6, -0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6, -0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6, -0xe79,0xe79,0xe79,0xe76,0xe76,0xe6d,0xe6d,0xe76,0xe73,0xe73,0xe73,0xe73,0x1a6a,0xf9,0xf9,0xf9, -0x12cc,0x12cc,0x12cc,0x12cf,0x12cf,0x12cf,0x12c6,0x12c6,0x12c9,0x12c6,0x14d,0x14d,0x14d,0x14d,0x14d,0x14d, -0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0x13f5,0x13f5,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xe7f, -0x1335,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0x1332, -0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42, -0xeac,0xe9d,0xe97,0xea9,0xea6,0xea0,0xea0,0xeaf,0xe9a,0xea3,0xff,0xff,0xff,0xff,0xff,0xff, -0xf33,0xf33,0xf1e,0xf33,0xf36,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0x1b2d,0x105,0x105,0x105, -0xf2d,0xf2d,0xf2d,0xf2d,0xf2d,0xf2d,0xf2d,0xf2d,0xf2d,0xf2d,0xf3f,0xf3f,0xf24,0xf2a,0xf3f,0xf3f, -0xf27,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf21,0xf21,0xf21,0xf21,0xf21, -0xf21,0xf21,0xf21,0xf21,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0x1b30,0x1b30,0x105, -0x1b39,0x1b33,0x19d1,0x19ce,0x19d1,0x19d1,0x19d1,0x1a70,0x1a6d,0x1a70,0x1a6d,0x108,0x108,0x108,0x108,0x108, -0x1b39,0x1b33,0x108,0x1b33,0x108,0x1b33,0x1b39,0x1b33,0x1b39,0x1b33,0x108,0x108,0x108,0x108,0x108,0x108, -0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x1b36,0x1b36, -0x1b36,0x1a70,0x1a6d,0x150c,0x13fe,0x13fe,0x1338,0x103b,0x103b,0x103b,0x103b,0x103b,0xf4e,0xf4e,0xf4e,0xf4e, -0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e, -0xf4b,0xf4b,0xf51,0xf51,0x10b,0x10b,0x10b,0x10b,0x10b,0x10b,0x10b,0x10b,0xf5a,0xf5a,0xf5a,0xf5a, -0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a, -0xf5a,0xf5a,0xf54,0xf54,0xf54,0xf54,0x116a,0x116a,0x10e,0x10e,0x10e,0xf57,0x1512,0x1512,0x1512,0x1512, -0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512, -0x1512,0x1512,0x1512,0x1512,0x1512,0x16f2,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111, -0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111, -0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0xf63,0xf63,0xf63,0x1518,0x1518,0x1518,0x1518,0x1518, -0x1518,0x1518,0x1518,0x1518,0x1518,0x1518,0x1518,0x114,0xf60,0xf60,0xf60,0xf60,0x1515,0x114,0x114,0x114, -0x114,0x114,0x114,0x114,0x114,0x114,0x114,0x114,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66, -0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0x191d,0x191d,0x191d,0x191d,0x191d,0x191d, -0x191d,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x1062,0x1062,0x1062,0x1062,0x105f,0x105f,0x105f,0x105f, -0x105f,0x105f,0x105f,0x105f,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x105f,0x105f,0x1056,0x1053, -0x11a,0x11a,0x11a,0x1065,0x1065,0x1059,0x1059,0x1059,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c, -0x105c,0x105c,0x11a,0x11a,0x11a,0x1062,0x1062,0x1062,0x1068,0x1068,0x1068,0x1068,0x1068,0x1068,0x1068,0x1068, -0x1068,0x1068,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x107d,0x107d,0x107d,0x107d,0x107d,0x107d,0x107d,0x107d, -0x107d,0x107d,0x1080,0x1080,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d, -0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x10a7,0x10a7,0x10a7,0x10a7,0x10a1,0x17a6,0x120,0x120, -0x120,0x120,0x120,0x120,0x120,0x120,0x10ad,0x10ad,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4, -0x10a4,0x10a4,0x120,0x120,0x120,0x120,0x120,0x120,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10bf, -0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10c5,0x10c8,0x123,0x123,0x123,0x123, -0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x10c2,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da, -0x10da,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10d7,0x10d7,0x10ce,0x10ce,0x10d7,0x10d7,0x10ce,0x10ce,0x126, -0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x10da,0x10da,0x10da,0x10ce,0x10da,0x10da,0x10da,0x10da, -0x10da,0x10da,0x10da,0x10da,0x10ce,0x10d7,0x126,0x126,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4, -0x10d4,0x10d4,0x126,0x126,0x10d1,0x10dd,0x10dd,0x10dd,0x1524,0x129,0x129,0x129,0x129,0x129,0x129,0x129, -0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129, -0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3, -0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3, -0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e6,0x12c,0x12c,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9, +0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7f,0xb7f,0xa2,0xb7f,0xb7f,0xb7f,0xb7f,0xa2, +0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xa2,0xb7f,0xa2,0xa2,0xa2,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f, +0xb7f,0xa2,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, +0xddd,0xddd,0xa2,0xa2,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f, +0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7c,0xb7c,0xb7c,0xb76, +0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xef4,0xef1,0xa2,0xa2,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, +0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xa5,0xb85,0xa5,0xa5, +0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5, +0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xc0c,0xc0c,0xc0c,0xc0c, +0xc0c,0xc0c,0xc0c,0xc0c,0xc0c,0xc0c,0xc0c,0xc0c,0xc0c,0x1b2a,0xc0c,0xc0c,0xc0c,0xc0c,0xc06,0xc06, +0xc09,0x1b27,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0x1b2a,0xc15,0xc15,0xc15,0xc15, +0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc0f,0xc0f, +0xc12,0xc75,0xc75,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xc1b,0xc1b,0xc1b,0xc1b, +0xc1b,0xc1b,0xc1b,0xc1b,0xc1b,0xc1b,0xc1b,0xc1b,0xc1b,0xc1b,0xc1b,0xc1b,0xc1b,0xc1b,0xc18,0xc18, +0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xc21,0xc21,0xc21,0xc21, +0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xb1,0xc21,0xc21,0xc21,0xb1,0xc1e,0xc1e, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xd05,0xd05,0xd05,0xd05, +0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05, +0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0x14f1,0x14f1,0xb4,0xcf6,0xcf6,0xcf6,0xd02, +0xd02,0xd02,0xd02,0xcf6,0xcf6,0xd02,0xd02,0xd02,0xb4,0xb4,0xb4,0xb4,0xd02,0xd02,0xcf6,0xd02, +0xd02,0xd02,0xd02,0xd02,0xd02,0xcf9,0xcf9,0xcf9,0xb4,0xb4,0xb4,0xb4,0xcfc,0xb4,0xb4,0xb4, +0xd08,0xd08,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xd0b,0xd0b,0xd0b,0xd0b, +0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xb7,0xb7, +0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7, +0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4, +0x14f4,0x14f4,0x14f4,0x14f4,0xba,0xba,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4, +0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0xba,0x1a76, +0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f, +0xd2f,0xd2f,0xd2f,0xd2f,0xbd,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f, +0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xbd,0xd2f,0xd2f,0xd2f,0xd2f, +0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xbd, +0xd2f,0xd2f,0xbd,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f, +0xd2f,0xd2f,0xbd,0xbd,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f, +0xd2f,0xd2f,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd, +0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd, +0xbd,0xbd,0xbd,0xbd,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32, +0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xc0, +0xc0,0xc0,0xc0,0xc0,0xd71,0xd71,0xd77,0xc3,0xc3,0xc3,0xc3,0xd6e,0xd6e,0xd6e,0xd6e,0xd6e, +0xd6e,0xd6e,0xd6e,0xd6e,0xd6e,0xd6e,0xd6e,0xd6e,0xd6e,0xd6e,0xd6e,0xd6e,0xd6e,0xd6e,0xd6e,0xd6e, +0xd6e,0xd6e,0xd6e,0xd6e,0xc3,0xc3,0xc3,0xd74,0xd74,0xd74,0xd74,0xd74,0xd74,0xd74,0xd74,0xd74, +0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38, +0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xc6,0xd35, +0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41, +0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xc9,0xc9, +0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9, +0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833, +0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xcc,0xcc,0xd44,0xcc,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44, +0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44, +0xd44,0xd44,0xcc,0xd44,0xd44,0xcc,0xcc,0xcc,0xd44,0xcc,0xcc,0xd44,0xd47,0xd47,0xd47,0xd47, +0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47, +0xd47,0xd47,0xd47,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xdf8,0xdf8,0xdf8,0xdf8, +0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0x14f7,0x14f7,0x17a9,0x17a9,0xd5,0x10e6,0x10e6,0x10e6,0x10e6, +0x10e6,0x10e6,0x10e6,0x10e6,0x10e6,0x10e6,0x10e6,0x10e6,0x1a85,0x126,0x126,0x126,0xe0a,0xe0a,0xe0a,0xe0a, +0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a, +0xe0a,0xe0a,0xe0a,0xe01,0xe01,0xe07,0xe07,0xe01,0xd8,0xd8,0xe04,0xe04,0x1113,0x1113,0x1113,0x1113, +0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0x1c56,0xc72,0xc72,0xc72,0xc72, +0xc72,0xc72,0xc72,0xc72,0xc72,0xc72,0xc72,0xc72,0xc72,0xc72,0xc72,0xc72,0xe1c,0xe19,0xe1c,0xe19, +0xe19,0xe10,0xe10,0xe10,0xe10,0xe10,0xe10,0x1161,0x115e,0x1161,0x115e,0x115b,0x115b,0x115b,0x13ef,0x13ec, +0xde,0xde,0xde,0xde,0xde,0xe16,0xe13,0xe13,0xe13,0xe10,0xe16,0xe13,0xe1f,0xe1f,0xe1f,0xe1f, +0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f, +0xe1f,0xe1f,0xe1f,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1f,0xe1f,0xe1f,0xe1f, +0xe1f,0xe1f,0xe1f,0xe1,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1,0xe1f,0xe1f,0xe1f,0xe1f, +0xe1f,0xe1f,0xe1f,0xe1,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1,0xe25,0xe25,0xe25,0xe25, +0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe22,0xe22,0xe22,0xe22, +0xe22,0xe22,0xe22,0xe22,0xe22,0xe22,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe28,0xe28,0xe28,0xe28, +0xe28,0xe28,0xe7,0x13f2,0xe7,0xe7,0xe7,0xe7,0xe7,0x13f2,0xe7,0xe7,0xe7f,0xe7f,0xe7f,0xe7f, +0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe40,0xe34,0xe34,0xe34, +0xea,0xe34,0xe34,0xea,0xea,0xea,0xea,0xea,0xe34,0xe34,0xe34,0xe34,0xe40,0xe40,0xe40,0xe40, +0xea,0xe40,0xe40,0xe40,0xea,0xe40,0xe40,0xe40,0xe40,0xe40,0xe40,0xe40,0xe40,0xe40,0xe40,0xe40, +0xe40,0xe40,0xe40,0xe40,0xe40,0xe40,0xe40,0xe40,0xe40,0xe40,0xe40,0xe40,0x1914,0x1914,0xea,0xea, +0xe31,0xe31,0xe31,0xea,0xea,0xea,0xea,0xe37,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a, +0x1911,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe43,0xe43, +0xe3a,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0x1167,0x1167,0xed,0xed,0xed,0xed,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe52,0xe52,0xe52, +0xe4f,0xe4f,0xe52,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xed,0xed, +0xed,0xed,0xed,0xed,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0x1164,0xed, +0xed,0xed,0xe49,0xe49,0xe58,0xe58,0xe58,0xe58,0xf0,0xf0,0xf0,0xf0,0xe58,0xe58,0xe58,0xe58, +0xe58,0xe58,0xe58,0xe58,0xe55,0xe58,0xe58,0xe58,0xe58,0xe58,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, +0xf0,0xf0,0xf0,0xf0,0x1506,0x150c,0x1509,0x1854,0x17af,0x1878,0x1878,0x1878,0x1878,0x1878,0x191a,0x1917, +0x191d,0x1917,0x191d,0x19dd,0x1a79,0x1a79,0x1a79,0x1b3c,0x1b3c,0x1b36,0x1b33,0x1b36,0x1b33,0x1b36,0x1b33,0x1b36, +0x1b33,0x1b39,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3, +0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3, +0xf3,0xf3,0xf3,0xf3,0xe7c,0xe7c,0xe7c,0xe79,0xe79,0xe70,0xe70,0xe79,0xe76,0xe76,0xe76,0xe76, +0x1a7c,0xf6,0xf6,0xf6,0x12cc,0x12cc,0x12cc,0x12cf,0x12cf,0x12cf,0x12d2,0x12d2,0x12d5,0x12d2,0x14a,0x14a, +0x14a,0x14a,0x14a,0x14a,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0x13fe,0x13fe,0xf9,0xf9,0xf9,0xf9, +0xf9,0xf9,0xf9,0xe82,0x133b,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9, +0xf9,0xf9,0xf9,0x1338,0xc45,0xc45,0xc45,0xc45,0xc45,0xc45,0xc45,0xc45,0xc45,0xc45,0xc45,0xc45, +0xc45,0xc45,0xc45,0xc45,0xeaf,0xea0,0xe9a,0xeac,0xea9,0xea3,0xea3,0xeb2,0xe9d,0xea6,0xfc,0xfc, +0xfc,0xfc,0xfc,0xfc,0xf36,0xf36,0xf21,0xf36,0xf39,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c, +0x1b3f,0x102,0x102,0x102,0xf30,0xf30,0xf30,0xf30,0xf30,0xf30,0xf30,0xf30,0xf30,0xf30,0xf42,0xf42, +0xf2a,0xf2d,0xf42,0xf42,0xf27,0xf2a,0xf2a,0xf2a,0xf2a,0xf2a,0xf2a,0xf2a,0xf2a,0xf2a,0xf2a,0xf24, +0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf2a,0xf2a,0xf2a,0xf2a,0xf2a,0xf2a,0xf2a,0xf2a, +0xf2a,0x1b42,0x1b42,0x102,0x1b4b,0x1b45,0x19e3,0x19e0,0x19e3,0x19e3,0x19e3,0x1a82,0x1a7f,0x1a82,0x1a7f,0x105, +0x105,0x105,0x105,0x105,0x1b4b,0x1b45,0x105,0x1b45,0x105,0x1b45,0x1b4b,0x1b45,0x1b4b,0x1b45,0x105,0x105, +0x105,0x105,0x105,0x105,0x105,0x105,0x105,0x105,0x105,0x105,0x105,0x105,0x105,0x105,0x105,0x105, +0x105,0x105,0x1b48,0x1b48,0x1b48,0x1a82,0x1a7f,0x1515,0x1407,0x1407,0x133e,0x103e,0x103e,0x103e,0x103e,0x103e, +0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51, +0xf51,0xf51,0xf51,0xf51,0xf4e,0xf4e,0xf54,0xf54,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108, +0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d, +0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf57,0xf57,0xf57,0xf57,0x1170,0x1170,0x10b,0x10b,0x10b,0xf5a, +0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b, +0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x1701,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e, +0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e, +0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0xf66,0xf66,0xf66,0x1521, +0x1521,0x1521,0x1521,0x1521,0x1521,0x1521,0x1521,0x1521,0x1521,0x1521,0x1521,0x111,0xf63,0xf63,0xf63,0xf63, +0x151e,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0xf69,0xf69,0xf69,0xf69, +0xf69,0xf69,0xf69,0xf69,0xf69,0xf69,0xf69,0xf69,0xf69,0xf69,0xf69,0xf69,0xf69,0xf69,0x192c,0x192c, +0x192c,0x192c,0x192c,0x192c,0x192c,0x114,0x114,0x114,0x114,0x114,0x114,0x114,0x1065,0x1065,0x1065,0x1065, +0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1053,0x1053,0x1053,0x1053,0x1053,0x1053,0x1053,0x1053, +0x1062,0x1062,0x1059,0x1056,0x117,0x117,0x117,0x1068,0x1068,0x105c,0x105c,0x105c,0x105f,0x105f,0x105f,0x105f, +0x105f,0x105f,0x105f,0x105f,0x105f,0x105f,0x117,0x117,0x117,0x1065,0x1065,0x1065,0x106b,0x106b,0x106b,0x106b, +0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x1080,0x1080,0x1080,0x1080, +0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1083,0x1083,0x11a,0x11a,0x11a,0x11a,0x11a,0x11a,0x11a,0x11a, +0x11a,0x11a,0x11a,0x11a,0x11a,0x11a,0x11a,0x11a,0x11a,0x11a,0x11a,0x11a,0x10aa,0x10aa,0x10aa,0x10aa, +0x10a4,0x17b5,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x10b0,0x10b0,0x10a7,0x10a7,0x10a7,0x10a7, +0x10a7,0x10a7,0x10a7,0x10a7,0x10a7,0x10a7,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x10ce,0x10ce,0x10ce,0x10ce, +0x10ce,0x10ce,0x10ce,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c8,0x10cb, +0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x10c5,0x10e0,0x10e0,0x10e0,0x10e0, +0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10da,0x10da,0x10d1,0x10d1,0x10da, +0x10da,0x10d1,0x10d1,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x10dd,0x10dd,0x10dd,0x10d1, +0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10d1,0x10da,0x123,0x123,0x10d7,0x10d7,0x10d7,0x10d7, +0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x123,0x123,0x10d4,0x10e3,0x10e3,0x10e3,0x152d,0x126,0x126,0x126, +0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126, +0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x10e9,0x10e9,0x10e9,0x10e9, 0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9, -0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x12f,0x12f,0x12f,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec, -0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x132,0x132,0x132,0x132,0x132,0x132,0x132, -0x132,0x132,0x132,0x132,0x132,0x132,0x132,0x132,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2, -0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2, -0x10f2,0x10f2,0x135,0x135,0x135,0x135,0x135,0x10ef,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5, -0x10f5,0x10f5,0x10f5,0x10f5,0x138,0x138,0x138,0x138,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8, -0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x13b,0x13b,0x13b,0x13b, -0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x1170,0x1170,0x1170,0x1170,0x1179,0x1170,0x1170,0x1170, -0x1179,0x1170,0x1170,0x1170,0x1170,0x116d,0x13e,0x13e,0x1176,0x1176,0x1176,0x1176,0x1176,0x1176,0x1176,0x117c, -0x1176,0x117c,0x1176,0x1176,0x1176,0x117c,0x117c,0x13e,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f, -0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x141,0x141, -0x141,0x141,0x141,0x141,0x141,0x141,0x141,0x141,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a, -0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x1197,0x1182,0x1197, -0x1182,0x1182,0x1182,0x1182,0x1182,0x1182,0x1182,0x144,0x118b,0x1194,0x1182,0x1194,0x1194,0x1182,0x1182,0x1182, -0x1182,0x1182,0x1182,0x1182,0x1182,0x1197,0x1197,0x1197,0x1197,0x1197,0x1197,0x1182,0x1182,0x1188,0x1188,0x1188, -0x1188,0x1188,0x1188,0x1188,0x1188,0x144,0x144,0x1185,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191, -0x1191,0x1191,0x144,0x144,0x144,0x144,0x144,0x144,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191, -0x1191,0x1191,0x144,0x144,0x144,0x144,0x144,0x144,0x118e,0x118e,0x118e,0x118e,0x118e,0x118e,0x118e,0x119d, -0x11a0,0x11a0,0x11a0,0x11a0,0x118e,0x118e,0x144,0x144,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563, -0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1560,0x1a85,0x12e1,0x12ba,0x12d8,0x12d8,0x12d8,0x12d8,0x12d8,0x12d8, -0x12d8,0x12c0,0x12bd,0x12b4,0x12b4,0x12de,0x12b4,0x12b4,0x12b4,0x12b4,0x12c3,0x149d,0x14a3,0x14a0,0x14a0,0x18e4, -0x16b9,0x16b9,0x1a52,0x147,0x147,0x147,0x147,0x147,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5, -0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11ac,0x11ac,0x11af,0x11b8,0x11b2,0x11b2,0x11b2,0x11b8, -0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5, -0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5, -0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x150,0x150,0x150,0x11d6,0x11ca,0x11ca,0x11ca,0x11ca,0x11ca,0x11ca,0x11cd, -0x11dc,0x11dc,0x11ca,0x11ca,0x11ca,0x11ca,0x153,0x12d5,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0, -0x11d0,0x11d0,0x153,0x153,0x153,0x153,0x11ca,0x11ca,0x11fa,0x11ee,0x11fa,0x156,0x156,0x156,0x156,0x156, -0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156, -0x156,0x156,0x156,0x11f7,0x11f7,0x11fd,0x11f1,0x11f4,0x1212,0x1212,0x1212,0x120c,0x120c,0x1203,0x120c,0x120c, -0x1203,0x120c,0x120c,0x1215,0x120f,0x1206,0x159,0x159,0x1209,0x1209,0x1209,0x1209,0x1209,0x1209,0x1209,0x1209, -0x1209,0x1209,0x159,0x159,0x159,0x159,0x159,0x159,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x15c, -0x15c,0x15c,0x15c,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218, -0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218, -0x15c,0x15c,0x15c,0x15c,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224, -0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x15f,0x1221,0x121e,0x121e,0x121e,0x121e, -0x121e,0x121e,0x121e,0x121e,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233, -0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x162,0x162,0x162,0x122d,0x1230,0x1230, -0x1230,0x1230,0x1230,0x1230,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239, -0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x165,0x165,0x1236,0x1236,0x1236,0x1236, -0x1236,0x1236,0x1236,0x1236,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f, -0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x168,0x168,0x168,0x168,0x168,0x123c,0x123c,0x123c,0x123c, -0x123c,0x123c,0x123c,0x123c,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245, -0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245, -0x1245,0x1245,0x1245,0x16e,0x125d,0x125d,0x1b3c,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171, -0x171,0x1926,0x171,0x171,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c, -0x147c,0x147c,0x147c,0x147c,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827, -0x1827,0x1a76,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174, -0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174, -0x174,0x174,0x174,0x174,0x174,0x174,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344, -0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344, -0x12ae,0x13a7,0x13a7,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177, +0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10ec,0x129,0x129,0x10ef,0x10ef,0x10ef,0x10ef, +0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef, +0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x10ef,0x12c,0x12c,0x12c,0x10f2,0x10f2,0x10f2,0x10f2, +0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x12f,0x12f,0x12f, +0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,0x10f8,0x10f8,0x10f8,0x10f8, +0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8, +0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x132,0x132,0x132,0x132,0x132,0x10f5,0x10fb,0x10fb,0x10fb,0x10fb, +0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x135,0x135,0x135,0x135,0x10fe,0x10fe,0x10fe,0x10fe, +0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe, +0x138,0x138,0x138,0x138,0x138,0x138,0x138,0x138,0x138,0x138,0x138,0x138,0x1176,0x1176,0x1176,0x1176, +0x117f,0x1176,0x1176,0x1176,0x117f,0x1176,0x1176,0x1176,0x1176,0x1173,0x13b,0x13b,0x117c,0x117c,0x117c,0x117c, +0x117c,0x117c,0x117c,0x1182,0x117c,0x1182,0x117c,0x117c,0x117c,0x1182,0x1182,0x13b,0x1185,0x1185,0x1185,0x1185, +0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185, +0x1185,0x1185,0x13e,0x13e,0x13e,0x13e,0x13e,0x13e,0x13e,0x13e,0x13e,0x13e,0x11a0,0x11a0,0x11a0,0x11a0, +0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0, +0x11a0,0x119d,0x1188,0x119d,0x1188,0x1188,0x1188,0x1188,0x1188,0x1188,0x1188,0x141,0x1191,0x119a,0x1188,0x119a, +0x119a,0x1188,0x1188,0x1188,0x1188,0x1188,0x1188,0x1188,0x1188,0x119d,0x119d,0x119d,0x119d,0x119d,0x119d,0x1188, +0x1188,0x118e,0x118e,0x118e,0x118e,0x118e,0x118e,0x118e,0x118e,0x141,0x141,0x118b,0x1197,0x1197,0x1197,0x1197, +0x1197,0x1197,0x1197,0x1197,0x1197,0x1197,0x141,0x141,0x141,0x141,0x141,0x141,0x1197,0x1197,0x1197,0x1197, +0x1197,0x1197,0x1197,0x1197,0x1197,0x1197,0x141,0x141,0x141,0x141,0x141,0x141,0x1194,0x1194,0x1194,0x1194, +0x1194,0x1194,0x1194,0x11a3,0x11a6,0x11a6,0x11a6,0x11a6,0x1194,0x1194,0x141,0x141,0x156c,0x156c,0x156c,0x156c, +0x156c,0x156c,0x156c,0x156c,0x156c,0x156c,0x156c,0x156c,0x156c,0x156c,0x1569,0x1a97,0x12e7,0x12c0,0x12de,0x12de, +0x12de,0x12de,0x12de,0x12de,0x12de,0x12c6,0x12c3,0x12ba,0x12ba,0x12e4,0x12ba,0x12ba,0x12ba,0x12ba,0x12c9,0x14a6, +0x14ac,0x14a9,0x14a9,0x18f3,0x16c8,0x16c8,0x1a64,0x144,0x144,0x144,0x144,0x144,0x11bb,0x11bb,0x11bb,0x11bb, +0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11b2,0x11b2,0x11b5,0x11be, +0x11b8,0x11b8,0x11b8,0x11be,0x147,0x147,0x147,0x147,0x147,0x147,0x147,0x147,0x12ab,0x12ab,0x12ab,0x12ab, 0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab, -0x12ab,0x12ab,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x182a,0x177,0x177,0x177,0x177, -0x12a8,0x12a8,0x12a8,0x12a8,0x12a8,0x12a8,0x12a8,0x12a8,0x12a8,0x177,0x177,0x177,0x177,0x177,0x177,0x177, -0x13cb,0x13cb,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177, -0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177, -0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177, -0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d, -0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d, -0x134d,0x1347,0x1347,0x1347,0x17a,0x17a,0x134a,0x17a,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x1350,0x1359, -0x1353,0x1353,0x1359,0x1359,0x1359,0x1353,0x1359,0x1353,0x1353,0x1353,0x135c,0x135c,0x17d,0x17d,0x17d,0x17d, -0x17d,0x17d,0x17d,0x17d,0x1356,0x1356,0x1356,0x1356,0x180,0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x180, -0x180,0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x180,0x180,0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x180, -0x180,0x180,0x180,0x180,0x180,0x180,0x180,0x180,0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x180, -0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x180,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0, -0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1368,0x137a, -0x137a,0x136e,0x136e,0x136e,0x136e,0x136e,0x183,0x183,0x183,0x183,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b, -0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371, -0x1371,0x1371,0x1371,0x1371,0x1b42,0x1b45,0x1b45,0x1b3f,0x1b3f,0x1b45,0x183,0x183,0x183,0x183,0x183,0x183, -0x183,0x183,0x183,0x1533,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d, -0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x186,0x186,0x186, -0x186,0x186,0x186,0x186,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380, -0x1380,0x1380,0x1380,0x189,0x189,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380, -0x1380,0x1380,0x1380,0x1536,0x189,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380, -0x1380,0x1380,0x1380,0x13b0,0x189,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380, -0x1380,0x1380,0x1380,0x1380,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536, -0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x189,0x189,0x189,0x189,0x189,0x189, -0x189,0x189,0x189,0x189,0x13c5,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542, -0x16b0,0x1542,0x1542,0x1542,0x1782,0x1833,0x1833,0x186c,0x186c,0x1a34,0x1adf,0x1adf,0x18c,0x18c,0x18c,0x18c, -0x1c2c,0x1bae,0x1bae,0x1bae,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x16ad, -0x16ad,0x18c,0x18c,0x18c,0x1542,0x1542,0x1542,0x1542,0x1833,0x1833,0x1833,0x18cf,0x18cf,0x19b0,0x1a34,0x1adf, -0x1adf,0x18c,0x18c,0x18c,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383, -0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1bd2,0x1bd2,0x1bd2,0x18f,0x18f,0x18f,0x18f,0x1bd2, -0x1bd2,0x1bd2,0x1bd2,0x1bd2,0x141f,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f, -0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f, -0x141f,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x192,0x141f,0x192,0x192,0x141f,0x192,0x141f,0x141f,0x141f, -0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x141f,0x141f,0x192,0x141f,0x192,0x141f, -0x192,0x192,0x192,0x192,0x192,0x192,0x141f,0x192,0x192,0x192,0x192,0x141f,0x192,0x141f,0x192,0x141f, -0x192,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x192,0x141f,0x192,0x192,0x141f,0x192,0x141f,0x192,0x141f, -0x192,0x141f,0x192,0x141f,0x192,0x141f,0x141f,0x192,0x141f,0x192,0x192,0x141f,0x141f,0x141f,0x141f,0x192, -0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x141f, -0x141f,0x192,0x141f,0x192,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x192,0x141f, -0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f, -0x192,0x192,0x192,0x192,0x192,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x141f,0x141f,0x141f,0x192,0x141f, -0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f, -0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192, -0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192, -0x141c,0x141c,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192, -0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1422,0x1422,0x1422,0x1422,0x1422,0x1431,0x1422,0x1425,0x1425, -0x1422,0x1422,0x1422,0x1428,0x1428,0x195,0x142e,0x142e,0x142e,0x142e,0x142e,0x142e,0x142e,0x142e,0x142e,0x142e, -0x142b,0x1437,0x1437,0x1437,0x1932,0x192f,0x192f,0x1a7c,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195, -0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2, -0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1440,0x143a,0x143a,0x1440,0x1440, -0x1449,0x1449,0x1443,0x1446,0x1446,0x1440,0x143d,0x198,0x198,0x198,0x198,0x198,0x198,0x198,0x198,0x198, -0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c, -0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x19b,0x19b,0x19b,0x19b,0x1707,0x1707,0x144c,0x144c, -0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707, -0x19b,0x19b,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707, -0x1458,0x1458,0x1458,0x1458,0x1458,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19e,0x19e,0x19e,0x19e,0x19d7, -0x1458,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455, -0x19da,0x19da,0x19da,0x19da,0x19da,0x19da,0x19da,0x19da,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x1452, -0x1452,0x1452,0x1452,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b, -0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1, -0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1, -0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4, -0x12db,0x12d8,0x12db,0x12b7,0x12d8,0x12de,0x12de,0x12e1,0x12de,0x12e1,0x12e4,0x12d8,0x12e1,0x12e1,0x12d8,0x12d8, -0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1482,0x148b,0x1482,0x148b,0x148b, -0x1482,0x1482,0x1482,0x1482,0x1482,0x1482,0x148e,0x1485,0x19e0,0x1b51,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7, -0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1aa,0x1aa, -0x1551,0x1551,0x1551,0x1551,0x1551,0x1557,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa, -0x155d,0x155d,0x155d,0x155d,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x155a, -0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x2b2,0x1b9c,0x1b9c,0x1b9c,0x1b9c, -0x16bc,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3, -0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x1b0,0x1b0,0x1b0,0x1b0, -0x1a85,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b54,0x1b54,0x1b54,0x1b3, -0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3, -0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3, -0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6, -0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x1b6,0x1b6,0x1b6, -0x1b6,0x1b6,0x1b6,0x1b6,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x1b6,0x1b6, -0x156c,0x1566,0x1569,0x1572,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1b9,0x1b9,0x1b9,0x1b9, -0x1b9,0x1b9,0x1b9,0x1b9,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d, -0x155d,0x155d,0x155d,0x155d,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578, -0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1935,0x1935,0x1935,0x1935,0x1bd5,0x1bc,0x1bc, -0x1bc,0x1bc,0x1bc,0x1bc,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37, -0x1bc,0x1bc,0x1bc,0x1bc,0x1bb1,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc, -0x1bc,0x1bc,0x1bc,0x1bc,0x171c,0x16bf,0x1581,0x16c5,0x1bf,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a, -0x158a,0x1bf,0x1bf,0x158a,0x158a,0x1bf,0x1bf,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a, -0x158a,0x158a,0x158a,0x158a,0x158a,0x1bf,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,0x1bf,0x158a,0x158a, -0x1bf,0x158a,0x158a,0x158a,0x158a,0x158a,0x1bf,0x19bc,0x16c2,0x158a,0x157b,0x1581,0x157b,0x1581,0x1581,0x1581, -0x1581,0x1bf,0x1bf,0x1581,0x1581,0x1bf,0x1bf,0x1584,0x1584,0x1587,0x1bf,0x1bf,0x171f,0x1bf,0x1bf,0x1bf, -0x1bf,0x1bf,0x1bf,0x157b,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x158d,0x158a,0x158a,0x158a,0x158a,0x1581,0x1581, -0x1bf,0x1bf,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x1bf,0x1bf,0x1bf,0x157e,0x157e,0x157e,0x157e, -0x157e,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x15a2,0x15a2,0x15a2,0x15a2, -0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x1c2,0x15a2, -0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15b4,0x15b4,0x15b4,0x15a8, -0x15a8,0x15a8,0x15a8,0x15a8,0x15a8,0x15ab,0x15ae,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x15b1,0x15b1,0x15b1,0x15b1, -0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1722,0x1722,0x1722,0x1722, -0x15c0,0x15bd,0x19e3,0x19e3,0x1a8b,0x1a8e,0x1a88,0x1a88,0x1c8,0x1c8,0x1c8,0x1c8,0x174f,0x174f,0x174f,0x174f, -0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x15c6,0x15c6,0x15c6,0x15c6, -0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6, -0x15c6,0x15c6,0x15c6,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x15c6,0x15c6,0x15c6,0x15c6, -0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6, -0x15c6,0x15c6,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x15c6,0x15c6,0x15c6,0x15c6, -0x15c6,0x15c6,0x15c6,0x15c6,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb, -0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x15d2,0x15d2,0x15d2,0x15d2, -0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15c9, -0x15cc,0x15cf,0x15d2,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x15e1,0x15e1,0x15e1,0x15e1, -0x15e1,0x15d5,0x15d5,0x1d1,0x1d1,0x1d1,0x1d1,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15de,0x15de,0x16c8,0x15de, -0x15de,0x15de,0x15db,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x15ea,0x15ea,0x15ea,0x15ea, -0x15ea,0x1d4,0x1d4,0x15e7,0x15e7,0x15e7,0x15e7,0x15e7,0x15e7,0x15e7,0x15e7,0x15e7,0x15e4,0x15e4,0x15e4,0x15e4, -0x15e4,0x15e4,0x15e4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x15ed,0x15ff,0x15ff,0x15f3, -0x15fc,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x15f6,0x15f6,0x15f6,0x15f6, -0x15f6,0x15f6,0x15f6,0x15f6,0x15f6,0x15f6,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1605,0x1605,0x1605,0x1605, -0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605, -0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1da,0x1602,0x1602,0x1602,0x1602, -0x1602,0x1602,0x1602,0x1602,0x1602,0x1602,0x1da,0x1da,0x1da,0x1da,0x1608,0x1608,0x1b8d,0x1b8d,0x1b8d,0x1b8d, -0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1611,0x1611,0x1611,0x1611, -0x1611,0x160b,0x1614,0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x160e,0x160e,0x160e,0x160e, -0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x1611,0x1611,0x1611,0x1611,0x1611,0x1dd,0x161a,0x161a,0x161a,0x161a, -0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a, -0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x1e0,0x1626,0x1626,0x1626,0x1626, -0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626, -0x1626,0x1626,0x1623,0x1623,0x1623,0x1623,0x1623,0x1e3,0x1e3,0x1e3,0x1e3,0x1e3,0x163e,0x163e,0x1641,0x1641, -0x1644,0x1635,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x163b,0x163b,0x163b,0x163b, -0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x1e6,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1e6,0x163e, -0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e, -0x163e,0x163e,0x163e,0x163e,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x163e,0x163e,0x163e,0x164d,0x164d,0x164d,0x164d, -0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d, -0x164d,0x164d,0x164d,0x164d,0x164d,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1656,0x1656,0x1656,0x1656, -0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1ec,0x1ec, -0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1653,0x1653,0x1653,0x1653,0x1ec,0x1ec,0x1ec,0x1671,0x1671,0x1671,0x1671, -0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1659,0x166b,0x166b,0x1659,0x1659, -0x1659,0x1659,0x1f2,0x1f2,0x166b,0x166b,0x166e,0x166e,0x1659,0x1659,0x166b,0x165f,0x165c,0x1662,0x1674,0x1674, -0x1665,0x1665,0x1668,0x1668,0x1668,0x1674,0x172b,0x172b,0x172b,0x172b,0x172b,0x172b,0x172b,0x172b,0x172b,0x172b, -0x172b,0x172b,0x172b,0x172b,0x1728,0x1728,0x1728,0x1728,0x1725,0x1725,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2, -0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2, -0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f5,0x1677,0x1677,0x1677, -0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677, -0x1677,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x167a,0x167a,0x167a,0x167a, -0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x1f8,0x1f8,0x1f8,0x1f8,0x167a,0x167a,0x167a,0x167a, -0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x1f8,0x1f8,0x1f8,0x1f8, -0x1f8,0x1f8,0x1f8,0x1f8,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x1f8,0x1f8, -0x1f8,0x1f8,0x1f8,0x1f8,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x1f8,0x1f8,0x1f8,0x1f8, -0x1f8,0x1f8,0x1f8,0x1f8,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a, -0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x1f8,0x1f8,0x1a91,0x1a91,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8, -0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8, -0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x167d,0x168c,0x1683,0x1680, -0x1692,0x1692,0x1686,0x1692,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1689,0x1689,0x1689,0x1689, -0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1698,0x1698,0x1698,0x1698, -0x1698,0x1698,0x1698,0x1698,0x1698,0x1698,0x1695,0x1695,0x1695,0x1695,0x1695,0x1695,0x1695,0x1695,0x1695,0x1fe, -0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x169e,0x1740,0x1740,0x1740,0x1740, -0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740, -0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1938,0x201,0x201,0x172e,0x172e,0x172e,0x173a,0x173a,0x172e,0x172e, -0x172e,0x172e,0x173d,0x172e,0x172e,0x172e,0x172e,0x1731,0x201,0x201,0x201,0x201,0x1737,0x1737,0x1737,0x1737, -0x1737,0x1737,0x1737,0x1737,0x1737,0x1737,0x1734,0x1734,0x1743,0x1743,0x1743,0x1734,0x1746,0x1746,0x1746,0x1746, -0x1746,0x1746,0x1746,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204, -0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204, -0x204,0x204,0x204,0x204,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758, -0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x20a,0x1758,0x1758,0x20a,0x20a,0x20a,0x20a,0x20a,0x1755, -0x1755,0x1755,0x1755,0x1755,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x20d,0x175b,0x20d,0x175b,0x175b, -0x175b,0x175b,0x20d,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b, -0x175b,0x175b,0x20d,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175e,0x20d,0x20d, -0x20d,0x20d,0x20d,0x20d,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7, -0x15b7,0x15b7,0x15b7,0x15b7,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767, -0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x210,0x210,0x210,0x210,0x210,0x210,0x210,0x210,0x210, -0x210,0x210,0x210,0x210,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764, -0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x210,0x210,0x210,0x210,0x210,0x210,0x210,0x1761,0x1761, -0x1761,0x1761,0x1761,0x1761,0x176d,0x176d,0x176d,0x176d,0x176a,0x176d,0x176d,0x1770,0x1773,0x1770,0x1770,0x176d, -0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x176a, -0x176a,0x176a,0x176a,0x176a,0x17ca,0x17ca,0x17ca,0x17ca,0x17c1,0x17c1,0x17c1,0x17bb,0x17be,0x17be,0x17be,0x19e6, -0x216,0x216,0x216,0x216,0x17c7,0x17c7,0x17c7,0x17c7,0x17c7,0x17c7,0x17c7,0x17c7,0x17c7,0x17c7,0x216,0x216, -0x216,0x216,0x17c4,0x17c4,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x219,0x17e5,0x17e5, -0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5, -0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e2,0x17d0,0x17d0,0x17d0,0x17d0,0x17d0,0x17d0,0x17d0,0x219, -0x17d0,0x17d0,0x17d0,0x17d0,0x17d0,0x17d0,0x17e2,0x17d3,0x17e5,0x17e8,0x17e8,0x17dc,0x17d9,0x17d9,0x219,0x219, -0x219,0x219,0x219,0x219,0x219,0x219,0x219,0x219,0x17df,0x17df,0x17df,0x17df,0x17df,0x17df,0x17df,0x17df, -0x17df,0x17df,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6, -0x17d6,0x219,0x219,0x219,0x17f4,0x17f7,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd, -0x17fd,0x17fd,0x17fd,0x17fd,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x21c,0x21c,0x21c, -0x21c,0x21c,0x21c,0x21c,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956, -0x1956,0x1956,0x1956,0x1956,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x21f,0x17ee,0x17ee,0x17ee,0x17ee, -0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x21f,0x21f,0x17ee, -0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x21f,0x17ee,0x17ee,0x21f,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x21f, -0x21f,0x21f,0x21f,0x21f,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc, -0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x183c,0x18d8,0x1a40,0x1a43,0x1aeb,0x222,0x222,0x222,0x222,0x222,0x222,0x222, -0x222,0x222,0x222,0x222,0x1ae8,0x1ae8,0x222,0x222,0x222,0x222,0x222,0x222,0x222,0x222,0x222,0x222, -0x222,0x222,0x222,0x222,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd, -0x17fd,0x17fd,0x17fd,0x17fd,0x225,0x225,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1, -0x17f1,0x17f1,0x17f1,0x17f1,0x225,0x17fa,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17fa,0x17f1,0x17f1, -0x17fa,0x17f1,0x17f1,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x1800,0x1800,0x1800,0x1800, -0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x228,0x228,0x228,0x228,0x228,0x228,0x228, -0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x1818,0x1818,0x1809,0x1803, -0x1803,0x1818,0x1806,0x181b,0x181b,0x181b,0x181b,0x181e,0x181e,0x1812,0x180f,0x180c,0x1815,0x1815,0x1815,0x1815, -0x1815,0x1815,0x1815,0x1815,0x1815,0x1815,0x1a94,0x1812,0x22b,0x180c,0x193b,0x19e9,0x1a97,0x1a97,0x22b,0x22b, -0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b, -0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x1824,0x1824,0x1824,0x1824, -0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824, -0x22e,0x22e,0x22e,0x22e,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821, -0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821, -0x22e,0x22e,0x22e,0x22e,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f, -0x183f,0x19b9,0x19b9,0x19b9,0x19b9,0x19b9,0x1a46,0x1a46,0x1a46,0x1a46,0x1a46,0x1a46,0x231,0x231,0x231,0x231, -0x231,0x231,0x231,0x231,0x1bba,0x1bba,0x1bba,0x234,0x234,0x234,0x234,0x234,0x234,0x234,0x234,0x234, -0x234,0x234,0x234,0x234,0x276,0x276,0x1c2f,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276, -0x276,0x276,0x276,0x276,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x237,0x187e,0x187e,0x237,0x187e, -0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e, -0x187e,0x187e,0x187e,0x187e,0x187e,0x1872,0x1872,0x1872,0x1872,0x1872,0x1872,0x237,0x237,0x237,0x1872,0x237, -0x1872,0x1872,0x237,0x1872,0x1872,0x1872,0x1875,0x1872,0x1878,0x1878,0x1881,0x1872,0x237,0x237,0x237,0x237, -0x237,0x237,0x237,0x237,0x187b,0x187b,0x187b,0x187b,0x187b,0x187b,0x187b,0x187b,0x187b,0x187b,0x237,0x237, -0x237,0x237,0x237,0x237,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1, -0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1, -0x23a,0x23a,0x23a,0x23a,0x1890,0x1893,0x1893,0x23d,0x23d,0x23d,0x23d,0x23d,0x23d,0x23d,0x23d,0x23d, -0x23d,0x23d,0x23d,0x23d,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96, -0x1b96,0x1b96,0x1b96,0x1b96,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x240, -0x240,0x240,0x240,0x240,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63, -0x1b63,0x1b63,0x1b63,0x1b63,0x18ae,0x18b1,0x18c0,0x18c0,0x18b1,0x18b4,0x18ae,0x18ab,0x243,0x243,0x243,0x243, -0x243,0x243,0x243,0x243,0x1899,0x1884,0x1884,0x1884,0x1884,0x1884,0x1884,0x1896,0x1896,0x1884,0x1884,0x1884, -0x1899,0x1899,0x1899,0x1899,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef, -0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x246,0x246,0x246,0x246,0x246,0x246,0x246,0x246, -0x246,0x246,0x246,0x246,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941, -0x1941,0x1941,0x246,0x246,0x1a4f,0x1a4f,0x1a4f,0x1a4f,0x1af1,0x1c35,0x1c35,0x1c35,0x1a4f,0x1a4f,0x1a4f,0x1bbd, -0x1bbd,0x279,0x279,0x279,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953, -0x1950,0x1950,0x1950,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1950,0x194a,0x1947,0x194d, -0x249,0x249,0x249,0x249,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956, -0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x24c, -0x24c,0x1956,0x1956,0x1956,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x24f,0x1965,0x1965,0x24f,0x1965,0x1965, +0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x14d,0x14d,0x14d,0x11dc,0x11d0,0x11d0,0x11d0, +0x11d0,0x11d0,0x11d0,0x11d3,0x11e2,0x11e2,0x11d0,0x11d0,0x11d0,0x11d0,0x150,0x12db,0x11d6,0x11d6,0x11d6,0x11d6, +0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x150,0x150,0x150,0x150,0x11d0,0x11d0,0x1200,0x11f4,0x1200,0x153, +0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153, +0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x11fd,0x11fd,0x1203,0x11f7,0x11fa,0x1218,0x1218,0x1218,0x1212, +0x1212,0x1209,0x1212,0x1212,0x1209,0x1212,0x1212,0x121b,0x1215,0x120c,0x156,0x156,0x120f,0x120f,0x120f,0x120f, +0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,0x156,0x156,0x156,0x156,0x156,0x156,0x1221,0x1221,0x1221,0x1221, +0x1221,0x1221,0x1221,0x159,0x159,0x159,0x159,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e, +0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e, +0x121e,0x121e,0x121e,0x121e,0x159,0x159,0x159,0x159,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a, +0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x15c,0x1227, +0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239, +0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x15f,0x15f, +0x15f,0x1233,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f, +0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x162,0x162, +0x123c,0x123c,0x123c,0x123c,0x123c,0x123c,0x123c,0x123c,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245, +0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x165,0x165,0x165,0x165,0x165, +0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b, +0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b, +0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x124b,0x16b,0x1263,0x1263,0x1b4e,0x16e,0x16e,0x16e,0x16e,0x16e, +0x16e,0x16e,0x16e,0x16e,0x16e,0x1935,0x16e,0x16e,0x1485,0x1485,0x1485,0x1485,0x1485,0x1485,0x1485,0x1485, +0x1485,0x1485,0x1485,0x1485,0x1485,0x1485,0x1485,0x1485,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836, +0x1836,0x1836,0x1836,0x1836,0x1836,0x1a88,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171, +0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171, +0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x134a,0x134a,0x134a,0x134a,0x134a,0x134a, +0x134a,0x134a,0x134a,0x134a,0x134a,0x134a,0x134a,0x134a,0x134a,0x134a,0x134a,0x134a,0x134a,0x134a,0x134a,0x134a, +0x134a,0x134a,0x134a,0x134a,0x12b4,0x13b0,0x13b0,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174, +0x174,0x174,0x174,0x174,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1, +0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x1839, +0x174,0x174,0x174,0x174,0x12ae,0x12ae,0x12ae,0x12ae,0x12ae,0x12ae,0x12ae,0x12ae,0x12ae,0x174,0x174,0x174, +0x174,0x174,0x174,0x174,0x13d4,0x13d4,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174, +0x174,0x174,0x174,0x174,0x18d8,0x18d8,0x18d8,0x18d8,0x18d8,0x18d8,0x174,0x174,0x174,0x174,0x174,0x174, +0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174, +0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x1353,0x1353,0x1353,0x1353, +0x1353,0x1353,0x1353,0x1353,0x1353,0x1353,0x1353,0x1353,0x1353,0x1353,0x1353,0x1353,0x1353,0x1353,0x1353,0x1353, +0x1353,0x1353,0x1353,0x1353,0x1353,0x134d,0x134d,0x134d,0x177,0x177,0x1350,0x177,0x1365,0x1365,0x1365,0x1365, +0x1365,0x1365,0x1356,0x135f,0x1359,0x1359,0x135f,0x135f,0x135f,0x1359,0x135f,0x1359,0x1359,0x1359,0x1362,0x1362, +0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x135c,0x135c,0x135c,0x135c,0x17d,0x1368,0x1368,0x1368, +0x1368,0x1368,0x1368,0x17d,0x17d,0x1368,0x1368,0x1368,0x1368,0x1368,0x1368,0x17d,0x17d,0x1368,0x1368,0x1368, +0x1368,0x1368,0x1368,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x1368,0x1368,0x1368,0x1368, +0x1368,0x1368,0x1368,0x17d,0x1368,0x1368,0x1368,0x1368,0x1368,0x1368,0x1368,0x17d,0x15cf,0x15cf,0x15cf,0x15cf, +0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x136b,0x136b,0x136b,0x136b, +0x136b,0x136b,0x136e,0x1383,0x1383,0x1374,0x1374,0x1374,0x1374,0x1374,0x180,0x180,0x180,0x180,0x1371,0x1371, +0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1377,0x1377, +0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1b54,0x1b57,0x1b57,0x1b51,0x1b51,0x1b57,0x180,0x180, +0x180,0x180,0x180,0x180,0x180,0x180,0x180,0x153c,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386, +0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386, +0x1386,0x183,0x183,0x183,0x183,0x183,0x183,0x183,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389, +0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x186,0x186,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389, +0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x153f,0x186,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389, +0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x13b9,0x186,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389, +0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x1389,0x153f,0x153f,0x153f,0x153f,0x153f,0x153f,0x153f,0x153f, +0x153f,0x153f,0x153f,0x153f,0x153f,0x153f,0x153f,0x153f,0x153f,0x153f,0x153f,0x153f,0x153f,0x153f,0x186,0x186, +0x186,0x186,0x186,0x186,0x186,0x186,0x186,0x186,0x13ce,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x154b,0x154b, +0x154b,0x154b,0x154b,0x154b,0x16bf,0x154b,0x154b,0x154b,0x1791,0x1842,0x1842,0x187b,0x187b,0x1a46,0x1af1,0x1af1, +0x189,0x189,0x189,0x189,0x1c3e,0x1bc0,0x1bc0,0x1bc0,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b, +0x154b,0x154b,0x154b,0x16bc,0x16bc,0x189,0x189,0x189,0x154b,0x154b,0x154b,0x154b,0x1842,0x1842,0x1842,0x18de, +0x18de,0x19c2,0x1a46,0x1af1,0x1af1,0x189,0x189,0x189,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x1be4,0x1be4,0x1be4,0x18c, +0x18c,0x18c,0x18c,0x1be4,0x1be4,0x1be4,0x1be4,0x1be4,0x1428,0x1428,0x1428,0x1428,0x18f,0x1428,0x1428,0x1428, +0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428, +0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x18f,0x1428,0x1428,0x18f,0x1428,0x18f,0x18f,0x1428, +0x18f,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x18f,0x1428,0x1428,0x1428,0x1428, +0x18f,0x1428,0x18f,0x1428,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x1428,0x18f,0x18f,0x18f,0x18f,0x1428, +0x18f,0x1428,0x18f,0x1428,0x18f,0x1428,0x1428,0x1428,0x18f,0x1428,0x1428,0x18f,0x1428,0x18f,0x18f,0x1428, +0x18f,0x1428,0x18f,0x1428,0x18f,0x1428,0x18f,0x1428,0x18f,0x1428,0x1428,0x18f,0x1428,0x18f,0x18f,0x1428, +0x1428,0x1428,0x1428,0x18f,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x18f,0x1428,0x1428,0x1428,0x1428, +0x18f,0x1428,0x1428,0x1428,0x1428,0x18f,0x1428,0x18f,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428, +0x1428,0x1428,0x18f,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428, +0x1428,0x1428,0x1428,0x1428,0x18f,0x18f,0x18f,0x18f,0x18f,0x1428,0x1428,0x1428,0x18f,0x1428,0x1428,0x1428, +0x1428,0x1428,0x18f,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428,0x1428, +0x1428,0x1428,0x1428,0x1428,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f, +0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f, +0x18f,0x18f,0x18f,0x18f,0x1425,0x1425,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f,0x18f, +0x18f,0x18f,0x18f,0x18f,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x142b,0x142b,0x142b,0x142b,0x142b, +0x143a,0x142b,0x142e,0x142e,0x142b,0x142b,0x142b,0x1431,0x1431,0x192,0x1437,0x1437,0x1437,0x1437,0x1437,0x1437, +0x1437,0x1437,0x1437,0x1437,0x1434,0x1440,0x1440,0x1440,0x1941,0x193e,0x193e,0x1a8e,0x192,0x192,0x192,0x192, +0x192,0x192,0x192,0x192,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1, +0x15e1,0x15e1,0x15e1,0x15e1,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x1449, +0x1443,0x1443,0x1449,0x1449,0x1452,0x1452,0x144c,0x144f,0x144f,0x1449,0x1446,0x195,0x195,0x195,0x195,0x195, +0x195,0x195,0x195,0x195,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455, +0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x198,0x198,0x198,0x198, +0x1716,0x1716,0x1455,0x1455,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716, +0x1716,0x1716,0x1716,0x1716,0x198,0x198,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716, +0x1716,0x1716,0x1716,0x1716,0x1461,0x1461,0x1461,0x1461,0x1461,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19b, +0x19b,0x19b,0x19b,0x19e9,0x1461,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e, +0x145e,0x145e,0x145e,0x145e,0x19ec,0x19ec,0x19ec,0x19ec,0x19ec,0x19ec,0x19ec,0x19ec,0x19b,0x19b,0x19b,0x19b, +0x19b,0x19b,0x19b,0x145b,0x145b,0x145b,0x145b,0x1464,0x1464,0x1464,0x1464,0x1464,0x1464,0x1464,0x1464,0x1464, +0x1464,0x1464,0x1464,0x1464,0x1485,0x1485,0x1485,0x1485,0x1485,0x1485,0x1485,0x1485,0x1485,0x19e,0x19e,0x19e, +0x19e,0x19e,0x19e,0x19e,0x1482,0x1482,0x1482,0x1482,0x1482,0x1482,0x1482,0x1482,0x1482,0x1482,0x19e,0x19e, +0x19e,0x19e,0x19e,0x19e,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1a1,0x1a1,0x1a1,0x1a1, +0x1a1,0x1a1,0x1a1,0x1a1,0x12e1,0x12de,0x12e1,0x12bd,0x12de,0x12e4,0x12e4,0x12e7,0x12e4,0x12e7,0x12ea,0x12de, +0x12e7,0x12e7,0x12de,0x12de,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x148b, +0x1494,0x148b,0x1494,0x1494,0x148b,0x148b,0x148b,0x148b,0x148b,0x148b,0x1497,0x148e,0x19f2,0x1b63,0x1a4,0x1a4, +0x1a4,0x1a4,0x1a4,0x1a4,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d, +0x155d,0x155d,0x1a7,0x1a7,0x155a,0x155a,0x155a,0x155a,0x155a,0x1560,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7, +0x1a7,0x1a7,0x1a7,0x1a7,0x1566,0x1566,0x1566,0x1566,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa, +0x1aa,0x1aa,0x1aa,0x1563,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x2af, +0x1bae,0x1bae,0x1bae,0x1bae,0x16cb,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2, +0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2, +0x1ad,0x1ad,0x1ad,0x1ad,0x1a97,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69, +0x1b66,0x1b66,0x1b66,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0, +0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0, +0x1b0,0x1b0,0x1b0,0x1b0,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1b3, +0x1b3,0x1b3,0x1b3,0x1b3,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578, +0x1578,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578, +0x1578,0x1578,0x1b3,0x1b3,0x1575,0x156f,0x1572,0x157b,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e, +0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566, +0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581, +0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1944,0x1944,0x1944, +0x1944,0x1be7,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1a49,0x1a49,0x1a49,0x1a49,0x1a49,0x1a49,0x1a49,0x1a49, +0x1a49,0x1a49,0x1a49,0x1a49,0x1b9,0x1b9,0x1b9,0x1b9,0x1bc3,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9, +0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x172b,0x16ce,0x158a,0x16d4,0x1bc,0x1596,0x1596,0x1596, +0x1596,0x1596,0x1596,0x1596,0x1596,0x1bc,0x1bc,0x1596,0x1596,0x1bc,0x1bc,0x1596,0x1596,0x1596,0x1596,0x1596, +0x1596,0x1596,0x1596,0x1596,0x1596,0x1596,0x1596,0x1596,0x1596,0x1bc,0x1596,0x1596,0x1596,0x1596,0x1596,0x1596, +0x1596,0x1bc,0x1596,0x1596,0x1bc,0x1596,0x1596,0x1596,0x1596,0x1596,0x1bc,0x19ce,0x16d1,0x1593,0x1584,0x158a, +0x1584,0x158a,0x158a,0x158a,0x158a,0x1bc,0x1bc,0x158a,0x158a,0x1bc,0x1bc,0x158d,0x158d,0x1590,0x1bc,0x1bc, +0x172e,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1584,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x159c,0x1599,0x1599, +0x1596,0x1596,0x158a,0x158a,0x1bc,0x1bc,0x1587,0x1587,0x1587,0x1587,0x1587,0x1587,0x1587,0x1bc,0x1bc,0x1bc, +0x1587,0x1587,0x1587,0x1587,0x1587,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc, +0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1, +0x15b1,0x15b1,0x1bf,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1, +0x15c3,0x15c3,0x15c3,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15ba,0x15bd,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2, +0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2, +0x1731,0x1731,0x1731,0x1731,0x15cf,0x15cc,0x19f5,0x19f5,0x1a9d,0x1aa0,0x1a9a,0x1a9a,0x1c5,0x1c5,0x1c5,0x1c5, +0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e, +0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5, +0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8, +0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5, +0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8, +0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8, +0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8, +0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1, +0x15e1,0x15e1,0x15e1,0x15d8,0x15db,0x15de,0x15e1,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb, +0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15e4,0x15e4,0x1ce,0x1ce,0x1ce,0x1ce,0x15e7,0x15e7,0x15e7,0x15e7,0x15e7, +0x15ed,0x15ed,0x16d7,0x15ed,0x15ed,0x15ed,0x15ea,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce, +0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x1d1,0x1d1,0x15f6,0x15f6,0x15f6,0x15f6,0x15f6,0x15f6,0x15f6,0x15f6,0x15f6, +0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1, +0x15fc,0x160e,0x160e,0x1602,0x160b,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4, +0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4, +0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614, +0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1d7, +0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x1d7,0x1d7,0x1d7,0x1d7,0x1617,0x1617, +0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f, +0x1620,0x1620,0x1620,0x1620,0x1620,0x161a,0x1623,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620, +0x161d,0x161d,0x161d,0x161d,0x161d,0x161d,0x161d,0x161d,0x161d,0x161d,0x1620,0x1620,0x1620,0x1620,0x1620,0x1da, +0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629, +0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1dd, +0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635, +0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1632,0x1632,0x1632,0x1632,0x1632,0x1e0,0x1e0,0x1e0,0x1e0,0x1e0, +0x164d,0x164d,0x1650,0x1650,0x1653,0x1644,0x1e3,0x1e3,0x1e3,0x1e3,0x1e3,0x1e3,0x1e3,0x1e3,0x1e3,0x1e3, +0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x1e3,0x1644,0x1644,0x1644,0x1644,0x1644, +0x1644,0x1644,0x1e3,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d, +0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x1e3,0x1e3,0x1e3,0x1e3,0x1e3,0x164d,0x164d,0x164d, +0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c, +0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, +0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665, +0x1665,0x1665,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1662,0x1662,0x1662,0x1662,0x1e9,0x1e9,0x1e9, +0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1668, +0x167a,0x167a,0x1668,0x1668,0x1668,0x1668,0x1ef,0x1ef,0x167a,0x167a,0x167d,0x167d,0x1668,0x1668,0x167a,0x166e, +0x166b,0x1671,0x1683,0x1683,0x1674,0x1674,0x1677,0x1677,0x1677,0x1683,0x173a,0x173a,0x173a,0x173a,0x173a,0x173a, +0x173a,0x173a,0x173a,0x173a,0x173a,0x173a,0x173a,0x173a,0x1737,0x1737,0x1737,0x1737,0x1734,0x1734,0x1ef,0x1ef, +0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef, +0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef, +0x1f2,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686, +0x1686,0x1686,0x1686,0x1686,0x1686,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2, +0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1f5,0x1f5,0x1f5,0x1f5, +0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689, +0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689, +0x1689,0x1689,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689, +0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689, +0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1f5,0x1f5,0x1aa3,0x1aa3,0x1f5,0x1f5, +0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5, +0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5, +0x168c,0x169b,0x1692,0x168f,0x16a1,0x16a1,0x1695,0x16a1,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8, +0x1698,0x1698,0x1698,0x1698,0x1698,0x1698,0x1698,0x1698,0x1698,0x1698,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8, +0x16a7,0x16a7,0x16a7,0x16a7,0x16a7,0x16a7,0x16a7,0x16a7,0x16a7,0x16a7,0x16a4,0x16a4,0x16a4,0x16a4,0x16a4,0x16a4, +0x16a4,0x16a4,0x16a4,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x16ad, +0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f, +0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x1947,0x1fe,0x1fe,0x173d,0x173d,0x173d, +0x1749,0x1749,0x173d,0x173d,0x173d,0x173d,0x174c,0x173d,0x173d,0x173d,0x173d,0x1740,0x1fe,0x1fe,0x1fe,0x1fe, +0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1743,0x1743,0x1752,0x1752,0x1752,0x1743, +0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201, +0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201, +0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767, +0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x207,0x1767,0x1767,0x207,0x207, +0x207,0x207,0x207,0x1764,0x1764,0x1764,0x1764,0x1764,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x20a, +0x176a,0x20a,0x176a,0x176a,0x176a,0x176a,0x20a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a, +0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x20a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a, +0x176a,0x176d,0x20a,0x20a,0x20a,0x20a,0x20a,0x20a,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6, +0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776, +0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x20d,0x20d,0x20d,0x20d,0x20d, +0x20d,0x20d,0x20d,0x20d,0x20d,0x20d,0x20d,0x20d,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773, +0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x20d,0x20d,0x20d,0x20d,0x20d, +0x20d,0x20d,0x1770,0x1770,0x1770,0x1770,0x1770,0x1770,0x177c,0x177c,0x177c,0x177c,0x1779,0x177c,0x177c,0x177f, +0x1782,0x177f,0x177f,0x177c,0x210,0x210,0x210,0x210,0x210,0x210,0x210,0x210,0x210,0x210,0x210,0x210, +0x210,0x210,0x210,0x1779,0x1779,0x1779,0x1779,0x1779,0x17d9,0x17d9,0x17d9,0x17d9,0x17d0,0x17d0,0x17d0,0x17ca, +0x17cd,0x17cd,0x17cd,0x19f8,0x213,0x213,0x213,0x213,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6, +0x17d6,0x17d6,0x213,0x213,0x213,0x213,0x17d3,0x17d3,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4, +0x17f4,0x216,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4, +0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f4,0x17f1,0x17df,0x17df,0x17df,0x17df, +0x17df,0x17df,0x17df,0x216,0x17df,0x17df,0x17df,0x17df,0x17df,0x17df,0x17f1,0x17e2,0x17f4,0x17f7,0x17f7,0x17eb, +0x17e8,0x17e8,0x216,0x216,0x216,0x216,0x216,0x216,0x216,0x216,0x216,0x216,0x17ee,0x17ee,0x17ee,0x17ee, +0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5, +0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x216,0x216,0x216,0x1803,0x1806,0x180c,0x180c,0x180c,0x180c,0x180c,0x180c, +0x180c,0x180c,0x180c,0x180c,0x180c,0x180c,0x180c,0x180c,0x17fa,0x17fa,0x17fa,0x17fa,0x17fa,0x17fa,0x17fa,0x17fa, +0x17fa,0x219,0x219,0x219,0x219,0x219,0x219,0x219,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965, +0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x21c, +0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd, +0x17fd,0x21c,0x21c,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x21c,0x17fd,0x17fd,0x21c,0x17fd,0x17fd, +0x17fd,0x17fd,0x17fd,0x21c,0x21c,0x21c,0x21c,0x21c,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e, +0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x184b,0x18e7,0x1a52,0x1a55,0x1afd,0x21f,0x21f,0x21f, +0x21f,0x21f,0x21f,0x21f,0x21f,0x21f,0x21f,0x21f,0x1afa,0x1afa,0x21f,0x21f,0x21f,0x21f,0x21f,0x21f, +0x21f,0x21f,0x21f,0x21f,0x21f,0x21f,0x21f,0x21f,0x180c,0x180c,0x180c,0x180c,0x180c,0x180c,0x180c,0x180c, +0x180c,0x180c,0x180c,0x180c,0x180c,0x180c,0x180c,0x180c,0x222,0x222,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800, +0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x222,0x1809,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800, +0x1800,0x1809,0x1800,0x1800,0x1809,0x1800,0x1800,0x222,0x222,0x222,0x222,0x222,0x222,0x222,0x222,0x222, +0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x225,0x225,0x225, +0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225, +0x1827,0x1827,0x1818,0x1812,0x1812,0x1827,0x1815,0x182a,0x182a,0x182a,0x182a,0x182d,0x182d,0x1821,0x181e,0x181b, +0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1aa6,0x1821,0x228,0x181b,0x194a,0x19fb, +0x1aa9,0x1aa9,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228, +0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228, +0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833,0x1833, +0x1833,0x1833,0x1833,0x1833,0x22b,0x22b,0x22b,0x22b,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830, +0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830, +0x1830,0x1830,0x1830,0x1830,0x22b,0x22b,0x22b,0x22b,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e, +0x184e,0x184e,0x184e,0x184e,0x184e,0x19cb,0x19cb,0x19cb,0x19cb,0x19cb,0x1a58,0x1a58,0x1a58,0x1a58,0x1a58,0x1a58, +0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x1bcc,0x1bcc,0x1bcc,0x231,0x231,0x231,0x231,0x231, +0x231,0x231,0x231,0x231,0x231,0x231,0x231,0x231,0x273,0x273,0x1c41,0x273,0x273,0x273,0x273,0x273, +0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x234, +0x188d,0x188d,0x234,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d, +0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x188d,0x1881,0x1881,0x1881,0x1881,0x1881,0x1881,0x234, +0x234,0x234,0x1881,0x234,0x1881,0x1881,0x234,0x1881,0x1881,0x1881,0x1884,0x1881,0x1887,0x1887,0x1890,0x1881, +0x234,0x234,0x234,0x234,0x234,0x234,0x234,0x234,0x188a,0x188a,0x188a,0x188a,0x188a,0x188a,0x188a,0x188a, +0x188a,0x188a,0x234,0x234,0x234,0x234,0x234,0x234,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0, +0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0, +0x18f0,0x18f0,0x18f0,0x18f0,0x237,0x237,0x237,0x237,0x189f,0x18a2,0x18a2,0x23a,0x23a,0x23a,0x23a,0x23a, +0x23a,0x23a,0x23a,0x23a,0x23a,0x23a,0x23a,0x23a,0x1ba8,0x1ba8,0x1ba8,0x1ba8,0x1ba8,0x1ba8,0x1ba8,0x1ba8, +0x1ba8,0x1ba8,0x1ba8,0x1ba8,0x1ba8,0x1ba8,0x1ba8,0x1ba8,0x18b1,0x18b1,0x18b1,0x18b1,0x18b1,0x18b1,0x18b1,0x18b1, +0x18b1,0x18b1,0x18b1,0x23d,0x23d,0x23d,0x23d,0x23d,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75, +0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x18bd,0x18c0,0x18cf,0x18cf,0x18c0,0x18c3,0x18bd,0x18ba, +0x240,0x240,0x240,0x240,0x240,0x240,0x240,0x240,0x18a8,0x1893,0x1893,0x1893,0x1893,0x1893,0x1893,0x18a5, +0x18a5,0x1893,0x1893,0x1893,0x18a8,0x18a8,0x18a8,0x18a8,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01, +0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x243,0x243,0x243,0x243, +0x243,0x243,0x243,0x243,0x243,0x243,0x243,0x243,0x1950,0x1950,0x1950,0x1950,0x1950,0x1950,0x1950,0x1950, +0x1950,0x1950,0x1950,0x1950,0x1950,0x1950,0x243,0x243,0x1a61,0x1a61,0x1a61,0x1a61,0x1b03,0x1c47,0x1c47,0x1c47, +0x1a61,0x1a61,0x1a61,0x1bcf,0x1bcf,0x276,0x276,0x276,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962, +0x1962,0x1962,0x1962,0x1962,0x195f,0x195f,0x195f,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953, +0x195f,0x1959,0x1956,0x195c,0x246,0x246,0x246,0x246,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965, 0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965, -0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1962,0x1962,0x1962,0x1962,0x1962,0x24f,0x1959,0x1959,0x24f,0x1962, -0x1962,0x1959,0x1962,0x195c,0x1965,0x24f,0x24f,0x24f,0x24f,0x24f,0x24f,0x24f,0x196e,0x196e,0x1971,0x1971, -0x1968,0x1968,0x1968,0x1968,0x252,0x252,0x252,0x252,0x252,0x252,0x252,0x252,0x196b,0x196b,0x196b,0x196b, -0x196b,0x196b,0x196b,0x196b,0x196b,0x196b,0x252,0x252,0x252,0x252,0x252,0x252,0x1974,0x1974,0x1974,0x1974, -0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1977,0x1974,0x1974,0x1974,0x1977,0x1974,0x1974,0x1974, -0x1974,0x255,0x255,0x255,0x255,0x255,0x255,0x255,0x255,0x255,0x255,0x255,0x1980,0x1980,0x1980,0x1980, -0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x197a, -0x197a,0x197d,0x197d,0x1983,0x1983,0x258,0x258,0x258,0x258,0x258,0x258,0x258,0x1986,0x1986,0x1986,0x1986, -0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986, -0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x1989,0x1989,0x1989,0x1989, -0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989, -0x1989,0x1989,0x1989,0x198c,0x1995,0x1989,0x1989,0x25e,0x25e,0x25e,0x25e,0x25e,0x1998,0x1998,0x1998,0x1998, -0x1998,0x1998,0x1998,0x199b,0x261,0x261,0x261,0x261,0x261,0x261,0x261,0x261,0x19a4,0x19a4,0x19a4,0x19a4, -0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x199e,0x199e, -0x199e,0x199e,0x199e,0x199e,0x199e,0x199e,0x199e,0x199e,0x199e,0x19a1,0x19a1,0x19a1,0x19a1,0x19a7,0x19a7,0x19a7, -0x19a7,0x19a7,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264, -0x264,0x264,0x264,0x264,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84, -0x1b84,0x1b84,0x1b84,0x1b84,0x1be7,0x1bed,0x1bed,0x1bed,0x1bed,0x1bed,0x1bed,0x1bea,0x1bea,0x1bea,0x1bea,0x1bea, -0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,0x267,0x267,0x267,0x267,0x267,0x267, -0x267,0x267,0x267,0x267,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb, -0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x26a,0x26a,0x26a,0x26a,0x26a, -0x26a,0x26a,0x26a,0x26a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x26d,0x26d,0x1a0a,0x1a0a, -0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a, -0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a07,0x1a07,0x1a07,0x19fe,0x19fe,0x19fe,0x19fe,0x26d,0x26d,0x19fe,0x19fe, -0x1a07,0x1a07,0x1a07,0x1a07,0x1a01,0x1a0a,0x1a04,0x1a0a,0x1a07,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d, -0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d, -0x26d,0x26d,0x26d,0x26d,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16, -0x1a16,0x270,0x270,0x270,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16, -0x1a19,0x1a19,0x270,0x270,0x273,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c, -0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c, -0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x273,0x273,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276, -0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x1a49,0x1a49,0x1a49,0x276,0x276,0x1c32,0x276,0x276, -0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x1a4c,0x1a4c,0x1a4c,0x1a4c,0x276,0x276,0x276,0x276, -0x276,0x276,0x276,0x276,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1, -0x18e1,0x18e1,0x18e1,0x18e1,0x1a4f,0x1a4f,0x1a4f,0x1af1,0x1af1,0x1af1,0x1af1,0x1c35,0x1c35,0x279,0x279,0x279, -0x279,0x279,0x279,0x279,0x1a4f,0x1a4f,0x1a4f,0x1a4f,0x1a4f,0x1a4f,0x1af1,0x1af1,0x1af1,0x1af1,0x1af1,0x1af1, -0x1af1,0x1af1,0x1af1,0x1af1,0x1af1,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1c35,0x1c35,0x1c35,0x1af1,0x1af1,0x1af1,0x1af1, -0x1af1,0x1af1,0x1af1,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1c35,0x1c35,0x1c35,0x279,0x1c35,0x1af1,0x1af1,0x1af1,0x1bc0, -0x1bc0,0x1bc0,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x1c35,0x1c35,0x1af1,0x1af1,0x1af1,0x1af1, -0x1af1,0x1af1,0x1af1,0x1bbd,0x1bbd,0x1bbd,0x1c35,0x1c35,0x279,0x279,0x279,0x279,0x1bbd,0x1bbd,0x1bbd,0x1bbd, -0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1c35,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x1bc0,0x1bc0,0x1bc0,0x1bc0, -0x1bc0,0x1bc0,0x1bc0,0x1c38,0x1c38,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x1a25,0x1a1f,0x1a1f,0x1a1f, -0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x27c,0x27c, -0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x1a22,0x1a31,0x1a31,0x1a31,0x1a31, -0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a28,0x1a28,0x1a28,0x1a28,0x1a2e,0x1a2e,0x1a2e,0x1a2e, -0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x27f,0x27f,0x27f,0x27f,0x27f,0x1a2b,0x1a9d,0x1a9d,0x1a9d,0x1a9d, -0x1a9d,0x1a9a,0x1a9a,0x1a9a,0x1a9a,0x1a9a,0x1a9a,0x1a9a,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282, -0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x1ab8,0x1ab8,0x1ab8,0x1ab8, -0x1ab8,0x1ab8,0x1ab8,0x285,0x285,0x1ab8,0x285,0x285,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8, -0x285,0x1ab8,0x1ab8,0x285,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8, -0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1aa0,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x285,0x1aaf,0x1ab2,0x285,0x285,0x1aa0, -0x1aa0,0x1ab5,0x1aa6,0x1abb,0x1aaf,0x1abb,0x1aaf,0x1aa3,0x1abe,0x1aa9,0x1abe,0x285,0x285,0x285,0x285,0x285, -0x285,0x285,0x285,0x285,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x285,0x285, -0x285,0x285,0x285,0x285,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7, -0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x288,0x288,0x288,0x288,0x288,0x288, -0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288, -0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x1ac4,0x1ac4,0x1ac4,0x1ac4, -0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x28e, -0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x28e, +0x1965,0x1965,0x1965,0x249,0x249,0x1965,0x1965,0x1965,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x24c,0x1974, +0x1974,0x24c,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974, +0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1971,0x1971,0x1971,0x1971,0x1971,0x24c, +0x1968,0x1968,0x24c,0x1971,0x1971,0x1968,0x1971,0x196b,0x1974,0x24c,0x24c,0x24c,0x24c,0x24c,0x24c,0x24c, +0x197d,0x197d,0x1980,0x1980,0x1977,0x1977,0x1977,0x1977,0x24f,0x24f,0x24f,0x24f,0x24f,0x24f,0x24f,0x24f, +0x197a,0x197a,0x197a,0x197a,0x197a,0x197a,0x197a,0x197a,0x197a,0x197a,0x24f,0x24f,0x24f,0x24f,0x24f,0x24f, +0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1986,0x1983,0x1983,0x1983, +0x1986,0x1983,0x1983,0x1983,0x1983,0x252,0x252,0x252,0x252,0x252,0x252,0x252,0x252,0x252,0x252,0x252, +0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992, +0x1992,0x1992,0x198f,0x1989,0x1989,0x198c,0x198c,0x1995,0x1995,0x255,0x255,0x255,0x255,0x255,0x255,0x255, +0x1998,0x1998,0x1998,0x1998,0x1998,0x1998,0x1998,0x1998,0x1998,0x1998,0x1998,0x1998,0x1998,0x1998,0x1998,0x1998, +0x1998,0x1998,0x1998,0x1998,0x258,0x258,0x258,0x258,0x258,0x258,0x258,0x258,0x258,0x258,0x258,0x258, +0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b, +0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199e,0x19a7,0x199b,0x199b,0x25b,0x25b,0x25b,0x25b,0x25b, +0x19aa,0x19aa,0x19aa,0x19aa,0x19aa,0x19aa,0x19aa,0x19ad,0x25e,0x25e,0x25e,0x25e,0x25e,0x25e,0x25e,0x25e, +0x19b6,0x19b6,0x19b6,0x19b6,0x19b6,0x19b6,0x19b6,0x19b6,0x19b6,0x19b6,0x19b6,0x19b6,0x19b6,0x19b6,0x19b6,0x19b6, +0x19b6,0x19b6,0x19b0,0x19b0,0x19b0,0x19b0,0x19b0,0x19b0,0x19b0,0x19b0,0x19b0,0x19b0,0x19b0,0x19b3,0x19b3,0x19b3, +0x19b3,0x19b9,0x19b9,0x19b9,0x19b9,0x19b9,0x261,0x261,0x261,0x261,0x261,0x261,0x261,0x261,0x261,0x261, +0x261,0x261,0x261,0x261,0x261,0x261,0x261,0x261,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96, +0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1bf9,0x1bff,0x1bff,0x1bff,0x1bff,0x1bff,0x1bff,0x1bfc, +0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x264,0x264, +0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d, +0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x267, +0x267,0x267,0x267,0x267,0x267,0x267,0x267,0x267,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c, +0x26a,0x26a,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c, +0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a19,0x1a19,0x1a19,0x1a10,0x1a10,0x1a10,0x1a10, +0x26a,0x26a,0x1a10,0x1a10,0x1a19,0x1a19,0x1a19,0x1a19,0x1a13,0x1a1c,0x1a16,0x1a1c,0x1a19,0x26a,0x26a,0x26a, +0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x26a, +0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x26a,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28, +0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x26d,0x26d,0x26d,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a28, +0x1a28,0x1a28,0x1a28,0x1a28,0x1a2b,0x1a2b,0x26d,0x26d,0x270,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e, +0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e, +0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x270,0x270,0x273,0x273,0x273,0x273, +0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x1a5b,0x1a5b,0x1a5b,0x273, +0x273,0x1c44,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x1a5e,0x1a5e,0x1a5e,0x1a5e, +0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0, +0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x1a61,0x1a61,0x1a61,0x1b03,0x1b03,0x1b03,0x1b03,0x1c47, +0x1c47,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x1a61,0x1a61,0x1a61,0x1a61,0x1a61,0x1a61,0x1b03,0x1b03, +0x1b03,0x1b03,0x1b03,0x1b03,0x1b03,0x1b03,0x1b03,0x1b03,0x1b03,0x1bcf,0x1bcf,0x1bcf,0x1bcf,0x1c47,0x1c47,0x1c47, +0x1b03,0x1b03,0x1b03,0x1b03,0x1b03,0x1b03,0x1b03,0x1bcf,0x1bcf,0x1bcf,0x1bcf,0x1c47,0x1c47,0x1c47,0x276,0x1c47, +0x1b03,0x1b03,0x1b03,0x1bd2,0x1bd2,0x1bd2,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x1c47,0x1c47, +0x1b03,0x1b03,0x1b03,0x1b03,0x1b03,0x1b03,0x1b03,0x1bcf,0x1bcf,0x1bcf,0x1c47,0x1c47,0x276,0x276,0x276,0x276, +0x1bcf,0x1bcf,0x1bcf,0x1bcf,0x1bcf,0x1bcf,0x1bcf,0x1bcf,0x1c47,0x276,0x276,0x276,0x276,0x276,0x276,0x276, +0x1bd2,0x1bd2,0x1bd2,0x1bd2,0x1bd2,0x1bd2,0x1bd2,0x1c4a,0x1c4a,0x276,0x276,0x276,0x276,0x276,0x276,0x276, +0x1a37,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31, +0x1a31,0x1a31,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x1a34, +0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a3a,0x1a3a,0x1a3a,0x1a3a, +0x1a40,0x1a40,0x1a40,0x1a40,0x1a40,0x1a40,0x1a40,0x1a40,0x1a40,0x1a40,0x27c,0x27c,0x27c,0x27c,0x27c,0x1a3d, +0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x27f,0x27f,0x27f,0x27f, +0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f, +0x1aca,0x1aca,0x1aca,0x1aca,0x1aca,0x1aca,0x1aca,0x282,0x282,0x1aca,0x282,0x282,0x1aca,0x1aca,0x1aca,0x1aca, +0x1aca,0x1aca,0x1aca,0x1aca,0x282,0x1aca,0x1aca,0x282,0x1aca,0x1aca,0x1aca,0x1aca,0x1aca,0x1aca,0x1aca,0x1aca, +0x1aca,0x1aca,0x1aca,0x1aca,0x1aca,0x1aca,0x1aca,0x1aca,0x1ab2,0x1ac1,0x1ac1,0x1ac1,0x1ac1,0x1ac1,0x282,0x1ac1, +0x1ac4,0x282,0x282,0x1ab2,0x1ab2,0x1ac7,0x1ab8,0x1acd,0x1ac1,0x1acd,0x1ac1,0x1ab5,0x1ad0,0x1abb,0x1ad0,0x282, +0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe, +0x1abe,0x1abe,0x282,0x282,0x282,0x282,0x282,0x282,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09, +0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x285,0x285, +0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285, +0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285, +0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6, +0x1ad6,0x1ad6,0x1ad6,0x28b,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6, +0x1ad6,0x1ad6,0x1ad6,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b, +0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9, +0x1ad9,0x1ad9,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x1b0c,0x1b0c,0x1b0c,0x1b0c,0x1b0c,0x1b0c,0x1b0c,0x1b0c, +0x1b0c,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e, 0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e, -0x28e,0x28e,0x28e,0x28e,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x28e,0x28e, -0x28e,0x28e,0x28e,0x28e,0x1afa,0x1afa,0x1afa,0x1afa,0x1afa,0x1afa,0x1afa,0x1afa,0x1afa,0x291,0x291,0x291, -0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291, -0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291, -0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x294,0x1aca,0x1aca,0x1acd,0x294,0x294, -0x1ad0,0x1ad0,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294, -0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b60,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x297, -0x1b66,0x1b66,0x297,0x297,0x297,0x297,0x297,0x297,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d, -0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c, -0x1b6c,0x1b69,0x1b69,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a, -0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x29d,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x29d,0x1b6f,0x1b6f,0x29d, -0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x29d, -0x1b72,0x1b78,0x1b78,0x1b75,0x1b75,0x1b75,0x2a3,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75, -0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75, -0x1b75,0x2a3,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3, -0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7e,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b, -0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x2a6, -0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x1bf0,0x1bf0,0x1bf0,0x1bf0,0x1bf0,0x1bf0,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6, -0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6, -0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x1b84,0x1b84,0x1b81,0x1b81, -0x1b81,0x1b81,0x1b87,0x1b87,0x1b87,0x1b87,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9, -0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x1a9d,0x1a9d,0x1a9d,0x1a9d, -0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1b8d,0x1b8d,0x1b8d,0x1b8d, +0x28e,0x28e,0x28e,0x28e,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x291,0x1adc, +0x1adc,0x1adf,0x291,0x291,0x1ae2,0x1ae2,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291, +0x291,0x291,0x291,0x291,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b72,0x1b75,0x1b75,0x1b75, +0x1b75,0x1b75,0x1b75,0x294,0x1b78,0x1b78,0x294,0x294,0x294,0x294,0x294,0x294,0x1b6f,0x1b6f,0x1b6f,0x1b6f, +0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e, +0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7b,0x1b7b,0x297,0x297,0x297,0x297,0x297,0x297,0x297,0x297,0x297, +0x297,0x297,0x297,0x297,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x29a,0x1b81,0x1b81,0x1b81,0x1b81, +0x29a,0x1b81,0x1b81,0x29a,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81, +0x1b81,0x1b81,0x1b81,0x29a,0x1b84,0x1b8a,0x1b8a,0x1b87,0x1b87,0x1b87,0x2a0,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87, +0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87, +0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x2a0,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x2a0, +0x2a0,0x2a0,0x2a0,0x2a0,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b90,0x1b8d, 0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d, -0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x2ac,0x1b8a,0x1b8a,0x1b8a,0x1b8a, -0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x1554,0x1554,0x1554,0x1554, -0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1b93,0x1b93,0x1b93,0x1b93, -0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b90,0x2af,0x2af,0x2af,0x2af,0x2af, -0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x1b9c,0x1b9c,0x1b9c,0x1b9c, -0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x2b2,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x2b2, -0x1b9c,0x1b9c,0x2b2,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x2b2,0x1b99, -0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x2b2,0x1b99, -0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x2b2,0x1b99,0x1b99,0x2b2,0x2b2,0x2b2,0x1ba2,0x1ba2,0x1ba2,0x1ba2, -0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x2b5,0x2b5,0x1ba2,0x1ba2,0x1ba2,0x1ba2, -0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x2b5, -0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f, -0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8, +0x1b8d,0x1b8d,0x1b8d,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x2a3, +0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3, +0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3, +0x1b96,0x1b96,0x1b93,0x1b93,0x1b93,0x1b93,0x1b99,0x1b99,0x1b99,0x1b99,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6, +0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6, +0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf, +0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f, +0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x2a9, +0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9, +0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d, +0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba2,0x2ac, +0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac, +0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x2af,0x1bae,0x1bae,0x1bae,0x1bae, +0x1bae,0x1bae,0x1bae,0x2af,0x1bae,0x1bae,0x2af,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab, +0x1bab,0x1bab,0x2af,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab, +0x1bab,0x1bab,0x2af,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x2af,0x1bab,0x1bab,0x2af,0x2af,0x2af, +0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x2b2,0x2b2, +0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4, +0x1bb4,0x1bb4,0x1bb4,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x1bb1,0x1bb1,0x1bb1,0x1bb1, +0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x2b5,0x2b5,0x2b5,0x2b5, +0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5, +0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x1c05,0x1c05,0x1c05, +0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0e,0x1c0e,0x1c0e,0x2b8,0x2b8, 0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8, -0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x1bf3,0x1bf3,0x1bf3,0x1bf9,0x1bf9,0x1bf9,0x1bf9, -0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bfc,0x1bfc,0x1bfc,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb, -0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x1bff,0x1bff,0x1bff,0x1bff, -0x1bff,0x1bff,0x1bff,0x1bff,0x1bff,0x1bff,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be, -0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be, -0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02, -0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x2c1,0x2c1,0x2c1,0x2c1, -0x2c1,0x2c1,0x2c1,0x2c1,0x2c1,0x2c1,0x2c1,0x2c1,0x1c05,0x1c05,0x1c1a,0x1c11,0x1c17,0x1c17,0x1c17,0x1c17, -0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x2c4,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17, -0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17, -0x1c11,0x1c11,0x1c05,0x1c05,0x1c05,0x1c05,0x1c05,0x2c4,0x2c4,0x2c4,0x1c11,0x1c11,0x1c05,0x1c14,0x1c08,0x1c1d, -0x1c1d,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0e,0x1c0e,0x1c0e,0x1c0e, -0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x1c26,0x1c26,0x1c26,0x1c26, -0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c20,0x1c20,0x1c20,0x1c20,0x1c23,0x1c23,0x1c23,0x1c23, -0x1c23,0x1c23,0x1c23,0x1c23,0x1c23,0x1c23,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2ca,0x2ca,0x2ca,0x2ca, +0x1c11,0x1c11,0x1c11,0x1c11,0x1c11,0x1c11,0x1c11,0x1c11,0x1c11,0x1c11,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb, +0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb, +0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x1c14,0x1c14,0x1c14,0x1c14, +0x1c14,0x1c14,0x1c14,0x1c14,0x1c14,0x1c14,0x1c14,0x1c14,0x1c14,0x1c14,0x1c14,0x1c14,0x1c14,0x1c14,0x1c14,0x1c14, +0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x1c17,0x1c17,0x1c2c,0x1c23, +0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x2c1,0x1c29,0x1c29, +0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29,0x1c29, +0x1c29,0x1c29,0x1c29,0x1c29,0x1c23,0x1c23,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x2c1,0x2c1,0x2c1,0x1c23,0x1c23, +0x1c17,0x1c26,0x1c1a,0x1c2f,0x1c2f,0x1c1d,0x1c1d,0x1c1d,0x1c1d,0x1c1d,0x1c1d,0x1c1d,0x1c1d,0x1c1d,0x1c1d,0x1c1d, +0x1c20,0x1c20,0x1c20,0x1c20,0x1c20,0x1c20,0x1c20,0x1c20,0x1c20,0x1c20,0x2c1,0x2c1,0x2c1,0x2c1,0x2c1,0x2c1, +0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c38,0x1c32,0x1c32,0x1c32,0x1c32, +0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x1c35,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4, +0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, +0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, +0x2c7,0x2c7,0x95d,0x95d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d, +0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, +0x2c7,0x2c7,0x2c7,0x2c7,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0x12a5, +0x12a5,0x12a5,0x2ca,0x2ca,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97, +0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0x2ca,0x2ca, 0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca, -0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x18db,0x2dc,0x2dc,0x2dc, -0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2ca,0x2ca,0x2ca,0x2ca, 0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca, -0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x95d,0x95d,0x1c3b,0x1c3b,0x1c3b,0x1c3b, -0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x2ca,0x2ca,0x2ca,0x2ca, -0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0xc6c,0xc6c,0xc6c,0xc6c, -0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0x129f,0x129f,0x129f,0x2cd,0x2cd,0xe94,0xe94,0xe94,0xe94, -0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94, -0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd, -0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd, -0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88, -0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88, -0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0x2d0,0x2d0,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1, -0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x1bab,0x1bab,0x1bab, -0x1bab,0x1c29,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8, -0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8, -0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x2d6,0x2d6,0x1785,0x1785,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9, -0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db, -0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4, -0x1af4,0x1af4,0x1af4,0x2df,0x2df,0x2df,0x2df,0x2df,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b, -0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x3e7,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db, -0x3db,0x3e7,0x3e7,0x3e7,0x3e7,0x3e1,0x111f,0x12f6,0x3ea,0x927,0x92a,0x3d8,0x3d8,0x111c,0x12f3,0x12f3, -0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x111c,0x3db,0x3db,0x3e7,0xcae,0x3ea,0x3ea,0x3ea, +0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b, +0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0x2cd,0x2cd, +0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7, +0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1c3b,0x2d0,0x2d0,0x2d0,0x2d0,0x2d0,0x2d0, +0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1, +0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x2d3,0x2d3, +0x1794,0x1794,0x2d6,0x2d6,0x2d6,0x2d6,0x2d6,0x2d6,0x2d6,0x2d6,0x2d6,0x2d6,0x2d6,0x2d6,0x2d6,0x2d6, +0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea, +0x18ea,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9, +0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59, +0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc, +0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d, +0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59, +0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x2df,0x2df, +0x3e7,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3e7,0x3e7,0x3e7,0x3e7,0x3e1,0x1125,0x12fc, +0x3ea,0x927,0x92a,0x3d8,0x3d8,0x1122,0x12f9,0x12f9,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed, +0x1122,0x3db,0x3db,0x3e7,0xcb1,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea, 0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea, -0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3db,0x3db,0x8af,0x8b2,0x945,0x945, -0x945,0x945,0x945,0x945,0x945,0x945,0x945,0x945,0x3e4,0xf7e,0xf7b,0x12f9,0x12f9,0x12f9,0x12f9,0x12f9, -0x14b8,0x1122,0x1122,0xed0,0xed0,0xda1,0xed0,0xed0,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea, -0x3ea,0x3ed,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ed,0x3ea,0x3ea,0x3ed,0x3ea,0x3ea,0x3ea, -0x3ea,0x3ea,0x12f3,0x12f6,0x3de,0x3ea,0x3e7,0x3e7,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489, -0x489,0x12ff,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489, -0x489,0x489,0x12ff,0x1857,0x1857,0xf9c,0x47a,0x483,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5, -0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0xba3, -0xba3,0xdb0,0xdb0,0x8b5,0xdad,0x13da,0x13da,0x13da,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8, +0x3ea,0x3ea,0x3db,0x3db,0x8af,0x8b2,0x945,0x945,0x945,0x945,0x945,0x945,0x945,0x945,0x945,0x945, +0x3e4,0xf81,0xf7e,0x12ff,0x12ff,0x12ff,0x12ff,0x12ff,0x14c1,0x1128,0x1128,0xed3,0xed3,0xda4,0xed3,0xed3, +0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ed,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea, +0x3ea,0x3ed,0x3ea,0x3ea,0x3ed,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x12f9,0x12fc,0x3de,0x3ea,0x3e7,0x3e7, +0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x1305,0x489,0x489,0x489,0x489,0x489,0x489, +0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x1305,0x1866,0x1866,0xf9f,0x47a,0x483, +0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5, +0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0xba6,0xba6,0xdb3,0xdb3,0x8b5,0xdb0,0x13e3,0x13e3,0x13e3, 0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8, -0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4ce,0x4ce,0x4ce,0x1137,0x1137,0x1137,0x1137,0x1137, -0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb, +0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8, +0x4ce,0x4ce,0x4ce,0x113d,0x113d,0x113d,0x113d,0x113d,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb, 0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb, -0x4cb,0x4cb,0x1134,0x1134,0x1134,0x1134,0x1134,0x1134,0x4d1,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce, +0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x113a,0x113a,0x113a,0x113a,0x113a,0x113a, +0x4d1,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce, 0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce, -0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4da,0x4d4,0x4da,0x4d4, +0x4ce,0x4ce,0x4ce,0x4ce,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4, 0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4, -0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4d4,0x4d4, -0x4d4,0x4d4,0x4d7,0x9a2,0xfc9,0xfc9,0xfcc,0xfc9,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4, +0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d7,0x9a2,0xfcc,0xfcc,0xfcf,0xfcc, 0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4, -0x4da,0x4d4,0xfcc,0xfc9,0xfcc,0xfc9,0xfcc,0xfc9,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6, -0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6, -0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x6a5,0x6a5,0x6a8,0x504,0x6b4,0x6b1,0x6b1,0x6ae, -0x52e,0x52e,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0xb34,0x6b7,0x510,0x6cf,0x6d2,0x525,0x6b7,0x513,0x513, -0x504,0x51f,0x51f,0x6a5,0x52b,0x528,0x6ab,0x4fe,0x4f5,0x4f5,0x4f8,0x4f8,0x4f8,0x4f8,0x4f8,0x4fb, -0x4f8,0x4f8,0x4f8,0x4ef,0x537,0x534,0x531,0x531,0x6c3,0x519,0x516,0x6c0,0x6bd,0x6ba,0x6cc,0x507, -0x6c9,0x6c9,0x51c,0x51f,0x6c6,0x6c6,0x51c,0x51f,0x501,0x504,0x504,0x504,0x522,0x50d,0x50a,0xbb8, -0xad7,0xad7,0xad4,0xad4,0xad4,0xad4,0xbaf,0xbaf,0xbaf,0xbaf,0xbb5,0xcdb,0xcd8,0xdbc,0xdbf,0xbb2, -0xdbf,0xdbf,0xdbf,0xdbf,0xdbc,0xdbf,0xdbf,0xbac,0x55b,0x55b,0x55b,0x55b,0x55b,0x55b,0x55b,0x558, -0x55e,0x73e,0x55b,0x9a5,0x9c6,0xada,0xada,0xada,0xbbe,0xbbe,0xdc5,0xdc5,0xdc5,0xdc5,0x1140,0x1143, -0x1143,0x1314,0x14a6,0x14d0,0x14d3,0x14d3,0x16da,0x185a,0x56a,0x56a,0x582,0x6e4,0x567,0x6de,0x56a,0x57f, -0x567,0x6e4,0x579,0x582,0x582,0x582,0x579,0x579,0x582,0x582,0x582,0x6ea,0x567,0x582,0x6e7,0x567, -0x576,0x582,0x582,0x582,0x582,0x582,0x567,0x567,0x56d,0x6de,0x6e1,0x567,0x582,0x567,0x6ed,0x567, -0x582,0x570,0x588,0x6f0,0x582,0x582,0x573,0x579,0x582,0x582,0x585,0x582,0x579,0x57c,0x57c,0x57c, -0x57c,0xae3,0xae0,0xcde,0xdce,0xbd3,0xbd6,0xbd6,0xbd0,0xbcd,0xbcd,0xbcd,0xbcd,0xbd6,0xbd3,0xbd3, -0xbd3,0xbd3,0xbca,0xbcd,0xdcb,0xedc,0xedf,0xfd2,0x1146,0x1146,0x1146,0x6f6,0x6f3,0x58b,0x58e,0x58e, -0x58e,0x58e,0x58e,0x6f3,0x6f6,0x6f6,0x6f3,0x58e,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc, -0x6fc,0x6fc,0x6fc,0x6fc,0x597,0x597,0x597,0x597,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9, -0x6f9,0x6f9,0x591,0x591,0x591,0x591,0x591,0x591,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d, -0x59a,0x59d,0x59d,0x59d,0x59d,0x59d,0x5a0,0x59a,0x59d,0x59d,0x59a,0x59a,0x59a,0x59a,0x59d,0x59d, -0x6ff,0x6ff,0x59a,0x59a,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d, -0x59d,0x5a0,0x5a0,0x5a0,0x59d,0x59d,0x702,0x59d,0x702,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d, -0x59a,0x59d,0x59a,0x59a,0x59a,0x59a,0x59a,0x59a,0x59d,0x59d,0x59a,0x6ff,0x59a,0x59a,0x59a,0xae9, -0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xbd9,0xbd9,0xbd9,0xbd9,0xbd9,0xbd9,0xbd9,0xbd9, -0xbd9,0xbd9,0xbd9,0xbd9,0x705,0x5a3,0x705,0x705,0x5a6,0x5a3,0x5a3,0x705,0x705,0x5a6,0x5a3,0x705, -0x5a6,0x5a3,0x5a3,0x705,0x5a3,0x705,0x5b2,0x5af,0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x5a3, -0x5a3,0x705,0x705,0x705,0x705,0x5a3,0x5a3,0x705,0x5a6,0x705,0x5a6,0x705,0x705,0x705,0x705,0x705, -0x70b,0x5a9,0x705,0x5a9,0x5a9,0x5a3,0x5a3,0x5a3,0x705,0x705,0x705,0x705,0x5a3,0x5a3,0x5a3,0x5a3, -0x705,0x705,0x5a3,0x5a3,0x5a3,0x5a6,0x5a3,0x5a3,0x5a6,0x5a3,0x5a3,0x5a6,0x705,0x5a6,0x5a3,0x5a3, -0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, -0x5a3,0x5a3,0x5a3,0x5a3,0x708,0x705,0x5a6,0x5a3,0x705,0x705,0x705,0x705,0x5a3,0x5a3,0x705,0x705, -0x5a3,0x5a6,0x708,0x708,0x5a6,0x5a6,0x5a3,0x5a3,0x5a6,0x5a6,0x5a3,0x5a3,0x5a6,0x5a6,0x5a3,0x5a3, -0x5a3,0x5a3,0x5a3,0x5a3,0x5a6,0x5a6,0x705,0x705,0x5a6,0x5a6,0x705,0x705,0x5a6,0x5a6,0x5a3,0x5a3, -0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x705,0x5a3,0x5a3, -0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a6,0x5a6,0x5a6,0x5a6, -0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x705, +0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0xfcf,0xfcc,0xfcf,0xfcc,0xfcf,0xfcc, +0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9, +0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9, +0x6a5,0x6a5,0x6a8,0x504,0x6b4,0x6b1,0x6b1,0x6ae,0x52e,0x52e,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0xb37, +0x6b7,0x510,0x6cf,0x6d2,0x525,0x6b7,0x513,0x513,0x504,0x51f,0x51f,0x6a5,0x52b,0x528,0x6ab,0x4fe, +0x4f5,0x4f5,0x4f8,0x4f8,0x4f8,0x4f8,0x4f8,0x4fb,0x4f8,0x4f8,0x4f8,0x4ef,0x537,0x534,0x531,0x531, +0x6c3,0x519,0x516,0x6c0,0x6bd,0x6ba,0x6cc,0x507,0x6c9,0x6c9,0x51c,0x51f,0x6c6,0x6c6,0x51c,0x51f, +0x501,0x504,0x504,0x504,0x522,0x50d,0x50a,0xbbb,0xada,0xada,0xad7,0xad7,0xad7,0xad7,0xbb2,0xbb2, +0xbb2,0xbb2,0xbb8,0xcde,0xcdb,0xdbf,0xdc2,0xbb5,0xdc2,0xdc2,0xdc2,0xdc2,0xdbf,0xdc2,0xdc2,0xbaf, +0x55b,0x55b,0x55b,0x55b,0x55b,0x55b,0x55b,0x558,0x55e,0x73e,0x55b,0x9a5,0x9c6,0xadd,0xadd,0xadd, +0xbc1,0xbc1,0xdc8,0xdc8,0xdc8,0xdc8,0x1146,0x1149,0x1149,0x131a,0x14af,0x14d9,0x14dc,0x14dc,0x16e9,0x1869, +0x56a,0x56a,0x582,0x6e4,0x567,0x6de,0x56a,0x57f,0x567,0x6e4,0x579,0x582,0x582,0x582,0x579,0x579, +0x582,0x582,0x582,0x6ea,0x567,0x582,0x6e7,0x567,0x576,0x582,0x582,0x582,0x582,0x582,0x567,0x567, +0x56d,0x6de,0x6e1,0x567,0x582,0x567,0x6ed,0x567,0x582,0x570,0x588,0x6f0,0x582,0x582,0x573,0x579, +0x582,0x582,0x585,0x582,0x579,0x57c,0x57c,0x57c,0x57c,0xae6,0xae3,0xce1,0xdd1,0xbd6,0xbd9,0xbd9, +0xbd3,0xbd0,0xbd0,0xbd0,0xbd0,0xbd9,0xbd6,0xbd6,0xbd6,0xbd6,0xbcd,0xbd0,0xdce,0xedf,0xee2,0xfd5, +0x114c,0x114c,0x114c,0x6f6,0x6f3,0x58b,0x58e,0x58e,0x58e,0x58e,0x58e,0x6f3,0x6f6,0x6f6,0x6f3,0x58e, +0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x597,0x597,0x597,0x597, +0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,0x591,0x591,0x591,0x591,0x591,0x591, +0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59a,0x59d,0x59d,0x59d,0x59d,0x59d,0x5a0,0x59a, +0x59d,0x59d,0x59a,0x59a,0x59a,0x59a,0x59d,0x59d,0x6ff,0x6ff,0x59a,0x59a,0x59d,0x59d,0x59d,0x59d, +0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x5a0,0x5a0,0x5a0,0x59d,0x59d,0x702,0x59d, +0x702,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59a,0x59d,0x59a,0x59a,0x59a,0x59a,0x59a,0x59a, +0x59d,0x59d,0x59a,0x6ff,0x59a,0x59a,0x59a,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec, +0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0x705,0x5a3,0x705,0x705, +0x5a6,0x5a3,0x5a3,0x705,0x705,0x5a6,0x5a3,0x705,0x5a6,0x5a3,0x5a3,0x705,0x5a3,0x705,0x5b2,0x5af, +0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x5a3,0x5a3,0x705,0x705,0x705,0x705,0x5a3,0x5a3,0x705, +0x5a6,0x705,0x5a6,0x705,0x705,0x705,0x705,0x705,0x70b,0x5a9,0x705,0x5a9,0x5a9,0x5a3,0x5a3,0x5a3, +0x705,0x705,0x705,0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x705,0x5a3,0x5a3,0x5a3,0x5a6,0x5a3,0x5a3, +0x5a6,0x5a3,0x5a3,0x5a6,0x705,0x5a6,0x5a3,0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x5a3, +0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x708,0x705,0x5a6,0x5a3, +0x705,0x705,0x705,0x705,0x5a3,0x5a3,0x705,0x705,0x5a3,0x5a6,0x708,0x708,0x5a6,0x5a6,0x5a3,0x5a3, +0x5a6,0x5a6,0x5a3,0x5a3,0x5a6,0x5a6,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a6,0x5a6,0x705,0x705, +0x5a6,0x5a6,0x705,0x705,0x5a6,0x5a6,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, +0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x5a3,0x5a3, +0x5a3,0x5a3,0x5a3,0x5a3,0x5a6,0x5a6,0x5a6,0x5a6,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, +0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, -0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, -0x5a6,0x5a6,0x5a6,0x5a6,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a6,0x5a6,0x5a6,0x5a6,0x5a3,0x5ac, -0x5a3,0x5a3,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc, -0x5b5,0xaec,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5be,0x5bb,0x5be,0x5bb,0x5b5,0x5b5,0x5b5,0x5b5, -0x5b5,0x5b5,0x70e,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x7fe,0x7fe,0x5b5,0x5b5,0x5b5,0x5b5, -0x5b8,0x5b8,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x804,0x801,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5, +0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a6,0x5a6,0x5a6,0x5a6,0x5a3,0x5a3,0x5a3,0x5a3, +0x5a3,0x5a3,0x5a6,0x5a6,0x5a6,0x5a6,0x5a3,0x5ac,0x5a3,0x5a3,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf, +0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0x5b5,0xaef,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5, +0x5be,0x5bb,0x5be,0x5bb,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x70e,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5, +0x5b5,0x5b5,0x7fe,0x7fe,0x5b5,0x5b5,0x5b5,0x5b5,0x5b8,0x5b8,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5, +0x5b5,0x804,0x801,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5, 0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5, -0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0xaec, -0xbe2,0xaec,0xaec,0xaec,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1, +0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0xaef,0xbe5,0xaef,0xaef,0xaef,0x5c1,0x5c1,0x5c1,0x5c1, 0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1, -0x5c1,0x5c1,0x5c1,0x5c1,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x5c7,0xc3f, -0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f, -0xc3f,0xc3f,0xc3f,0xd4d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d, -0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x5ca,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd, -0x5cd,0x5cd,0x5cd,0x5cd,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d, -0x5cd,0x5cd,0x5cd,0x5cd,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d, -0x71d,0x71d,0x71d,0x71d,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720, -0x720,0x720,0x720,0x720,0x5d0,0x5d0,0x720,0x720,0x720,0x720,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5, -0xbe5,0xbe5,0xbe5,0xbe5,0x726,0x726,0x5d3,0x723,0x723,0x723,0x723,0x723,0x723,0x723,0x5d3,0x5d3, -0x5d3,0x5d3,0x5d6,0x5d6,0x5d6,0x5d6,0x726,0x726,0x5d6,0x5d6,0x726,0x726,0x5d3,0x5d3,0x5d3,0x5d3, -0x726,0x726,0x5d6,0x5d6,0x726,0x726,0x5d3,0x5d3,0x5d3,0x5d3,0x726,0x726,0x723,0x5d3,0x5d6,0x726, -0x5d3,0x5d3,0x723,0x726,0x726,0x726,0x5d6,0x5d6,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3, -0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x726,0x723,0x726,0x723,0x5d3,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6, -0x5d6,0x5d3,0x5d3,0x723,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xbe8,0xbe8,0xbe8,0xbe8, -0xbe8,0xc57,0xc57,0xbe8,0x5dc,0x5dc,0x5dc,0x5dc,0x5d9,0x72f,0x72f,0x5d9,0x5d9,0x729,0x5d9,0x5d9, -0x5d9,0x5d9,0x729,0x729,0x5d9,0x5d9,0x5d9,0x5d9,0xd56,0xd56,0xbeb,0xbeb,0xdd7,0xaf5,0x5dc,0x5dc, -0x72c,0x5df,0x72c,0x5dc,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9, -0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5dc,0x5dc,0x5dc, -0x5d9,0x5d9,0x5d9,0x5d9,0x72f,0x5d9,0x72f,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x807,0x807,0x807,0x807, -0x807,0x807,0x807,0x807,0x807,0x807,0x807,0x807,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9, -0x5d9,0x5d9,0x5d9,0x5d9,0x72f,0x72f,0x5e2,0x72f,0x729,0x729,0x5d9,0x729,0x72c,0x729,0x729,0x5d9, -0x729,0x72f,0x5e2,0x72f,0xaf5,0xaf5,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee, -0xbee,0xbee,0xdd4,0xe8b,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5, -0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e8,0x139b,0x139b,0x139b,0x5e8,0x5e8,0x5e8,0x5e8, -0x5e8,0x5e8,0x5e8,0x5e8,0x14d9,0x5ee,0x5ee,0x5ee,0x5ee,0x139b,0x5e8,0x5e8,0x5ee,0x5ee,0x139e,0x139e, -0x5f4,0x5f4,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8, -0x5e8,0x5e8,0x5e8,0x5e8,0x139b,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8, -0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x735,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8, -0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x139b,0x5e8,0x139b,0x5e8,0x5e8,0x5e8,0x5e8,0x139b, -0x139b,0x139b,0x5e8,0x1299,0x5e8,0x5e8,0x5e8,0x5f1,0x5f1,0x5f1,0x5f1,0x1320,0x1320,0x5e8,0x5eb,0x5eb, -0x5ee,0x5e8,0x5e8,0x5e8,0xbf4,0xbf1,0xbf4,0xbf1,0xbf4,0xbf1,0xbf4,0xbf1,0xbf4,0xbf1,0xbf4,0xbf1, -0xbf4,0xbf1,0x732,0x732,0x732,0x732,0x732,0x732,0x732,0x732,0x732,0x732,0x5e8,0x5e8,0x5e8,0x5e8, -0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x139b,0x5e8,0x5e8,0x5e8, -0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x139b,0x615,0x615,0x615,0x615, +0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x717,0x717,0x717,0x717, +0x717,0x717,0x717,0x717,0x717,0x717,0x5c7,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42, +0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xd50,0x71d,0x71d,0x71d,0x71d, +0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d, +0x5ca,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd,0x71d,0x71d,0x71d,0x71d, +0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x5cd,0x5cd,0x5cd,0x5cd,0x71d,0x71d,0x71d,0x71d, +0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x720,0x720,0x720,0x720, +0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x5d0,0x5d0,0x720,0x720, +0x720,0x720,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0x726,0x726,0x5d3,0x723, +0x723,0x723,0x723,0x723,0x723,0x723,0x5d3,0x5d3,0x5d3,0x5d3,0x5d6,0x5d6,0x5d6,0x5d6,0x726,0x726, +0x5d6,0x5d6,0x726,0x726,0x5d3,0x5d3,0x5d3,0x5d3,0x726,0x726,0x5d6,0x5d6,0x726,0x726,0x5d3,0x5d3, +0x5d3,0x5d3,0x726,0x726,0x723,0x5d3,0x5d6,0x726,0x5d3,0x5d3,0x723,0x726,0x726,0x726,0x5d6,0x5d6, +0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x726,0x723, +0x726,0x723,0x5d3,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d3,0x5d3,0x723,0xaf5,0xaf5,0xaf5,0xaf5, +0xaf5,0xaf5,0xaf5,0xaf5,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xc5a,0xc5a,0xbeb,0x5dc,0x5dc,0x5dc,0x5dc, +0x5d9,0x72f,0x72f,0x5d9,0x5d9,0x729,0x5d9,0x5d9,0x5d9,0x5d9,0x729,0x729,0x5d9,0x5d9,0x5d9,0x5d9, +0xd59,0xd59,0xbee,0xbee,0xdda,0xaf8,0x5dc,0x5dc,0x72c,0x5df,0x72c,0x5dc,0x5d9,0x5d9,0x5d9,0x5d9, +0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9, +0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5dc,0x5dc,0x5dc,0x5d9,0x5d9,0x5d9,0x5d9,0x72f,0x5d9,0x72f,0x5d9, +0x5d9,0x5d9,0x5d9,0x5d9,0x807,0x807,0x807,0x807,0x807,0x807,0x807,0x807,0x807,0x807,0x807,0x807, +0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x72f,0x72f,0x5e2,0x72f, +0x729,0x729,0x5d9,0x729,0x72c,0x729,0x729,0x5d9,0x729,0x72f,0x5e2,0x72f,0xaf8,0xaf8,0xbf1,0xbf1, +0xbf1,0xbf1,0xbf1,0xbf1,0xbf1,0xbf1,0xbf1,0xbf1,0xbf1,0xbf1,0xdd7,0xe8e,0x5e5,0x5e5,0x5e5,0x5e5, +0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5, +0x5e8,0x13a4,0x13a4,0x13a4,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x14e2,0x5ee,0x5ee,0x5ee, +0x5ee,0x13a4,0x5e8,0x5e8,0x5ee,0x5ee,0x13a7,0x13a7,0x5f4,0x5f4,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8, +0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x13a4,0x5e8,0x5e8,0x5e8, +0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8, +0x5e8,0x735,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8, +0x13a4,0x5e8,0x13a4,0x5e8,0x5e8,0x5e8,0x5e8,0x13a4,0x13a4,0x13a4,0x5e8,0x129f,0x5e8,0x5e8,0x5e8,0x5f1, +0x5f1,0x5f1,0x5f1,0x1326,0x1326,0x5e8,0x5eb,0x5eb,0x5ee,0x5e8,0x5e8,0x5e8,0xbf7,0xbf4,0xbf7,0xbf4, +0xbf7,0xbf4,0xbf7,0xbf4,0xbf7,0xbf4,0xbf7,0xbf4,0xbf7,0xbf4,0x732,0x732,0x732,0x732,0x732,0x732, +0x732,0x732,0x732,0x732,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8, +0x5e8,0x5e8,0x5e8,0x5e8,0x13a4,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8, +0x5e8,0x5e8,0x5e8,0x13a4,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615, 0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615, -0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x60c,0x60c,0x60c,0x60c,0x60c,0x60c, +0x615,0x615,0x60c,0x60c,0x60c,0x60c,0x60c,0x60c,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f, 0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f, -0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0xb46,0xb46,0xb46,0xb46, -0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0x615,0x615,0x95a,0x615, -0x615,0x615,0x615,0x615,0x615,0x615,0x60c,0x60c,0xbf7,0xd7a,0x1b0f,0x1b0f,0x612,0x618,0x615,0x60f, +0x60f,0x60f,0x60f,0x60f,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49, +0xb49,0xb49,0xb49,0xb49,0x615,0x615,0x95a,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x60c,0x60c, +0xbfa,0xd7d,0x1b21,0x1b21,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f, 0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f, -0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x615,0x60f,0x615,0x60f, -0x615,0x60f,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f, -0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x615,0x60f,0x612,0x618,0x615,0x60f,0x615,0x60f, -0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x615,0x60f,0x1323,0x1323,0x1323,0x1323,0x1323,0x1323, -0x1323,0x1323,0x1323,0x1323,0x1323,0x1323,0x1323,0x1323,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x612,0x618, 0x612,0x618,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x615,0x60f, -0x612,0x615,0x60f,0x612,0x615,0x60f,0x612,0x618,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f, -0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x612, -0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615, -0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f, -0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x612,0x612,0x612,0x612,0x612,0x612,0x612, -0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x60f,0x615,0x918,0x91b,0x1b0f,0x1b0f,0x1b0f,0x1b0f, -0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x612,0x60f,0x612,0x612, -0x612,0x612,0x612,0x612,0x60f,0x612,0x60f,0x60f,0x612,0x612,0x60f,0x60f,0x612,0x612,0x60f,0x612, -0x60f,0x612,0x60f,0x60f,0x612,0x60f,0x60f,0x612,0x60f,0x612,0x60f,0x60f,0x612,0x60f,0x612,0x612, -0x60f,0x60f,0x60f,0x612,0x60f,0x60f,0x60f,0x60f,0x60f,0x612,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f, +0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f, +0x615,0x60f,0x612,0x618,0x615,0x60f,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f, +0x615,0x60f,0x1329,0x1329,0x1329,0x1329,0x1329,0x1329,0x1329,0x1329,0x1329,0x1329,0x1329,0x1329,0x1329,0x1329, +0x615,0x60f,0x615,0x60f,0x615,0x60f,0x612,0x618,0x612,0x618,0x615,0x60f,0x615,0x60f,0x615,0x60f, +0x615,0x60f,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x612,0x615,0x60f,0x612,0x615,0x60f,0x612,0x618, 0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f, -0x612,0x612,0x60f,0x60f,0x612,0x60f,0x612,0x60f,0x60f,0x60f,0x60f,0x60f,0x612,0x612,0x612,0x612, -0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612, -0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x618, +0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612, 0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615, +0x615,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f, +0x60f,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618, +0x60f,0x615,0x918,0x91b,0x1b21,0x1b21,0x1b21,0x1b21,0x1b21,0x1b21,0x1b21,0x1b21,0x1b21,0x1b21,0x1b21,0x1b21, +0x1b21,0x1b21,0x1b21,0x1b21,0x612,0x60f,0x612,0x612,0x612,0x612,0x612,0x612,0x60f,0x612,0x60f,0x60f, +0x612,0x612,0x60f,0x60f,0x612,0x612,0x60f,0x612,0x60f,0x612,0x60f,0x60f,0x612,0x60f,0x60f,0x612, +0x60f,0x612,0x60f,0x60f,0x612,0x60f,0x612,0x612,0x60f,0x60f,0x60f,0x612,0x60f,0x60f,0x60f,0x60f, +0x60f,0x612,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f, +0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x612,0x612,0x60f,0x60f,0x612,0x60f,0x612,0x60f, +0x60f,0x60f,0x60f,0x60f,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612, +0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612, +0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x618,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615, 0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615, -0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618, -0x618,0x618,0x618,0x618,0x618,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615, -0x61b,0x61b,0x61b,0x61b,0xfde,0xfde,0xfde,0x14dc,0x14dc,0x14dc,0x14dc,0x14dc,0x14dc,0x14dc,0x16e0,0x16e0, -0x864,0x86a,0x86a,0x876,0x876,0x867,0x85e,0x867,0x85e,0x867,0x85e,0x867,0x85e,0x867,0x85e,0x867, -0x62a,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x62a, -0x624,0x627,0x62d,0x62a,0x624,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627, -0x62d,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627, +0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618, +0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x615,0x615,0x615, +0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x61b,0x61b,0x61b,0x61b,0xfe1,0xfe1,0xfe1,0x14e5, +0x14e5,0x14e5,0x14e5,0x14e5,0x14e5,0x14e5,0x16ef,0x16ef,0x864,0x86a,0x86a,0x876,0x876,0x867,0x85e,0x867, +0x85e,0x867,0x85e,0x867,0x85e,0x867,0x85e,0x867,0x62a,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x62a, +0x624,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x62a,0x624,0x627, +0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x62a, +0x624,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627, 0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627, -0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x714,0x714,0x714,0x714, -0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714, +0x62d,0x62a,0x624,0x627,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714, +0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711, 0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711, -0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711, -0x711,0x711,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a, -0x71a,0x71a,0x71a,0x71a,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717, -0x717,0x717,0x717,0x717,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d, +0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a, +0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x717,0x717,0x717,0x717, +0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x71d,0x71d,0x71d,0x71d, 0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d, -0x71d,0x71d,0x71d,0x71d,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738, +0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x738,0x738,0x738,0x738, 0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738, -0x738,0x738,0x738,0x738,0xc45,0x8c7,0x8c1,0x8be,0x8c4,0x8bb,0x74d,0x750,0x750,0x750,0x750,0x750, -0x750,0x750,0x750,0x750,0x8cd,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d, +0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0xc48,0x8c7,0x8be,0x8bb, +0x8c1,0x8c4,0x74d,0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x8cd,0x74d,0x74d,0x74d, 0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d, -0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x8ca,0x8ca,0x753,0x8dc,0x8df,0x8e5,0x80a,0x816,0x8fa,0x813, -0x8d3,0x8d0,0x8d3,0x8d0,0x8d9,0x8d6,0x8d9,0x8d6,0x8d3,0x8d0,0x810,0x8e5,0x8d3,0x8d0,0x8d3,0x8d0, -0x8d3,0x8d0,0x8d3,0x8d0,0x8eb,0x8f1,0x8ee,0x8ee,0x759,0x795,0x795,0x795,0x795,0x795,0x795,0x78f, -0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f, -0x78f,0x78f,0x78f,0x75c,0x777,0x756,0x77d,0x780,0x77a,0x792,0x792,0x792,0x792,0x792,0x792,0x78c, -0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c, -0x78c,0x78c,0x78c,0x75c,0x777,0x756,0x777,0xc48,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8, +0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x8ca,0x8ca, +0x753,0x8dc,0x8df,0x8e5,0x80a,0x816,0x8fa,0x813,0x8d3,0x8d0,0x8d3,0x8d0,0x8d9,0x8d6,0x8d9,0x8d6, +0x8d3,0x8d0,0x810,0x8e5,0x8d3,0x8d0,0x8d3,0x8d0,0x8d3,0x8d0,0x8d3,0x8d0,0x8eb,0x8f1,0x8ee,0x8ee, +0x759,0x795,0x795,0x795,0x795,0x795,0x795,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f, +0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x75c,0x777,0x756,0x77d,0x780, +0x77a,0x792,0x792,0x792,0x792,0x792,0x792,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c, +0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x75c,0x777,0x756,0x777,0xc4b, +0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8, 0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8, -0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x1293,0x1293,0x1293,0x1293,0x1293,0x7fb, -0x810,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x933,0x933,0x933,0x933,0x819,0x819, -0x8e8,0x8f7,0x8f7,0x8f7,0x8f7,0x8f4,0x80d,0x8e2,0xb19,0xb19,0xb19,0xc5a,0xc78,0xc75,0xb37,0x8b8, -0x81f,0x81c,0x81f,0x822,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81c,0x81c,0x81c,0x81c,0x81c, -0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,0x81c, -0xc7b,0x831,0x82b,0x831,0x82b,0x831,0x82b,0x831,0x82b,0x831,0x82b,0x82b,0x82e,0x82b,0x82e,0x82b, -0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b, -0x82e,0x82b,0x82e,0x831,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b, -0x82e,0x82e,0x82b,0x82e,0x82e,0x82b,0x82e,0x82e,0x82b,0x82e,0x82e,0x82b,0x82e,0x82e,0x82b,0x82b, -0x82b,0x82b,0x82b,0x831,0x82b,0x831,0x82b,0x831,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x831,0x82b, -0x82b,0x82b,0x82b,0x82b,0x82e,0x831,0x831,0x82e,0x82e,0x82e,0x82e,0x900,0x903,0x834,0x837,0xc63, +0x7f8,0x7f8,0x1299,0x1299,0x1299,0x1299,0x1299,0x7fb,0x810,0x813,0x813,0x813,0x813,0x813,0x813,0x813, +0x813,0x813,0x933,0x933,0x933,0x933,0x819,0x819,0x8e8,0x8f7,0x8f7,0x8f7,0x8f7,0x8f4,0x80d,0x8e2, +0xb1c,0xb1c,0xb1c,0xc5d,0xc7b,0xc78,0xb3a,0x8b8,0x81f,0x81c,0x81f,0x822,0x81c,0x81f,0x81c,0x81f, +0x81c,0x81f,0x81c,0x81c,0x81c,0x81c,0x81c,0x81c,0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,0x81f,0x81f, +0x81c,0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,0x81c,0xc7e,0x831,0x82b,0x831,0x82b,0x831,0x82b,0x831, +0x82b,0x831,0x82b,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b, +0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x831,0x82b,0x82e,0x82b,0x82e, +0x82b,0x82e,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82e,0x82e,0x82b,0x82e,0x82e,0x82b,0x82e,0x82e, +0x82b,0x82e,0x82e,0x82b,0x82e,0x82e,0x82b,0x82b,0x82b,0x82b,0x82b,0x831,0x82b,0x831,0x82b,0x831, +0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x831,0x82b,0x82b,0x82b,0x82b,0x82b,0x82e,0x831,0x831,0x82e, +0x82e,0x82e,0x82e,0x900,0x903,0x834,0x837,0xc66,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d, 0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d, +0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x840,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d, 0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d, -0x840,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d, -0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x849,0x849,0x849,0x849, +0x83d,0x83d,0x83d,0x83d,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849, 0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849, -0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0xd5f,0xd5f,0xe8e,0x843,0x90c,0x90c,0x90c,0x90c, -0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0xd59,0xd59,0xd59,0xd59,0x84c,0x84c,0x84c,0x84c, +0xd62,0xd62,0xe91,0x843,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c, +0xd5c,0xd5c,0xd5c,0xd5c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c, 0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c, -0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x1a58,0x912,0x912,0x912,0x912, -0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x84f,0x84f,0x84f, -0x84f,0x84f,0x84f,0xd62,0xd62,0xd62,0xd62,0x915,0x915,0x915,0x915,0x915,0x84f,0x84f,0x84f,0x84f, +0x84c,0x84c,0x84c,0x1a6a,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912, +0x912,0x912,0x912,0x912,0x912,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0xd65,0xd65,0xd65,0xd65,0x915, +0x915,0x915,0x915,0x915,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f, 0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f, -0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0xd62,0xd62, -0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852, +0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0xd65,0xd65,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852, 0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852, -0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855, +0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912, 0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855, -0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91, -0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91, -0x1104,0x1104,0x1104,0x1104,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858, +0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855, +0x855,0x855,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94, +0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0x110a,0x110a,0x110a,0x110a,0x858,0x858,0x858,0x858, 0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858, -0x858,0x858,0x858,0x858,0x858,0x858,0x85b,0x85b,0x858,0x85b,0x858,0x85b,0x85b,0x858,0x858,0x858, -0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x85b,0x858,0x85b,0x858,0x85b,0x85b,0x858,0x858,0x85b, -0x85b,0x85b,0x858,0x858,0x858,0x858,0x1497,0x1497,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c, -0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c, +0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x85b,0x85b, +0x858,0x85b,0x858,0x85b,0x85b,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x85b, +0x858,0x85b,0x858,0x85b,0x85b,0x858,0x858,0x85b,0x85b,0x85b,0x858,0x858,0x858,0x858,0x14a0,0x14a0, +0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f, +0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c, 0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c, -0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x12d2,0x12d2,0x12d2,0x12d2,0x127b,0x127b,0x127b,0x127b, -0x127b,0x127b,0x127b,0x127b,0xd59,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66, -0xc66,0xc66,0xc66,0xc66,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f, +0x12d8,0x12d8,0x12d8,0x12d8,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0xd5c,0xc69,0xc69,0xc69, +0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0x90f,0x90f,0x90f,0x90f, 0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f, -0x90f,0x90f,0x90f,0x90f,0x90f,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66, -0xc66,0xc66,0xc66,0xc66,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912, +0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0xc69,0xc69,0xc69, +0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0xc69,0x912,0x912,0x912,0x912, 0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912, -0x912,0x912,0x912,0xd62,0x99c,0x97e,0x97e,0x97e,0x97e,0x978,0x97e,0x97e,0x990,0x97e,0x97e,0x97b, -0x987,0x98d,0x98d,0x98d,0x98d,0x98d,0x990,0x978,0x984,0x978,0x978,0x978,0x96c,0x96c,0x978,0x978, -0x978,0x978,0x978,0x978,0x993,0x993,0x993,0x993,0x993,0x993,0x993,0x993,0x993,0x993,0x978,0x978, -0x978,0x978,0x978,0x978,0x978,0x978,0x978,0x978,0x97b,0x96c,0x978,0x96c,0x978,0x96c,0x98a,0x981, -0x98a,0x981,0x999,0x999,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8, +0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0xd65,0x99c,0x97e,0x97e,0x97e, +0x97e,0x978,0x97e,0x97e,0x990,0x97e,0x97e,0x97b,0x987,0x98d,0x98d,0x98d,0x98d,0x98d,0x990,0x978, +0x984,0x978,0x978,0x978,0x96c,0x96c,0x978,0x978,0x978,0x978,0x978,0x978,0x993,0x993,0x993,0x993, +0x993,0x993,0x993,0x993,0x993,0x993,0x978,0x978,0x978,0x978,0x978,0x978,0x978,0x978,0x978,0x978, +0x97b,0x96c,0x978,0x96c,0x978,0x96c,0x98a,0x981,0x98a,0x981,0x999,0x999,0x9a8,0x9a8,0x9a8,0x9a8, 0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8, -0x9a8,0x9a8,0x9a8,0x9a8,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab, +0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9ab,0x9ab,0x9ab,0x9ab, 0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab, -0x9ab,0x9ab,0x9ab,0x9ab,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae, +0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ae,0x9ae,0x9ae,0x9ae, 0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae, -0x9ae,0x9ae,0x9ae,0x9ae,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7, +0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9b7,0x9b7,0x9b7,0x9b7, 0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7, -0x9b7,0x9b7,0x9b1,0x9b1,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba, +0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b1,0x9b1,0x9ba,0x9ba,0x9ba,0x9ba, 0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba, -0x9ba,0x9ba,0x9b4,0x9b4,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7, +0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9b4,0x9b4,0x9b7,0x9b7,0x9b7,0x9b7, 0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7, -0x9b7,0x9b7,0x9b7,0x9b7,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba, +0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9ba,0x9ba,0x9ba,0x9ba, 0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba, -0x9ba,0x9ba,0x9ba,0x9ba,0x9bd,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0, +0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9bd,0x9c0,0x9c0,0x9c0, +0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0, +0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9bd,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0, 0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0, -0x9bd,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0, -0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0xa4d,0xa4d,0xfc3,0xa4d, -0xa4d,0xa4d,0xa50,0xa4d,0xfc3,0xa4d,0xa4d,0xfba,0xa47,0xa3b,0xa3b,0xa3b,0xa3b,0xa4a,0xa3b,0xfab, -0xfab,0xfab,0xa3b,0xa3e,0xa47,0xa41,0xfb1,0xfbd,0xfbd,0xfab,0xfab,0xfc3,0xb3d,0xb3d,0xb3d,0xb3d, -0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xa53,0xa53,0xa44,0xa44,0xa44,0xa44,0xa4d,0xa4d,0xa4d,0xa4d, -0xa4d,0xa4d,0xa4a,0xa4a,0xa3b,0xa3b,0xfc3,0xfc3,0xfc3,0xfc3,0xfab,0xfab,0xa4d,0xa4d,0xa4d,0xa4d, +0x9c0,0x9c0,0x9c0,0x9c0,0xa4d,0xa4d,0xfc6,0xa4d,0xa4d,0xa4d,0xa50,0xa4d,0xfc6,0xa4d,0xa4d,0xfbd, +0xa47,0xa3b,0xa3b,0xa3b,0xa3b,0xa4a,0xa3b,0xfae,0xfae,0xfae,0xa3b,0xa3e,0xa47,0xa41,0xfb4,0xfc0, +0xfc0,0xfae,0xfae,0xfc6,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xa53,0xa53, +0xa44,0xa44,0xa44,0xa44,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4a,0xa4a,0xa3b,0xa3b,0xfc6,0xfc6, +0xfc6,0xfc6,0xfae,0xfae,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d, 0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d, -0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa62,0xa62,0xa62,0xa62, -0xa62,0xa62,0xa62,0xdb9,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62, +0xa4d,0xa4d,0xa4d,0xa4d,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdbc,0xa62,0xa62,0xa62,0xa62, 0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62, -0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdb9,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62, -0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68, +0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdbc, +0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62, +0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68, 0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68, -0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e, -0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6b,0xa71,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0x113d, -0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113a,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e, +0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6b,0xa71,0xa6e, +0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143, +0x1140,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e, 0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e, -0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa83,0xa83,0xa83,0xa83, +0xa6e,0xa6e,0xa6e,0xa6e,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83, 0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83, -0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xaa7,0xaa7,0xaa7,0xaaa, -0xaaa,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7, -0xa8f,0xa8f,0xaa4,0xa86,0xa86,0xa86,0xa86,0xa86,0xa86,0xa86,0xaa4,0xaa4,0xaa7,0xaa7,0xaa7,0xaa7, +0xa83,0xa83,0xa83,0xa83,0xaa7,0xaa7,0xaa7,0xaaa,0xaaa,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7, +0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xa8f,0xa8f,0xaa4,0xa86,0xa86,0xa86,0xa86,0xa86, +0xa86,0xa86,0xaa4,0xaa4,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7, 0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7, -0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xac8,0xac8,0xac8,0xac8, -0xac8,0xab3,0xab3,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8, -0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8, -0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xacb,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8, -0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8, -0xac8,0xac8,0xac8,0xac8,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec, -0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xbe2, -0xbe2,0xbe2,0xbe2,0xbe2,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8, -0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8, -0xaf8,0xaf8,0xaf8,0xaf8,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a, -0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a, -0xb0a,0xb0a,0xb0a,0xb0a,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10, -0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10, -0xb10,0xb10,0xb10,0xb10,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c, -0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0x13a1,0x13a1,0x13a1,0x1ad3, -0x1ad3,0x1ad3,0x1ad3,0x1ad3,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f, +0xaa7,0xaa7,0xaa7,0xaa7,0xacb,0xacb,0xacb,0xacb,0xacb,0xab6,0xab6,0xacb,0xacb,0xacb,0xacb,0xacb, +0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb, +0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xace, +0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb, +0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xacb,0xaef,0xaef,0xaef,0xaef, +0xaef,0xaef,0xaef,0xaef,0xaef,0xaef,0xaef,0xaef,0xaef,0xaef,0xaef,0xaef,0xaef,0xaef,0xaef,0xaef, +0xaef,0xaef,0xaef,0xaef,0xaef,0xaef,0xaef,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xafb,0xafb,0xafb,0xafb, +0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb, +0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xb0d,0xb0d,0xb0d,0xb0d, +0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d, +0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb13,0xb13,0xb13,0xb13, +0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13, +0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb1f,0xb1f,0xb1f,0xb1f, 0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f, -0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6, +0xb1f,0xb1f,0xb1f,0xb1f,0x13aa,0x13aa,0x13aa,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0xb22,0xb22,0xb22,0xb22, 0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22, -0xb22,0xb22,0xb22,0xb22,0xb22,0xb25,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22, -0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22, -0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb28,0xb28,0xc69,0xc69,0xb28,0xb28,0xb28,0xb28, -0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xc69,0xb28,0xb28,0xb28, -0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c, -0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c, -0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0x14df,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xced,0xced, -0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52, -0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xcea,0xcea,0xd38,0xd38,0xd38,0xd38, -0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xb55,0xb55,0xb55,0xb55, +0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0x1ae8,0x1ae8, +0x1ae8,0x1ae8,0x1ae8,0x1ae8,0x1ae8,0x1ae8,0x1ae8,0x1ae8,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25, +0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb28,0xb25,0xb25, +0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25, +0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25, +0xb2b,0xb2b,0xc6c,0xc6c,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b, +0xb2b,0xb2b,0xb2b,0xb2b,0xc6c,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b, +0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f, +0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0x14e8, +0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xcf0,0xcf0,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55, 0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55, -0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb58,0xb58,0xb58,0xb58, +0xb55,0xb55,0xced,0xced,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b, +0xd3b,0xd3b,0xd3b,0xd3b,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58, 0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58, -0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb67,0xb67,0xb67,0xb67, -0xb67,0xb5e,0xb6a,0xb70,0xb70,0xb70,0xb64,0xb64,0xb64,0xb6d,0xb61,0xb61,0xb61,0xb61,0xb61,0xb5b, -0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb70,0xb70,0xb70,0xb70,0xb70,0xb64,0xb64,0xb64,0xb64, -0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64, -0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb67,0xb67, -0xb70,0xb70,0xb70,0xb64,0xb64,0xb70,0xb70,0xb70,0xb70,0xb70,0xb70,0xb70,0xb64,0xb64,0xb64,0xb64, -0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64, -0xb64,0xb64,0xb70,0xb70,0xb70,0xb70,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64, -0xb64,0xb64,0xb64,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64, -0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64, -0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0x16e3,0x16e3,0xb7c,0xb73,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, -0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, -0xb79,0xb79,0xb79,0xb73,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, -0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, -0xb7c,0xb7c,0xb7c,0xb73,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, -0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb73,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, +0xb58,0xb58,0xb58,0xb58,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b, +0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b, +0xb5b,0xb5b,0xb5b,0xb5b,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb61,0xb6d,0xb73,0xb73,0xb73,0xb67,0xb67, +0xb67,0xb70,0xb64,0xb64,0xb64,0xb64,0xb64,0xb5e,0xb5e,0xb5e,0xb5e,0xb5e,0xb5e,0xb5e,0xb5e,0xb73, +0xb73,0xb73,0xb73,0xb73,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67, +0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67, +0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb6a,0xb6a,0xb73,0xb73,0xb73,0xb67,0xb67,0xb73,0xb73,0xb73, +0xb73,0xb73,0xb73,0xb73,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67, +0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb73,0xb73,0xb73,0xb73,0xb67,0xb67, +0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a, +0xb6a,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67, +0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0x16f2,0x16f2, +0xb7f,0xb76,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, +0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb76,0xb7c,0xb7c,0xb7c,0xb7c, +0xb7c,0xb7c,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f, +0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb76,0xb7c,0xb7c,0xb7c,0xb7c, 0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, -0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb73,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, -0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb76,0xb76,0xb76,0xb76, -0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76, -0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb7c,0xb7c,0xb7c,0xb7c, +0xb7c,0xb76,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f, +0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb76,0xb7c,0xb7c, 0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, -0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, -0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb7c,0xb7c,0xb7c,0xb7c, -0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, -0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, +0xb7c,0xb7c,0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, 0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79, +0xb79,0xb79,0xb79,0xb79,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f, +0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7c,0xb7c, +0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, 0xb7c,0xb7c,0xb7c,0xb7c,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f, -0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f, -0xb7f,0xb7f,0xb7f,0xb7f,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85, -0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85, -0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1ba8,0x1ba8, -0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88, +0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7c,0xb7c, +0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c, +0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7f,0xb7f,0xb7f,0xb7f,0xb82,0xb82,0xb82,0xb82, +0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82, +0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb82,0xb88,0xb88,0xb88,0xb88, 0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88, -0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2, -0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbdf,0xbe2,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf, -0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xce1,0xce4,0xdd1,0xdd1,0xdd1,0xdd1,0xdd1,0xdd1,0xdd1, -0xdd1,0xdd1,0xdd1,0xdd1,0xee8,0xee8,0xee8,0xee8,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee, -0xbee,0xbee,0xce7,0xce7,0xce7,0xce7,0xce7,0xce7,0xce7,0xce7,0xdd4,0xe88,0xdd4,0xdd4,0xdd4,0xdd4, -0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xfd8,0x1272,0x1272,0xddd,0xddd,0xddd,0xddd,0xddd,0xde3,0xde0,0xefa, -0xefa,0xefa,0xefa,0x13e0,0xfea,0x13e0,0x132c,0x132c,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21, -0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc4e,0xc4b,0xc4e,0xc4b,0xc4e,0xc4b, -0x10fe,0x10fb,0xff0,0xfed,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24, -0xc24,0xc24,0xc24,0xc24,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27, -0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27, -0xc27,0xc27,0xc27,0xc27,0xc2a,0xc2a,0xc2a,0xc30,0xc2d,0xc54,0xc51,0xc30,0xc2d,0xc30,0xc2d,0xc30, -0xc2d,0xc30,0xc2d,0xc30,0xc2d,0xc30,0xc2d,0xc30,0xc2d,0xc30,0xc2d,0xc30,0xc2d,0xc2a,0xc2a,0xc2a, -0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a, +0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0x1aee, +0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1bba,0x1bba,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b, +0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b, +0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xb8b,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5, +0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe2,0xbe5, +0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xce4, +0xce7,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xeeb,0xeeb,0xeeb,0xeeb, +0xbf1,0xbf1,0xbf1,0xbf1,0xbf1,0xbf1,0xbf1,0xbf1,0xbf1,0xbf1,0xcea,0xcea,0xcea,0xcea,0xcea,0xcea, +0xcea,0xcea,0xdd7,0xe8b,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xfdb,0x1278,0x1278, +0xde0,0xde0,0xde0,0xde0,0xde0,0xde6,0xde3,0xefd,0xefd,0xefd,0xefd,0x13e9,0xfed,0x13e9,0x1332,0x1332, +0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24, +0xc24,0xc24,0xc51,0xc4e,0xc51,0xc4e,0xc51,0xc4e,0x1104,0x1101,0xff3,0xff0,0xc27,0xc27,0xc27,0xc27, +0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc2a,0xc2a,0xc2a,0xc2a, 0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a, -0xc30,0xc2d,0xc30,0xc2d,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a, -0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a, -0xc30,0xc2d,0xc2a,0xc2a,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33, -0xc39,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33, -0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33, -0xc33,0xc33,0xc33,0xc33,0xc39,0xc39,0xc39,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33, -0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33, -0xc33,0xc33,0xc33,0xc33,0xc36,0xc33,0xc33,0xc33,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c, -0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c, -0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xce7,0xd53,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4, -0xdd4,0xdd4,0xe88,0xe88,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xeeb,0xfd8,0xfd8,0xfd8,0xfd8,0xfd8, -0xfd8,0xfd8,0xfd8,0xfd8,0xfd8,0x1296,0x1296,0x1275,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b, -0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b, -0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd11,0xd11, -0xd11,0xd11,0xd11,0xd0e,0xd23,0xd23,0xd23,0xd1d,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23, -0xd23,0xd23,0xd23,0xd1d,0xd23,0xd23,0xd23,0xd23,0xd17,0xd17,0xd20,0xd20,0xd20,0xd20,0xd14,0xd14, -0xd14,0xd14,0xd14,0xd1a,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9, -0xde6,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23, -0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd1d,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23, -0xd23,0xd23,0xd23,0xd23,0xd23,0xd17,0xd17,0xd17,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a, -0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a, -0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26, -0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xdec,0xdec,0xdec,0xdec,0xdec,0xdec,0xefd,0xefd,0xefd,0xefd, -0xefd,0xefd,0xefd,0x1107,0x1107,0xff3,0xff3,0xff3,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29, -0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29, -0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f, -0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f, -0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38, -0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38, -0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44, -0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44, -0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50, -0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50, -0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2, -0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2, -0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8, -0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf5,0xdf5,0xdf5, -0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8, -0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8, -0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xeb8,0xeb8,0xe0a,0xe0a,0xf00,0xf00,0xf00,0xf00, -0xf00,0xf00,0xf00,0xfff,0xfff,0x1002,0xfff,0xfff,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc, -0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16, -0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16, -0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25, -0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25, -0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b, -0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0x1b1e,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, +0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2d,0xc2d,0xc2d,0xc33, +0xc30,0xc57,0xc54,0xc33,0xc30,0xc33,0xc30,0xc33,0xc30,0xc33,0xc30,0xc33,0xc30,0xc33,0xc30,0xc33, +0xc30,0xc33,0xc30,0xc33,0xc30,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d, +0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d, +0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc33,0xc30,0xc33,0xc30,0xc2d,0xc2d,0xc2d,0xc2d, +0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d, +0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc33,0xc30,0xc2d,0xc2d,0xc36,0xc36,0xc36,0xc36, +0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc3c,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36, +0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36, +0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc3c,0xc3c,0xc3c,0xc36, +0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36, +0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc36,0xc39,0xc36,0xc36,0xc36, +0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f, +0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f, +0xcea,0xd56,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xe8b,0xe8b,0xdd7,0xdd7,0xdd7,0xdd7, +0xdd7,0xdd7,0xeee,0xfdb,0xfdb,0xfdb,0xfdb,0xfdb,0xfdb,0xfdb,0xfdb,0xfdb,0xfdb,0x129c,0x129c,0x127b, +0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e, +0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e, +0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd14,0xd14,0xd14,0xd14,0xd14,0xd11,0xd26,0xd26,0xd26,0xd20, +0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd20,0xd26,0xd26,0xd26,0xd26, +0xd1a,0xd1a,0xd23,0xd23,0xd23,0xd23,0xd17,0xd17,0xd17,0xd17,0xd17,0xd1d,0xdec,0xdec,0xdec,0xdec, +0xdec,0xdec,0xdec,0xdec,0xdec,0xdec,0xdec,0xdec,0xde9,0xdec,0xdec,0xdec,0xdec,0xdec,0xdec,0xdec, +0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd20,0xd26, +0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd1a,0xd1a,0xd1a, +0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d, +0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d, +0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xdef,0xdef, +0xdef,0xdef,0xdef,0xdef,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0x110d,0x110d,0xff6,0xff6,0xff6, +0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c, +0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c, +0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32, +0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32, +0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b, +0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b, +0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47, +0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47,0xd47, +0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53, +0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53,0xd53, +0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5, +0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5, +0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb, +0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8, +0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb, +0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb, +0xebb,0xebb,0xe0d,0xe0d,0xf03,0xf03,0xf03,0xf03,0xf03,0xf03,0xf03,0x1002,0x1002,0x1005,0x1002,0x1002, +0xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0xfff, +0xe1c,0xe19,0xe1c,0xe19,0xe1c,0xe19,0xe1c,0xe19,0xe1c,0xe19,0xe1c,0xe19,0xe1c,0xe19,0xe1c,0xe19, +0xe1c,0xe19,0xe1c,0xe19,0xe1c,0xe19,0xe1c,0xe19,0xe1c,0xe19,0xe1c,0xe19,0xe1c,0xe19,0xe1c,0xe19, +0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, 0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28, -0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0x1b1b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b, +0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0x1b30, 0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b, -0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xeb2,0xeb2,0xeb2,0xeb2,0xeb2,0xeb2,0xeb2,0xeb2, -0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xf03, -0xf03,0xf03,0xf03,0x1005,0x1005,0x1005,0x1005,0x1005,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c, -0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c, -0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55, -0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55, -0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e, +0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0x1b2d, +0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e, +0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e,0xe2e, +0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xe46,0xe46,0xe46,0xe46,0xe46,0xe46,0xe46,0xe46, +0xe46,0xe46,0xe46,0xe46,0xe46,0xe46,0xe46,0xf06,0xf06,0xf06,0xf06,0x1008,0x1008,0x1008,0x1008,0x1008, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f,0xe4f, +0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58, +0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58,0xe58, +0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61, +0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe61,0xe5b, 0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e, -0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe58,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b, -0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b, -0xe5b,0xe5b,0xe5b,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67, -0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe64,0xe64,0xe64,0xe64,0xe64,0xe64,0xe64,0xe64,0xe61,0xe6a, -0x1011,0x100b,0x101a,0x1008,0xe67,0xe67,0x1008,0x1008,0xe79,0xe79,0xe6d,0xe79,0xe79,0xe79,0xe70,0xe79, -0xe79,0xe79,0xe79,0xe6d,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79, -0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c, +0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe61,0xe61,0xe61,0xe61,0xe61, +0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe67,0xe67, +0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe64,0xe6d,0x1014,0x100e,0x101d,0x100b,0xe6a,0xe6a,0x100b,0x100b, +0xe7c,0xe7c,0xe70,0xe7c,0xe7c,0xe7c,0xe73,0xe7c,0xe7c,0xe7c,0xe7c,0xe70,0xe7c,0xe7c,0xe7c,0xe7c, 0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c, -0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94, -0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94, -0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5, -0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0x1110,0x1110,0x1110,0x1110,0x1110,0x1110,0x1110,0x1110, -0x1110,0x1110,0x1110,0x1110,0x1110,0x1110,0x1110,0x1110,0xee8,0xee8,0xee8,0xee5,0xee5,0xee5,0xee5,0xee5, -0x1149,0x1392,0x1392,0x1392,0x1392,0x1317,0x1317,0x1317,0x1395,0x131a,0x131a,0x1395,0x14d6,0x14d6,0x14d6,0x14d6, -0x14d6,0x14d6,0x14d6,0x1797,0x1797,0x1797,0x1797,0x185d,0xefd,0xefd,0xefd,0xefd,0xff3,0xff3,0xff3,0xff3, -0xff3,0xff3,0xff3,0xff3,0xff3,0xff3,0xff3,0xff3,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6, -0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0x14f1, -0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f4,0x1866,0x1866, -0x18e7,0x1866,0x1bc6,0x179d,0x132f,0x1152,0xf00,0xf00,0xf1e,0xf1e,0xf1e,0xf1e,0xf30,0xf39,0xf3c,0xf39, -0xf3c,0xf39,0xf3c,0xf39,0xf3c,0xf39,0xf3c,0xf39,0xf39,0xf39,0xf3c,0xf39,0xf39,0xf39,0xf39,0xf39, -0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39, -0xf21,0xf1e,0xf1e,0xf1e,0xf1e,0xf1e,0xf1e,0xf33,0xf1e,0xf33,0xf30,0xf30,0xf45,0xf42,0xf45,0xf45, -0xf45,0xf42,0xf42,0xf45,0xf42,0xf45,0xf42,0xf45,0xf42,0x102c,0x102c,0x102c,0x1167,0x1023,0x102c,0x1023, -0xf42,0xf45,0xf42,0xf42,0x1023,0x1023,0x1023,0x1023,0x1026,0x1029,0x1167,0x1167,0xf48,0xf48,0x103e,0x1035, -0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x1035,0x1035,0x103e,0x1035, -0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0xf4e,0xf4e,0xf4e,0xf4e, -0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e, -0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf5d,0xf5d,0xf5d,0xf5d, -0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d, -0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0x1512, -0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512, -0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63, -0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63, -0xfab,0xfc3,0xfba,0xfc0,0xfc0,0xfc3,0xfc3,0xfba,0xfba,0xfc0,0xfc0,0xfc0,0xfc0,0xfc0,0xfc3,0xfc3, -0xfc3,0xfab,0xfab,0xfab,0xfab,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3, -0xfc3,0xfc3,0xfab,0xfba,0xfbd,0xfab,0xfab,0xfc0,0xfc0,0xfc0,0xfc0,0xfc0,0xfc0,0xfae,0xfc3,0xfc0, -0xfb7,0xfb7,0xfb7,0xfb7,0xfb7,0xfb7,0xfb7,0xfb7,0xfb7,0xfb7,0x1131,0x1131,0x112e,0x112b,0xfb4,0xfb4, -0xfdb,0xfdb,0xfdb,0xfdb,0x1296,0x1296,0x1275,0x1275,0x1275,0x1272,0x1272,0x1272,0x1272,0x1275,0x1398,0x1275, -0x1275,0x1275,0x1272,0x1275,0x1296,0x1272,0x1272,0x1272,0x1275,0x1275,0x1272,0x1272,0x1275,0x1272,0x1272,0x1275, -0xff6,0xff6,0xff6,0xff6,0xff6,0xff3,0xff3,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0x14eb,0x14eb,0x14eb, -0x1107,0xff3,0xff3,0xff3,0xff3,0x12a2,0x127e,0x127e,0x127e,0x127e,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb, -0x1017,0x1017,0x1014,0x100e,0x1014,0x100e,0x1014,0x100e,0x1014,0x100e,0x100b,0x100b,0x100b,0x100b,0x1020,0x101d, -0x100b,0x1164,0x13ec,0x13ef,0x13ef,0x13ec,0x13ec,0x13ec,0x13ec,0x13ec,0x13f2,0x13f2,0x1506,0x14fa,0x14fa,0x14f7, -0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x1032,0x102f,0x102f,0x103e,0x1035,0x133b,0x1338,0x16ec, -0x133b,0x1338,0x13fb,0x13f8,0x1509,0x1509,0x150f,0x1509,0x150f,0x1509,0x150f,0x1509,0x150f,0x1509,0x150f,0x1509, -0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035, -0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035, -0x1038,0x1035,0x1035,0x1035,0x1035,0x1035,0x1035,0x1035,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x103e,0x1035, -0x1041,0x1041,0x1047,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d, -0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d, -0x104d,0x1047,0x1041,0x1041,0x1041,0x1041,0x1047,0x1047,0x1041,0x1041,0x104a,0x1404,0x1401,0x1401,0x104d,0x104d, -0x1044,0x1044,0x1044,0x1044,0x1044,0x1044,0x1044,0x1044,0x1044,0x1044,0x1407,0x1407,0x1407,0x1407,0x1407,0x1407, -0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062, -0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062, -0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b, -0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106e,0x106e,0x106e,0x1071,0x106e,0x106e,0x1074,0x1074, -0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077, -0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077, -0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1083,0x107a,0x1089,0x1086, -0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080, -0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080, -0x1341,0x133e,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x1098,0x1119, -0x108c,0x108c,0x108c,0x1092,0x140a,0x140a,0x140a,0x140a,0x140a,0x140a,0x140a,0x140a,0x108f,0x108f,0x1092,0x109e, -0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095, -0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095, -0x151e,0x151b,0x151e,0x151b,0x1521,0x1521,0x16f5,0x140a,0x10a7,0x10a7,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa, -0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa, -0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10a7,0x10a7,0x10a7,0x10a7,0x10a7,0x10a7,0x10a7,0x10a7, -0x10a7,0x10a7,0x10a7,0x10a7,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b0,0x10b0,0x10b0,0x10b0,0x10b0,0x10b3, -0x10b3,0x10b3,0x110d,0x10bc,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb, -0x10cb,0x10cb,0x10cb,0x10cb,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b9,0x10b9, -0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9, -0x10b9,0x10b9,0x10b9,0x10b9,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da, -0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da, -0x10da,0x10da,0x10da,0x10da,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec, -0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec, -0x10ec,0x10ec,0x10ec,0x10ec,0x10f5,0x10f5,0x10f5,0x10f5,0x110a,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5, -0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5, -0x10f5,0x10f5,0x10f5,0x10f5,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8, -0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8, -0x10f8,0x10f8,0x10f8,0x10f8,0x1104,0x1104,0x1104,0x1104,0x129c,0x129c,0x129c,0x129c,0x129c,0x129c,0x129c,0x129c, -0x1494,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6, -0x18c6,0x18c6,0x18c6,0x18c6,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179, -0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1170,0x1170,0x1173,0x1173,0x1179,0x1170, -0x1170,0x1170,0x1170,0x1170,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f, +0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f, +0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f, +0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97, +0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97,0xe97, +0xeb8,0xeb8,0xeb8,0xeb8,0xeb8,0xeb8,0xeb8,0xeb8,0xeb8,0xeb8,0xeb8,0xeb8,0xeb8,0xeb8,0xeb8,0xeb8, +0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113, +0xeeb,0xeeb,0xeeb,0xee8,0xee8,0xee8,0xee8,0xee8,0x114f,0x139b,0x139b,0x139b,0x139b,0x131d,0x131d,0x131d, +0x139e,0x1320,0x1320,0x139e,0x14df,0x14df,0x14df,0x14df,0x14df,0x14df,0x14df,0x17a6,0x17a6,0x17a6,0x17a6,0x186c, +0xf00,0xf00,0xf00,0xf00,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6, +0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9, +0xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0x14fa,0x14fa,0x14fa,0x14fa,0x14fa,0x14fa,0x14fa,0x14fa,0x14fa, +0x14fa,0x14fa,0x14fa,0x14fa,0x14fa,0x14fd,0x1875,0x1875,0x18f6,0x1875,0x1bd8,0x17ac,0x1335,0x1158,0xf03,0xf03, +0xf21,0xf21,0xf21,0xf21,0xf33,0xf3c,0xf3f,0xf3c,0xf3f,0xf3c,0xf3f,0xf3c,0xf3f,0xf3c,0xf3f,0xf3c, +0xf3c,0xf3c,0xf3f,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c, +0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf24,0xf21,0xf21,0xf21,0xf21,0xf21,0xf21,0xf36, +0xf21,0xf36,0xf33,0xf33,0xf48,0xf45,0xf48,0xf48,0xf48,0xf45,0xf45,0xf48,0xf45,0xf48,0xf45,0xf48, +0xf45,0x102f,0x102f,0x102f,0x116d,0x1026,0x102f,0x1026,0xf45,0xf48,0xf45,0xf45,0x1026,0x1026,0x1026,0x1026, +0x1029,0x102c,0x116d,0x116d,0xf4b,0xf4b,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038, +0x1041,0x1038,0x1041,0x1038,0x1038,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038, +0x1041,0x1038,0x1041,0x1038,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51, +0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51, +0xf51,0xf51,0xf51,0xf51,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60, +0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60, +0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b, +0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0x151b,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66, +0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66, +0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xfae,0xfc6,0xfbd,0xfc3,0xfc3,0xfc6,0xfc6,0xfbd, +0xfbd,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc6,0xfc6,0xfc6,0xfae,0xfae,0xfae,0xfae,0xfc6,0xfc6,0xfc6, +0xfc6,0xfc6,0xfc6,0xfc6,0xfc6,0xfc6,0xfc6,0xfc6,0xfc6,0xfc6,0xfae,0xfbd,0xfc0,0xfae,0xfae,0xfc3, +0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfb1,0xfc6,0xfc3,0xfba,0xfba,0xfba,0xfba,0xfba,0xfba,0xfba,0xfba, +0xfba,0xfba,0x1137,0x1137,0x1134,0x1131,0xfb7,0xfb7,0xfde,0xfde,0xfde,0xfde,0x129c,0x129c,0x127b,0x127b, +0x127b,0x1278,0x1278,0x1278,0x1278,0x127b,0x13a1,0x127b,0x127b,0x127b,0x1278,0x127b,0x129c,0x1278,0x1278,0x1278, +0x127b,0x127b,0x1278,0x1278,0x127b,0x1278,0x1278,0x127b,0xff9,0xff9,0xff9,0xff9,0xff9,0xff6,0xff6,0xff9, +0xff9,0xff9,0xff9,0xff9,0xff9,0x14f4,0x14f4,0x14f4,0x110d,0xff6,0xff6,0xff6,0xff6,0x12a8,0x1284,0x1284, +0x1284,0x1284,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x101a,0x101a,0x1017,0x1011,0x1017,0x1011,0x1017,0x1011, +0x1017,0x1011,0x100e,0x100e,0x100e,0x100e,0x1023,0x1020,0x100e,0x116a,0x13f5,0x13f8,0x13f8,0x13f5,0x13f5,0x13f5, +0x13f5,0x13f5,0x13fb,0x13fb,0x150f,0x1503,0x1503,0x1500,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038, +0x1035,0x1032,0x1032,0x1041,0x1038,0x1341,0x133e,0x16fb,0x1341,0x133e,0x1404,0x1401,0x1512,0x1512,0x1518,0x1512, +0x1518,0x1512,0x1518,0x1512,0x1518,0x1512,0x1518,0x1512,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038, +0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038, +0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1038,0x103b,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038, +0x1038,0x1041,0x1038,0x1041,0x1038,0x1041,0x1041,0x1038,0x1044,0x1044,0x104a,0x1050,0x1050,0x1050,0x1050,0x1050, +0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050, +0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x104a,0x1044,0x1044,0x1044,0x1044,0x104a,0x104a, +0x1044,0x1044,0x104d,0x140d,0x140a,0x140a,0x1050,0x1050,0x1047,0x1047,0x1047,0x1047,0x1047,0x1047,0x1047,0x1047, +0x1047,0x1047,0x1410,0x1410,0x1410,0x1410,0x1410,0x1410,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065, +0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065, +0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x1065,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e, +0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e,0x106e, +0x1071,0x1071,0x1071,0x1074,0x1071,0x1071,0x1077,0x1077,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a, +0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a, +0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083, +0x1083,0x1083,0x1083,0x1083,0x1086,0x107d,0x108c,0x1089,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083, +0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083, +0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1083,0x1347,0x1344,0x109e,0x1098,0x109e,0x1098,0x109e,0x1098, +0x109e,0x1098,0x109e,0x1098,0x109e,0x1098,0x109b,0x111f,0x108f,0x108f,0x108f,0x1095,0x1413,0x1413,0x1413,0x1413, +0x1413,0x1413,0x1413,0x1413,0x1092,0x1092,0x1095,0x10a1,0x109e,0x1098,0x109e,0x1098,0x109e,0x1098,0x109e,0x1098, +0x109e,0x1098,0x109e,0x1098,0x109e,0x1098,0x109e,0x1098,0x109e,0x1098,0x109e,0x1098,0x109e,0x1098,0x109e,0x1098, +0x109e,0x1098,0x109e,0x1098,0x109e,0x1098,0x109e,0x1098,0x1527,0x1524,0x1527,0x1524,0x152a,0x152a,0x1704,0x1413, +0x10aa,0x10aa,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad, +0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad, +0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10bc,0x10bc,0x10bc,0x10bc, +0x10bc,0x10bc,0x10b3,0x10b3,0x10b3,0x10b3,0x10b3,0x10b6,0x10b6,0x10b6,0x1116,0x10bf,0x10ce,0x10ce,0x10ce,0x10ce, +0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10b9,0x10b9,0x10b9,0x10b9, +0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc, +0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10e0,0x10e0,0x10e0,0x10e0, +0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0, +0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10f2,0x10f2,0x10f2,0x10f2, +0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2, +0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10fb,0x10fb,0x10fb,0x10fb, +0x1110,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb, +0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fe,0x10fe,0x10fe,0x10fe, +0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe, +0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x10fe,0x110a,0x110a,0x110a,0x110a, +0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x149d,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785, +0x1785,0x1785,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x117f,0x117f,0x117f,0x117f, 0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f, -0x117f,0x117f,0x117f,0x117f,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a, -0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a, -0x119a,0x119a,0x119a,0x119a,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6, -0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6, -0x11a6,0x11a6,0x11a3,0x11a9,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5, -0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5, -0x11b5,0x11b5,0x11b5,0x11b5,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb, -0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x12e7,0x11c1,0x12ea,0x11c1,0x11c1,0x11c1,0x11c1,0x11be,0x11be,0x11be,0x11c1, -0x16f8,0x16fb,0x1923,0x1920,0x11c4,0x11c4,0x11c4,0x11d3,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9, -0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9, -0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11c7,0x11d3,0x11d3,0x11c4,0x11c4,0x11c4,0x11c4,0x11d3,0x11d3, -0x11c4,0x11c4,0x11d3,0x11d3,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5, -0x11e5,0x11e5,0x11e5,0x11e5,0x11e8,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11df,0x11df,0x11df,0x11e5,0x11e2, -0x1527,0x152a,0x152d,0x152d,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7, -0x11f7,0x11f7,0x11f7,0x11f7,0x11eb,0x11f7,0x11eb,0x11eb,0x11eb,0x1200,0x1200,0x11eb,0x11eb,0x1200,0x11f7,0x1200, -0x1200,0x11f7,0x11eb,0x11ee,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7, -0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7, -0x11f7,0x11f7,0x11f7,0x11f7,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212, -0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212, -0x1212,0x1212,0x1212,0x1212,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a, -0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a, -0x122a,0x1227,0x1227,0x1227,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233, -0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233, -0x1233,0x1233,0x1233,0x1233,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242, -0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242, -0x1242,0x1242,0x1242,0x1242,0x1248,0x1248,0x1254,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257, -0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x125a,0x1257, -0x125a,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x125a, -0x1257,0x1257,0x1257,0x1257,0x1254,0x1254,0x1254,0x1248,0x1248,0x1248,0x1248,0x1254,0x1254,0x124e,0x124b,0x1251, -0x1251,0x1260,0x125d,0x125d,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263, -0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263, -0x1263,0x1263,0x1263,0x1263,0x1269,0x1269,0x1269,0x1266,0x1266,0x1266,0x1263,0x1263,0x1263,0x1263,0x1266,0x1263, -0x1263,0x1263,0x1269,0x1266,0x1269,0x1266,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263, -0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263, -0x1263,0x1269,0x1266,0x1266,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263, -0x1263,0x1263,0x1263,0x1bcf,0x19f5,0x19f5,0x19f5,0x19f5,0x19f5,0x19f5,0x19f5,0x19f8,0x19f2,0x1be1,0x1be1,0x1be1, -0x1be4,0x1bde,0x1be4,0x1bde,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1287, -0x1287,0x1287,0x126c,0x1929,0x138f,0x1290,0x138f,0x138f,0x138f,0x138f,0x138f,0x138f,0x138f,0x138f,0x138f,0x138f, -0x138f,0x1290,0x138f,0x1290,0x1275,0x1275,0x131d,0x1272,0x131d,0x131d,0x131d,0x131d,0x1272,0x1272,0x1296,0x1272, -0x1272,0x1272,0x1272,0x1272,0x1272,0x1275,0x1296,0x1296,0x1275,0x1296,0x1272,0x1275,0x1275,0x1278,0x1296,0x1272, -0x1272,0x1296,0x1275,0x1275,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x1281,0x1281, -0x1281,0x1281,0x13a4,0x1386,0x128a,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x1827, -0x1827,0x1827,0x1827,0x1827,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1530, -0x1530,0x1a76,0x1a76,0x1a76,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284, -0x1284,0x1284,0x1284,0x1284,0x138f,0x138f,0x1290,0x138f,0x138f,0x138f,0x1290,0x138f,0x138f,0x138f,0x128a,0x128a, -0x128a,0x128a,0x128a,0x1389,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x128d,0x138c,0x138c,0x138c,0x138c, -0x138c,0x138c,0x138c,0x128d,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x140d,0x140d, -0x19d4,0x1a76,0x1a76,0x1a76,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x128d,0x138c,0x128d, -0x128d,0x138c,0x138c,0x128d,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1, -0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1, -0x12b1,0x12b1,0x12b1,0x12b1,0x133b,0x1338,0x133b,0x1338,0x133b,0x1338,0x133b,0x1338,0x133b,0x1338,0x13fb,0x150f, -0x150f,0x150f,0x17a3,0x1917,0x150f,0x150f,0x16ef,0x16ef,0x16ef,0x16e9,0x16ef,0x16e9,0x191a,0x1917,0x19d1,0x19ce, -0x19d1,0x19ce,0x19d1,0x19ce,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f, -0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f, -0x135f,0x135f,0x135f,0x135f,0x1374,0x1365,0x1374,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377, -0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377, -0x1377,0x1377,0x1377,0x1377,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x137d,0x137d,0x137d,0x137d, -0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d, -0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x1383,0x1383,0x1383,0x1383, -0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383, -0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x13ad,0x13aa,0x18cc,0x18cc, -0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc, -0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x13b6,0x13b6,0x13b6,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6, -0x13b6,0x13b3,0x13b3,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b3,0x13b6,0x13b6,0x13b6,0x13b3,0x13b6,0x13b3,0x13b6, -0x13b3,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b9,0x13b6,0x13b6,0x13b6,0x13b6,0x13b3,0x13b6,0x13b3,0x13b3,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b3,0x13b3,0x13b3,0x13b3, -0x13b3,0x13b3,0x13b3,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b6,0x13b6,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3, -0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x1539,0x1539,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c, -0x153c,0x153c,0x153c,0x153c,0x153c,0x1779,0x1779,0x1779,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x153c,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x153c,0x1779,0x1779, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b9,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b6,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x1539,0x1539,0x153c,0x153c, -0x13b6,0x13b6,0x13b9,0x13b9,0x13b9,0x16a4,0x13b6,0x13b9,0x13b6,0x13b6,0x13b9,0x153f,0x153f,0x153c,0x153c,0x1779, -0x1779,0x1779,0x1779,0x1779,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6, -0x13b6,0x153c,0x153c,0x153c,0x16a4,0x153c,0x153c,0x153c,0x1779,0x1779,0x1779,0x177c,0x177c,0x177c,0x177c,0x177c, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x153c, -0x13b6,0x153c,0x13b9,0x13b9,0x13b6,0x13b6,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9, -0x13b9,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6, -0x13b6,0x13b6,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9, -0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b6,0x13b6,0x13b6,0x13b9,0x13b6,0x13b6,0x13b6,0x13b6,0x13b9,0x13b9,0x13b9, -0x13b6,0x13b9,0x13b9,0x13b9,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b9,0x13b6,0x13b9,0x13b6,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x16a4,0x13b6,0x13b6,0x13b6,0x13b6,0x153c,0x153c,0x1779, -0x1410,0x1410,0x1410,0x1410,0x1539,0x1539,0x1539,0x1539,0x1539,0x1539,0x153c,0x1779,0x1779,0x1779,0x1779,0x16fe, -0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6, -0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153f,0x153f,0x153c,0x153c, -0x153c,0x153c,0x1830,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c, -0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x1539,0x1539,0x1539,0x1539,0x1539,0x1539,0x153c,0x13b6, -0x13b6,0x13b6,0x13b6,0x13b6,0x149a,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc, -0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x149a,0x13bc,0x13bc,0x13bc,0x149a,0x13bc,0x149a,0x13bc,0x149a,0x13bc,0x149a, -0x13bc,0x13bc,0x13bc,0x149a,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x149a,0x149a,0x13bc,0x13bc,0x13bc,0x13bc, -0x149a,0x13bc,0x149a,0x149a,0x13bc,0x13bc,0x13bc,0x13bc,0x149a,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc, -0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x16aa,0x16aa,0x177f,0x177f,0x13bf,0x13bf,0x13bf,0x13bc,0x13bc,0x13bc,0x13bf, -0x13bf,0x13bf,0x13bf,0x13bf,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629, -0x1629,0x1629,0x1629,0x1629,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2, -0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2, -0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c5,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2, -0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c5,0x13c5,0x13c5,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2, -0x13c2,0x13c2,0x13c2,0x13c2,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8, -0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8, -0x13c8,0x13c8,0x13c8,0x13c8,0x17ac,0x17ac,0x17a9,0x1701,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1413,0x1413, -0x1413,0x1413,0x1413,0x1413,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416, -0x1416,0x1416,0x1416,0x1545,0x1419,0x1548,0x1419,0x1419,0x1419,0x1419,0x1419,0x1419,0x1419,0x1419,0x1419,0x1419, -0x1419,0x1548,0x1548,0x1548,0x1548,0x1548,0x1548,0x1704,0x1704,0x1b4b,0x17b2,0x17b2,0x17b2,0x17b2,0x17b2,0x17b2, -0x17b2,0x17b2,0x1a79,0x1a79,0x1422,0x1422,0x1422,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434, -0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434, -0x1434,0x1434,0x1434,0x1434,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f, -0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f, -0x144f,0x144f,0x144f,0x144f,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455, -0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455, -0x1455,0x1455,0x1455,0x19da,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458, +0x117f,0x117f,0x1176,0x1176,0x1179,0x1179,0x117f,0x1176,0x1176,0x1176,0x1176,0x1176,0x1185,0x1185,0x1185,0x1185, +0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185, +0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x11a0,0x11a0,0x11a0,0x11a0, +0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0, +0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11ac,0x11ac,0x11ac,0x11ac, +0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac, +0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11a9,0x11af,0x11bb,0x11bb,0x11bb,0x11bb, +0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb, +0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11c1,0x11c1,0x11c1,0x11c1, +0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x12ed,0x11c7,0x12f0, +0x11c7,0x11c7,0x11c7,0x11c7,0x11c4,0x11c4,0x11c4,0x11c7,0x1707,0x170a,0x1932,0x192f,0x11ca,0x11ca,0x11ca,0x11d9, +0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df, +0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11cd, +0x11d9,0x11d9,0x11ca,0x11ca,0x11ca,0x11ca,0x11d9,0x11d9,0x11ca,0x11ca,0x11d9,0x11d9,0x11eb,0x11eb,0x11eb,0x11eb, +0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11ee,0x11eb,0x11eb,0x11eb, +0x11eb,0x11eb,0x11eb,0x11e5,0x11e5,0x11e5,0x11eb,0x11e8,0x1530,0x1533,0x1536,0x1536,0x11fd,0x11fd,0x11fd,0x11fd, +0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11f1,0x11fd,0x11f1,0x11f1, +0x11f1,0x1206,0x1206,0x11f1,0x11f1,0x1206,0x11fd,0x1206,0x1206,0x11fd,0x11f1,0x11f4,0x11fd,0x11fd,0x11fd,0x11fd, +0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd, +0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x1218,0x1218,0x1218,0x1218, +0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218, +0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1230,0x1230,0x1230,0x1230, +0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230, +0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x122d,0x122d,0x122d,0x1239,0x1239,0x1239,0x1239, +0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239, +0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1248,0x1248,0x1248,0x1248, +0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248, +0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x1248,0x124e,0x124e,0x125a,0x125d, +0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d, +0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x1260,0x125d,0x1260,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d, +0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x125d,0x1260,0x125d,0x125d,0x125d,0x125d,0x125a,0x125a,0x125a,0x124e, +0x124e,0x124e,0x124e,0x125a,0x125a,0x1254,0x1251,0x1257,0x1257,0x1266,0x1263,0x1263,0x1269,0x1269,0x1269,0x1269, +0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269, +0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x126f,0x126f,0x126f,0x126c, +0x126c,0x126c,0x1269,0x1269,0x1269,0x1269,0x126c,0x1269,0x1269,0x1269,0x126f,0x126c,0x126f,0x126c,0x1269,0x1269, +0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269, +0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x126f,0x126c,0x126c,0x1269,0x1269,0x1269,0x1269, +0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1be1,0x1a07,0x1a07,0x1a07,0x1a07, +0x1a07,0x1a07,0x1a07,0x1a0a,0x1a04,0x1bf3,0x1bf3,0x1bf3,0x1bf6,0x1bf0,0x1bf6,0x1bf0,0x128a,0x128a,0x128a,0x128a, +0x128a,0x128a,0x128a,0x128a,0x128a,0x128a,0x128a,0x128d,0x128d,0x128d,0x1272,0x1938,0x1398,0x1296,0x1398,0x1398, +0x1398,0x1398,0x1398,0x1398,0x1398,0x1398,0x1398,0x1398,0x1398,0x1296,0x1398,0x1296,0x127b,0x127b,0x1323,0x1278, +0x1323,0x1323,0x1323,0x1323,0x1278,0x1278,0x129c,0x1278,0x1278,0x1278,0x1278,0x1278,0x1278,0x127b,0x129c,0x129c, +0x127b,0x129c,0x1278,0x127b,0x127b,0x127e,0x129c,0x1278,0x1278,0x129c,0x127b,0x127b,0x1395,0x1395,0x1395,0x1395, +0x1395,0x1395,0x1395,0x1395,0x1395,0x1395,0x1287,0x1287,0x1287,0x1287,0x13ad,0x138f,0x1290,0x13ad,0x13ad,0x13ad, +0x13ad,0x13ad,0x13ad,0x13ad,0x13ad,0x13ad,0x13ad,0x1836,0x1836,0x1836,0x1836,0x1836,0x128a,0x128a,0x128a,0x128a, +0x128a,0x128a,0x128a,0x128a,0x128a,0x128a,0x128a,0x1539,0x1539,0x1a88,0x1a88,0x1a88,0x128a,0x128a,0x128a,0x128a, +0x128a,0x128a,0x128a,0x128a,0x128a,0x128a,0x128a,0x128a,0x128a,0x128a,0x128a,0x128a,0x1398,0x1398,0x1296,0x1398, +0x1398,0x1398,0x1296,0x1398,0x1398,0x1398,0x1290,0x1290,0x1290,0x1290,0x1290,0x1392,0x1395,0x1395,0x1395,0x1395, +0x1395,0x1395,0x1395,0x1293,0x1395,0x1395,0x1395,0x1395,0x1395,0x1395,0x1395,0x1293,0x1395,0x1395,0x1395,0x1395, +0x1395,0x1395,0x1395,0x1395,0x1395,0x1395,0x1416,0x1416,0x19e6,0x1a88,0x1a88,0x1a88,0x1395,0x1395,0x1395,0x1395, +0x1395,0x1395,0x1395,0x1395,0x1395,0x1293,0x1395,0x1293,0x1293,0x1395,0x1395,0x1293,0x12b7,0x12b7,0x12b7,0x12b7, +0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7, +0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x12b7,0x1341,0x133e,0x1341,0x133e, +0x1341,0x133e,0x1341,0x133e,0x1341,0x133e,0x1404,0x1518,0x1518,0x1518,0x17b2,0x1926,0x1518,0x1518,0x16fe,0x16fe, +0x16fe,0x16f8,0x16fe,0x16f8,0x1929,0x1926,0x19e3,0x19e0,0x19e3,0x19e0,0x19e3,0x19e0,0x1365,0x1365,0x1365,0x1365, +0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365, +0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x137a,0x136b,0x137a,0x1380, +0x1380,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d, +0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x136b,0x136b,0x136b,0x136b, +0x136b,0x136b,0x136b,0x136b,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386, +0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386,0x1386, +0x1386,0x1386,0x1386,0x1386,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c, +0x138c,0x138c,0x138c,0x138c,0x13b6,0x13b3,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db, +0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db, +0x18db,0x18db,0x18db,0x18db,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bc,0x13bc,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bc,0x13bf,0x13bf,0x13bf,0x13bc,0x13bf,0x13bc,0x13bf,0x13bc,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13c2,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bc,0x13bf,0x13bc,0x13bc,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc, +0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x1542,0x1542, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1788,0x1788,0x1788, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x1545,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x1545,0x1788,0x1788,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13c2,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x1545,0x1545,0x1545,0x1545, +0x1545,0x1545,0x1545,0x1545,0x1542,0x1542,0x1545,0x1545,0x13bf,0x13bf,0x13c2,0x13c2,0x13c2,0x16b3,0x13bf,0x13c2, +0x13bf,0x13bf,0x13c2,0x1548,0x1548,0x1545,0x1545,0x1788,0x1788,0x1788,0x1788,0x1788,0x1545,0x1545,0x1545,0x1545, +0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x1545,0x1545,0x1545,0x16b3,0x1545,0x1545,0x1545, +0x1788,0x1788,0x1788,0x178b,0x178b,0x178b,0x178b,0x178b,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x1545,0x13bf,0x1545,0x13c2,0x13c2,0x13bf,0x13bf,0x13c2,0x13c2, +0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2, +0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13bf,0x13bf,0x13bf, +0x13c2,0x13bf,0x13bf,0x13bf,0x13bf,0x13c2,0x13c2,0x13c2,0x13bf,0x13c2,0x13c2,0x13c2,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13c2,0x13bf,0x13c2,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x16b3,0x13bf,0x13bf,0x13bf,0x13bf,0x1545,0x1545,0x1788,0x1419,0x1419,0x1419,0x1419,0x1542,0x1542,0x1542,0x1542, +0x1542,0x1542,0x1545,0x1788,0x1788,0x1788,0x1788,0x170d,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf, +0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545, +0x1545,0x1545,0x1545,0x1545,0x1548,0x1548,0x1545,0x1545,0x1545,0x1545,0x183f,0x1545,0x1545,0x1545,0x1545,0x1545, +0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545, +0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1545,0x13bf,0x13bf,0x13bf,0x13bf,0x13bf,0x14a3,0x13c5,0x13c5,0x13c5, +0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x14a3,0x13c5,0x13c5, +0x13c5,0x14a3,0x13c5,0x14a3,0x13c5,0x14a3,0x13c5,0x14a3,0x13c5,0x13c5,0x13c5,0x14a3,0x13c5,0x13c5,0x13c5,0x13c5, +0x13c5,0x13c5,0x14a3,0x14a3,0x13c5,0x13c5,0x13c5,0x13c5,0x14a3,0x13c5,0x14a3,0x14a3,0x13c5,0x13c5,0x13c5,0x13c5, +0x14a3,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x13c5,0x16b9,0x16b9,0x178e, +0x178e,0x13c8,0x13c8,0x13c8,0x13c5,0x13c5,0x13c5,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x1638,0x1638,0x1638,0x1638, +0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x13cb,0x13cb,0x13cb,0x13cb, +0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb, +0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13ce, +0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb, +0x13ce,0x13ce,0x13ce,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13cb,0x13d1,0x13d1,0x13d1,0x13d1, +0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1, +0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x13d1,0x17bb,0x17bb,0x17b8,0x1710, +0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141c,0x141c,0x141c,0x141c,0x141c,0x141c,0x141f,0x141f,0x141f,0x141f, +0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x154e,0x1422,0x1551,0x1422,0x1422, +0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1551,0x1551,0x1551,0x1551,0x1551,0x1551,0x1713, +0x1713,0x1b5d,0x17c1,0x17c1,0x17c1,0x17c1,0x17c1,0x17c1,0x17c1,0x17c1,0x1a8b,0x1a8b,0x142b,0x142b,0x142b,0x143d, +0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d, +0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x1458,0x1458,0x1458,0x1458, 0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458, -0x1458,0x1458,0x1458,0x1458,0x145e,0x145e,0x146a,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470, -0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470, -0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x146a,0x146a,0x146a,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e, -0x145e,0x145e,0x145e,0x146a,0x146d,0x1470,0x1473,0x1473,0x1470,0x1476,0x1476,0x1461,0x1464,0x170a,0x170d,0x170d, -0x170d,0x154e,0x1a82,0x1a7f,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x154b,0x1713, -0x1716,0x1710,0x1719,0x1719,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491, -0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491, -0x1491,0x1491,0x1491,0x1491,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb, -0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x18ff,0x18ff, -0x18ff,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x19c8,0x14eb,0x14eb, -0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x1863,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff, -0x18ff,0x18ff,0x18ff,0x18ff,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c, -0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x1539,0x1539,0x1539,0x1539,0x1539,0x1539,0x1539,0x1539, -0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c, -0x153f,0x153c,0x153c,0x153c,0x153c,0x16a7,0x16a7,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c, -0x182d,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c, -0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x155d,0x155d,0x155d,0x155d, -0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d, -0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x156f,0x156f,0x156f,0x156f, -0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f, -0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x1575,0x1575,0x1575,0x1575, -0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575, -0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1578,0x1578,0x1578,0x1578, +0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x145e,0x145e,0x145e,0x145e, +0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e, +0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x19ec,0x1461,0x1461,0x1461,0x1461, +0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461, +0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1461,0x1467,0x1467,0x1473,0x1479, +0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479, +0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1473, +0x1473,0x1473,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1473,0x1476,0x1479,0x147c,0x147c, +0x1479,0x147f,0x147f,0x146a,0x146d,0x1719,0x171c,0x171c,0x171c,0x1557,0x1a94,0x1a91,0x1470,0x1470,0x1470,0x1470, +0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1554,0x1722,0x1725,0x171f,0x1728,0x1728,0x149a,0x149a,0x149a,0x149a, +0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a, +0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x149a,0x14f4,0x14f4,0x14f4,0x14f4, +0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4, +0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x190e,0x190e,0x190e,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4, +0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x19da,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x14f4,0x1872,0x190e, +0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x1545,0x1545,0x1545,0x1545, +0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545, +0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545, +0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1548,0x1545,0x1545,0x1545,0x1545,0x16b6,0x16b6,0x1545, +0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x183c,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545, +0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545,0x1545, +0x1545,0x1545,0x1545,0x1545,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566, +0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566, +0x1566,0x1566,0x1566,0x1566,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578, 0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578, -0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x15a2,0x15a2,0x15a2,0x15a2, -0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x159c,0x159c,0x159c,0x1590,0x1590,0x1590,0x159c,0x159c, -0x1590,0x159f,0x1593,0x1590,0x15a5,0x15a5,0x1599,0x15a5,0x15a5,0x1596,0x17b5,0x1bdb,0x15b7,0x15b7,0x15b7,0x15b7, -0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7, -0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15a8,0x15c0,0x15c0,0x15c0,0x15c0, -0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0, -0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15ba,0x15c3,0x15c3,0x15c3,0x15c3,0x15c6,0x15c6,0x15c6,0x15c6, +0x1578,0x1578,0x1578,0x1578,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e, +0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e, +0x157e,0x157e,0x157e,0x157e,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581, +0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581,0x1581, +0x1581,0x1581,0x1581,0x1581,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1, +0x15ab,0x15ab,0x15ab,0x159f,0x159f,0x159f,0x15ab,0x15ab,0x159f,0x15ae,0x15a2,0x159f,0x15b4,0x15b4,0x15a8,0x15b4, +0x15b4,0x15a5,0x17c4,0x1bed,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6, 0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6, -0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15e1,0x15e1,0x15e1,0x15e1, -0x15e1,0x15e1,0x15e1,0x15e1,0x15d8,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1, -0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15ea,0x15ea,0x15ea,0x15ea, -0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea, -0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15fc,0x15fc,0x15fc,0x15fc, -0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15f9,0x15f9,0x15f9,0x15ed, -0x15ed,0x15ed,0x15ed,0x15ed,0x15ed,0x15ed,0x15ed,0x15f9,0x15f9,0x15ed,0x15f9,0x15f0,0x15fc,0x15fc,0x15fc,0x15fc, -0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc, -0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x1620,0x1620,0x1620,0x1620, -0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620, -0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x161d,0x161d,0x161d,0x1629,0x1629,0x1629,0x1629, -0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629, -0x1629,0x1629,0x162f,0x162f,0x162f,0x162c,0x162c,0x162c,0x1629,0x1629,0x1629,0x1629,0x163e,0x163e,0x163e,0x163e, -0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x1632,0x1632,0x1632,0x1632, -0x1632,0x1632,0x1632,0x1644,0x1644,0x1638,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x163e,0x163e,0x163e,0x163e, -0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e, -0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x164a,0x164a,0x164a,0x164a, -0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a, -0x164a,0x164a,0x164a,0x1647,0x1647,0x1647,0x1647,0x1647,0x1647,0x1647,0x1647,0x1647,0x164d,0x164d,0x164d,0x164d, +0x15c6,0x15c6,0x15c6,0x15b7,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf, +0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15c9, +0x15d2,0x15d2,0x15d2,0x15d2,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5, +0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5, +0x15d5,0x15d5,0x15d5,0x15d5,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15e7,0x15f0,0x15f0,0x15f0, +0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0, +0x15f0,0x15f0,0x15f0,0x15f0,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9, +0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9,0x15f9, +0x15f9,0x15f9,0x15f9,0x15f9,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b, +0x160b,0x160b,0x160b,0x160b,0x1608,0x1608,0x1608,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x1608, +0x1608,0x15fc,0x1608,0x15ff,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b, +0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b,0x160b, +0x160b,0x160b,0x160b,0x160b,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f, +0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f,0x162f, +0x162f,0x162c,0x162c,0x162c,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638, +0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x163e,0x163e,0x163e,0x163b,0x163b,0x163b, +0x1638,0x1638,0x1638,0x1638,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d, +0x164d,0x164d,0x164d,0x164d,0x1641,0x1641,0x1641,0x1641,0x1641,0x1641,0x1641,0x1653,0x1653,0x1647,0x1644,0x1644, +0x1644,0x1644,0x1644,0x1644,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d, 0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d, -0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x1671,0x1671,0x1671,0x1671, -0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671, -0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x167a,0x167a,0x167a,0x167a, -0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a, -0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x1692,0x1692,0x1692,0x1692, -0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x167d,0x168c,0x168c,0x167d, -0x167d,0x167d,0x167d,0x167d,0x167d,0x168c,0x167d,0x168f,0x168f,0x167d,0x168f,0x167d,0x1692,0x1692,0x1692,0x1692, -0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692, -0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x169b,0x169b,0x169b,0x169b, -0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b, -0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x16a1,0x16a1,0x16a1,0x16a1, +0x164d,0x164d,0x164d,0x164d,0x1659,0x1659,0x1659,0x1659,0x1659,0x1659,0x1659,0x1659,0x1659,0x1659,0x1659,0x1659, +0x1659,0x1659,0x1659,0x1659,0x1659,0x1659,0x1659,0x1659,0x1659,0x1659,0x1659,0x1656,0x1656,0x1656,0x1656,0x1656, +0x1656,0x1656,0x1656,0x1656,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c, +0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c,0x165c, +0x165c,0x165c,0x165c,0x165c,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680, +0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680, +0x1680,0x1680,0x1680,0x1680,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689, +0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689, +0x1689,0x1689,0x1689,0x1689,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1, +0x16a1,0x16a1,0x16a1,0x16a1,0x168c,0x169b,0x169b,0x168c,0x168c,0x168c,0x168c,0x168c,0x168c,0x169b,0x168c,0x169e, +0x169e,0x168c,0x169e,0x168c,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1, 0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1, -0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x18ff,0x18ff,0x18ff,0x18ff, -0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x16e6,0x16e6,0x16e6,0x16e6,0x18ff,0x18ff,0x18ff,0x18ff, -0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x19c8,0x1707,0x1707,0x1707,0x1707, -0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707, -0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1746,0x1746,0x1746,0x1746, -0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746, -0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x174c,0x1749, -0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746, -0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f, -0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f, -0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752, -0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752, -0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764, -0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764, -0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767, -0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767, -0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a, -0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a, -0x176a,0x176a,0x176a,0x176d,0x176d,0x176d,0x176d,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a, -0x176a,0x176a,0x176a,0x176a,0x176a,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176a,0x176d,0x176d, -0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d, -0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d, -0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785, -0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785, -0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x1ae5,0x1a3a,0x1a3a,0x1a3d, -0x1788,0x1788,0x1788,0x1788,0x1788,0x1788,0x1788,0x1788,0x178b,0x1839,0x1839,0x1839,0x1839,0x1839,0x1839,0x18d5, -0x1788,0x1788,0x1788,0x1788,0x1788,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836, -0x1836,0x1836,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3, -0x1788,0x19b3,0x19b3,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1ae2,0x1bb4,0x1a3d,0x1a3d,0x1a3d, -0x18d2,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d2,0x18d2, -0x1a79,0x1a79,0x1a79,0x1a79,0x1a79,0x1a79,0x1a79,0x1a79,0x1b4b,0x1b4e,0x1b48,0x1b48,0x1b48,0x1b48,0x1b48,0x1b48, -0x1b48,0x1b48,0x1b48,0x192c,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af, -0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1839,0x1836,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2, -0x1839,0x18d5,0x18d5,0x1839,0x1839,0x1839,0x1839,0x1839,0x1839,0x1839,0x1836,0x17b8,0x1839,0x1839,0x1839,0x1a3a, -0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x17b8,0x1836,0x1836,0x1836,0x1836,0x1836,0x18d2,0x19b3,0x19b3,0x19b3, -0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x18d2, -0x17cd,0x17cd,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca, -0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca, -0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd, -0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd, -0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b, -0x181b,0x181b,0x181b,0x181b,0x181b,0x1818,0x1818,0x1818,0x1803,0x1803,0x1803,0x1803,0x1803,0x1803,0x1803,0x1803, -0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b, -0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b, -0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f, -0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f, -0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842, -0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842, -0x1842,0x1842,0x1842,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee, -0x1899,0x1899,0x1899,0x1899,0x19ec,0x19ec,0x189c,0x189c,0x189c,0x189c,0x1884,0x1884,0x1884,0x1884,0x1884,0x1884, -0x1884,0x1884,0x1884,0x1884,0x1884,0x1884,0x1884,0x1896,0x1887,0x188a,0x188d,0x189f,0x189f,0x193e,0x1890,0x1890, -0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899, -0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899, -0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba, -0x18ba,0x18ba,0x18ba,0x18a5,0x18ab,0x18a8,0x18a8,0x18a8,0x18a8,0x18b7,0x18bd,0x18a8,0x18a8,0x18a8,0x18a8,0x18b4, -0x18ba,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba, -0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba, -0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad, -0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ba5,0x1ba5,0x1ba5, -0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc, -0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc, -0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x19b3,0x19b3,0x19b3,0x19b3, -0x19b3,0x1a3a,0x1ae2,0x19b3,0x19b3,0x19b3,0x19b3,0x1ae5,0x1ae2,0x1bb4,0x19b3,0x1a3a,0x19b3,0x19b3,0x19b3,0x19b3, -0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3, -0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3, +0x16a1,0x16a1,0x16a1,0x16a1,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa, +0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa, +0x16aa,0x16aa,0x16aa,0x16aa,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0, +0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0,0x16b0, +0x16b0,0x16b0,0x16b0,0x16b0,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e, +0x16f5,0x16f5,0x16f5,0x16f5,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e,0x190e, +0x190e,0x190e,0x190e,0x19da,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716, +0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716,0x1716, +0x1716,0x1716,0x1716,0x1716,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755, +0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755, +0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x175b,0x1758,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755, +0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e, +0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e, +0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x175e,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761, +0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761, +0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1761,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773, +0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773, +0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776, +0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776, +0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779, +0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779, +0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x177c,0x177c,0x177c,0x177c,0x1779, +0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x1779,0x177c,0x177c,0x177c, +0x177c,0x177c,0x177c,0x177c,0x177c,0x1779,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c, +0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c, +0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x177c,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794, +0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794, +0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x1794,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e, +0x187e,0x187e,0x187e,0x187e,0x1af7,0x1a4c,0x1a4c,0x1a4f,0x1797,0x1797,0x1797,0x1797,0x1797,0x1797,0x1797,0x1797, +0x179a,0x1848,0x1848,0x1848,0x1848,0x1848,0x1848,0x18e4,0x1797,0x1797,0x1797,0x1797,0x1797,0x1845,0x1845,0x1845, +0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1, +0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x1797,0x19c5,0x19c5,0x1a4c,0x1a4c,0x1a4c,0x1a4c,0x1a4c, +0x1a4c,0x1a4c,0x1a4c,0x1af4,0x1bc6,0x1a4f,0x1a4f,0x1a4f,0x18e1,0x18e4,0x18e4,0x18e4,0x18e4,0x18e4,0x18e4,0x18e4, +0x18e4,0x18e4,0x18e4,0x18e4,0x18e4,0x18e4,0x18e1,0x18e1,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b, +0x1b5d,0x1b60,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x193b,0x17be,0x17be,0x17be,0x17be, +0x17be,0x17be,0x17be,0x17be,0x17be,0x17be,0x17be,0x17be,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1848,0x1845, +0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x1848,0x18e4,0x18e4,0x1848,0x1848,0x1848,0x1848,0x1848, +0x1848,0x1848,0x1845,0x17c7,0x1848,0x1848,0x1848,0x1a4c,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x17c7,0x1845, +0x1845,0x1845,0x1845,0x1845,0x18e1,0x19c5,0x19c5,0x19c5,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845, +0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x18e1,0x17dc,0x17dc,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9, +0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9, +0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc, +0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc, +0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a, +0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x1827,0x1827,0x1827, +0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a, +0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a, +0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x182a,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e, +0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e, +0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x184e,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851, +0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851, +0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1851,0x1b00,0x1b00,0x1b00,0x1b00,0x1b00, +0x1b00,0x1b00,0x1b00,0x1b00,0x1b00,0x1b00,0x1b00,0x1b00,0x18a8,0x18a8,0x18a8,0x18a8,0x19fe,0x19fe,0x18ab,0x18ab, +0x18ab,0x18ab,0x1893,0x1893,0x1893,0x1893,0x1893,0x1893,0x1893,0x1893,0x1893,0x1893,0x1893,0x1893,0x1893,0x18a5, +0x1896,0x1899,0x189c,0x18ae,0x18ae,0x194d,0x189f,0x189f,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8, +0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8, +0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9, +0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18b4,0x18ba,0x18b7,0x18b7,0x18b7, +0x18b7,0x18c6,0x18cc,0x18b7,0x18b7,0x18b7,0x18b7,0x18c3,0x18c9,0x18b7,0x18b7,0x18b7,0x18b7,0x18b7,0x18b7,0x18b7, +0x18b7,0x18b7,0x18b7,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9, +0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5, +0x18d5,0x18d5,0x18d5,0x19bf,0x19bf,0x19bf,0x19bf,0x19bf,0x1aeb,0x1aeb,0x1aeb,0x1aeb,0x1aeb,0x1aeb,0x1aeb,0x1aeb, +0x1aeb,0x1aeb,0x1aeb,0x1aeb,0x1aeb,0x1bb7,0x1bb7,0x1bb7,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db, 0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db, -0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db, -0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de, -0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x1bb7, -0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1, -0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1, -0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953, -0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953, -0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e, -0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e, -0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974, -0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974, -0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f, -0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f, -0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992, -0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992, -0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b, -0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x1998,0x1998,0x1998, -0x19b3,0x19b3,0x19b3,0x1ae2,0x1ae2,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1ae2,0x1ae2,0x1ae2,0x1a3a,0x1a3a, -0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b6,0x19b6,0x19b3,0x19b6,0x19b6,0x1a3a,0x1a3d,0x1a3a,0x1a3a,0x1a3a,0x1a3a, -0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef, -0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef, -0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16, -0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16, -0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f, -0x1a55,0x1a55,0x1a1f,0x1a55,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a25,0x1a25,0x1a25, -0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31, -0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31, -0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4, -0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4, -0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0, -0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0, -0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4, -0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4, -0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7, -0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7, -0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c, -0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c, -0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d, -0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d, +0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1, +0x18e1,0x18e1,0x18e1,0x18e1,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x1a4c,0x1af4,0x19c5,0x19c5,0x19c5,0x19c5,0x1af7, +0x1af4,0x1bc6,0x19c5,0x1a4c,0x19c5,0x19c5,0x19c5,0x19c5,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x19c5, +0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5, +0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea, +0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea, +0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ea,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed, +0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed, +0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x1bc9,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0, +0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0, +0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x18f0,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962, +0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962, +0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d, +0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d, +0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983, +0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983, +0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x1983,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1, +0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1, +0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4, +0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4, +0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad, +0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad, +0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,0x19aa,0x19aa,0x19aa,0x19c5,0x19c5,0x19c5,0x1af4,0x1af4,0x1a4c,0x1a4c,0x1a4c, +0x1a4c,0x1a4c,0x1a4c,0x1af4,0x1af4,0x1af4,0x1a4c,0x1a4c,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c8,0x19c8,0x19c5, +0x19c8,0x19c8,0x1a4c,0x1a4f,0x1a4c,0x1a4c,0x1a4c,0x1a4c,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01, +0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01, +0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28, +0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28, +0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31, +0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a67,0x1a67,0x1a31,0x1a67,0x1a31,0x1a31,0x1a31,0x1a31, +0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a37,0x1a37,0x1a37,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43, +0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43, +0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1a43,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6, +0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6, +0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2, +0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2, +0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06, +0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06, +0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b06,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09, +0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09, +0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b09,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e, +0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e, +0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b7e,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f, 0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f, -0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f, -0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2, -0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2, -0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc, -0x1bfc,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9, -0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b, -0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b, -0,0,0,0 +0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1, +0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1, +0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4, +0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4, +0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1bb4,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e, +0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b, +0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d, +0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d, +0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c4d,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59, +0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59, +0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0x1c59,0,0,0,0 }; static const UTrie2 propsVectorsTrie={ propsVectorsTrie_index, - propsVectorsTrie_index+5348, + propsVectorsTrie_index+5368, nullptr, - 5348, - 27344, + 5368, + 27396, 0xa40, - 0x1564, + 0x1578, 0x0, 0x0, 0x110000, - 0x7fb0, + 0x7ff8, nullptr, 0, false, false, 0, nullptr }; -static const uint32_t propsVectors[7230]={ +static const uint32_t propsVectors[7260]={ 0x67,0,0,0x67,0,0xe00000,0x67,0x80000,0x20,0x867,0,0,0xa67,0,0,0xb67, 0,0,0xd67,0,0,0xe67,0,0,0x1067,0,0,0x1167,0,0,0x1267,0, 0,0x1367,0,0,0x1467,0,0,0x1567,0,0,0x1667,0,0,0x1767,0,0, 0x1867,0,0,0x1967,0,0,0x1a67,0,0,0x1b67,0,0,0x1d67,0,0,0x1f67, 0,0,0x2067,0,0,0x2267,0,0,0x2367,0,0,0x2467,0,0,0x2567,0, 0,0x2767,0,0,0x2867,0x80000,0x20,0x2967,0,0,0x2a67,0,0x1600000,0x2b67,0,0, -0x2d67,0,0,0x3167,0x20000000,0,0x3267,0x20000000,0,0x3a67,0,0,0x3b67,0,0,0x3c67, -0,0,0x3e67,0,0,0x4067,0,0,0x4167,0,0,0x4467,0,0,0x4867,0, -0,0x4967,0,0,0x4a67,0,0,0x5067,0,0,0x5167,0,0,0x5467,0,0, -0x5567,0,0,0x5667,0x80000,0x20,0x5767,0,0,0x5867,0,0,0x5967,0,0,0x5b67, -0,0,0x5c67,0,0,0x5d67,0,0,0x6067,0x80000,0x20,0x6267,0,0,0x6367,0, -0,0x6467,0,0,0x6567,0,0,0x6f67,0,0,0x7067,0,0,0x7367,0x20000000,0, -0x7567,0,0,0x7667,0,0,0x7767,0,0,0x7867,0,0,0x7a67,0,0,0x7b67, -0,0,0x7c67,0,0,0x7e67,0,0,0x7f67,0,0,0x8167,0,0,0x8267,0, -0,0x8467,0,0,0x8567,0,0,0x8667,0,0,0x8767,0,0,0x8967,0,0, -0x8b67,0,0,0x8c67,0,0,0x8e67,0x20000000,0,0x8f67,0,0,0x9067,0,0,0x9167, -0,0,0x9267,0,0,0x9367,0,0,0x9567,0,0,0x9667,0,0,0x9767,0, -0,0x9867,0,0,0x9967,0,0,0x9a67,0,0,0x9c67,0,0,0x9f67,0,0, -0xa167,0,0,0xa367,0,0,0xa467,0,0,0xa567,0,0,0xa667,0,0,0xa767, -0,0,0xa867,0,0,0xa967,0,0,0xaa67,0,0xe00000,0xab67,0,0xe00000,0xac67,0, -0,0xad67,0,0,0xae67,0,0,0xaf67,0,0,0xb167,0,0,0xb267,0,0, -0xb467,0,0,0xb567,0,0,0xb767,0,0,0xb867,0,0,0xb967,0,0,0xba67, -0,0,0xbc67,0,0,0xbd67,0,0,0xbe67,0,0,0xbf67,0,0,0xc067,0, -0,0xc167,0,0,0xc367,0,0xe00000,0xc467,0,0xe00000,0xc667,0,0,0xc767,0,0, -0xc867,0,0,0xc967,0,0,0xca67,0,0,0xcc67,0,0xe00000,0xcf67,0,0xe00000,0xd067, -0,0xe00000,0xd367,0,0,0xd467,0,0,0xd567,0,0,0xd667,0,0,0xd867,0, -0,0xda67,0,0,0xdb67,0,0,0xdc67,0,0,0xdd67,0,0,0xde67,0,0, -0xdf67,0,0,0xe067,0,0,0xe167,0,0,0xe267,0,0,0xe367,0,0xe00000,0xe467, -0,0,0xe567,0,0,0xe667,0,0,0xe767,0,0,0xe867,0,0,0xe967,0, -0,0xea67,0,0,0xeb67,0,0,0xec67,0,0,0xed67,0,0,0xee67,0,0, -0xef67,0,0,0xf167,0,0,0xf367,0,0,0xf567,0,0,0xf667,0,0,0xf767, -0,0,0xf867,0,0,0xf967,0,0,0xfa67,0,0xe00000,0xfb67,0,0,0xfc67,0, -0,0xfd67,0,0,0xfe67,0,0,0x10167,0,0,0x10267,0,0,0x10367,0,0, -0x10467,0,0,0x10667,0,0,0x10767,0,0,0x10867,0,0,0x10967,0,0,0x10a67, -0,0,0x10b67,0,0,0x10c67,0,0,0x10d67,0,0,0x10e67,0,0,0x10f67,0, -0,0x11067,0,0,0x11367,0,0,0x11467,0,0,0x11567,0,0,0x11667,0,0, -0x11767,0,0,0x11867,0,0,0x11967,0,0xe00000,0x11a67,0,0,0x11b67,0,0,0x11c67, -0,0,0x11d67,0,0,0x11e67,0,0,0x11f67,0,0,0x12067,0,0,0x12167,0, -0,0x12267,0,0,0x12367,0,0,0x12467,0,0,0x12567,0,0,0x12667,0,0, -0x12767,0,0,0x12867,0,0,0x12967,0,0,0x12a67,0,0xe00000,0x12b67,0,0,0x12c67, -0,0,0x12d67,0,0,0x12f67,0,0,0x13067,0,0,0x13167,0,0,0x13267,0, -0,0x13367,0,0,0x13467,0,0,0x13567,0,0,0x13667,0,0,0x13767,0,0, -0x13867,0,0,0x13967,0,0,0x13a67,0,0,0x13b67,0,0,0x13c67,0,0,0x13d67, -0,0,0x13f67,0,0,0x14067,0,0,0x14167,0,0,0x14367,0,0,0x14467,0, -0,0x14567,0,0,0x14667,0,0,0x14767,0,0,0xa0067,0,0xe00000,0xa4f67,0,0xe00000, -0xa5f67,0,0xe00000,0xac567,0,0xe00000,0xad167,0,0xe00000,0xb0067,0,0xe00000,0xb1267,0,0xe00000,0xb2e67, +0x2d67,0,0,0x3167,0x20000000,0,0x3267,0x20000000,0,0x3a67,0,0,0x3b67,0,0,0x3e67, +0,0,0x4067,0,0,0x4167,0,0,0x4467,0,0,0x4867,0,0,0x4967,0, +0,0x4a67,0,0,0x5067,0,0,0x5167,0,0,0x5467,0,0,0x5567,0,0, +0x5667,0x80000,0x20,0x5767,0,0,0x5867,0,0,0x5967,0,0,0x5b67,0,0,0x5c67, +0,0,0x5d67,0,0,0x6067,0x80000,0x20,0x6267,0,0,0x6367,0,0,0x6467,0, +0,0x6567,0,0,0x6f67,0,0,0x7067,0,0,0x7367,0x20000000,0,0x7567,0,0, +0x7667,0,0,0x7767,0,0,0x7867,0,0,0x7a67,0,0,0x7b67,0,0,0x7c67, +0,0,0x7e67,0,0,0x7f67,0,0,0x8167,0,0,0x8267,0,0,0x8467,0, +0,0x8567,0,0,0x8667,0,0,0x8767,0,0,0x8967,0,0,0x8b67,0,0, +0x8c67,0,0,0x8e67,0x20000000,0,0x8f67,0,0,0x9067,0,0,0x9167,0,0,0x9267, +0,0,0x9367,0,0,0x9567,0,0,0x9667,0,0,0x9767,0,0,0x9867,0, +0,0x9967,0,0,0x9a67,0,0,0x9c67,0,0,0x9f67,0,0,0xa167,0,0, +0xa367,0,0,0xa467,0,0,0xa567,0,0,0xa667,0,0,0xa767,0,0,0xa867, +0,0,0xa967,0,0,0xaa67,0,0xe00000,0xab67,0,0xe00000,0xac67,0,0,0xad67,0, +0,0xae67,0,0,0xaf67,0,0,0xb167,0,0,0xb267,0,0,0xb467,0,0, +0xb567,0,0,0xb767,0,0,0xb867,0,0,0xb967,0,0,0xba67,0,0,0xbc67, +0,0,0xbd67,0,0,0xbe67,0,0,0xbf67,0,0,0xc067,0,0,0xc167,0, +0,0xc367,0,0xe00000,0xc467,0,0xe00000,0xc667,0,0,0xc767,0,0,0xc867,0,0, +0xc967,0,0,0xca67,0,0,0xcc67,0,0xe00000,0xcf67,0,0xe00000,0xd067,0,0xe00000,0xd367, +0,0,0xd467,0,0,0xd567,0,0,0xd667,0,0,0xd867,0,0,0xda67,0, +0,0xdb67,0,0,0xdc67,0,0,0xdd67,0,0,0xde67,0,0,0xdf67,0,0, +0xe067,0,0,0xe167,0,0,0xe267,0,0,0xe367,0,0xe00000,0xe467,0,0,0xe567, +0,0,0xe667,0,0,0xe767,0,0,0xe867,0,0,0xe967,0,0,0xea67,0, +0,0xeb67,0,0,0xec67,0,0,0xed67,0,0,0xee67,0,0,0xef67,0,0, +0xf167,0,0,0xf367,0,0,0xf567,0,0,0xf667,0,0,0xf767,0,0,0xf867, +0,0,0xf967,0,0,0xfa67,0,0xe00000,0xfb67,0,0,0xfc67,0,0,0xfd67,0, +0,0xfe67,0,0,0x10167,0,0,0x10267,0,0,0x10367,0,0,0x10467,0,0, +0x10667,0,0,0x10767,0,0,0x10867,0,0,0x10967,0,0,0x10a67,0,0,0x10b67, +0,0,0x10c67,0,0,0x10d67,0,0,0x10e67,0,0,0x10f67,0,0,0x11067,0, +0,0x11367,0,0,0x11467,0,0,0x11567,0,0,0x11667,0,0,0x11767,0,0, +0x11867,0,0,0x11967,0,0xe00000,0x11a67,0,0,0x11b67,0,0,0x11c67,0,0,0x11d67, +0,0,0x11e67,0,0,0x11f67,0,0,0x12067,0,0,0x12167,0,0,0x12267,0, +0,0x12367,0,0,0x12467,0,0,0x12567,0,0,0x12667,0,0,0x12767,0,0, +0x12867,0,0,0x12967,0,0,0x12a67,0,0xe00000,0x12b67,0,0,0x12c67,0,0,0x12d67, +0,0,0x12f67,0,0,0x13067,0,0,0x13167,0,0,0x13267,0,0,0x13367,0, +0,0x13467,0,0,0x13567,0,0,0x13667,0,0,0x13767,0,0,0x13867,0,0, +0x13967,0,0,0x13a67,0,0,0x13b67,0,0,0x13c67,0,0,0x13d67,0,0,0x13f67, +0,0,0x14067,0,0,0x14167,0,0,0x14367,0,0,0x14467,0,0,0x14567,0, +0,0x14667,0,0,0x14767,0,0,0xa0067,0,0xe00000,0xa4f67,0,0xe00000,0xa5f67,0,0xe00000, +0xac567,0,0xe00000,0xad167,0,0xe00000,0xb0067,0,0xe00000,0xb1267,0,0xe00000,0xb2e67,0,0xe00000,0xb4867, 0,0xe00000,0x11000100,0,0x900020,0x11000100,0x40000001,0x440020,0x11000100,0x40000001,0x643020,0x11000100,0x40000001,0xa5a040,0x11000100,0x40000001, 0x116a8a0,0x11000200,0,0x900020,0x11000200,0x4000001,0xc4000b,0x11000200,0x7c00100,0x220402,0x11000200,0x24000000,0x200000,0x11000200,0x24000008,0x1710000, 0x11000200,0x40000001,0x1d3b020,0x11000219,0x7c00100,0x220401,0x11000219,0x7c00100,0x250401,0x11000319,0x7c00100,0x220401,0x11000319,0x7c00100,0x220402,0x11000319, @@ -3590,7 +3603,7 @@ static const uint32_t propsVectors[7230]={ 0x250400,0x11000908,0x7c00100,0x250401,0x11000a03,0x4000000,0x200400,0x11000a03,0x4000000,0x201000,0x11000a03,0x4000000,0x270000,0x11000a03,0x7c00100,0x220400, 0x11000a03,0x7c00100,0x220402,0x11000a03,0x7c00100,0x250400,0x11000a03,0x7c00500,0x230400,0x11000a03,0xc000010,0x1049400,0x11000b13,0x2802500,0x962460,0x11000b13, 0x4000000,0x200000,0x11000b13,0x4000000,0x201000,0x11000b13,0x4000000,0x230400,0x11000b13,0x4000002,0x400000,0x11000b13,0x4000010,0x200000,0x11000b13,0x7c00100, -0x2633800,0x11000c00,0x80000000,0x218960,0x11000c02,0x2802100,0x962460,0x11000c02,0x2802400,0x962460,0x11000c02,0x4000000,0x200000,0x11000c02,0x4000000,0x1329400, +0x2633800,0x11000c00,0x80000000,0x1329960,0x11000c02,0x2802100,0x962460,0x11000c02,0x2802400,0x962460,0x11000c02,0x4000000,0x200000,0x11000c02,0x4000000,0x1329400, 0x11000c02,0x4000000,0x1329800,0x11000c02,0x4000000,0x1500000,0x11000c02,0x6800000,0x1329800,0x11000c02,0x7c00100,0x230400,0x11000c02,0x7c00100,0x230401,0x11000c02, 0x7c00100,0x230402,0x11000c02,0x7c00500,0x230400,0x11000c02,0x7d00100,0x230400,0x11000f01,0x2802400,0x962460,0x11000f0a,0x2802100,0x962460,0x11000f0a,0x2802400, 0x962460,0x11000f0a,0x2806400,0x962460,0x11000f0a,0x4000000,0x200000,0x11000f0a,0x6800100,0x962540,0x11000f0a,0x7c00100,0x230400,0x11000f0a,0x7c00100,0x230401, @@ -3614,7 +3627,7 @@ static const uint32_t propsVectors[7230]={ 0x201c00,0x11002800,0x6800020,0x201c00,0x11002800,0x24000000,0x200000,0x11002800,0x24000000,0x200002,0x11002800,0x24000000,0x810000,0x11002800,0x24000000,0x1410000, 0x11002800,0x24000000,0x1500000,0x11002800,0x24000000,0x1500002,0x11002800,0x24000002,0x400000,0x11002800,0x24000006,0xc0000b,0x11002800,0x24000008,0x1410000,0x11002800, 0x24000008,0x1710000,0x11002800,0x24000020,0x1001400,0x11002800,0x24000020,0x1500002,0x11002800,0x2c000010,0x1248000,0x11002800,0x2c000010,0x1248002,0x11002800,0x40000001, -0x63b020,0x11002800,0x40080000,0x918820,0x11002801,0x80000,0x2a65620,0x11002801,0x82000,0x962460,0x11002900,0x4000000,0x20000e,0x11002900,0x4000000,0x20000f, +0x63b020,0x11002800,0x40080000,0x918820,0x11002801,0x2880000,0x2a65620,0x11002801,0x2882000,0x962460,0x11002900,0x4000000,0x20000e,0x11002900,0x4000000,0x20000f, 0x11002900,0x4000020,0x20000e,0x11002900,0x4000020,0x20000f,0x11002900,0x4000020,0x81000e,0x11002900,0x4000020,0x81000f,0x11002900,0x4000020,0x141000e,0x11002900, 0x4000020,0x141000f,0x11002900,0x4000022,0x20000e,0x11002900,0x4000022,0x20000f,0x11002a00,0x4000000,0x1500000,0x11002a00,0x4000000,0x1600000,0x11002a00,0x4000000, 0x1600002,0x11002b01,0x2000,0x962460,0x11002b01,0x2802020,0x962460,0x11002c00,0x4000000,0x200000,0x11002c00,0x4000000,0x200002,0x11002c00,0x4000000,0x20000f, @@ -3670,17 +3683,17 @@ static const uint32_t propsVectors[7230]={ 0x4000000,0x141000c,0x110a5400,0x4000000,0x150000c,0x110a5400,0x4000000,0x160000c,0x110a5400,0x4000002,0xe7000c,0x110a5400,0x4000010,0x87140c,0x110a5400,0x4000010, 0xe7000c,0x110a5400,0x4000010,0x120140c,0x110a5400,0x4000010,0x127100c,0x110a5400,0x4000020,0xe0000c,0x110a5400,0x4000026,0xe7000c,0x110a5400,0xc000010,0x80ac0c, 0x110a5400,0xc000010,0xb4800c,0x11400c0c,0x4000010,0xb00000,0x11400c0c,0x4000010,0x1071400,0x11400c17,0xc000010,0xb48000,0x11400c1e,0x7c00900,0x230400,0x11400f4b, -0xc000010,0x448000,0x11400f5f,0xc000010,0x448000,0x11401d94,0x4000000,0x200000,0x11403dca,0x4000000,0xe00000,0x114457bf,0x4000004,0x120000a,0x114457bf,0x4000008, -0x81000a,0x114457bf,0x4000008,0x141000a,0x114457bf,0x4000010,0x87000a,0x114457bf,0xc000010,0x84800a,0x114457c8,0x3802500,0x126246a,0x114457c8,0x7c00d00,0x2530c0a, -0x114a3dbf,0x24000000,0x810000,0x114a3dbf,0x24000000,0x1410000,0x114a3dbf,0x24000008,0x810000,0x114a3dbf,0x24000008,0x1410000,0x114a3dbf,0x24000010,0x870000,0x114a3dbf, -0x2c000010,0x848000,0x114a3dc5,0x4000000,0xe00000,0x114a3dc5,0x24000000,0xe00000,0x114a3dc5,0x24000002,0xe00000,0x114a3dc5,0x24000002,0x1200000,0x114a3dc5,0x24000008, -0x810000,0x114a3dc5,0x24000008,0x1410000,0x114a3dc8,0x7c00900,0x930c00,0x114a3dc8,0x7c00900,0xe30c00,0x114a3dca,0x7c00300,0xe30000,0x114a3ec8,0x7000400,0x1200c02, -0x114a3fbf,0x4000004,0x1200000,0x114a3fc8,0x7c00d00,0x2530c00,0x114a42ca,0x4000000,0xe00000,0x114a42ca,0x4000000,0xe0000f,0x114a44ca,0x4000000,0xe00002,0x114a44ca, -0x4000000,0xe00003,0x114a45ca,0x4000000,0xe00002,0x114a45ca,0x4000000,0xe0000d,0x11505103,0x24000000,0x810000,0x11505103,0x24000000,0x1410000,0x1180090a,0x2802400, +0xc000010,0x448000,0x11400f5f,0xc000010,0x448000,0x11401d94,0x4000000,0x200000,0x11403dcc,0x4000000,0xe00000,0x114457c1,0x4000008,0x81000a,0x114457c1,0x4000008, +0x141000a,0x114457c1,0x4000010,0x87000a,0x114457c1,0x6800004,0x120000a,0x114457c1,0xc000010,0x84800a,0x114457ca,0x3802500,0x126246a,0x114457ca,0x7c00d00,0x2530c0a, +0x114a3dc1,0x24000000,0x810000,0x114a3dc1,0x24000000,0x1410000,0x114a3dc1,0x24000008,0x810000,0x114a3dc1,0x24000008,0x1410000,0x114a3dc1,0x24000010,0x870000,0x114a3dc1, +0x2c000010,0x848000,0x114a3dc7,0x4000000,0xe00000,0x114a3dc7,0x24000000,0xe00000,0x114a3dc7,0x24000002,0xe00000,0x114a3dc7,0x24000002,0x1200000,0x114a3dc7,0x24000008, +0x810000,0x114a3dc7,0x24000008,0x1410000,0x114a3dca,0x7c00900,0x930c00,0x114a3dca,0x7c00900,0xe30c00,0x114a3dcc,0x7c00300,0xe30000,0x114a3eca,0x7000400,0x1200c02, +0x114a3fc1,0x6800004,0x1200000,0x114a3fca,0x7c00d00,0x2530c00,0x114a42cc,0x4000000,0xe00000,0x114a42cc,0x4000000,0xe0000f,0x114a44cc,0x4000000,0xe00002,0x114a44cc, +0x4000000,0xe00003,0x114a45cc,0x4000000,0xe00002,0x114a45cc,0x4000000,0xe0000d,0x11505113,0x24000000,0x810000,0x11505113,0x24000000,0x1410000,0x1180090a,0x2802400, 0x962460,0x11800c27,0x2802100,0x962460,0x11800c27,0x2802500,0x962460,0x11800f32,0x2802400,0x962460,0x11800f3f,0x2802400,0x962460,0x11820700,0x2802400,0x962460, -0x11820700,0x2802500,0x962460,0x118a3dcb,0x2802400,0x962460,0x118a3ec8,0x2802400,0x962460,0x11c00904,0x2802400,0x962460,0x11c00908,0x2802400,0x962460,0x11c00c2c, +0x11820700,0x2802500,0x962460,0x118a3dcd,0x2802400,0x962460,0x118a3eca,0x2802400,0x962460,0x11c00904,0x2802400,0x962460,0x11c00908,0x2802400,0x962460,0x11c00c2c, 0x6800000,0x1329800,0x11c00c30,0xc000010,0xb48000,0x11c00f78,0x6800000,0x1329800,0x11c0107d,0x6800000,0x1329800,0x11c01181,0x6800000,0x1329800,0x11c01285,0x6800000, -0x1329800,0x11c01489,0x4000000,0x200000,0x11c01489,0x6800000,0x1329800,0x11c0168d,0x6800000,0x1329800,0x11d05107,0x7c00100,0x230408,0x20000067,0x1000,0, +0x1329800,0x11c01489,0x4000000,0x200000,0x11c01489,0x6800000,0x1329800,0x11c0168d,0x6800000,0x1329800,0x11d05117,0x7c00100,0x230408,0x20000067,0x1000,0, 0x20000b13,0x2802400,0x962460,0x20000b13,0x2802500,0x962460,0x20001b27,0x2802100,0x962460,0x20001b27,0x2802100,0x962461,0x20001b27,0x2802400,0x962460,0x20001b27, 0x2802500,0x962460,0x20001b27,0x2806400,0x962460,0x20001b27,0x2902100,0x962462,0x20001b27,0x4000000,0x200000,0x20001b27,0x4000000,0x400000,0x20001b27,0x4000000, 0x500000,0x20001b27,0x4000000,0x810000,0x20001b27,0x4000000,0xb00000,0x20001b27,0x4000000,0xc0000b,0x20001b27,0x4000000,0x1410000,0x20001b27,0x4000010,0xb00000, @@ -3692,7 +3705,7 @@ static const uint32_t propsVectors[7230]={ 0x200400,0x3000080e,0x7c00100,0x220400,0x30000908,0x2000,0x962460,0x30000908,0x7c00100,0x220400,0x30000908,0x7c00100,0x220401,0x30000908,0x7c00100,0x250400, 0x30000908,0x7c00100,0x250401,0x30000a03,0x4000006,0x400400,0x30000c02,0x4000000,0x200000,0x30000c02,0x7c00100,0x230400,0x30000d22,0x2802100,0x962460,0x30000d22, 0x2802400,0x962460,0x30000d22,0x2802500,0x962460,0x30000d22,0x4000000,0x200000,0x30000d22,0x4000010,0x200000,0x30000d22,0x7c00100,0x230400,0x30000d22,0xc000010, -0x248000,0x30000d22,0x80000000,0x218960,0x30000e25,0x2802500,0x962460,0x30000e25,0x7c00100,0x230400,0x30001821,0x2802100,0x962460,0x30001821,0x2806400,0x962460, +0x248000,0x30000d22,0x80000000,0x218560,0x30000e25,0x2802500,0x962460,0x30000e25,0x7c00100,0x230400,0x30001821,0x2802100,0x962460,0x30001821,0x2806400,0x962460, 0x30001821,0x4000000,0x200000,0x30001821,0x6800100,0x962540,0x30001821,0x6800100,0x962541,0x30001821,0x7c00100,0x230400,0x30001b27,0x2802100,0x962460,0x30001b27, 0x2802400,0x962460,0x30001b27,0x4000000,0x200000,0x30001b27,0x4000000,0x400000,0x30001b27,0x7c00100,0x230400,0x30001c1c,0x2802100,0x1862460,0x30001c1c,0x2802400, 0x1862460,0x30001c1c,0x2806400,0x1862460,0x30001c1c,0x4000000,0x200000,0x30001c1c,0x6800100,0x1862400,0x30001c1c,0x6800100,0x1862540,0x30001c1c,0x7c00100,0x1830000, @@ -3701,292 +3714,294 @@ static const uint32_t propsVectors[7230]={ 0x230400,0x30002128,0xc000010,0x248000,0x3000221d,0x4000000,0x810000,0x3000221d,0x4000000,0x1410000,0x3000221d,0x4000001,0x445800,0x3000221d,0x7c00100,0x230400, 0x30002300,0x4000010,0x400000,0x30002320,0x7c00100,0x230400,0x30002417,0x2802100,0x1862460,0x30002417,0x2802400,0x1862460,0x30002417,0x2806400,0x1862460,0x30002417, 0x2882000,0x1862460,0x30002417,0x4000000,0x200000,0x30002417,0x4000000,0x400000,0x30002417,0x4000000,0x1600000,0x30002417,0x4000010,0x400000,0x30002417,0x4000010, -0x1200000,0x30002417,0x6800000,0x1329800,0x30002417,0x6800100,0x1862540,0x30002417,0x7c00100,0x1830000,0x30002417,0x7d00100,0x1830000,0x3000251b,0x80000,0xc18820, -0x3000251b,0x2802100,0x962460,0x3000251b,0x3c02100,0x962460,0x3000251b,0x4000000,0x200000,0x3000251b,0x4000006,0x500000,0x3000251b,0x4000010,0x400000,0x3000251b, -0x4000010,0xb70000,0x3000251b,0x4000800,0x200000,0x3000251b,0x6800000,0x1329800,0x3000251b,0x7c00100,0x230400,0x3000251b,0x7c00900,0x230400,0x3000251b,0xc000010, -0xb48000,0x3000251b,0x12882000,0x962460,0x30002800,0x24000000,0x200000,0x30002800,0x2c000010,0x1248002,0x30002a00,0x4000000,0x1600000,0x30002b01,0x2000,0x962460, -0x30002c00,0x4000000,0x200000,0x30002c00,0x7c00100,0x220405,0x30002d19,0x7c00100,0x250400,0x30002e00,0x24000000,0x200000,0x30003000,0x24000000,0x200000,0x30003100, -0x24000000,0x200000,0x30003600,0x24000000,0x200000,0x30003700,0x24000000,0x200000,0x3000392e,0x24000000,0x200000,0x30005013,0x7c00100,0x2633801,0x30005600,0, -0x918820,0x30020600,0x4000400,0x500400,0x30020701,0x2802400,0x962460,0x30020701,0x2802400,0xc62460,0x300a3a11,0x4020000,0xe00000,0x300a3a11,0x4020000,0xe00002, -0x300a3b11,0x4020000,0xe00002,0x300a3c00,0x4008000,0xe00000,0x300a3c00,0x4010000,0xe00000,0x300a3d11,0x7c00300,0xe30002,0x300a4305,0x7c00100,0xe30400,0x300a4611, -0x7c40300,0xe30000,0x300a4829,0x7c00100,0xe30400,0x300a4829,0x7c00900,0x1230400,0x300a4929,0x4000000,0xe00000,0x3040259a,0x4000010,0x400000,0x3040259a,0x4000010, -0xb70000,0x3040259a,0xc000010,0xb48000,0x304028ba,0x4000001,0xc41c0b,0x304a3dca,0x4000000,0xe00000,0x30800c27,0x2802100,0x962460,0x30c01c92,0x6800000,0x1329800, -0x3100080e,0x7c00120,0x220402,0x3100080e,0x7c00120,0x250402,0x31005167,0x1000,0,0x3100581e,0x4000000,0x200000,0x3100581e,0x7c00100,0x230400,0x3100590d, -0x7c00100,0x230400,0x31005a09,0x7c00100,0x220400,0x31005a09,0x7c00100,0x250400,0x31005b00,0x4000000,0x200000,0x31005c00,0x80000,0x918820,0x31005c00,0x2802000, -0x962460,0x31005c00,0x2802400,0x962460,0x31005c00,0x4000000,0x200000,0x31005c00,0x4000000,0x200001,0x31005c00,0x6800000,0x962540,0x31005c00,0x6800400,0x962540, -0x31005c01,0x2802400,0x962460,0x31005d00,0x4000020,0x200005,0x31005d00,0x6800020,0x1329805,0x31005d00,0x7c00120,0x220405,0x31005d00,0x7c00120,0x250405,0x31006000, -0x82000,0x962460,0x31006000,0x180000,0x918820,0x310a5e11,0x7c40300,0xe30000,0x310a5f11,0x7c00300,0xe30001,0x32000419,0x7c00100,0x250400,0x3200080e,0x4000020, -0x200000,0x3200080e,0x7c00100,0x220400,0x3200080e,0x7c00100,0x250400,0x32000908,0x7c00100,0x220400,0x32000908,0x7c00100,0x250400,0x32000c02,0x7c00100,0x230400, -0x32000e25,0x7c00100,0x230400,0x32001d0c,0x7c00100,0x230400,0x32002800,0x80000,0x1e18820,0x32002800,0x80020,0x218820,0x32002800,0x4000001,0x445802,0x32002800, -0x24000000,0x200000,0x32002800,0x24000000,0x1500002,0x32002800,0x24000020,0x200000,0x32002800,0x2c000010,0x1248002,0x32002919,0x7c00100,0x22040f,0x32002a00,0x4000000, -0x1600000,0x32002b01,0x2000,0x962460,0x32002b01,0x2802000,0x962460,0x32002b01,0x2802020,0x962460,0x32002c00,0x4000000,0x200000,0x32002c00,0x4000020,0x200000, -0x32002c00,0x4000020,0x200005,0x32002c00,0x7c00120,0x220405,0x32002c00,0x7c00120,0x250405,0x32002e00,0x24000020,0x200000,0x32002f00,0x24000020,0x200000,0x32003000, -0x24000000,0x200000,0x32003000,0x24000020,0x200000,0x32003500,0x24000000,0x200000,0x32003600,0x24000020,0x200000,0x32003700,0x24000000,0x100000,0x32003700,0x24000000, -0x200000,0x32003800,0x24000000,0x810000,0x32003800,0x24000000,0x1410000,0x32005102,0x4000000,0x1500008,0x32005502,0x7c00100,0x230400,0x32006108,0x7c00100,0x220400, -0x32006108,0x7c00100,0x250400,0x3200622a,0x2802100,0x962460,0x3200622a,0x2806400,0x962460,0x3200622a,0x7c00100,0x230400,0x3200632b,0x2802100,0x962460,0x3200632b, -0x6804000,0x962540,0x3200632b,0x7c00100,0x230400,0x3200642c,0x2802100,0x962460,0x3200642c,0x7c00100,0x230400,0x3200652d,0x2802100,0x962460,0x3200652d,0x7c00100, -0x230400,0x32006600,0x24000020,0x200000,0x32006700,0x24000020,0x200000,0x32006800,0x24000020,0x200000,0x32006900,0x24000020,0x200000,0x32006900,0x24000020,0x810000, -0x32006900,0x24000020,0x1410000,0x32006a00,0x24000020,0x200000,0x32006a00,0x24000020,0x200001,0x32006a00,0x24000020,0x200002,0x32020701,0x2882000,0xc62460,0x32023300, -0x4000000,0x100000,0x32026c01,0x12882000,0x962460,0x32065700,0x4000000,0x810011,0x32065700,0x4000000,0x1410011,0x32086600,0x24000020,0x810000,0x32086600,0x24000020, -0x1410000,0x32086900,0x24000020,0x810000,0x32086900,0x24000020,0x1410000,0x320a3600,0x24000020,0x200000,0x320a3d11,0x7c00100,0x1230400,0x320a3e14,0x7c00100,0xe30010, -0x320a3e14,0x7c00100,0x2530000,0x320a3f16,0x7c00100,0xe30c10,0x320a4400,0x4000000,0xe00003,0x320a4929,0x4000000,0xe00000,0x320a4f11,0x7c00300,0xe30001,0x320a6b16, -0x7c00100,0x2530c00,0x32406396,0xc000010,0x448000,0x324a3dcd,0x4000000,0xe00000,0x324a3dcd,0x7c00100,0x1230400,0x324a3fc8,0x4000002,0x1200c00,0x324a53c5,0x24000000, -0xe00000,0x32820701,0x2802000,0x962460,0x40000419,0x7c00100,0x220400,0x40000519,0x7c00100,0x220400,0x40000600,0x4000400,0x200400,0x4000080e,0x7c00100,0x220400, -0x4000080e,0x7c00100,0x250400,0x4000080e,0x7c00100,0x250402,0x40000c02,0x2802100,0x962460,0x40000c02,0x2802400,0x962460,0x40000c02,0x2802500,0x962460,0x40000c02, -0x4000000,0x200000,0x40000c02,0x4000000,0x1071400,0x40000c02,0x7c00100,0x230400,0x40000c02,0x80000000,0x218960,0x40000d22,0x7c00100,0x230400,0x40000f0a,0x7c00100, -0x230400,0x40001004,0x7c00100,0x230400,0x40001110,0x2802100,0x962460,0x40001110,0x6800100,0x962540,0x4000120f,0x2802100,0x962460,0x4000120f,0x4000000,0x1600000, -0x4000120f,0x7c00100,0x230400,0x4000131f,0x7c00100,0x230400,0x40001423,0x4000000,0x200000,0x40001423,0x4000000,0x1600000,0x40001615,0x2802400,0x962460,0x40001615, -0x7c00100,0x230400,0x40002417,0x2802400,0x1862460,0x40002417,0x4000000,0x200000,0x40002800,0x6800000,0x201c00,0x40002800,0x24000002,0x200000,0x40002c00,0x4000000, -0x200002,0x40003000,0x24000000,0x200000,0x40003000,0x24000020,0x200000,0x40003700,0x24000000,0x200000,0x40005a09,0x7c00100,0x220400,0x40005a09,0x7c00100,0x250400, -0x40005d00,0x7c00120,0x220405,0x40006f30,0x2802100,0x962460,0x40006f30,0x2802400,0x962460,0x40006f30,0x4000000,0x200000,0x40006f30,0x6800000,0x1329800,0x40006f30, -0x6800100,0x962540,0x40006f30,0x7c00100,0x230400,0x40006f30,0xc000010,0xb48000,0x40007034,0x7c00100,0x1830000,0x40007117,0x4000000,0x200000,0x40007208,0x7c00100, -0x220400,0x4000720e,0x7c00100,0x220400,0x4000720e,0x7c00500,0x22040e,0x4000720e,0x7c00500,0x22040f,0x40007219,0x7c00100,0x220400,0x40007219,0x7c00500,0x220400, -0x40007219,0x7c00500,0x22040e,0x40007219,0x7c00500,0x22040f,0x40007300,0x24000000,0x200000,0x40007400,0x4000000,0x200000,0x40007531,0x7c00100,0x230400,0x40007631, -0x7c00100,0x230400,0x40007835,0x4000010,0x400000,0x40007835,0x7c00100,0x230400,0x40007933,0x7c00100,0x230400,0x40007a32,0x6800000,0x1329800,0x40007a32,0x7c00100, -0x230400,0x40007b2f,0x7c00100,0x230400,0x40007c00,0x4000000,0x200000,0x40020701,0x2802400,0x962460,0x40020701,0x2802400,0xc62460,0x40023300,0x4000000,0x200000, -0x40027d01,0x12882000,0x962460,0x400a3700,0x24000000,0x200000,0x400a3700,0x24000000,0xe00000,0x400a4400,0x4000000,0xe0000d,0x400a4412,0x4000000,0xe00002,0x400a4412, -0x4000000,0xe00003,0x400a4500,0x4000000,0xe0000d,0x400a5300,0x4000000,0x810010,0x400a5300,0x4000000,0x1410010,0x40507709,0x4000000,0x200000,0x4050770c,0x4000000, -0x400000,0x4050770f,0x4000000,0x200000,0x4050770f,0x4000000,0x400000,0x40c01489,0x4000000,0x200000,0x40d05107,0x4000000,0x200000,0x41000419,0x7c00100,0x220400, -0x41000419,0x7c00100,0x250400,0x4100080e,0x7c00100,0x220400,0x4100080e,0x7c00100,0x250400,0x41000908,0x7c00100,0x220400,0x41000908,0x7c00100,0x250400,0x41000b13, -0x2802000,0x962460,0x41000b13,0x2802100,0x962460,0x41000b13,0x4000000,0xb00000,0x41000c02,0x2802100,0x962460,0x41000c02,0x4000000,0x1500000,0x41000c02,0xc000010, -0xb48000,0x41000f0a,0x7c00100,0x230400,0x41001004,0x7c00100,0x230400,0x41001423,0x7c00100,0x230400,0x41001b27,0x4000000,0x500000,0x41001d0c,0x7c00100,0x22040f, -0x41001d0c,0x7c00100,0x230400,0x41001f0b,0x2802400,0x962460,0x41001f0b,0x4000000,0x200000,0x41001f0b,0x7c00100,0x230400,0x41002800,0x24000000,0x200000,0x41002800, -0x24000000,0x400000,0x41002919,0x7c00100,0x22040e,0x41002a00,0x4000000,0x1600000,0x41002b01,0x2802020,0x962460,0x41002c00,0x4000000,0x200000,0x41002c00,0x7c00120, -0x220405,0x41003000,0x24000000,0x200000,0x41003700,0x24000000,0x200000,0x41003700,0x24000000,0xe00000,0x41005d00,0x7c00120,0x220405,0x41006600,0x24000020,0x200000, -0x41006600,0x24000020,0x810000,0x41006600,0x24000020,0x1410000,0x41007208,0x7c00100,0x22040f,0x41007219,0x7c00100,0x220400,0x41007300,0x24000000,0x200000,0x41007e0e, -0x2802000,0x962460,0x41007e0e,0x4000000,0x200000,0x41007f0e,0x4000000,0x200000,0x41007f0e,0x7c00100,0x230400,0x41008002,0x7c00100,0x230400,0x41008137,0x2802100, -0x962460,0x41008137,0x4000000,0x200000,0x41008137,0x6800100,0x962540,0x41008137,0x7c00100,0x230400,0x41008301,0x2802000,0x962460,0x41008407,0x4000000,0x200000, -0x41008407,0x4000000,0x400000,0x41008407,0x4000000,0xb00000,0x41008407,0x7c00100,0x220400,0x41008407,0x7c00100,0x250400,0x4100850b,0x7c00100,0x230400,0x4100860b, -0x4000000,0x200000,0x4100860b,0x7c00100,0x230400,0x4100870c,0x7c00100,0x220400,0x41008838,0x7c00100,0x220400,0x41008838,0x7c00100,0x250400,0x41008939,0x2802000, -0x962460,0x41008939,0x2802100,0x962460,0x41008939,0x2806000,0x962460,0x41008939,0x4000000,0x200000,0x41008939,0x4000000,0x400000,0x41008939,0x7c00100,0x230400, -0x41008939,0xc000010,0x448000,0x41008a00,0x4000400,0x200400,0x41008b3b,0x4000000,0x1800000,0x41008b3b,0x6800000,0x1329800,0x41008b3b,0x7c00100,0x1830000,0x41008b3b, -0x7e00100,0x1830000,0x41008c3d,0x4000010,0x400000,0x41008c3d,0x7c00100,0x230400,0x41008d0e,0x7c00100,0x22040f,0x41008d19,0x7c00100,0x220400,0x41008d19,0x7c00100, -0x22040f,0x41008e00,0x24000000,0x200000,0x41008e00,0x24000000,0x400000,0x41008e00,0x24000000,0x1710000,0x41008e00,0x24000006,0x400000,0x41008f3a,0x2802100,0x962460, -0x41008f3a,0x2806000,0x962460,0x41008f3a,0x4000000,0x200000,0x41008f3a,0x6800100,0x962540,0x41008f3a,0x7c00100,0x230400,0x4100903c,0x7c00100,0x230400,0x4100903c, -0x7c00100,0x23040f,0x41020701,0x2802000,0x962460,0x41020701,0x2802000,0xc62460,0x410a3700,0x24000000,0x200000,0x410a3700,0x24000000,0xe00000,0x410a4412,0x4000000, -0xe00003,0x410a4711,0x7c40300,0xe30000,0x410a4f11,0x7c00300,0xe30001,0x410a9100,0x4000000,0x800010,0x410a9100,0x4000000,0x810010,0x410a9100,0x4000000,0x870010, -0x410a9100,0x4000000,0xb00010,0x410a9100,0x4000000,0xf00010,0x410a9100,0x4000000,0x1001410,0x410a9100,0x4000000,0x1071010,0x410a9100,0x4000000,0x1071410,0x410a9100, -0x4000000,0x1410010,0x41408ad0,0x4000400,0x200000,0x414a82ca,0x4000000,0xe00000,0x41808300,0x2802000,0x962460,0x41c01489,0x6800000,0x1329800,0x50000419,0x7c00100, -0x220400,0x50000419,0x7c00100,0x250400,0x5000080e,0x7c00100,0x220400,0x50000908,0x7c00100,0x220400,0x50000908,0x7c00100,0x250400,0x50000b13,0x2802500,0x962460, -0x50000f0a,0x7c00100,0x230400,0x50001615,0x2802100,0x962460,0x50001615,0x7c00100,0x230400,0x50002b01,0x2802020,0x962460,0x50002c00,0x4000000,0x200000,0x50002c19, -0x7c00100,0x220400,0x50002d19,0x7c00100,0x220400,0x50003000,0x24000000,0x200000,0x50003000,0x24000020,0x200000,0x50003700,0x24000000,0x200000,0x50005d00,0x7c00120, -0x220405,0x50005d00,0x7c00120,0x250405,0x50006108,0x7c00100,0x220400,0x50006108,0x7c00100,0x250400,0x50006600,0x24000020,0x200000,0x50007300,0x24000000,0x200000, -0x50008301,0x2802400,0x962460,0x50008a00,0x7c00500,0x230400,0x50009257,0x2802400,0x962460,0x50009257,0x4000000,0x200000,0x50009257,0x4000010,0x1071400,0x50009257, -0x6800000,0x1329800,0x50009257,0x7c00100,0x230400,0x50009257,0x7c00500,0x230400,0x50009257,0x7c00900,0x230400,0x50009257,0xc000010,0xb48000,0x5000933e,0x2802100, -0x962460,0x5000933e,0x2802400,0x962460,0x5000933e,0x4000000,0x200000,0x5000933e,0x4000000,0x400000,0x5000933e,0x4000010,0x400000,0x5000933e,0x6800000,0x1329800, -0x5000933e,0x6800100,0x962540,0x5000933e,0x6800100,0x962541,0x5000933e,0x6804400,0x962540,0x5000933e,0x7c00100,0x230400,0x5000933e,0x7c00100,0x230401,0x5000933e, -0xc000010,0x448000,0x50009419,0x7c00100,0x220400,0x50009419,0x7c00100,0x250400,0x50009500,0x4000400,0x200400,0x5000965a,0x4000000,0x500000,0x5000965a,0x7c00100, -0x230400,0x5000965a,0xc000010,0xb48000,0x5000975b,0x4000000,0x200000,0x5000975b,0x4000010,0x400000,0x5000975b,0x7c00100,0x230400,0x50009865,0x7c00100,0x230400, -0x50009965,0x4000010,0x400000,0x50009965,0x7c00100,0x230400,0x50409aca,0x4000000,0x200000,0x5100080e,0x7c00100,0x220400,0x5100080e,0x7c00100,0x250400,0x51000c02, -0x2802100,0x962460,0x51000c02,0x4000000,0x1500000,0x51000c02,0x4000020,0x200000,0x51000c02,0x7c00100,0x230400,0x51000f0a,0x7c00100,0x230400,0x51000f0a,0x7c00500, -0x230400,0x51001110,0x2802100,0x962460,0x5100131f,0x2802100,0x962460,0x51001423,0x7c00100,0x230400,0x51001524,0x2802100,0x962460,0x51001524,0x4000000,0x200000, -0x51001524,0x7c00100,0x230400,0x5100171a,0x2802100,0x962460,0x5100171a,0x4000000,0x200000,0x5100171a,0x4000000,0x1500000,0x5100171a,0x7c00100,0x230400,0x51001b27, -0x4000000,0x200000,0x51001b27,0x4000000,0x400000,0x51001b27,0x4000000,0x500000,0x51001b27,0x7c00100,0x230400,0x51001c1c,0x2802100,0x1862460,0x51001c1c,0x2802500, -0x1862460,0x51001c1c,0x2806400,0x1862460,0x51001c1c,0x4000000,0x1800000,0x51001c1c,0x6800000,0x1329800,0x51001c1c,0x6800100,0x1862400,0x51001c1c,0x6800100,0x1862540, -0x51001c1c,0x6800500,0x1862400,0x51001c1c,0x7c00100,0x1830000,0x5100251b,0x7c00100,0x230400,0x51002619,0x7c00100,0x220400,0x51002619,0x7c00100,0x250400,0x51002800, -0x80020,0x218820,0x51002c00,0x4000000,0x200000,0x51002d19,0x7c00100,0x230400,0x51003700,0x24000000,0x200000,0x51003700,0x24000000,0xe00000,0x51005201,0x2802400, -0x962460,0x51005c00,0x4000000,0x200000,0x51006108,0x7c00100,0x220400,0x51006108,0x7c00100,0x250400,0x51006600,0x24000020,0x200000,0x51006600,0x24000020,0x810000, -0x51006600,0x24000020,0x1410000,0x51007300,0x24000000,0x200000,0x51007300,0x24000020,0x200000,0x51008002,0x7c00100,0x230400,0x51008301,0x2802000,0x962460,0x51008301, -0x2802400,0x962460,0x51008301,0x2802400,0xc62460,0x51008a00,0x7c00500,0x230400,0x51008e00,0x24000000,0x200000,0x51008e00,0x24000000,0x400000,0x51008e00,0x24000000, -0x810000,0x51008e00,0x24000000,0x1400000,0x51008e00,0x24000000,0x1410000,0x51008e00,0x24000000,0x1710000,0x51008e00,0x24000002,0x200000,0x51008e00,0x24000500,0x230400, -0x51008e00,0x2c000010,0xb48000,0x51009419,0x7c00100,0x220400,0x51009419,0x7c00100,0x22040e,0x51009419,0x7c00100,0x22040f,0x51009419,0x7c00100,0x250400,0x51009500, -0x4000400,0x200400,0x51009500,0x7c00500,0x230400,0x51009519,0x7c00100,0x220400,0x51009519,0x7c00100,0x22040f,0x51009519,0x7c00100,0x230400,0x51009519,0x7c00100, -0x250400,0x51009b71,0x2802100,0x962460,0x51009b71,0x6800000,0x1329800,0x51009b71,0x6800100,0x962540,0x51009b71,0x6804400,0x962540,0x51009b71,0x7c00100,0x230400, -0x51009c52,0x2802100,0x962460,0x51009c52,0x2802400,0x962460,0x51009c52,0x2802d00,0x962460,0x51009c52,0x4000010,0x400000,0x51009c52,0x6800000,0x1329800,0x51009c52, -0x6800100,0x962540,0x51009c52,0x7c00100,0x230400,0x51009c52,0xc000010,0x448000,0x51009d6d,0x6800000,0x1329800,0x51009d6d,0x7c00100,0x230400,0x51009d6d,0x7c00500, -0x230400,0x51009d6d,0x7c00d00,0x230400,0x51009d6d,0xc000010,0x448000,0x51009e08,0x2802100,0x962460,0x51009f63,0x4000010,0x400000,0x51009f63,0x6800000,0x1329800, -0x51009f63,0x7c00100,0x230400,0x51009f63,0x7c00900,0x230400,0x51009f63,0xc000010,0x448000,0x51009f63,0xc000010,0xb48000,0x5100a008,0x2000,0x962460,0x5100a008, -0x2802400,0x962460,0x5100a008,0x4000000,0x200000,0x5100a008,0x7c00100,0x220400,0x5100a008,0x7c00100,0x230400,0x5100a008,0x7c00100,0x250400,0x5100a008,0x7c00500, -0x230400,0x5100a16f,0x2806400,0x962460,0x5100a16f,0x6800000,0x1329800,0x5100a16f,0x6800100,0x962540,0x5100a16f,0x7c00100,0x230400,0x5100a16f,0xc000010,0x448000, -0x5100a24f,0x2802100,0x962460,0x5100a24f,0x2802400,0x962460,0x5100a24f,0x6800000,0x1329800,0x5100a24f,0x7c00100,0x230400,0x5100a24f,0xc000010,0x448000,0x5100a36e, -0x2802100,0x962460,0x5100a36e,0x4000000,0x200000,0x5100a36e,0x6800100,0x962540,0x5100a36e,0x6804400,0x962540,0x5100a36e,0x7c00100,0x230400,0x5100a442,0x2802100, -0x962460,0x5100a442,0x4000000,0x200000,0x5100a442,0x6800000,0x1329800,0x5100a442,0x6800100,0x962540,0x5100a442,0x7c00100,0x230400,0x5100a442,0xc000010,0x448000, -0x5100a500,0x4000000,0x200000,0x5100a600,0x4000000,0x200000,0x5100a601,0x2802000,0x962460,0x5100a76b,0x7c00100,0x230400,0x5100a868,0x7c00100,0x230400,0x5100a96c, -0x4000000,0x200000,0x5100a96c,0x7c00100,0x230400,0x5100aa00,0x4000000,0xe00000,0x5100ab00,0x4000000,0xe00000,0x51086600,0x24000020,0x810000,0x51086600,0x24000020, -0x1410000,0x510a4005,0x7c00100,0xe30400,0x510a4711,0x7c40300,0xe30000,0x510a7300,0x24000000,0x200000,0x510aaa00,0x4000000,0xe00000,0x5140a2fe,0x4000400,0x400000, -0x514a82ca,0x4000000,0xe00000,0x51802bbc,0x2802000,0x962460,0x51c00908,0x2802400,0x962460,0x51c0a008,0x2802400,0x962460,0x52000f0a,0x2802100,0x962460,0x52000f0a, -0x6800100,0x962540,0x52000f0a,0x7c00100,0x230400,0x52001004,0x4000000,0x1600000,0x52001b00,0x4000000,0x200000,0x52001c1c,0x2802100,0x1862460,0x52001c1c,0x6800100, -0x1862400,0x52001c1c,0x6800500,0x1862400,0x52001e12,0x7c00100,0x2230500,0x52001e12,0x7c00100,0x2330520,0x52002128,0x4000002,0x400000,0x52002128,0x7c00100,0x230400, -0x52002a00,0x4000000,0x1500000,0x52002a00,0x4000000,0x1600000,0x52002d00,0x4000000,0x200006,0x52003000,0x24000000,0x200000,0x52006108,0x7c00100,0x220400,0x52006108, -0x7c00100,0x250400,0x52008301,0x2802400,0x962460,0x52008407,0x2802400,0x962460,0x52008407,0x7c00100,0x220400,0x52008407,0x7c00100,0x250400,0x52008b3b,0x6800000, -0x1800000,0x52008b3b,0x7c00100,0x1830000,0x52008e00,0x24000000,0x400000,0x52009419,0x7c00100,0x250400,0x5200975b,0x4000000,0x200000,0x5200ac7e,0x2802000,0x962460, -0x5200ac7e,0x2802100,0x962460,0x5200ac7e,0x2802400,0x962460,0x5200ac7e,0x4000010,0x200000,0x5200ac7e,0x7c00100,0x230400,0x5200ac7e,0xc000010,0x248000,0x5200ad28, -0x7c00100,0x230400,0x5200ae6a,0x2802100,0x1862460,0x5200ae6a,0x2802400,0x962460,0x5200ae6a,0x2802400,0x1862460,0x5200ae6a,0x2806000,0x1862460,0x5200ae6a,0x4000000, -0x1800000,0x5200ae6a,0x6800000,0x1329800,0x5200ae6a,0x6800100,0x1862400,0x5200ae6a,0x6800100,0x1862540,0x5200ae6a,0x7c00100,0x1830000,0x5200ae6a,0x7c00900,0x1830000, -0x5200ae6a,0xc000010,0x1848000,0x5200b083,0x4000010,0x400000,0x5200b083,0x7c00100,0x230400,0x5200b083,0xc000010,0x448000,0x5200b182,0x2802400,0x962460,0x5200b182, -0x4000000,0x200000,0x5200b182,0x4000010,0x400000,0x5200b182,0x7c00100,0x230400,0x5200b182,0xc000010,0x448000,0x5200b30a,0x2802400,0x962460,0x5200b30a,0x4000000, -0x200000,0x5200b30a,0x7c00100,0x230400,0x5200b54e,0x2802100,0x962460,0x5200b54e,0x2802400,0x962460,0x5200b54e,0x4000000,0x200000,0x5200b54e,0x4000010,0x400000, -0x5200b54e,0x6800000,0x1329800,0x5200b54e,0x6800100,0x962540,0x5200b54e,0x6804400,0x962540,0x5200b54e,0x7c00100,0x230400,0x5200b54e,0xc000010,0x448000,0x5200b61c, -0x4000000,0x1800000,0x5200b61c,0x6800500,0x1862400,0x5200b61c,0x7c00100,0x1830000,0x5200b61c,0x7c00900,0x1830000,0x5200b77f,0x2802100,0x1862460,0x5200b77f,0x2802400, -0x1862460,0x5200b77f,0x4000000,0x1800000,0x5200b77f,0x4000010,0x1800000,0x5200b77f,0x7c00100,0x1830000,0x5200b77f,0x7c00500,0x1830000,0x5200b77f,0x7c00900,0x1830000, -0x5200b77f,0x7e00100,0x1830000,0x5200b873,0x2802100,0x962460,0x5200b873,0x2806400,0x962460,0x5200b873,0x6800000,0x1329800,0x5200b873,0x6800100,0x962540,0x5200b873, -0x6800400,0x962540,0x5200b873,0x7c00100,0x230400,0x5200b873,0xc000010,0x448000,0x5200b912,0x7c00100,0x2230500,0x5200b912,0x7c00100,0x2330520,0x5200ba74,0x4000000, -0x200000,0x5200ba74,0x4000010,0x400000,0x5200ba74,0x7c00100,0x230400,0x5200bb85,0x4000000,0x200000,0x5200bb85,0x7c00100,0x230400,0x5200bc75,0x4000000,0x400000, -0x5200bc75,0x4000010,0x400000,0x5200bc75,0x7c00100,0x230400,0x5200bd7d,0x4000000,0x200000,0x5200bd7d,0x7c00100,0x230400,0x5200be7a,0x4000000,0x200000,0x5200be7a, -0x7c00100,0x230400,0x5200bf58,0x7c00100,0x230400,0x5200c002,0x4000000,0x200000,0x5200c178,0x2802100,0x962460,0x5200c178,0x2802400,0x962460,0x5200c178,0x2806400, -0x962460,0x5200c178,0x4000000,0x200000,0x5200c178,0x6800100,0x962540,0x5200c178,0x7c00100,0x230400,0x5200c178,0x7c00100,0x230401,0x5200c178,0xc000010,0x448000, -0x5200c178,0x80000000,0x218960,0x5200c247,0x7c00100,0x230400,0x5200c247,0x7c00100,0x830400,0x5200c247,0x7c00100,0x1430400,0x5200c300,0x4000000,0x200003,0x52022d00, -0x4000000,0x100006,0x52023700,0x24000000,0x100000,0x52023700,0x24000000,0xe00000,0x52023700,0x24000000,0x2800000,0x52024400,0x4000000,0x100000,0x52027300,0x24000000, -0x100000,0x5202c300,0x4000000,0x100000,0x5202c300,0x4000000,0x100002,0x5202c300,0x4000000,0x100003,0x5202c300,0x4000000,0x10000d,0x5202c300,0x4000100,0x150400, -0x5202c300,0x4000100,0x15040d,0x520a1e12,0x7c00100,0x2130480,0x520a3700,0x24000000,0xe00000,0x520a3800,0x24000000,0x100000,0x520a4711,0x7c40300,0xe30000,0x520a4f11, -0x7c00300,0xe30001,0x520a7300,0x24000000,0x100000,0x520ab412,0x7c00100,0x2130480,0x520ac400,0x4000000,0xe00002,0x520ac400,0x4000000,0xe0000d,0x520ac414,0x4000000, -0xe0000d,0x520ac511,0x7c40300,0xe30000,0x5240af9c,0x7c00100,0x230400,0x5240afa1,0x4000400,0x200000,0x5240afa3,0x6800400,0x962540,0x5240afa3,0x7c00100,0x230400, -0x5240afad,0x7c00100,0x230400,0x5240afaf,0x7c00100,0x230400,0x5240b2d2,0x4000000,0x200000,0x5240b2d2,0x4000000,0x1500000,0x5240b2dd,0x4000000,0x200000,0x5240b2eb, -0x4000000,0x200000,0x524a44ca,0x4000000,0xe00003,0x5250b501,0x7c00900,0x230400,0x5280af9c,0x2802400,0x962460,0x5280af9d,0x2802400,0x962460,0x5280afa3,0x2802400, -0x962460,0x5280afa5,0x2802400,0x962460,0x5280afa7,0x2802400,0x962460,0x52c0b3f8,0x2802400,0x962460,0x52c0b3fc,0x7c00100,0x230400,0x60000c02,0x2802100,0x962460, -0x60000c02,0x7c00100,0x230400,0x60000f0a,0x2802100,0x962460,0x60000f0a,0x6800100,0x962540,0x60000f0a,0x7c00100,0x230400,0x6000131f,0x4000000,0x200000,0x6000171a, -0x7c00100,0x230400,0x6000171a,0x7c00100,0x230560,0x60001b27,0x2802100,0x962460,0x60001b27,0x4000000,0xc00000,0x60001b27,0x7c00100,0x230400,0x60001f0b,0x2802400, -0x962460,0x60002919,0x7c00100,0x22040e,0x60002a00,0x4000000,0x1600000,0x60003000,0x24000000,0x200000,0x60003000,0x24000000,0xe00000,0x60003700,0x24000000,0x200000, -0x60003800,0x24000000,0x1710000,0x60005102,0x4000000,0x200000,0x60006108,0x7c00100,0x220400,0x60006108,0x7c00100,0x250400,0x60006600,0x24000020,0x200000,0x60008301, -0x2802400,0xc62460,0x6000903c,0x2806000,0x962460,0x6000903c,0x4000000,0x400000,0x60009519,0x7c00100,0x220400,0x60009519,0x7c00100,0x250400,0x6000a008,0x7c00100, -0x220400,0x6000a008,0x7c00100,0x250400,0x6000c300,0x4000000,0x2703580,0x6000c654,0x2802000,0x962460,0x6000c654,0x4000010,0x200000,0x6000c654,0x7c00100,0x230400, -0x6000c73f,0x2802000,0x962460,0x6000c73f,0x2802100,0x962460,0x6000c73f,0x4000000,0x200000,0x6000c73f,0x6800100,0x962540,0x6000c73f,0x6804000,0x962540,0x6000c73f, -0x7c00100,0x230400,0x6000c80b,0x7c00100,0x230400,0x6000c941,0x2802100,0x962460,0x6000c941,0x2806400,0x962460,0x6000c941,0x4000000,0x200000,0x6000c941,0x4000010, -0x200000,0x6000c941,0x6800000,0x1329800,0x6000c941,0x6800100,0x962540,0x6000c941,0x7c00100,0x230400,0x6000c941,0xc000010,0x448000,0x6000ca82,0x7c00100,0x230400, -0x6000cc00,0x4000000,0xe00000,0x6000d000,0x4000000,0x200000,0x6002c300,0x4000000,0x100000,0x6002c300,0x4000000,0x10000d,0x6002c300,0x4000100,0x150400,0x6002c300, -0x4000100,0x15040d,0x600a3000,0x24000000,0x200000,0x600a3000,0x24000000,0xe00000,0x600a3700,0x24000000,0x200000,0x600a3800,0x24000000,0x200000,0x600a3800,0x24000000, -0x2800000,0x600a4305,0x7c00100,0xe30400,0x600ac300,0x4000000,0x100000,0x600ac400,0x4000000,0xe0000d,0x600acb14,0x7c00100,0xe30000,0x600acb16,0x7c00100,0xe30c00, -0x600acc00,0x4000000,0xe00000,0x600acd00,0x4000000,0x200000,0x600acd00,0x4000000,0xe00000,0x600acd00,0x4000000,0x2800000,0x600ace00,0x4000000,0xe00000,0x600ace00, -0x4000000,0x2800000,0x600acf00,0x4000000,0xe00000,0x600acf00,0x4000000,0x2800000,0x600ad111,0x7c40300,0xe30000,0x604ac4ca,0x4000000,0xe00003,0x61000a03,0x4000000, -0x1600000,0x61000c02,0x80000000,0x218960,0x6100120f,0x4000000,0x200000,0x61001a18,0x7c00100,0x1830000,0x61001d0c,0x7c00100,0x230400,0x61001d0c,0x7c00100,0x250400, -0x61006600,0x24000020,0x200000,0x61008407,0x7c00100,0x220400,0x61008407,0x7c00100,0x250400,0x6100870c,0x7c00100,0x220400,0x61008e00,0x24000000,0x200000,0x61008e00, -0x24000000,0x400000,0x61008e00,0x24000002,0x300000,0x6100903c,0x7c00100,0x230400,0x61009519,0x7c00100,0x220400,0x61009519,0x7c00100,0x250400,0x61009519,0x7c00500, -0x22040f,0x61009b71,0x2802100,0x962460,0x61009b71,0x2806400,0x962460,0x61009b71,0x7c00100,0x230400,0x6100a008,0x2802100,0x962460,0x6100c300,0x4000000,0x20000f, -0x6100cd00,0x4000000,0x200000,0x6100d202,0x2802400,0x962460,0x6100d202,0x2802500,0x962460,0x6100d202,0x7c00100,0x230400,0x6100d302,0x4000020,0x200000,0x6100d302, -0x7c00120,0x230405,0x6100d476,0x2802100,0x962460,0x6100d476,0x2802100,0x962461,0x6100d476,0x2806400,0x962460,0x6100d476,0x4000000,0x400000,0x6100d476,0x6800000, -0x1329800,0x6100d476,0x6800100,0x962540,0x6100d476,0x7c00100,0x230400,0x6100d476,0xc000010,0x448000,0x6100d573,0x2802100,0x962460,0x6100d573,0x2806400,0x962460, -0x6100d573,0x6800100,0x962540,0x6100d573,0x7c00100,0x230400,0x6100d573,0x7c00900,0x230400,0x6100d573,0xc000010,0x448000,0x6100d68d,0x7c00100,0x230400,0x6100d756, -0x7c00100,0x230400,0x6100d85c,0x2802500,0x962460,0x6100d85c,0x6800100,0x962540,0x6100d85c,0x7c00100,0x230400,0x6100d85c,0x7c00500,0x230400,0x6100d997,0x2802100, -0x962460,0x6100d997,0x4000000,0x200000,0x6100d997,0x4000000,0x400000,0x6100d997,0x6800000,0x1329800,0x6100d997,0x6800100,0x962540,0x6100d997,0x6804400,0x962540, -0x6100d997,0x7c00100,0x230400,0x6100d997,0x7c00100,0x230560,0x6100d997,0xc000010,0x448000,0x6100da98,0x6800000,0x1329800,0x6100da98,0x7c00100,0x230400,0x6100db71, -0x4000000,0x200000,0x6100dc99,0x2802100,0x962460,0x6100dc99,0x2802400,0x962460,0x6100dc99,0x6800000,0x1329800,0x6100dc99,0x6800100,0x962540,0x6100dc99,0x6804400, -0x962540,0x6100dc99,0x7c00100,0x230400,0x610a4711,0x7c40300,0xe30000,0x610a4f11,0x7c00300,0xe30001,0x610ace00,0x4000000,0xe00000,0x6140afa1,0x7c00100,0x230400, -0x6140afa3,0x7c00100,0x230400,0x6180af9e,0x2802400,0x962460,0x62002a00,0x4000000,0x1600000,0x63002800,0x80000,0x918820,0x63c00c15,0x80000,0x918820,0x7000080e, -0x7c00100,0x250400,0x70000a03,0x4000000,0x200000,0x70000c00,0x80000000,0x218960,0x70000f0a,0x7c00100,0x230400,0x70001004,0x7c00100,0x230400,0x70001524,0x2802100, -0x962460,0x70001524,0x7c00100,0x230400,0x70001615,0x2802100,0x962460,0x7000171a,0x2802100,0x962460,0x70001821,0x6800000,0x1329800,0x70002320,0x7c00100,0x230400, -0x70002a00,0x4000000,0x1500000,0x70002a00,0x4000000,0x1600000,0x70003000,0x24000000,0x200000,0x70003800,0x24000000,0xe00000,0x70005201,0x2802400,0x962460,0x7000581e, -0x7c00100,0x230400,0x70006108,0x7c00100,0x220400,0x70006108,0x7c00100,0x250400,0x70006f30,0x7c00100,0x230400,0x70007300,0x24000000,0x200000,0x70007f0e,0x4000000, -0x200000,0x70008301,0x2802100,0x962460,0x70008301,0x2802400,0x962460,0x70008e00,0x24000000,0x200000,0x70008e00,0x24000000,0x400000,0x70008e00,0x24000002,0x400000, -0x70008e00,0x24000008,0x1410000,0x70008e00,0x24000010,0x400000,0x70008e00,0x2c000010,0x448000,0x70009519,0x7c00100,0x220400,0x70009519,0x7c00100,0x230400,0x70009519, -0x7c00100,0x250400,0x70009865,0x7c00100,0x230400,0x70009965,0x4000010,0x400000,0x70009965,0x7c00100,0x230400,0x7000a008,0x7c00100,0x220400,0x7000a008,0x7c00100, -0x250400,0x7000a008,0x7c00500,0x22040f,0x7000a50e,0x4000000,0x200000,0x7000b61c,0x2802500,0x1862460,0x7000b61c,0x6800500,0x1862400,0x7000b61c,0x7c00100,0x1830000, -0x7000c300,0x4000000,0x100000,0x7000c941,0x2806000,0x962460,0x7000cc00,0x4000000,0xe00000,0x7000cd00,0x4000000,0x200000,0x7000cd00,0x4000000,0xe00000,0x7000cd00, -0x4000000,0x2800000,0x7000cf00,0x4000000,0xe00000,0x7000d202,0x2802100,0x962460,0x7000d202,0x7c00100,0x230400,0x7000d997,0x7c00100,0x230400,0x7000d997,0xc000010, -0x248000,0x7000dd86,0x2802400,0x962460,0x7000dd86,0x7c00100,0x230400,0x7000dd86,0xc000010,0x448000,0x7000de9f,0x4000000,0x200000,0x7000de9f,0x7c00100,0x230400, -0x7000e001,0x2400,0x962460,0x7000e001,0x2802400,0x962460,0x7000e187,0x2802000,0x962460,0x7000e187,0x2802100,0x962460,0x7000e187,0x4000000,0x200000,0x7000e187, -0x7c00100,0x230400,0x7000e187,0xc000010,0x448000,0x7000e288,0x7c00100,0x230400,0x7000e300,0x4000000,0x200000,0x7000e489,0x2802100,0x962460,0x7000e489,0x2802400, -0x962460,0x7000e489,0x6800100,0x962540,0x7000e489,0x6800100,0x962541,0x7000e489,0x6804400,0x962540,0x7000e489,0x7c00100,0x230400,0x7000e489,0x7c00900,0x230400, -0x7000e59d,0x2802100,0x962460,0x7000e59d,0x2802400,0x962460,0x7000e59d,0x4000000,0x200000,0x7000e59d,0x4000010,0x200000,0x7000e59d,0x6800100,0x962540,0x7000e59d, -0x6804400,0x962540,0x7000e59d,0x7c00100,0x230400,0x7000e59d,0xc000010,0x448000,0x7000e691,0x2802100,0x962460,0x7000e691,0x2802400,0x962460,0x7000e691,0x2806400, -0x962460,0x7000e691,0x6800000,0x1329800,0x7000e691,0x6800100,0x962540,0x7000e691,0x7c00100,0x230400,0x7000e700,0x4000400,0x200400,0x7000e70e,0x7c00100,0x220400, -0x7000e719,0x7c00100,0x220400,0x7000e719,0x7c00500,0x22040f,0x7000e853,0x7c00100,0x230400,0x7000e9a0,0x2802400,0x962460,0x7000e9a0,0x4000000,0x200000,0x7000e9a0, -0x4000000,0x500000,0x7000e9a0,0x7c00100,0x230400,0x7000ea79,0x2802400,0x962460,0x7000ea79,0x4000000,0x200000,0x7000ea79,0x4000000,0xf00000,0x7000ea79,0x4000010, -0x400000,0x7000ea79,0x7c00100,0x230400,0x7000eb8c,0x2802400,0x962460,0x7000eb8c,0x4000000,0x200000,0x7000eb8c,0x7c00100,0x230400,0x7000eca3,0x2802100,0x962460, -0x7000eca3,0x2806400,0x962460,0x7000eca3,0x4000000,0x200000,0x7000eca3,0x6800000,0x1329800,0x7000eca3,0x6800100,0x962540,0x7000eca3,0x7c00100,0x230400,0x7000eca3, -0xc000010,0x448000,0x7000ed95,0x6800000,0x1329800,0x7000ed95,0x7c00100,0x230400,0x7000ed95,0xc000010,0x448000,0x7000ee1c,0x2802500,0x1862460,0x7000ee1c,0x6800000, -0x1329800,0x7000ee1c,0x7c00100,0x1830000,0x7000ee1c,0x7c00900,0x1830000,0x7000ef8f,0x4000000,0x200000,0x7000ef8f,0x7c00100,0x230400,0x7000f08e,0x4000000,0x200000, -0x7000f08e,0x7c00100,0x230400,0x7000f159,0x2802100,0x962460,0x7000f159,0x7c00100,0x230400,0x7000f200,0x4000000,0x200000,0x7000f200,0x4000000,0x1200000,0x7000f200, -0x4000000,0x1710000,0x7000f34b,0x2802400,0x962460,0x7000f34b,0x4000000,0x200000,0x7000f34b,0x4000010,0x400000,0x7000f34b,0x6800000,0x1329800,0x7000f34b,0x7c00100, -0x230400,0x7000f34b,0x7c00900,0x230400,0x7000f34b,0xc000010,0x448000,0x7000f490,0x4000000,0x200000,0x7000f490,0x7c00100,0x230400,0x7000f5a5,0x7c00100,0x230400, -0x7000f67b,0x4000000,0x200000,0x7000f67b,0x4000010,0x200000,0x7000f67b,0x7c00100,0x230400,0x7000f8a6,0x2802100,0x962460,0x7000f8a6,0x2802400,0x962460,0x7000f8a6, -0x2806400,0x962460,0x7000f8a6,0x4000000,0x500000,0x7000f8a6,0x4000010,0xb00000,0x7000f8a6,0x4000800,0x200000,0x7000f8a6,0x6800100,0x962540,0x7000f8a6,0x6800100, -0x962541,0x7000f8a6,0x7c00100,0x230400,0x7000f8a6,0xc000010,0x448000,0x7000f921,0x4000000,0x200000,0x7000fa00,0x4000000,0x200000,0x7000fb9e,0x2802100,0x962460, -0x7000fb9e,0x2802400,0x962460,0x7000fb9e,0x2806400,0x962460,0x7000fb9e,0x4000000,0x200000,0x7000fb9e,0x6800000,0x1329800,0x7000fb9e,0x6800100,0x962540,0x7000fb9e, -0x6800100,0x962541,0x7000fb9e,0x7c00100,0x230400,0x7000fc92,0x4000000,0x200000,0x7000fc92,0x6800000,0x1329800,0x7000fc92,0x7c00100,0x220400,0x7000fc92,0x7c00100, -0x230400,0x7000fc92,0x7c00100,0x250400,0x700acd00,0x4000000,0xe00000,0x700acd00,0x4000000,0x2800000,0x700ace00,0x4000000,0xe00000,0x700acf00,0x4000000,0xe00000, -0x700acf00,0x4000000,0x2800000,0x7050df11,0x4000000,0x200000,0x7050f719,0x80000,0x918820,0x7080afa1,0x2802400,0x962460,0x7090df11,0x2802400,0x962460,0x70d0e417, -0x2802100,0x962460,0x70d0e417,0x2802400,0x962460,0x70d0e417,0x6800100,0x962540,0x70d0ea15,0x4000010,0x400000,0x8000120f,0x7c00100,0x230400,0x80001524,0x7c00100, -0x230400,0x8000171a,0x7c00100,0x230400,0x80002006,0x7c00100,0x220400,0x80002006,0x7c00100,0x250400,0x80002a00,0x4000000,0x1500000,0x80002d00,0x4000000,0x200000, -0x80005208,0x2802400,0x962460,0x80005c00,0x4000000,0x200000,0x80007300,0x24000000,0x200000,0x80009519,0x7c00100,0x220400,0x80009519,0x7c00100,0x230400,0x80009519, -0x7c00100,0x250400,0x80009865,0x7c00100,0x230400,0x8000a008,0x2802100,0x962460,0x8000b30a,0x4000000,0x500000,0x8000b30a,0x7c00100,0x230400,0x8000cd00,0x4000000, -0xe00000,0x8000d202,0x2802500,0x962460,0x8000d202,0x7c00100,0x230400,0x8000d68d,0x4000000,0x200000,0x8000d997,0x2802000,0x962460,0x8000d997,0x2802400,0x962460, -0x8000d997,0x4000000,0x400000,0x8000d997,0x4000000,0x500000,0x8000d997,0x7c00100,0x230400,0x8000d997,0xc000010,0x448000,0x8000e489,0x2802100,0x962460,0x8000e489, -0x7c00100,0x230400,0x8000e719,0x7c00100,0x220400,0x8000f8a6,0x2802100,0x962460,0x8000f8a6,0x7c00100,0x230400,0x8000f8a6,0xc000010,0x448000,0x8000fda1,0x2802100, -0x1862460,0x8000fda1,0x2806400,0x1862460,0x8000fda1,0x4000000,0x1800000,0x8000fda1,0x6800000,0x1329800,0x8000fda1,0x6800100,0x1862400,0x8000fda1,0x6800100,0x1862540, -0x8000fda1,0x7c00100,0x1830000,0x8000fda1,0xc000010,0x448000,0x8000fe9c,0x7c00100,0x230400,0x8000fe9c,0x7c00100,0x830400,0x8000fe9c,0x7c00100,0x1430400,0x8000ff06, -0x7c00100,0x220400,0x80010165,0x7c00100,0x230400,0x800102a2,0x4000000,0x200000,0x800102a2,0x7c00100,0x230400,0x800103a4,0x7c00100,0x230400,0x800103a4,0xc000010, -0x448000,0x8001044c,0x4000000,0x200000,0x8001044c,0x7c00100,0x220400,0x8001044c,0x7c00100,0x250400,0x80010670,0x2802000,0x962460,0x80010670,0x4000000,0x200000, -0x80010670,0x4000010,0x400000,0x80010670,0xc000010,0x448000,0x800a4711,0x7c40300,0xe30000,0x800acd00,0x4000000,0xe00000,0x800acd00,0x4000000,0x2902460,0x800ace00, -0x4000000,0xe00000,0x800acf00,0x4000000,0xe00000,0x800b0011,0x7c40300,0xe30000,0x800b0500,0x4000000,0xe00000,0x800b0500,0x4000000,0x2800000,0x90001615,0x7c00100, -0x230400,0x9000171a,0x4000000,0x200000,0x9000171a,0x7c00100,0x230400,0x90003000,0x24000000,0x200000,0x90007f0e,0x4000000,0x200000,0x90008301,0x2802400,0x962460, -0x90008e00,0x24000000,0x400000,0x90009519,0x7c00100,0x250400,0x9000a16f,0x2802100,0x962460,0x9000d200,0x80000000,0x218960,0x9000d202,0x2802000,0x962460,0x9000d202, -0x2802100,0x962460,0x9000d202,0x7c00100,0x230400,0x9000e59d,0x2802100,0x962460,0x90010500,0x4000000,0xe00000,0x900107a7,0x2802100,0x962460,0x900107a7,0x2802400, -0x962460,0x900107a7,0x2802c00,0x962460,0x900107a7,0x4000000,0x1400000,0x900107a7,0x6800000,0x1329800,0x900107a7,0x7c00100,0x220400,0x900107a7,0x7c00100,0x250400, -0x900108a8,0x2802100,0x962460,0x900108a8,0x2806400,0x962460,0x900108a8,0x4000000,0x200000,0x900108a8,0x4000000,0x400000,0x900108a8,0x4000010,0x400000,0x900108a8, -0x6800000,0x1329800,0x900108a8,0x6800100,0x962540,0x900108a8,0x7c00100,0x230400,0x900108a8,0xc000010,0x448000,0x90010908,0x7c00100,0x220400,0x90010a38,0x2802100, -0x962460,0x90010ca9,0x2802100,0x962460,0x90010ca9,0x4000000,0x500000,0x90010ca9,0x4000010,0xb00000,0x90010ca9,0x6800100,0x962540,0x90010ca9,0x7c00100,0x230400, -0x90010d1b,0x4000000,0x500000,0x90010eaa,0x2802100,0x962460,0x90010eaa,0x2802400,0x962460,0x90010eaa,0x2806400,0x962460,0x90010eaa,0x4000000,0x200000,0x90010eaa, -0x4000000,0x400000,0x90010eaa,0x4000010,0x400000,0x90010eaa,0x6800000,0x1329800,0x90010eaa,0x6800100,0x962540,0x90010eaa,0x7c00100,0x230400,0x90010eaa,0xc000010, -0x448000,0x90010fab,0x7c00100,0x220400,0x90010fab,0x7c00100,0x250400,0x9002c300,0x4000000,0x100000,0x900ac400,0x4000000,0xe0000d,0x900acd00,0x4000000,0xe00000, -0x900acd00,0x4000000,0x2800000,0x900acf00,0x4000000,0xe00000,0x900b0500,0x4000000,0xe00000,0x900b0500,0x4000000,0x2800000,0x900b0b9a,0x7c00900,0x1230400,0x900b109a, -0x7c00300,0xe30000,0x900b119a,0x7c00300,0xe30000,0x90408e06,0x24000000,0x400000,0xa0001004,0x4000000,0x200000,0xa0001004,0x7c00100,0x230400,0xa000120f,0x2802100, -0x962460,0xa000120f,0x2802400,0x962460,0xa000171a,0x2802100,0x962460,0xa000171a,0x2806400,0x962460,0xa0002a00,0x4000000,0x1600000,0xa0003000,0x24000000,0x200000, -0xa000581e,0x7c00100,0x230400,0xa0007300,0x24000000,0x200000,0xa0008301,0x2802400,0x962460,0xa0008e00,0x24000000,0x400000,0xa000cf00,0x4000000,0xe00000,0xa0010500, -0x4000000,0x200000,0xa00114af,0x2802100,0x962460,0xa00114af,0x2802400,0x962460,0xa00114af,0x2806400,0x962460,0xa00114af,0x6800000,0x1329800,0xa00114af,0x7c00100, -0x230400,0xa00114af,0x7c00100,0x230560,0xa00116b0,0x2802100,0x962460,0xa00116b0,0x2802800,0x962460,0xa00116b0,0x2806400,0x962460,0xa00116b0,0x4000000,0x400000, -0xa00116b0,0x4000000,0x500000,0xa00116b0,0x4000010,0x400000,0xa00116b0,0x6800100,0x962540,0xa00116b0,0x7c00100,0x230400,0xa00116b0,0x7c00100,0x230560,0xa00116b0, -0xc000010,0x448000,0xa0011722,0x7c00100,0x230400,0xa00118b1,0x2802000,0x962460,0xa00118b1,0x2802100,0x962460,0xa00118b1,0x2806400,0x962460,0xa00118b1,0x4000000, -0x200000,0xa00118b1,0x4000000,0x400000,0xa00118b1,0x4000000,0x500000,0xa00118b1,0x6800100,0x962540,0xa00118b1,0x7c00100,0x230400,0xa00118b1,0x7c00100,0x230560, -0xa00118b1,0xc000010,0x448000,0xa00a4005,0x7c00100,0xe30400,0xa00a4711,0x7c40300,0xe30000,0xa00ac400,0x4000000,0xe00000,0xa00acb14,0x7c00100,0xe30000,0xa00acf00, -0x4000000,0xe00000,0xa00b0500,0x4000000,0xe00000,0xa00b0500,0x4000000,0x2800000,0xa00b0b96,0x7c00900,0x1230400,0xa00b1211,0x7c40300,0xe30000,0xa00b1314,0x7c00100, -0xe30000,0xa00b1596,0x7c00300,0xe30000,0xa040afb7,0x6800400,0x962540,0xa08083b8,0x2802400,0x962460,0xb0000a03,0x7c00100,0x220400,0xb0000b13,0x7c00100,0x2633800, -0xb0001004,0x2802000,0x962460,0xb0001110,0x4000000,0x200000,0xb0001524,0x2802100,0x962460,0xb0001615,0x4000000,0x500000,0xb000251b,0x7c00100,0x230400,0xb0007300, -0x24000000,0x200000,0xb0008939,0x4000000,0x200000,0xb0008939,0x7c00100,0x230400,0xb0008e00,0x24000000,0x200000,0xb0008e00,0x24000000,0x400000,0xb0008e00,0x24000010, -0x400000,0xb0009257,0x2802000,0x962460,0xb0009257,0x4000000,0x1600000,0xb0009519,0x7c00100,0x220400,0xb0009519,0x7c00100,0x250400,0xb0009a00,0x4000000,0x200000, -0xb000b30a,0x2802100,0x962460,0xb000b30a,0x7c00100,0x230400,0xb000c178,0x80000000,0x218960,0xb000c300,0x4000000,0x200000,0xb000d202,0x2802000,0x962460,0xb000d476, -0x6800100,0x962540,0xb000d476,0x7c00100,0x230400,0xb000e300,0x4000000,0xe00000,0xb000fda1,0x7c00100,0x1830000,0xb0010eaa,0x2802000,0x962460,0xb00116b0,0x7c00100, -0x230400,0xb0011900,0x4000000,0xe00000,0xb0011ab2,0x2802100,0x962460,0xb0011ab2,0x2802400,0x962460,0xb0011ab2,0x2806400,0x962460,0xb0011ab2,0x4000000,0x200000, -0xb0011ab2,0x6800100,0x962540,0xb0011ab2,0x7c00100,0x230400,0xb0011b0c,0x7c00100,0x230400,0xb0011cb3,0x2802100,0x962460,0xb0011cb3,0x2806400,0x962460,0xb0011cb3, -0x6800000,0x1329800,0xb0011cb3,0x6800100,0x962540,0xb0011cb3,0x7c00100,0x230400,0xb0011db6,0x2802500,0x962460,0xb0011db6,0x6800000,0x1329800,0xb0011db6,0x7c00100, -0x230400,0xb0011db6,0x7c00500,0x230400,0xb0011e00,0x4000000,0x200000,0xb0011e00,0x4000000,0x1500000,0xb0011fb4,0x2802100,0x962460,0xb0011fb4,0x6800100,0x962540, -0xb0011fb4,0x7c00100,0x230400,0xb0011fb4,0xc000010,0x248000,0xb0012000,0x4000000,0x200000,0xb00121b5,0x4000000,0x200000,0xb00121b5,0x4000010,0x400000,0xb00121b5, -0x7c00100,0x220400,0xb00121b5,0x7c00100,0x250400,0xb00121b5,0xc000010,0x448000,0xb00122b8,0x4000000,0x200000,0xb00122b8,0x7c00100,0x230400,0xb00123b7,0x2802400, -0x962460,0xb00123b7,0x4000000,0x200000,0xb00123b7,0x7c00100,0x230400,0xb00123b7,0xc000010,0x248000,0xb00a4005,0x7c00100,0xe30400,0xb00a4711,0x7c40300,0xe30000, -0xb00acf00,0x4000000,0xe00000,0xb00b0500,0x4000000,0xe00000,0xb00b0500,0x4000000,0x2800000,0xb00b109a,0x7c00300,0xe30000,0xb080e487,0x2802000,0x962460,0xc0001524, -0x4000000,0x500000,0xc0001a18,0x2806400,0x1862460,0xc0001a18,0x7c00100,0x1830000,0xc0007300,0x24000000,0x200000,0xc0008e00,0x24000010,0x400000,0xc0009519,0x7c00100, -0x220400,0xc0009519,0x7c00100,0x250400,0xc000c300,0x4000000,0x20000f,0xc000d85c,0x2802100,0x962460,0xc000d85c,0x6800100,0x962540,0xc000d85c,0x7c00100,0x230400, -0xc000dc99,0x7c00100,0x230400,0xc000e719,0x7c00100,0x220400,0xc00107a7,0x7c00100,0x230400,0xc0010eaa,0x7c00100,0x230400,0xc00116b0,0x7c00100,0x230560,0xc0011900, -0x4000000,0x200000,0xc0012447,0,0x818820,0xc0012447,0,0xc18820,0xc0012447,0,0x1418820,0xc00125b9,0x7c00100,0x230400,0xc00126bb,0x2802100, -0x962460,0xc00126bb,0x2806400,0x962460,0xc00126bb,0x4000000,0x500000,0xc00126bb,0x6800100,0x962540,0xc00126bb,0x7c00100,0x230400,0xc00127ba,0x2802400,0x962460, -0xc00127ba,0x4000000,0x200000,0xc00127ba,0x6800000,0x1329800,0xc00127ba,0x7c00100,0x230400,0xc00127ba,0x7c00900,0x230400,0xc0012800,0x4000000,0x200000,0xc0012b23, -0x4000000,0x200000,0xc0012b23,0x4000000,0x400000,0xc0012b23,0x4000000,0x1500000,0xc0012cbc,0x2802400,0x962460,0xc0012cbc,0x4000000,0x1600000,0xc0012cbc,0x6800000, -0x1329800,0xc0012cbc,0x7c00100,0x230400,0xc00acf00,0x4000000,0xe00000,0xc00ae300,0x4000000,0xe00000,0xc00b0500,0x4000000,0xe00000,0xc00b0500,0x4000000,0x2800000, -0xc00b0b11,0x4000000,0x1200000,0xc00b0b11,0x7c00900,0x1230400,0xc00b109a,0x7c00300,0xe30000,0xc00b2914,0x7c00100,0x2530000,0xc00b2916,0x7c00100,0x2530c00,0xc00b2a00, -0x4000000,0xe00000,0xc040af5e,0x7c00100,0x230400,0xc0c12b89,0x4000000,0x200000,0xc14a44ca,0x4000000,0xe0000d,0xd000131f,0x2802c00,0x962460,0xd000171a,0x7c00100, -0x230400,0xd0001821,0x2802100,0x962460,0xd0007300,0x24000000,0x200000,0xd0008e00,0x24000000,0x200000,0xd0008f3a,0x2806000,0x962460,0xd0009519,0x7c00100,0x220400, -0xd0009519,0x7c00100,0x250400,0xd000a500,0x4000000,0x200000,0xd000c300,0x4000000,0xe00000,0xd000d202,0x7c00100,0x230400,0xd000d476,0x7c00100,0x230400,0xd000d997, -0x2802100,0x962460,0xd000d997,0x6800100,0x962540,0xd000e001,0x2802100,0x962460,0xd000e700,0x4000400,0x200000,0xd000e719,0x7c00100,0x220400,0xd000e719,0x7c00500, -0x22040f,0xd000fa00,0x4000000,0xe00000,0xd0010eaa,0x4000010,0x400000,0xd0010eaa,0x7c00100,0x230400,0xd0012dbd,0x4000000,0x200000,0xd0012dbd,0x7c00100,0x230400, -0xd0012fbe,0x2802100,0x962460,0xd0012fbe,0x2802400,0x962460,0xd0012fbe,0x2806400,0x962460,0xd0012fbe,0x4000000,0x400000,0xd0012fbe,0x6800000,0x1329800,0xd0012fbe, -0x6800100,0x962540,0xd0012fbe,0x6800100,0x962541,0xd0012fbe,0x6804400,0x962540,0xd0012fbe,0x7c00100,0x230400,0xd0012fbe,0x7c00100,0x230560,0xd0012fbe,0xc000010, -0x448000,0xd0013183,0x7c00100,0x230400,0xd0013200,0x4000000,0x200000,0xd0013200,0x6800000,0x1329805,0xd00134c0,0x2802100,0x962460,0xd00134c0,0x4000002,0x400000, -0xd00134c0,0x7c00100,0x230400,0xd00a4305,0x7c00100,0xe30400,0xd00a4611,0x7c40300,0xe30000,0xd00a4711,0x7c40300,0xe30000,0xd00a5e11,0x7c40300,0xe30000,0xd00acf00, -0x4000000,0xe00000,0xd00b0500,0x4000000,0xe00000,0xd00b0500,0x4000000,0x2800000,0xd00b0b11,0x6800500,0x962540,0xd00b0bbf,0x2802200,0xc62460,0xd00b119a,0x7c00300, -0xe30000,0xd00b2a00,0x4000000,0xe00000,0xd00b2e11,0x7c40300,0xe30000,0xd00b30bf,0x7c00300,0x230000,0xd00b339a,0x7c00300,0xe30000,0xe0000c02,0xc000010,0xb48000, -0xe0001524,0x2802400,0x962460,0xe0001524,0x7c00100,0x230400,0xe0001615,0x7c00100,0x230400,0xe000251b,0x12882000,0x962460,0xe0002a00,0x4000000,0x1500000,0xe0005102, -0x4000000,0x200000,0xe0005c00,0x4000000,0x200000,0xe000622a,0x6804400,0x962540,0xe000622a,0x7c00100,0x230400,0xe0008838,0x7c00100,0x220400,0xe0008838,0x7c00100, -0x250400,0xe0008e00,0x24000000,0x810000,0xe0008e00,0x24000000,0x1410000,0xe0008e00,0x24000002,0x400000,0xe0008e00,0x2c000010,0xb48000,0xe000933e,0x7c00100,0x230400, -0xe000933e,0xc000010,0x448000,0xe0009519,0x7c00100,0x220400,0xe0009519,0x7c00100,0x22040f,0xe0009519,0x7c00100,0x250400,0xe000c178,0x2802100,0x962460,0xe000c941, -0x2802100,0x962460,0xe000c941,0x2806400,0x962460,0xe000c941,0x7c00100,0x230400,0xe000d202,0x2802400,0x962460,0xe000d202,0x7c00100,0x230400,0xe000d202,0x7c00500, -0x230400,0xe000dc99,0x4000000,0x200000,0xe000e001,0x2802100,0x962460,0xe000e001,0x2802400,0x962460,0xe000fda1,0x7c00100,0x1830000,0xe0013502,0x2802400,0x962460, -0xe0013502,0x4000000,0x200000,0xe0013502,0x7c00100,0x230400,0xe0013502,0x80000000,0x218960,0xe00136c1,0x4000000,0x200000,0xe00136c1,0x7c00100,0x230400,0xe001370b, -0x7c00100,0x230400,0xe0013919,0x7c00500,0x220400,0xe0013919,0x7c00500,0x22040f,0xe0013919,0x7c00d00,0x23040f,0xe0013a19,0x7c00100,0x220400,0xe0013a19,0x7c00100, -0x230400,0xe0013bc2,0x2802400,0x962460,0xe0013bc2,0x7c00100,0x230400,0xe0013bc2,0xc000010,0x248000,0xe0013cc3,0x6800000,0x1329800,0xe0013cc3,0x7c00100,0x230400, -0xe0013dc4,0x2802400,0x962460,0xe0013dc4,0x7c00100,0x230400,0xe0013e28,0x7c00100,0x230400,0xe0013fc5,0x7c00100,0x220400,0xe0013fc5,0x7c00100,0x250400,0xe0014000, -0x4000000,0x200000,0xe0014001,0x2802400,0x962460,0xe00a4711,0x7c40300,0xe30000,0xe00a5e11,0x7c40300,0xe30000,0xe00ac511,0x7c40300,0xe30000,0xe00acf00,0x4000000, -0xe00000,0xe00ae300,0x4000000,0xe00000,0xe00b0500,0x4000000,0xe00000,0xe00b1314,0x7c00100,0xe30000,0xe00b1316,0x7c00100,0xe30c00,0xe00b2a00,0x4000000,0xe00000, -0xe00b2a00,0x4000000,0x2800000,0xe00b3816,0x7c00500,0x230c00,0xe0808328,0x2802400,0x962460,0xf0001615,0x6800100,0x962540,0xf0001a18,0x2802000,0x1862460,0xf000c247, -0x7c00100,0x230400,0xf000d000,0x4000000,0xe00000,0xf000e300,0x4000000,0xe00000,0xf000e59d,0x2802100,0x962460,0xf000e59d,0x7c00100,0x230400,0xf0012447,0, -0x818820,0xf0012447,0,0xc18820,0xf0012447,0,0x1418820,0xf0012447,0x2802000,0x962460,0xf0012447,0x2802400,0x962460,0xf0012447,0x7c00100,0x230400, -0xf0013a19,0x7c00100,0x220400,0xf0014102,0x2802400,0x962460,0xf0014308,0x2802100,0x962460,0xf0014308,0x7c00500,0x22040e,0xf0014308,0x7c00500,0x22040f,0xf001440a, -0x4000000,0x500000,0xf0014500,0x4000000,0x200000,0xf00146c6,0x2802100,0x962460,0xf00146c6,0x2806000,0x962460,0xf00146c6,0x4000000,0xe00000,0xf00146c6,0x6800000, -0x1329800,0xf00146c6,0x6800100,0x962540,0xf00146c6,0x6804000,0x962540,0xf00146c6,0x7c00100,0x230400,0xf00146c6,0x7c00100,0x230560,0xf00146c6,0xc000010,0x448000, -0xf00147c7,0x2802000,0x962460,0xf00147c7,0x6800000,0x1329800,0xf00147c7,0x7c00100,0x230400,0xf00ac511,0x7c40300,0xe30000,0xf00acf00,0x4000000,0xe00000,0xf00b2914, -0x7c00100,0x2530000,0xf00b2916,0x7c00100,0x2530c00,0xf00b2a00,0x4000000,0xe00000,0xf00b2a00,0x4000000,0x2800000,0xf00b4211,0x7c40300,0xe30000}; +0x1200000,0x30002417,0x6800000,0x1329800,0x30002417,0x6800100,0x1862540,0x30002417,0x7c00100,0x1830000,0x30002417,0x7d00100,0x1830000,0x30002417,0xc000010,0x448000, +0x3000251b,0x80000,0xc18820,0x3000251b,0x2802100,0x962460,0x3000251b,0x3c02100,0x962460,0x3000251b,0x4000000,0x200000,0x3000251b,0x4000006,0x500000,0x3000251b, +0x4000010,0x400000,0x3000251b,0x4000010,0xb70000,0x3000251b,0x4000800,0x200000,0x3000251b,0x6800000,0x1329800,0x3000251b,0x7c00100,0x230400,0x3000251b,0x7c00900, +0x230400,0x3000251b,0xc000010,0xb48000,0x3000251b,0x12882000,0x962460,0x30002800,0x24000000,0x200000,0x30002800,0x2c000010,0x1248002,0x30002a00,0x4000000,0x1600000, +0x30002b01,0x2000,0x962460,0x30002c00,0x4000000,0x200000,0x30002c00,0x7c00100,0x220405,0x30002d19,0x7c00100,0x250400,0x30002e00,0x24000000,0x200000,0x30003000, +0x24000000,0x200000,0x30003100,0x24000000,0x200000,0x30003600,0x24000000,0x200000,0x30003700,0x24000000,0x200000,0x3000392e,0x24000000,0x200000,0x30005013,0x7c00100, +0x2633801,0x30005600,0,0x918820,0x30020600,0x4000400,0x500400,0x30020701,0x2802400,0x962460,0x30020701,0x2802400,0xc62460,0x300a3a11,0x4020000,0xe00000, +0x300a3a11,0x4020000,0xe00002,0x300a3b11,0x4020000,0xe00002,0x300a3c00,0x4008000,0xe00000,0x300a3c00,0x4010000,0xe00000,0x300a3d11,0x7c00300,0xe30002,0x300a4305, +0x7c00100,0xe30400,0x300a4611,0x7c40300,0xe30000,0x300a4829,0x7c00100,0xe30400,0x300a4829,0x7c00900,0x1230400,0x300a4929,0x4000000,0xe00000,0x3040259a,0x4000010, +0x400000,0x3040259a,0x4000010,0xb70000,0x3040259a,0xc000010,0xb48000,0x304028bc,0x4000001,0xc41c0b,0x304a3dcc,0x4000000,0xe00000,0x30800c27,0x2802100,0x962460, +0x30c01c92,0x6800000,0x1329800,0x3100080e,0x7c00120,0x220402,0x3100080e,0x7c00120,0x250402,0x31005167,0x1000,0,0x3100581e,0x4000000,0x200000,0x3100581e, +0x7c00100,0x230400,0x3100590d,0x7c00100,0x230400,0x31005a09,0x7c00100,0x220400,0x31005a09,0x7c00100,0x250400,0x31005b00,0x4000000,0x200000,0x31005c00,0x80000, +0x918820,0x31005c00,0x2802000,0x962460,0x31005c00,0x2802400,0x962460,0x31005c00,0x4000000,0x200000,0x31005c00,0x4000000,0x200001,0x31005c00,0x6800000,0x962540, +0x31005c00,0x6800400,0x962540,0x31005c01,0x2802400,0x962460,0x31005d00,0x4000020,0x200005,0x31005d00,0x6800020,0x1329805,0x31005d00,0x7c00120,0x220405,0x31005d00, +0x7c00120,0x250405,0x31006000,0x82000,0x962460,0x31006000,0x180000,0x918820,0x310a5e11,0x7c40300,0xe30000,0x310a5f11,0x7c00300,0xe30001,0x32000419,0x7c00100, +0x250400,0x3200080e,0x4000020,0x200000,0x3200080e,0x7c00100,0x220400,0x3200080e,0x7c00100,0x250400,0x32000908,0x7c00100,0x220400,0x32000908,0x7c00100,0x250400, +0x32000c02,0x7c00100,0x230400,0x32000e25,0x7c00100,0x230400,0x32001d0c,0x7c00100,0x230400,0x32002800,0x80000,0x1e18820,0x32002800,0x80020,0x218820,0x32002800, +0x4000001,0x445802,0x32002800,0x24000000,0x200000,0x32002800,0x24000000,0x1500002,0x32002800,0x24000020,0x200000,0x32002800,0x2c000010,0x1248002,0x32002919,0x7c00100, +0x22040f,0x32002a00,0x4000000,0x1600000,0x32002b01,0x2000,0x962460,0x32002b01,0x2802000,0x962460,0x32002b01,0x2802020,0x962460,0x32002c00,0x4000000,0x200000, +0x32002c00,0x4000020,0x200000,0x32002c00,0x4000020,0x200005,0x32002c00,0x7c00120,0x220405,0x32002c00,0x7c00120,0x250405,0x32002e00,0x24000020,0x200000,0x32002f00, +0x24000020,0x200000,0x32003000,0x24000000,0x200000,0x32003000,0x24000020,0x200000,0x32003500,0x24000000,0x200000,0x32003600,0x24000020,0x200000,0x32003700,0x24000000, +0x100000,0x32003700,0x24000000,0x200000,0x32003800,0x24000000,0x810000,0x32003800,0x24000000,0x1410000,0x32005102,0x4000000,0x1500008,0x32005502,0x7c00100,0x230400, +0x32006108,0x7c00100,0x220400,0x32006108,0x7c00100,0x250400,0x3200622a,0x2802100,0x962460,0x3200622a,0x2806400,0x962460,0x3200622a,0x7c00100,0x230400,0x3200632b, +0x2802100,0x962460,0x3200632b,0x6804000,0x962540,0x3200632b,0x7c00100,0x230400,0x3200642c,0x2802100,0x962460,0x3200642c,0x7c00100,0x230400,0x3200652d,0x2802100, +0x962460,0x3200652d,0x7c00100,0x230400,0x32006600,0x24000020,0x200000,0x32006700,0x24000020,0x200000,0x32006800,0x24000020,0x200000,0x32006900,0x24000020,0x200000, +0x32006900,0x24000020,0x810000,0x32006900,0x24000020,0x1410000,0x32006a00,0x24000020,0x200000,0x32006a00,0x24000020,0x200001,0x32006a00,0x24000020,0x200002,0x32020701, +0x2882000,0xc62460,0x32023300,0x4000000,0x100000,0x32026c01,0x12882000,0x962460,0x32065700,0x4000000,0x810011,0x32065700,0x4000000,0x1410011,0x32086600,0x24000020, +0x810000,0x32086600,0x24000020,0x1410000,0x32086900,0x24000020,0x810000,0x32086900,0x24000020,0x1410000,0x320a3600,0x24000020,0x200000,0x320a3d11,0x7c00100,0x1230400, +0x320a3e14,0x7c00100,0xe30010,0x320a3e14,0x7c00100,0x2530000,0x320a3f16,0x7c00100,0xe30c10,0x320a4400,0x4000000,0xe00003,0x320a4929,0x4000000,0xe00000,0x320a4f11, +0x7c00300,0xe30001,0x320a6b16,0x7c00100,0x2530c00,0x32406396,0xc000010,0x448000,0x324a3dcf,0x4000000,0xe00000,0x324a3dcf,0x7c00100,0x1230400,0x324a3fca,0x4000002, +0x1200c00,0x324a53c7,0x24000000,0xe00000,0x32820701,0x2802000,0x962460,0x40000419,0x7c00100,0x220400,0x40000519,0x7c00100,0x220400,0x40000600,0x4000400,0x200400, +0x4000080e,0x7c00100,0x220400,0x4000080e,0x7c00100,0x250400,0x4000080e,0x7c00100,0x250402,0x40000c02,0x2802100,0x962460,0x40000c02,0x2802400,0x962460,0x40000c02, +0x2802500,0x962460,0x40000c02,0x4000000,0x200000,0x40000c02,0x4000000,0x1071400,0x40000c02,0x7c00100,0x230400,0x40000c02,0x80000000,0x1329960,0x40000d22,0x7c00100, +0x230400,0x40000f0a,0x7c00100,0x230400,0x40001004,0x7c00100,0x230400,0x40001110,0x2802100,0x962460,0x40001110,0x6800100,0x962540,0x4000120f,0x2802100,0x962460, +0x4000120f,0x4000000,0x1600000,0x4000120f,0x7c00100,0x230400,0x4000131f,0x7c00100,0x230400,0x40001423,0x4000000,0x200000,0x40001423,0x4000000,0x1600000,0x40001615, +0x2802400,0x962460,0x40001615,0x7c00100,0x230400,0x40002417,0x2802400,0x1862460,0x40002417,0x4000000,0x200000,0x40002800,0x6800000,0x201c00,0x40002800,0x24000002, +0x200000,0x40002c00,0x4000000,0x200002,0x40003000,0x24000000,0x200000,0x40003000,0x24000020,0x200000,0x40003700,0x24000000,0x200000,0x40005a09,0x7c00100,0x220400, +0x40005a09,0x7c00100,0x250400,0x40005d00,0x7c00120,0x220405,0x40006f30,0x2802100,0x962460,0x40006f30,0x2802400,0x962460,0x40006f30,0x4000000,0x200000,0x40006f30, +0x6800000,0x1329800,0x40006f30,0x6800100,0x962540,0x40006f30,0x7c00100,0x230400,0x40006f30,0xc000010,0xb48000,0x40007034,0x7c00100,0x1830000,0x40007117,0x4000000, +0x200000,0x40007208,0x7c00100,0x220400,0x4000720e,0x7c00100,0x220400,0x4000720e,0x7c00500,0x22040e,0x4000720e,0x7c00500,0x22040f,0x40007219,0x7c00100,0x220400, +0x40007219,0x7c00500,0x220400,0x40007219,0x7c00500,0x22040e,0x40007219,0x7c00500,0x22040f,0x40007300,0x24000000,0x200000,0x40007400,0x4000000,0x200000,0x40007531, +0x7c00100,0x230400,0x40007631,0x7c00100,0x230400,0x40007835,0x4000010,0x400000,0x40007835,0x7c00100,0x230400,0x40007933,0x7c00100,0x230400,0x40007a32,0x6800000, +0x1329800,0x40007a32,0x7c00100,0x230400,0x40007b2f,0x7c00100,0x230400,0x40007c00,0x4000000,0x200000,0x40020701,0x2802400,0x962460,0x40020701,0x2802400,0xc62460, +0x40023300,0x4000000,0x200000,0x40027d01,0x12882000,0x962460,0x400a3700,0x24000000,0x200000,0x400a3700,0x24000000,0xe00000,0x400a4400,0x4000000,0xe0000d,0x400a4412, +0x4000000,0xe00002,0x400a4412,0x4000000,0xe00003,0x400a4500,0x4000000,0xe0000d,0x400a5300,0x4000000,0x810010,0x400a5300,0x4000000,0x1410010,0x40507719,0x4000000, +0x200000,0x4050771c,0x4000000,0x400000,0x4050771f,0x4000000,0x200000,0x4050771f,0x4000000,0x400000,0x40c01489,0x4000000,0x200000,0x40d05117,0x4000000,0x200000, +0x41000419,0x7c00100,0x220400,0x41000419,0x7c00100,0x250400,0x4100080e,0x7c00100,0x220400,0x4100080e,0x7c00100,0x250400,0x41000908,0x7c00100,0x220400,0x41000908, +0x7c00100,0x250400,0x41000b13,0x2802000,0x962460,0x41000b13,0x2802100,0x962460,0x41000b13,0x4000000,0xb00000,0x41000c02,0x2802100,0x962460,0x41000c02,0x4000000, +0x1500000,0x41000c02,0xc000010,0xb48000,0x41000f0a,0x7c00100,0x230400,0x41001004,0x7c00100,0x230400,0x41001423,0x7c00100,0x230400,0x41001b27,0x4000000,0x500000, +0x41001d0c,0x7c00100,0x22040f,0x41001d0c,0x7c00100,0x230400,0x41001f0b,0x2802400,0x962460,0x41001f0b,0x4000000,0x200000,0x41001f0b,0x7c00100,0x230400,0x41002800, +0x24000000,0x200000,0x41002800,0x24000000,0x400000,0x41002919,0x7c00100,0x22040e,0x41002a00,0x4000000,0x1600000,0x41002b01,0x2802020,0x962460,0x41002c00,0x4000000, +0x200000,0x41002c00,0x7c00120,0x220405,0x41003000,0x24000000,0x200000,0x41003700,0x24000000,0x200000,0x41003700,0x24000000,0xe00000,0x41005d00,0x7c00120,0x220405, +0x41006600,0x24000020,0x200000,0x41006600,0x24000020,0x810000,0x41006600,0x24000020,0x1410000,0x41007208,0x7c00100,0x22040f,0x41007219,0x7c00100,0x220400,0x41007300, +0x24000000,0x200000,0x41007e0e,0x2802000,0x962460,0x41007e0e,0x4000000,0x200000,0x41007f0e,0x4000000,0x200000,0x41007f0e,0x7c00100,0x230400,0x41008002,0x7c00100, +0x230400,0x41008137,0x2802100,0x962460,0x41008137,0x4000000,0x200000,0x41008137,0x6800100,0x962540,0x41008137,0x7c00100,0x230400,0x41008301,0x2802000,0x962460, +0x41008407,0x4000000,0x200000,0x41008407,0x4000000,0x400000,0x41008407,0x4000000,0xb00000,0x41008407,0x7c00100,0x220400,0x41008407,0x7c00100,0x250400,0x4100850b, +0x7c00100,0x230400,0x4100860b,0x4000000,0x200000,0x4100860b,0x7c00100,0x230400,0x4100870c,0x7c00100,0x220400,0x41008838,0x7c00100,0x220400,0x41008838,0x7c00100, +0x250400,0x41008939,0x2802000,0x962460,0x41008939,0x2802100,0x962460,0x41008939,0x2806000,0x962460,0x41008939,0x4000000,0x200000,0x41008939,0x4000000,0x400000, +0x41008939,0x7c00100,0x230400,0x41008939,0xc000010,0x448000,0x41008a00,0x4000400,0x200400,0x41008b3b,0x4000000,0x1800000,0x41008b3b,0x6800000,0x1329800,0x41008b3b, +0x7c00100,0x1830000,0x41008b3b,0x7e00100,0x1830000,0x41008c3d,0x4000010,0x400000,0x41008c3d,0x7c00100,0x230400,0x41008d0e,0x7c00100,0x22040f,0x41008d19,0x7c00100, +0x220400,0x41008d19,0x7c00100,0x22040f,0x41008e00,0x24000000,0x200000,0x41008e00,0x24000000,0x400000,0x41008e00,0x24000000,0x1710000,0x41008e00,0x24000006,0x400000, +0x41008f3a,0x2802100,0x962460,0x41008f3a,0x2806000,0x962460,0x41008f3a,0x4000000,0x200000,0x41008f3a,0x6800100,0x962540,0x41008f3a,0x7c00100,0x230400,0x4100903c, +0x7c00100,0x230400,0x4100903c,0x7c00100,0x23040f,0x41020701,0x2802000,0x962460,0x41020701,0x2802000,0xc62460,0x410a3700,0x24000000,0x200000,0x410a3700,0x24000000, +0xe00000,0x410a4412,0x4000000,0xe00003,0x410a4711,0x7c40300,0xe30000,0x410a4f11,0x7c00300,0xe30001,0x410a9100,0x4000000,0x800010,0x410a9100,0x4000000,0x810010, +0x410a9100,0x4000000,0x870010,0x410a9100,0x4000000,0xb00010,0x410a9100,0x4000000,0xf00010,0x410a9100,0x4000000,0x1001410,0x410a9100,0x4000000,0x1071010,0x410a9100, +0x4000000,0x1071410,0x410a9100,0x4000000,0x1410010,0x41408ad2,0x4000400,0x200000,0x414a82cc,0x4000000,0xe00000,0x41808300,0x2802000,0x962460,0x41c01489,0x6800000, +0x1329800,0x50000419,0x7c00100,0x220400,0x50000419,0x7c00100,0x250400,0x5000080e,0x7c00100,0x220400,0x50000908,0x7c00100,0x220400,0x50000908,0x7c00100,0x250400, +0x50000b13,0x2802500,0x962460,0x50000f0a,0x7c00100,0x230400,0x50001615,0x2802100,0x962460,0x50001615,0x7c00100,0x230400,0x50002b01,0x2802020,0x962460,0x50002c00, +0x4000000,0x200000,0x50002c19,0x7c00100,0x220400,0x50002d19,0x7c00100,0x220400,0x50003000,0x24000000,0x200000,0x50003000,0x24000020,0x200000,0x50003700,0x24000000, +0x200000,0x50005d00,0x7c00120,0x220405,0x50005d00,0x7c00120,0x250405,0x50006108,0x7c00100,0x220400,0x50006108,0x7c00100,0x250400,0x50006600,0x24000020,0x200000, +0x50007300,0x24000000,0x200000,0x50008301,0x2802400,0x962460,0x50008a00,0x7c00500,0x230400,0x50009257,0x2802400,0x962460,0x50009257,0x4000000,0x200000,0x50009257, +0x4000010,0x1071400,0x50009257,0x6800000,0x1329800,0x50009257,0x7c00100,0x230400,0x50009257,0x7c00500,0x230400,0x50009257,0x7c00900,0x230400,0x50009257,0xc000010, +0xb48000,0x5000933e,0x2802100,0x962460,0x5000933e,0x2802400,0x962460,0x5000933e,0x4000000,0x400000,0x5000933e,0x4000000,0xe00000,0x5000933e,0x4000010,0x400000, +0x5000933e,0x6800000,0xe29800,0x5000933e,0x6800100,0x962540,0x5000933e,0x6800100,0x962541,0x5000933e,0x6804400,0x2f62540,0x5000933e,0x7c00100,0x2b30400,0x5000933e, +0x7c00100,0x2b30401,0x5000933e,0xc000010,0x448000,0x50009419,0x7c00100,0x220400,0x50009419,0x7c00100,0x250400,0x50009500,0x4000400,0x200400,0x5000965a,0x4000000, +0x500000,0x5000965a,0x7c00100,0x230400,0x5000965a,0xc000010,0xb48000,0x5000975b,0x4000000,0x200000,0x5000975b,0x4000010,0x400000,0x5000975b,0x7c00100,0x230400, +0x50009865,0x7c00100,0x230400,0x50009965,0x4000010,0x400000,0x50009965,0x7c00100,0x230400,0x50409acc,0x4000000,0x200000,0x5100080e,0x7c00100,0x220400,0x5100080e, +0x7c00100,0x250400,0x51000c02,0x2802100,0x962460,0x51000c02,0x4000000,0x1500000,0x51000c02,0x4000020,0x200000,0x51000c02,0x7c00100,0x230400,0x51000f0a,0x7c00100, +0x230400,0x51000f0a,0x7c00500,0x230400,0x51001110,0x2802100,0x962460,0x5100131f,0x2802100,0x962460,0x51001423,0x7c00100,0x230400,0x51001524,0x2802100,0x962460, +0x51001524,0x4000000,0x200000,0x51001524,0x7c00100,0x230400,0x5100171a,0x2802100,0x962460,0x5100171a,0x4000000,0x200000,0x5100171a,0x4000000,0x1500000,0x5100171a, +0x7c00100,0x230400,0x51001b27,0x4000000,0x200000,0x51001b27,0x4000000,0x400000,0x51001b27,0x4000000,0x500000,0x51001b27,0x7c00100,0x230400,0x51001c1c,0x2802100, +0x1862460,0x51001c1c,0x2802500,0x1862460,0x51001c1c,0x2806400,0x1862460,0x51001c1c,0x4000000,0x1800000,0x51001c1c,0x6800000,0x1329800,0x51001c1c,0x6800100,0x1862400, +0x51001c1c,0x6800100,0x1862540,0x51001c1c,0x6800500,0x1862400,0x51001c1c,0x7c00100,0x1830000,0x5100251b,0x7c00100,0x230400,0x51002619,0x7c00100,0x220400,0x51002619, +0x7c00100,0x250400,0x51002800,0x80020,0x218820,0x51002c00,0x4000000,0x200000,0x51002d19,0x7c00100,0x230400,0x51003700,0x24000000,0x200000,0x51003700,0x24000000, +0xe00000,0x51005201,0x2802400,0x962460,0x51005c00,0x4000000,0x200000,0x51006108,0x7c00100,0x220400,0x51006108,0x7c00100,0x250400,0x51006600,0x24000020,0x200000, +0x51006600,0x24000020,0x810000,0x51006600,0x24000020,0x1410000,0x51007300,0x24000000,0x200000,0x51007300,0x24000020,0x200000,0x51008002,0x7c00100,0x230400,0x51008301, +0x2802000,0x962460,0x51008301,0x2802400,0x962460,0x51008301,0x2802400,0xc62460,0x51008a00,0x7c00500,0x230400,0x51008e00,0x24000000,0x200000,0x51008e00,0x24000000, +0x400000,0x51008e00,0x24000000,0x810000,0x51008e00,0x24000000,0x1400000,0x51008e00,0x24000000,0x1410000,0x51008e00,0x24000000,0x1710000,0x51008e00,0x24000002,0x200000, +0x51008e00,0x24000500,0x230400,0x51008e00,0x2c000010,0xb48000,0x51009419,0x7c00100,0x220400,0x51009419,0x7c00100,0x22040e,0x51009419,0x7c00100,0x22040f,0x51009419, +0x7c00100,0x250400,0x51009500,0x4000400,0x200400,0x51009500,0x7c00500,0x230400,0x51009519,0x7c00100,0x220400,0x51009519,0x7c00100,0x22040f,0x51009519,0x7c00100, +0x230400,0x51009519,0x7c00100,0x250400,0x51009b71,0x2802100,0x962460,0x51009b71,0x6800000,0x1329800,0x51009b71,0x6800100,0x962540,0x51009b71,0x6804400,0x962540, +0x51009b71,0x7c00100,0x230400,0x51009c52,0x2802100,0x962460,0x51009c52,0x2802400,0x962460,0x51009c52,0x2802d00,0x962460,0x51009c52,0x4000010,0x400000,0x51009c52, +0x6800000,0x1329800,0x51009c52,0x6800100,0x962540,0x51009c52,0x7c00100,0x230400,0x51009c52,0xc000010,0x448000,0x51009d6d,0x6800000,0x1329800,0x51009d6d,0x7c00100, +0x230400,0x51009d6d,0x7c00500,0x230400,0x51009d6d,0x7c00d00,0x230400,0x51009d6d,0xc000010,0x448000,0x51009e08,0x2802100,0x962460,0x51009f63,0x4000010,0x400000, +0x51009f63,0x6800000,0x1329800,0x51009f63,0x7c00100,0x230400,0x51009f63,0x7c00900,0x230400,0x51009f63,0xc000010,0x448000,0x51009f63,0xc000010,0xb48000,0x5100a008, +0x2000,0x962460,0x5100a008,0x2802400,0x962460,0x5100a008,0x4000000,0x200000,0x5100a008,0x7c00100,0x220400,0x5100a008,0x7c00100,0x230400,0x5100a008,0x7c00100, +0x250400,0x5100a008,0x7c00500,0x230400,0x5100a16f,0x2806400,0x962460,0x5100a16f,0x6800000,0x1329800,0x5100a16f,0x6800100,0x962540,0x5100a16f,0x7c00100,0x230400, +0x5100a16f,0xc000010,0x448000,0x5100a24f,0x2802100,0x962460,0x5100a24f,0x2802400,0x962460,0x5100a24f,0x6800000,0x1329800,0x5100a24f,0x7c00100,0x230400,0x5100a24f, +0xc000010,0x448000,0x5100a36e,0x2802100,0x962460,0x5100a36e,0x4000000,0x200000,0x5100a36e,0x6800100,0x962540,0x5100a36e,0x6804400,0x962540,0x5100a36e,0x7c00100, +0x230400,0x5100a442,0x2802100,0x962460,0x5100a442,0x4000000,0xe00000,0x5100a442,0x6800000,0xe29800,0x5100a442,0x6800100,0x962540,0x5100a442,0x7c00100,0x430400, +0x5100a442,0x7c00100,0x2d30400,0x5100a442,0xc000010,0x448000,0x5100a500,0x4000000,0x200000,0x5100a600,0x4000000,0x200000,0x5100a601,0x2802000,0x962460,0x5100a76b, +0x7c00100,0x230400,0x5100a868,0x7c00100,0x230400,0x5100a96c,0x4000000,0x200000,0x5100a96c,0x7c00100,0x230400,0x5100aa00,0x4000000,0xe00000,0x5100ab00,0x4000000, +0xe00000,0x51086600,0x24000020,0x810000,0x51086600,0x24000020,0x1410000,0x510a4005,0x7c00100,0xe30400,0x510a4711,0x7c40300,0xe30000,0x510a7300,0x24000000,0x200000, +0x510aaa00,0x4000000,0xe00000,0x514a82cc,0x4000000,0xe00000,0x5150a20e,0x4000400,0x400000,0x51802bbe,0x2802000,0x962460,0x51c00908,0x2802400,0x962460,0x51c0a008, +0x2802400,0x962460,0x52000f0a,0x2802100,0x962460,0x52000f0a,0x6800100,0x962540,0x52000f0a,0x7c00100,0x230400,0x52001004,0x4000000,0x1600000,0x52001b00,0x4000000, +0x200000,0x52001c1c,0x2802100,0x1862460,0x52001c1c,0x6800100,0x1862400,0x52001c1c,0x6800500,0x1862400,0x52001e12,0x7c00100,0x2230500,0x52001e12,0x7c00100,0x2330520, +0x52002128,0x4000002,0x400000,0x52002128,0x7c00100,0x230400,0x52002a00,0x4000000,0x1500000,0x52002a00,0x4000000,0x1600000,0x52002d00,0x4000000,0x200006,0x52003000, +0x24000000,0x200000,0x52006108,0x7c00100,0x220400,0x52006108,0x7c00100,0x250400,0x52008301,0x2802400,0x962460,0x52008407,0x2802400,0x962460,0x52008407,0x7c00100, +0x220400,0x52008407,0x7c00100,0x250400,0x52008b3b,0x6800000,0x1800000,0x52008b3b,0x7c00100,0x1830000,0x52008e00,0x24000000,0x400000,0x52009419,0x7c00100,0x250400, +0x5200975b,0x4000000,0x200000,0x5200ac7e,0x2802000,0x962460,0x5200ac7e,0x2802100,0x962460,0x5200ac7e,0x2802400,0x962460,0x5200ac7e,0x4000010,0x200000,0x5200ac7e, +0x7c00100,0x230400,0x5200ac7e,0xc000010,0x248000,0x5200ad28,0x7c00100,0x230400,0x5200ae6a,0x2802100,0x1862460,0x5200ae6a,0x2802400,0x962460,0x5200ae6a,0x2802400, +0x1862460,0x5200ae6a,0x2806000,0x1862460,0x5200ae6a,0x4000000,0x1800000,0x5200ae6a,0x6800000,0x1329800,0x5200ae6a,0x6800100,0x1862400,0x5200ae6a,0x6800100,0x1862540, +0x5200ae6a,0x7c00100,0x1830000,0x5200ae6a,0x7c00900,0x1830000,0x5200ae6a,0xc000010,0x1848000,0x5200b083,0x4000010,0x400000,0x5200b083,0x7c00100,0x230400,0x5200b083, +0xc000010,0x448000,0x5200b182,0x2802400,0x962460,0x5200b182,0x4000000,0x200000,0x5200b182,0x4000010,0x400000,0x5200b182,0x7c00100,0x230400,0x5200b182,0xc000010, +0x448000,0x5200b30a,0x2802400,0x962460,0x5200b30a,0x4000000,0x200000,0x5200b30a,0x7c00100,0x230400,0x5200b54e,0x2802100,0x962460,0x5200b54e,0x2802400,0x962460, +0x5200b54e,0x4000000,0xe00000,0x5200b54e,0x4000010,0x400000,0x5200b54e,0x6800000,0xe29800,0x5200b54e,0x6800100,0x962540,0x5200b54e,0x6804400,0x2f62540,0x5200b54e, +0x7c00100,0x2b30400,0x5200b54e,0xc000010,0x448000,0x5200b61c,0x4000000,0x1800000,0x5200b61c,0x6800500,0x1862400,0x5200b61c,0x7c00100,0x1830000,0x5200b61c,0x7c00900, +0x1830000,0x5200b77f,0x2802100,0x1862460,0x5200b77f,0x2802400,0x1862460,0x5200b77f,0x4000000,0x1800000,0x5200b77f,0x4000010,0x1800000,0x5200b77f,0x7c00100,0x1830000, +0x5200b77f,0x7c00500,0x1830000,0x5200b77f,0x7c00900,0x1830000,0x5200b77f,0x7e00100,0x1830000,0x5200b873,0x2802100,0x962460,0x5200b873,0x2806400,0x962460,0x5200b873, +0x6800000,0x1329800,0x5200b873,0x6800100,0x962540,0x5200b873,0x6800400,0x962540,0x5200b873,0x7c00100,0x230400,0x5200b873,0xc000010,0x448000,0x5200b912,0x7c00100, +0x2230500,0x5200b912,0x7c00100,0x2330520,0x5200ba74,0x4000000,0x200000,0x5200ba74,0x4000010,0x400000,0x5200ba74,0x7c00100,0x230400,0x5200bb85,0x4000000,0x200000, +0x5200bb85,0x7c00100,0x230400,0x5200bc75,0x4000000,0x400000,0x5200bc75,0x4000010,0x400000,0x5200bc75,0x7c00100,0x230400,0x5200bd7d,0x4000000,0x200000,0x5200bd7d, +0x7c00100,0x230400,0x5200be7a,0x4000000,0x200000,0x5200be7a,0x7c00100,0x230400,0x5200bf58,0x7c00100,0x230400,0x5200c002,0x4000000,0x200000,0x5200c178,0x2802100, +0x962460,0x5200c178,0x2802400,0x962460,0x5200c178,0x2806400,0x962460,0x5200c178,0x4000000,0x200000,0x5200c178,0x6800100,0x962540,0x5200c178,0x7c00100,0x230400, +0x5200c178,0x7c00100,0x230401,0x5200c178,0xc000010,0x448000,0x5200c178,0x80000000,0x1329960,0x5200c247,0x7c00100,0x230400,0x5200c247,0x7c00100,0x830400,0x5200c247, +0x7c00100,0x1430400,0x5200c300,0x4000000,0x200003,0x52022d00,0x4000000,0x100006,0x52023700,0x24000000,0x100000,0x52023700,0x24000000,0xe00000,0x52023700,0x24000000, +0x2800000,0x52024400,0x4000000,0x100000,0x52027300,0x24000000,0x100000,0x5202c300,0x4000000,0x100000,0x5202c300,0x4000000,0x100002,0x5202c300,0x4000000,0x100003, +0x5202c300,0x4000000,0x10000d,0x5202c300,0x4000100,0x150400,0x5202c300,0x4000100,0x15040d,0x520a1e12,0x7c00100,0x2130480,0x520a3700,0x24000000,0xe00000,0x520a3800, +0x24000000,0x100000,0x520a4711,0x7c40300,0xe30000,0x520a4f11,0x7c00300,0xe30001,0x520a7300,0x24000000,0x100000,0x520ab412,0x7c00100,0x2130480,0x520ac400,0x4000000, +0xe00002,0x520ac400,0x4000000,0xe0000d,0x520ac414,0x4000000,0xe0000d,0x520ac511,0x7c40300,0xe30000,0x5240af9c,0x7c00100,0x230400,0x5240afa1,0x4000400,0x200000, +0x5240afa3,0x6800400,0x962540,0x5240afa3,0x7c00100,0x230400,0x5240afad,0x7c00100,0x230400,0x5240afaf,0x7c00100,0x230400,0x5240b2d4,0x4000000,0x200000,0x5240b2e3, +0x4000000,0x200000,0x5240b2f1,0x4000000,0x200000,0x5240b2fc,0x4000000,0x1500000,0x524a44cc,0x4000000,0xe00003,0x5250b511,0x7c00900,0x430400,0x5280af9c,0x2802400, +0x962460,0x5280af9d,0x2802400,0x962460,0x5280afa3,0x2802400,0x962460,0x5280afa5,0x2802400,0x962460,0x5280afa7,0x2802400,0x962460,0x52d0b308,0x2802400,0x962460, +0x52d0b30c,0x7c00100,0x230400,0x60000c02,0x2802100,0x962460,0x60000c02,0x7c00100,0x230400,0x60000f0a,0x2802100,0x962460,0x60000f0a,0x6800100,0x962540,0x60000f0a, +0x7c00100,0x230400,0x6000131f,0x4000000,0x200000,0x6000171a,0x7c00100,0x230400,0x6000171a,0x7c00100,0x230560,0x60001b27,0x2802100,0x962460,0x60001b27,0x4000000, +0xc00000,0x60001b27,0x7c00100,0x230400,0x60001f0b,0x2802400,0x962460,0x60002919,0x7c00100,0x22040e,0x60002a00,0x4000000,0x1600000,0x60003000,0x24000000,0x200000, +0x60003000,0x24000000,0xe00000,0x60003700,0x24000000,0x200000,0x60003800,0x24000000,0x1710000,0x60005102,0x4000000,0x200000,0x60006108,0x7c00100,0x220400,0x60006108, +0x7c00100,0x250400,0x60006600,0x24000020,0x200000,0x60008301,0x2802400,0xc62460,0x6000903c,0x2806000,0x962460,0x6000903c,0x4000000,0x400000,0x60009519,0x7c00100, +0x220400,0x60009519,0x7c00100,0x250400,0x6000a008,0x7c00100,0x220400,0x6000a008,0x7c00100,0x250400,0x6000c300,0x4000000,0x2703580,0x6000c654,0x2802000,0x962460, +0x6000c654,0x4000010,0x200000,0x6000c654,0x7c00100,0x230400,0x6000c73f,0x2802000,0x962460,0x6000c73f,0x2802100,0x962460,0x6000c73f,0x4000000,0x200000,0x6000c73f, +0x6800100,0x962540,0x6000c73f,0x6804000,0x2e62540,0x6000c73f,0x7c00100,0x2d30400,0x6000c80b,0x7c00100,0x230400,0x6000c941,0x2802100,0x962460,0x6000c941,0x2806400, +0x2f62460,0x6000c941,0x4000000,0xe00000,0x6000c941,0x4000010,0xe00000,0x6000c941,0x6800000,0x2d29800,0x6000c941,0x6800100,0x962540,0x6000c941,0x7c00100,0x2b30400, +0x6000c941,0x7c00100,0x2c30400,0x6000c941,0xc000010,0x448000,0x6000ca82,0x7c00100,0x230400,0x6000cc00,0x4000000,0xe00000,0x6000d000,0x4000000,0x200000,0x6002c300, +0x4000000,0x100000,0x6002c300,0x4000000,0x10000d,0x6002c300,0x4000100,0x150400,0x6002c300,0x4000100,0x15040d,0x600a3000,0x24000000,0x200000,0x600a3000,0x24000000, +0xe00000,0x600a3700,0x24000000,0x200000,0x600a3800,0x24000000,0x200000,0x600a3800,0x24000000,0x2800000,0x600a4305,0x7c00100,0xe30400,0x600ac300,0x4000000,0x100000, +0x600ac400,0x4000000,0xe0000d,0x600acb14,0x7c00100,0xe30000,0x600acb16,0x7c00100,0xe30c00,0x600acc00,0x4000000,0xe00000,0x600acd00,0x4000000,0x200000,0x600acd00, +0x4000000,0xe00000,0x600acd00,0x4000000,0x2800000,0x600ace00,0x4000000,0xe00000,0x600ace00,0x4000000,0x2800000,0x600acf00,0x4000000,0xe00000,0x600acf00,0x4000000, +0x2800000,0x600ad111,0x7c40300,0xe30000,0x604ac4cc,0x4000000,0xe00003,0x61000a03,0x4000000,0x1600000,0x61000c02,0x80000000,0x1329960,0x6100120f,0x4000000,0x200000, +0x61001a18,0x7c00100,0x1830000,0x61001d0c,0x7c00100,0x230400,0x61001d0c,0x7c00100,0x250400,0x61006600,0x24000020,0x200000,0x61008407,0x7c00100,0x220400,0x61008407, +0x7c00100,0x250400,0x6100870c,0x7c00100,0x220400,0x61008e00,0x24000000,0x200000,0x61008e00,0x24000000,0x400000,0x61008e00,0x24000002,0x300000,0x6100903c,0x7c00100, +0x230400,0x61009519,0x7c00100,0x220400,0x61009519,0x7c00100,0x250400,0x61009519,0x7c00500,0x22040f,0x61009b71,0x2802100,0x962460,0x61009b71,0x2806400,0x962460, +0x61009b71,0x7c00100,0x230400,0x6100a008,0x2802100,0x962460,0x6100c300,0x4000000,0x20000f,0x6100cd00,0x4000000,0x200000,0x6100d202,0x2802400,0x962460,0x6100d202, +0x2802500,0x962460,0x6100d202,0x7c00100,0x230400,0x6100d302,0x4000020,0x200000,0x6100d302,0x7c00120,0x230405,0x6100d476,0x2802100,0x962460,0x6100d476,0x2802100, +0x962461,0x6100d476,0x2806400,0x962460,0x6100d476,0x4000000,0x400000,0x6100d476,0x6800000,0x1329800,0x6100d476,0x6800100,0x962540,0x6100d476,0x7c00100,0x230400, +0x6100d476,0xc000010,0x448000,0x6100d573,0x2802100,0x962460,0x6100d573,0x2806400,0x962460,0x6100d573,0x6800100,0x962540,0x6100d573,0x7c00100,0x230400,0x6100d573, +0x7c00900,0x230400,0x6100d573,0xc000010,0x448000,0x6100d68d,0x7c00100,0x230400,0x6100d756,0x7c00100,0x230400,0x6100d85c,0x2802500,0x962460,0x6100d85c,0x6800100, +0x962540,0x6100d85c,0x7c00100,0x230400,0x6100d85c,0x7c00500,0x230400,0x6100d997,0x2802100,0x962460,0x6100d997,0x4000000,0x200000,0x6100d997,0x4000000,0x400000, +0x6100d997,0x6800000,0x1329800,0x6100d997,0x6800100,0x962540,0x6100d997,0x6804400,0x962540,0x6100d997,0x7c00100,0x230400,0x6100d997,0x7c00100,0x230560,0x6100d997, +0xc000010,0x448000,0x6100da98,0x6800000,0x1329800,0x6100da98,0x7c00100,0x230400,0x6100db71,0x4000000,0x200000,0x6100dc99,0x2802100,0x962460,0x6100dc99,0x2802400, +0x962460,0x6100dc99,0x6800000,0x1329800,0x6100dc99,0x6800100,0x962540,0x6100dc99,0x6804400,0x962540,0x6100dc99,0x7c00100,0x230400,0x610a4711,0x7c40300,0xe30000, +0x610a4f11,0x7c00300,0xe30001,0x610ace00,0x4000000,0xe00000,0x6140afa1,0x7c00100,0x230400,0x6140afa3,0x7c00100,0x230400,0x6180af9e,0x2802400,0x962460,0x62002a00, +0x4000000,0x1600000,0x63002800,0x80000,0x918820,0x63c00c15,0x80000,0x918820,0x7000080e,0x7c00100,0x250400,0x70000a03,0x4000000,0x200000,0x70000c00,0x80000000, +0x1329960,0x70000f0a,0x7c00100,0x230400,0x70001004,0x7c00100,0x230400,0x70001524,0x2802100,0x962460,0x70001524,0x7c00100,0x230400,0x70001615,0x2802100,0x962460, +0x7000171a,0x2802100,0x962460,0x70001821,0x6800000,0x1329800,0x70002320,0x7c00100,0x230400,0x70002a00,0x4000000,0x1500000,0x70002a00,0x4000000,0x1600000,0x70003000, +0x24000000,0x200000,0x70003800,0x24000000,0xe00000,0x70005201,0x2802400,0x962460,0x7000581e,0x7c00100,0x230400,0x70006108,0x7c00100,0x220400,0x70006108,0x7c00100, +0x250400,0x70006f30,0x7c00100,0x230400,0x70007300,0x24000000,0x200000,0x70007f0e,0x4000000,0x200000,0x70008301,0x2802100,0x962460,0x70008301,0x2802400,0x962460, +0x70008e00,0x24000000,0x200000,0x70008e00,0x24000000,0x400000,0x70008e00,0x24000002,0x400000,0x70008e00,0x24000008,0x1410000,0x70008e00,0x24000010,0x400000,0x70008e00, +0x2c000010,0x448000,0x70009519,0x7c00100,0x220400,0x70009519,0x7c00100,0x230400,0x70009519,0x7c00100,0x250400,0x70009865,0x7c00100,0x230400,0x70009965,0x4000010, +0x400000,0x70009965,0x7c00100,0x230400,0x7000a008,0x7c00100,0x220400,0x7000a008,0x7c00100,0x250400,0x7000a008,0x7c00500,0x22040f,0x7000a50e,0x4000000,0x200000, +0x7000b61c,0x2802500,0x1862460,0x7000b61c,0x6800500,0x1862400,0x7000b61c,0x7c00100,0x1830000,0x7000c300,0x4000000,0x100000,0x7000c941,0x2806000,0xc62460,0x7000cc00, +0x4000000,0xe00000,0x7000cd00,0x4000000,0x200000,0x7000cd00,0x4000000,0xe00000,0x7000cd00,0x4000000,0x2800000,0x7000cf00,0x4000000,0xe00000,0x7000d202,0x2802100, +0x962460,0x7000d202,0x7c00100,0x230400,0x7000d997,0x7c00100,0x230400,0x7000d997,0xc000010,0x248000,0x7000dd86,0x2802400,0x962460,0x7000dd86,0x7c00100,0x230400, +0x7000dd86,0xc000010,0x448000,0x7000de9f,0x4000000,0x200000,0x7000de9f,0x7c00100,0x230400,0x7000e001,0x2400,0x962460,0x7000e001,0x2802400,0x962460,0x7000e187, +0x2802000,0x962460,0x7000e187,0x2802100,0x962460,0x7000e187,0x4000000,0x200000,0x7000e187,0x7c00100,0x230400,0x7000e187,0xc000010,0x448000,0x7000e288,0x7c00100, +0x230400,0x7000e300,0x4000000,0x200000,0x7000e489,0x2802100,0x962460,0x7000e489,0x2802400,0x962460,0x7000e489,0x6800100,0x962540,0x7000e489,0x6800100,0x962541, +0x7000e489,0x6804400,0x2f62540,0x7000e489,0x7c00100,0x430400,0x7000e489,0x7c00100,0x2b30400,0x7000e489,0x7c00100,0x2d30400,0x7000e489,0x7c00900,0x430400,0x7000e59d, +0x2802100,0x962460,0x7000e59d,0x2802400,0x962460,0x7000e59d,0x4000000,0x200000,0x7000e59d,0x4000010,0x200000,0x7000e59d,0x6800100,0x962540,0x7000e59d,0x6804400, +0x962540,0x7000e59d,0x7c00100,0x230400,0x7000e59d,0xc000010,0x448000,0x7000e691,0x2802100,0x962460,0x7000e691,0x2802400,0x962460,0x7000e691,0x2806400,0x962460, +0x7000e691,0x6800000,0x1329800,0x7000e691,0x6800100,0x962540,0x7000e691,0x7c00100,0x230400,0x7000e700,0x4000400,0x200400,0x7000e70e,0x7c00100,0x220400,0x7000e719, +0x7c00100,0x220400,0x7000e719,0x7c00500,0x22040f,0x7000e853,0x7c00100,0x230400,0x7000e9a0,0x2802400,0x962460,0x7000e9a0,0x4000000,0x200000,0x7000e9a0,0x4000000, +0x500000,0x7000e9a0,0x7c00100,0x230400,0x7000ea79,0x2802400,0x962460,0x7000ea79,0x4000000,0x200000,0x7000ea79,0x4000000,0xf00000,0x7000ea79,0x4000010,0x400000, +0x7000ea79,0x7c00100,0x230400,0x7000eb8c,0x2802400,0x962460,0x7000eb8c,0x4000000,0x200000,0x7000eb8c,0x7c00100,0x230400,0x7000eca3,0x2802100,0x962460,0x7000eca3, +0x2806400,0x962460,0x7000eca3,0x4000000,0x200000,0x7000eca3,0x6800000,0x1329800,0x7000eca3,0x6800100,0x962540,0x7000eca3,0x7c00100,0x230400,0x7000eca3,0xc000010, +0x448000,0x7000ed95,0x6800000,0x1329800,0x7000ed95,0x7c00100,0x230400,0x7000ed95,0xc000010,0x448000,0x7000ee1c,0x2802500,0x1862460,0x7000ee1c,0x6800000,0x1329800, +0x7000ee1c,0x7c00100,0x1830000,0x7000ee1c,0x7c00900,0x1830000,0x7000ef8f,0x4000000,0x200000,0x7000ef8f,0x7c00100,0x230400,0x7000f08e,0x4000000,0x200000,0x7000f08e, +0x7c00100,0x230400,0x7000f159,0x2802100,0x962460,0x7000f159,0x7c00100,0x230400,0x7000f200,0x4000000,0x200000,0x7000f200,0x4000000,0x1200000,0x7000f200,0x4000000, +0x1710000,0x7000f34b,0x2802400,0x962460,0x7000f34b,0x4000000,0x200000,0x7000f34b,0x4000010,0x400000,0x7000f34b,0x6800000,0x1329800,0x7000f34b,0x7c00100,0x230400, +0x7000f34b,0x7c00900,0x230400,0x7000f34b,0xc000010,0x448000,0x7000f490,0x4000000,0x200000,0x7000f490,0x7c00100,0x230400,0x7000f5a5,0x7c00100,0x230400,0x7000f67b, +0x4000000,0x200000,0x7000f67b,0x4000010,0x200000,0x7000f67b,0x7c00100,0x230400,0x7000f8a6,0x2802100,0x962460,0x7000f8a6,0x2802400,0x962460,0x7000f8a6,0x2806400, +0x962460,0x7000f8a6,0x4000000,0x500000,0x7000f8a6,0x4000010,0xb00000,0x7000f8a6,0x4000800,0x200000,0x7000f8a6,0x6800100,0x962540,0x7000f8a6,0x6800100,0x962541, +0x7000f8a6,0x7c00100,0x230400,0x7000f8a6,0xc000010,0x448000,0x7000f921,0x4000000,0x200000,0x7000fa00,0x4000000,0x200000,0x7000fb9e,0x2802100,0x962460,0x7000fb9e, +0x2802400,0x962460,0x7000fb9e,0x2806400,0x962460,0x7000fb9e,0x4000000,0x200000,0x7000fb9e,0x6800000,0x1329800,0x7000fb9e,0x6800100,0x962540,0x7000fb9e,0x6800100, +0x962541,0x7000fb9e,0x7c00100,0x230400,0x7000fc92,0x4000000,0x200000,0x7000fc92,0x6800000,0x1329800,0x7000fc92,0x7c00100,0x220400,0x7000fc92,0x7c00100,0x230400, +0x7000fc92,0x7c00100,0x250400,0x700acd00,0x4000000,0xe00000,0x700acd00,0x4000000,0x2800000,0x700ace00,0x4000000,0xe00000,0x700acf00,0x4000000,0xe00000,0x700acf00, +0x4000000,0x2800000,0x7050df21,0x4000000,0x200000,0x7050f729,0x80000,0x918820,0x7080afa1,0x2802400,0x962460,0x7090df21,0x2802400,0x962460,0x70d0e427,0x2802100, +0x962460,0x70d0e427,0x2802400,0x962460,0x70d0e427,0x6800100,0x962540,0x70d0ea25,0x4000010,0x400000,0x8000120f,0x7c00100,0x230400,0x80001524,0x7c00100,0x230400, +0x8000171a,0x7c00100,0x230400,0x80002006,0x7c00100,0x220400,0x80002006,0x7c00100,0x250400,0x80002a00,0x4000000,0x1500000,0x80002d00,0x4000000,0x200000,0x80005208, +0x2802400,0x962460,0x80005c00,0x4000000,0x200000,0x80007300,0x24000000,0x200000,0x80009519,0x7c00100,0x220400,0x80009519,0x7c00100,0x230400,0x80009519,0x7c00100, +0x250400,0x80009865,0x7c00100,0x230400,0x8000a008,0x2802100,0x962460,0x8000b30a,0x4000000,0x500000,0x8000b30a,0x7c00100,0x230400,0x8000cd00,0x4000000,0xe00000, +0x8000d202,0x2802500,0x962460,0x8000d202,0x7c00100,0x230400,0x8000d68d,0x4000000,0x200000,0x8000d997,0x2802000,0x962460,0x8000d997,0x2802400,0x962460,0x8000d997, +0x4000000,0x400000,0x8000d997,0x4000000,0x500000,0x8000d997,0x7c00100,0x230400,0x8000d997,0xc000010,0x448000,0x8000e489,0x2802100,0x962460,0x8000e489,0x7c00100, +0x2d30400,0x8000e719,0x7c00100,0x220400,0x8000f8a6,0x2802100,0x962460,0x8000f8a6,0x7c00100,0x230400,0x8000f8a6,0xc000010,0x448000,0x8000fda1,0x2802100,0x1862460, +0x8000fda1,0x2806400,0x1862460,0x8000fda1,0x4000000,0x1800000,0x8000fda1,0x6800000,0x1329800,0x8000fda1,0x6800100,0x1862400,0x8000fda1,0x6800100,0x1862540,0x8000fda1, +0x7c00100,0x1830000,0x8000fda1,0xc000010,0x448000,0x8000fe9c,0x7c00100,0x230400,0x8000fe9c,0x7c00100,0x830400,0x8000fe9c,0x7c00100,0x1430400,0x8000ff06,0x7c00100, +0x220400,0x80010165,0x7c00100,0x230400,0x800102a2,0x4000000,0x200000,0x800102a2,0x7c00100,0x230400,0x800103a4,0x7c00100,0x230400,0x800103a4,0xc000010,0x448000, +0x8001044c,0x4000000,0x200000,0x8001044c,0x7c00100,0x220400,0x8001044c,0x7c00100,0x250400,0x80010670,0x2802000,0x962460,0x80010670,0x4000000,0x200000,0x80010670, +0x4000010,0x400000,0x80010670,0xc000010,0x448000,0x800a4711,0x7c40300,0xe30000,0x800acd00,0x4000000,0xe00000,0x800acd00,0x4000000,0x2902460,0x800ace00,0x4000000, +0xe00000,0x800acf00,0x4000000,0xe00000,0x800b0011,0x7c40300,0xe30000,0x800b0500,0x4000000,0xe00000,0x800b0500,0x4000000,0x2800000,0x90001615,0x7c00100,0x230400, +0x9000171a,0x4000000,0x200000,0x9000171a,0x7c00100,0x230400,0x90003000,0x24000000,0x200000,0x90007f0e,0x4000000,0x200000,0x90008301,0x2802400,0x962460,0x90008e00, +0x24000000,0x400000,0x90009519,0x7c00100,0x250400,0x9000a16f,0x2802100,0x962460,0x9000d200,0x80000000,0x1329960,0x9000d202,0x2802000,0x962460,0x9000d202,0x2802100, +0x962460,0x9000d202,0x7c00100,0x230400,0x9000e59d,0x2802100,0x962460,0x90010500,0x4000000,0xe00000,0x900107a7,0x2802100,0x962460,0x900107a7,0x2802400,0x962460, +0x900107a7,0x2802c00,0x962460,0x900107a7,0x4000000,0x1400000,0x900107a7,0x6800000,0x1329800,0x900107a7,0x7c00100,0x220400,0x900107a7,0x7c00100,0x250400,0x900108a8, +0x2802100,0x962460,0x900108a8,0x2806400,0x962460,0x900108a8,0x4000000,0x200000,0x900108a8,0x4000000,0x400000,0x900108a8,0x4000010,0x400000,0x900108a8,0x6800000, +0x1329800,0x900108a8,0x6800100,0x962540,0x900108a8,0x7c00100,0x230400,0x900108a8,0xc000010,0x448000,0x90010908,0x7c00100,0x220400,0x90010a38,0x2802100,0x962460, +0x90010ca9,0x2802100,0x962460,0x90010ca9,0x4000000,0x500000,0x90010ca9,0x4000010,0xb00000,0x90010ca9,0x6800100,0x962540,0x90010ca9,0x7c00100,0x230400,0x90010d1b, +0x4000000,0x500000,0x90010eaa,0x2802100,0x962460,0x90010eaa,0x2802400,0x962460,0x90010eaa,0x2806400,0x962460,0x90010eaa,0x4000000,0x200000,0x90010eaa,0x4000000, +0x400000,0x90010eaa,0x4000010,0x400000,0x90010eaa,0x6800000,0x1329800,0x90010eaa,0x6800100,0x962540,0x90010eaa,0x7c00100,0x230400,0x90010eaa,0xc000010,0x448000, +0x90010fab,0x7c00100,0x220400,0x90010fab,0x7c00100,0x250400,0x9002c300,0x4000000,0x100000,0x900ac400,0x4000000,0xe0000d,0x900acd00,0x4000000,0xe00000,0x900acd00, +0x4000000,0x2800000,0x900acf00,0x4000000,0xe00000,0x900b0500,0x4000000,0xe00000,0x900b0500,0x4000000,0x2800000,0x900b0b9a,0x7c00900,0x1230400,0x900b109a,0x7c00300, +0xe30000,0x900b119a,0x7c00300,0xe30000,0x90408e06,0x24000000,0x400000,0xa0001004,0x4000000,0x200000,0xa0001004,0x7c00100,0x230400,0xa000120f,0x2802100,0x962460, +0xa000120f,0x2802400,0x962460,0xa000171a,0x2802100,0x962460,0xa000171a,0x2806400,0x962460,0xa0002a00,0x4000000,0x1600000,0xa0003000,0x24000000,0x200000,0xa000581e, +0x7c00100,0x230400,0xa0007300,0x24000000,0x200000,0xa0008301,0x2802400,0x962460,0xa0008e00,0x24000000,0x400000,0xa000cf00,0x4000000,0xe00000,0xa0010500,0x4000000, +0x200000,0xa00114af,0x2802100,0x962460,0xa00114af,0x2802400,0x962460,0xa00114af,0x2806400,0x962460,0xa00114af,0x6800000,0x1329800,0xa00114af,0x7c00100,0x230400, +0xa00114af,0x7c00100,0x230560,0xa00116b0,0x2802100,0x962460,0xa00116b0,0x2802800,0x962460,0xa00116b0,0x2806400,0x962460,0xa00116b0,0x4000000,0x400000,0xa00116b0, +0x4000000,0x500000,0xa00116b0,0x4000010,0x400000,0xa00116b0,0x6800100,0x962540,0xa00116b0,0x7c00100,0x230400,0xa00116b0,0x7c00100,0x230560,0xa00116b0,0xc000010, +0x448000,0xa0011722,0x7c00100,0x230400,0xa00118b1,0x2802000,0x962460,0xa00118b1,0x2802100,0x962460,0xa00118b1,0x2806400,0x962460,0xa00118b1,0x4000000,0x200000, +0xa00118b1,0x4000000,0x400000,0xa00118b1,0x4000000,0x500000,0xa00118b1,0x6800100,0x962540,0xa00118b1,0x7c00100,0x230400,0xa00118b1,0x7c00100,0x230560,0xa00118b1, +0xc000010,0x448000,0xa00a4005,0x7c00100,0xe30400,0xa00a4711,0x7c40300,0xe30000,0xa00ac400,0x4000000,0xe00000,0xa00acb14,0x7c00100,0xe30000,0xa00acf00,0x4000000, +0xe00000,0xa00b0500,0x4000000,0xe00000,0xa00b0500,0x4000000,0x2800000,0xa00b0b96,0x7c00900,0x1230400,0xa00b1211,0x7c40300,0xe30000,0xa00b1314,0x7c00100,0xe30000, +0xa00b1596,0x7c00300,0xe30000,0xa040afb9,0x6800400,0x962540,0xa08083ba,0x2802400,0x962460,0xb0000a03,0x7c00100,0x220400,0xb0000b13,0x7c00100,0x2633800,0xb0001004, +0x2802000,0x962460,0xb0001110,0x4000000,0x200000,0xb0001524,0x2802100,0x962460,0xb0001615,0x4000000,0x500000,0xb000251b,0x7c00100,0x230400,0xb0007300,0x24000000, +0x200000,0xb0008939,0x4000000,0x200000,0xb0008939,0x7c00100,0x230400,0xb0008e00,0x24000000,0x200000,0xb0008e00,0x24000000,0x400000,0xb0008e00,0x24000010,0x400000, +0xb0009257,0x2802000,0x962460,0xb0009257,0x4000000,0x1600000,0xb0009519,0x7c00100,0x220400,0xb0009519,0x7c00100,0x250400,0xb0009a00,0x4000000,0x200000,0xb000b30a, +0x2802100,0x962460,0xb000b30a,0x7c00100,0x230400,0xb000c178,0x80000000,0x1329960,0xb000c300,0x4000000,0x200000,0xb000d202,0x2802000,0x962460,0xb000d476,0x6800100, +0x962540,0xb000d476,0x7c00100,0x230400,0xb000e300,0x4000000,0xe00000,0xb000fda1,0x7c00100,0x1830000,0xb0010eaa,0x2802000,0x962460,0xb00116b0,0x7c00100,0x230400, +0xb0011900,0x4000000,0xe00000,0xb0011ab2,0x2802100,0x962460,0xb0011ab2,0x2802400,0x962460,0xb0011ab2,0x2806400,0x962460,0xb0011ab2,0x4000000,0x200000,0xb0011ab2, +0x6800100,0x962540,0xb0011ab2,0x7c00100,0x230400,0xb0011b0c,0x7c00100,0x230400,0xb0011cb3,0x2802100,0x962460,0xb0011cb3,0x2806400,0x962460,0xb0011cb3,0x6800000, +0x1329800,0xb0011cb3,0x6800100,0x962540,0xb0011cb3,0x7c00100,0x230400,0xb0011db6,0x2802500,0x962460,0xb0011db6,0x6800000,0x1329800,0xb0011db6,0x7c00100,0x230400, +0xb0011db6,0x7c00500,0x230400,0xb0011e00,0x4000000,0x200000,0xb0011e00,0x4000000,0x1500000,0xb0011fb4,0x2802100,0x962460,0xb0011fb4,0x6800100,0x962540,0xb0011fb4, +0x7c00100,0x430400,0xb0011fb4,0x7c00100,0x2d30400,0xb0011fb4,0xc000010,0x448000,0xb0012000,0x4000000,0x200000,0xb00121b5,0x4000000,0x200000,0xb00121b5,0x4000010, +0x400000,0xb00121b5,0x7c00100,0x220400,0xb00121b5,0x7c00100,0x250400,0xb00121b5,0xc000010,0x448000,0xb00122b8,0x4000000,0x200000,0xb00122b8,0x7c00100,0x230400, +0xb00123b7,0x2802400,0x962460,0xb00123b7,0x4000000,0x200000,0xb00123b7,0x7c00100,0x230400,0xb00123b7,0xc000010,0x248000,0xb00a4005,0x7c00100,0xe30400,0xb00a4711, +0x7c40300,0xe30000,0xb00acf00,0x4000000,0xe00000,0xb00b0500,0x4000000,0xe00000,0xb00b0500,0x4000000,0x2800000,0xb00b109a,0x7c00300,0xe30000,0xb080e487,0x2802000, +0x962460,0xc0001524,0x4000000,0x500000,0xc0001a18,0x2806400,0x1862460,0xc0001a18,0x7c00100,0x1830000,0xc0007300,0x24000000,0x200000,0xc0008e00,0x24000010,0x400000, +0xc0009519,0x7c00100,0x220400,0xc0009519,0x7c00100,0x250400,0xc000c300,0x4000000,0x20000f,0xc000d85c,0x2802100,0x962460,0xc000d85c,0x6800100,0x962540,0xc000d85c, +0x7c00100,0x230400,0xc000dc99,0x7c00100,0x230400,0xc000e719,0x7c00100,0x220400,0xc00107a7,0x7c00100,0x230400,0xc0010eaa,0x7c00100,0x230400,0xc00116b0,0x7c00100, +0x230560,0xc0011900,0x4000000,0x200000,0xc0012447,0,0x818820,0xc0012447,0,0xc18820,0xc0012447,0,0x1418820,0xc00125b9,0x7c00100,0x230400, +0xc00126bb,0x2802100,0x962460,0xc00126bb,0x2806400,0x962460,0xc00126bb,0x4000000,0x500000,0xc00126bb,0x6800100,0x962540,0xc00126bb,0x7c00100,0x230400,0xc00127ba, +0x2802400,0x962460,0xc00127ba,0x4000000,0x200000,0xc00127ba,0x6800000,0x1329800,0xc00127ba,0x7c00100,0x230400,0xc00127ba,0x7c00900,0x230400,0xc0012800,0x4000000, +0x200000,0xc0012b23,0x4000000,0x200000,0xc0012b23,0x4000000,0x400000,0xc0012b23,0x4000000,0x1500000,0xc0012cbc,0x2802400,0x962460,0xc0012cbc,0x4000000,0x1600000, +0xc0012cbc,0x6800000,0x1329800,0xc0012cbc,0x7c00100,0x230400,0xc00acf00,0x4000000,0xe00000,0xc00ae300,0x4000000,0xe00000,0xc00b0500,0x4000000,0xe00000,0xc00b0500, +0x4000000,0x2800000,0xc00b0b11,0x4000000,0x1200000,0xc00b0b11,0x7c00900,0x1230400,0xc00b109a,0x7c00300,0xe30000,0xc00b2914,0x7c00100,0x2530000,0xc00b2916,0x7c00100, +0x2530c00,0xc00b2a00,0x4000000,0xe00000,0xc040af5e,0x7c00100,0x230400,0xc0c12b89,0x4000000,0x200000,0xc14a44cc,0x4000000,0xe0000d,0xd000131f,0x2802c00,0x962460, +0xd000171a,0x7c00100,0x230400,0xd0001821,0x2802100,0x962460,0xd0007300,0x24000000,0x200000,0xd0008e00,0x24000000,0x200000,0xd0008f3a,0x2806000,0x962460,0xd0009519, +0x7c00100,0x220400,0xd0009519,0x7c00100,0x250400,0xd000a500,0x4000000,0x200000,0xd000c300,0x4000000,0xe00000,0xd000d202,0x7c00100,0x230400,0xd000d476,0x7c00100, +0x230400,0xd000d997,0x2802100,0x962460,0xd000d997,0x6800100,0x962540,0xd000e001,0x2802100,0x962460,0xd000e700,0x4000400,0x200000,0xd000e719,0x7c00100,0x220400, +0xd000e719,0x7c00500,0x22040f,0xd000fa00,0x4000000,0xe00000,0xd0010eaa,0x4000010,0x400000,0xd0010eaa,0x7c00100,0x230400,0xd0012dbd,0x4000000,0x200000,0xd0012dbd, +0x7c00100,0x230400,0xd0012fbe,0x2802100,0x962460,0xd0012fbe,0x2802400,0x962460,0xd0012fbe,0x2806400,0x2f62460,0xd0012fbe,0x4000000,0x400000,0xd0012fbe,0x6800000, +0xe29800,0xd0012fbe,0x6800100,0x962540,0xd0012fbe,0x6800100,0x962541,0xd0012fbe,0x6804400,0x962540,0xd0012fbe,0x7c00100,0x2b30400,0xd0012fbe,0x7c00100,0x2c30560, +0xd0012fbe,0xc000010,0x448000,0xd0013183,0x7c00100,0x230400,0xd0013200,0x4000000,0x200000,0xd0013200,0x6800000,0x1329805,0xd00134c0,0x2802100,0x962460,0xd00134c0, +0x4000002,0x400000,0xd00134c0,0x7c00100,0x230400,0xd00a4305,0x7c00100,0xe30400,0xd00a4611,0x7c40300,0xe30000,0xd00a4711,0x7c40300,0xe30000,0xd00a5e11,0x7c40300, +0xe30000,0xd00acf00,0x4000000,0xe00000,0xd00b0500,0x4000000,0xe00000,0xd00b0500,0x4000000,0x2800000,0xd00b0b11,0x6800500,0x962540,0xd00b0bbf,0x2802200,0xc62460, +0xd00b119a,0x7c00300,0xe30000,0xd00b2a00,0x4000000,0xe00000,0xd00b2e11,0x7c40300,0xe30000,0xd00b30bf,0x7c00300,0x230000,0xd00b339a,0x7c00300,0xe30000,0xe0000c02, +0xc000010,0xb48000,0xe0001524,0x2802400,0x962460,0xe0001524,0x7c00100,0x230400,0xe0001615,0x7c00100,0x230400,0xe000251b,0x12882000,0x962460,0xe0002a00,0x4000000, +0x1500000,0xe0005102,0x4000000,0x200000,0xe0005c00,0x4000000,0x200000,0xe000622a,0x6804400,0x962540,0xe000622a,0x7c00100,0x230400,0xe0008838,0x7c00100,0x220400, +0xe0008838,0x7c00100,0x250400,0xe0008e00,0x24000000,0x810000,0xe0008e00,0x24000000,0x1410000,0xe0008e00,0x24000002,0x400000,0xe0008e00,0x2c000010,0xb48000,0xe000933e, +0x7c00100,0x2b30400,0xe000933e,0xc000010,0x448000,0xe0009519,0x7c00100,0x220400,0xe0009519,0x7c00100,0x22040f,0xe0009519,0x7c00100,0x250400,0xe000c178,0x2802100, +0x962460,0xe000c941,0x2802100,0x962460,0xe000c941,0x2806400,0x962460,0xe000c941,0x7c00100,0x2b30400,0xe000d202,0x2802400,0x962460,0xe000d202,0x7c00100,0x230400, +0xe000d202,0x7c00500,0x230400,0xe000dc99,0x4000000,0x200000,0xe000e001,0x2802100,0x962460,0xe000e001,0x2802400,0x962460,0xe000fda1,0x7c00100,0x1830000,0xe0013502, +0x2802400,0x962460,0xe0013502,0x4000000,0x200000,0xe0013502,0x7c00100,0x230400,0xe0013502,0x80000000,0x1329960,0xe00136c1,0x4000000,0x200000,0xe00136c1,0x7c00100, +0x230400,0xe001370b,0x7c00100,0x230400,0xe0013919,0x7c00500,0x220400,0xe0013919,0x7c00500,0x22040f,0xe0013919,0x7c00d00,0x23040f,0xe0013a19,0x7c00100,0x220400, +0xe0013a19,0x7c00100,0x230400,0xe0013bc2,0x2802400,0x962460,0xe0013bc2,0x7c00100,0x230400,0xe0013bc2,0xc000010,0x248000,0xe0013cc3,0x6800000,0x1329800,0xe0013cc3, +0x7c00100,0x230400,0xe0013dc4,0x2802400,0x962460,0xe0013dc4,0x7c00100,0x230400,0xe0013e28,0x7c00100,0x230400,0xe0013fc5,0x7c00100,0x220400,0xe0013fc5,0x7c00100, +0x250400,0xe0014000,0x4000000,0x200000,0xe0014001,0x2802400,0x962460,0xe00a4711,0x7c40300,0xe30000,0xe00a5e11,0x7c40300,0xe30000,0xe00ac511,0x7c40300,0xe30000, +0xe00acf00,0x4000000,0xe00000,0xe00ae300,0x4000000,0xe00000,0xe00b0500,0x4000000,0xe00000,0xe00b1314,0x7c00100,0xe30000,0xe00b1316,0x7c00100,0xe30c00,0xe00b2a00, +0x4000000,0xe00000,0xe00b2a00,0x4000000,0x2800000,0xe00b3816,0x7c00500,0x230c00,0xe0808328,0x2802400,0x962460,0xf0001615,0x6800100,0x962540,0xf0001a18,0x2802000, +0x1862460,0xf000c247,0x7c00100,0x1430400,0xf000d000,0x4000000,0xe00000,0xf000e300,0x4000000,0xe00000,0xf000e59d,0x2802100,0x962460,0xf000e59d,0x7c00100,0x230400, +0xf0012447,0,0x818820,0xf0012447,0,0xc18820,0xf0012447,0,0x1418820,0xf0012447,0x2802000,0x962460,0xf0012447,0x2802400,0x962460,0xf0012447, +0x7c00100,0x230400,0xf0013a19,0x7c00100,0x220400,0xf0014102,0x2802400,0x962460,0xf0014308,0x2802100,0x962460,0xf0014308,0x7c00500,0x22040e,0xf0014308,0x7c00500, +0x22040f,0xf001440a,0x4000000,0x500000,0xf0014500,0x4000000,0x200000,0xf00146c6,0x2802100,0x962460,0xf00146c6,0x2806000,0x2f62460,0xf00146c6,0x4000000,0xe00000, +0xf00146c6,0x6800000,0x2d29800,0xf00146c6,0x6800100,0x962540,0xf00146c6,0x6804000,0x962540,0xf00146c6,0x7c00100,0x2b30400,0xf00146c6,0x7c00100,0x2c30560,0xf00146c6, +0xc000010,0x448000,0xf00147c7,0x2802000,0x962460,0xf00147c7,0x6800000,0x1329800,0xf00147c7,0x7c00100,0x230400,0xf00ac511,0x7c40300,0xe30000,0xf00acf00,0x4000000, +0xe00000,0xf00b2914,0x7c00100,0x2530000,0xf00b2916,0x7c00100,0x2530c00,0xf00b2a00,0x4000000,0xe00000,0xf00b2a00,0x4000000,0x2800000,0xf00b4211,0x7c40300,0xe30000, +0xf10a3c00,0x4000000,0xe00000,0xf10a3c00,0x4008000,0xe00000,0xf10a8200,0x4008000,0xe00000,0xf10b4811,0x7c40300,0xe30000}; -static const int32_t countPropsVectors=7230; +static const int32_t countPropsVectors=7260; static const int32_t propsVectorsColumns=3; -static const uint16_t scriptExtensions[282]={ +static const uint16_t scriptExtensions[298]={ 0x800e,0x8019,8,0x8059,8,2,8,0x8038,8,6,8,0x8019,2,0x22,0x25,0x57, 0xb6,0x80c0,2,0x22,0x8025,2,0x12,2,0x22,0x25,0x57,0xa7,0xb6,0x80c0,2,0x22, 0x54,0x79,0x7b,0xa7,0xb6,0xb7,0x80c2,2,0x8022,2,0x25,0x80c0,2,0x29,2,0x80b6, @@ -3998,14 +4013,15 @@ static const uint16_t scriptExtensions[282]={ 0x80a4,0x10,0x7f,0xf,0x809d,0xf,0x83,0x23,0x8089,0x23,0x87,0x15,0x80bb,0x15,0x8b,0x1c, 0x34,0x8076,0x1c,0x8f,0xc,0x8019,0x2a,0x2b,0x2c,0x802d,0x1b,0x805a,0x800a,4,0xa,0x15, 0x8089,0xa,0x8089,4,0x800a,0xa,0x8097,0xa,0x15,0x1a,0x1f,0x23,0x8024,0xa,0x80bb,4, -0xa,0x15,0x1f,0x24,0x89,0x9e,0x80bb,0x8004,8,0x8022,0x19,0x801b,0xa,0x19,0x8089,5, -0x11,0x12,0x14,0x16,0x8029,5,0x11,0x12,0x14,0x8016,0x8011,5,0x8011,0x11,0x14,0x8016, -0x11,0x8019,0xa,0xf,0x10,0x78,0x91,0x99,0x9d,0x9e,0xa0,0xa3,0x80b2,0xa,0xf,0x10, -0x15,0x1a,0x78,0x91,0x99,0x9d,0x9e,0xa0,0xa3,0xb2,0x80bb,0xa,0xf,0x10,0x15,0x78, -0x91,0x99,0x9d,0x9e,0xa0,0xa3,0xb2,0x80bb,0xa,0xa3,0xa,0x8023,0xa,0xfa,0x19,0x1c, -0x804f,0x37,0x804e,2,0x8057,2,0x8025,2,0x105,0x2f,0x31,0x8053,0x2f,0x31,0x80c1,0x2f, -0x8031,2,0x8007,0x79,0x80c2,0x79,0x113,0x89,0x87,0x8087}; +0xa,0x15,0x1a,0x1f,0x21,0x24,0x89,0x9e,0x80bb,0x8004,8,0x8022,0x19,0x801b,0xa,0x19, +0x8089,5,0x11,0x12,0x14,0x16,0x8029,5,0x11,0x12,0x14,0x8016,0x8011,5,0x8011,0x11, +0x14,0x8016,0x11,0x8019,0xa,0xf,0x10,0x15,0x1a,0x78,0x91,0x97,0x99,0x9d,0x9e,0xa0, +0xa3,0xb2,0x80bb,0xa,0xf,0x10,0x15,0x78,0x91,0x97,0x99,0x9d,0x9e,0xa0,0xa3,0xb2, +0x80bb,0xa,0xf,0x10,0x78,0x91,0x99,0x9d,0x9e,0xa0,0xa3,0x80b2,0xa,0xf,0x10,0x78, +0x91,0x97,0x99,0x9d,0x9e,0xa0,0xa3,0x80b2,0xa,0xa3,0xa,0x8023,0xa,0x10a,0x19,0x1c, +0x804f,0x37,0x804e,2,0x8057,2,0x8025,2,0x115,0x2f,0x31,0x8053,0x2f,0x31,0x80c1,0x2f, +0x8031,2,0x8007,0x79,0x80c2,0x79,0x123,0x89,0x87,0x8087}; -static const int32_t indexes[UPROPS_INDEX_COUNT]={0x2d08,0x2d08,0x2d08,0x2d08,0x6ce6,3,0x8924,0x89b1,0x89b1,0x89b1,0xb47c7,0x2a75a31,0,0,0,0}; +static const int32_t indexes[UPROPS_INDEX_COUNT]={0x2d4e,0x2d4e,0x2d4e,0x2d4e,0x6d50,3,0x89ac,0x8a41,0x8a41,0x8a41,0xb48c7,0x2f75a31,0,0,0,0}; #endif // INCLUDED_FROM_UCHAR_C diff --git a/thirdparty/icu4c/common/ucurr.cpp b/thirdparty/icu4c/common/ucurr.cpp index ffca8aac5f..70b1bbf223 100644 --- a/thirdparty/icu4c/common/ucurr.cpp +++ b/thirdparty/icu4c/common/ucurr.cpp @@ -11,6 +11,8 @@ #if !UCONFIG_NO_FORMATTING +#include <utility> + #include "unicode/ucurr.h" #include "unicode/locid.h" #include "unicode/ures.h" @@ -20,6 +22,7 @@ #include "unicode/usetiter.h" #include "unicode/utf16.h" #include "ustr_imp.h" +#include "bytesinkutil.h" #include "charstr.h" #include "cmemory.h" #include "cstring.h" @@ -520,14 +523,18 @@ ucurr_forLocale(const char* locale, return 0; } - char currency[4]; // ISO currency codes are alpha3 codes. UErrorCode localStatus = U_ZERO_ERROR; - int32_t resLen = uloc_getKeywordValue(locale, "currency", - currency, UPRV_LENGTHOF(currency), &localStatus); - if (U_SUCCESS(localStatus) && resLen == 3 && uprv_isInvariantString(currency, resLen)) { + CharString currency; + { + CharStringByteSink sink(¤cy); + ulocimp_getKeywordValue(locale, "currency", sink, &localStatus); + } + int32_t resLen = currency.length(); + + if (U_SUCCESS(localStatus) && resLen == 3 && uprv_isInvariantString(currency.data(), resLen)) { if (resLen < buffCapacity) { - T_CString_toUpperCase(currency); - u_charsToUChars(currency, buff, resLen); + T_CString_toUpperCase(currency.data()); + u_charsToUChars(currency.data(), buff, resLen); } return u_terminateUChars(buff, buffCapacity, resLen, ec); } @@ -597,11 +604,15 @@ ucurr_forLocale(const char* locale, if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0) { // We don't know about it. Check to see if we support the variant. - uloc_getParent(locale, id, UPRV_LENGTHOF(id), ec); + CharString parent; + { + CharStringByteSink sink(&parent); + ulocimp_getParent(locale, sink, ec); + } *ec = U_USING_FALLBACK_WARNING; - // TODO: Loop over the shortened id rather than recursing and + // TODO: Loop over the parent rather than recursing and // looking again for a currency keyword. - return ucurr_forLocale(id, buff, buffCapacity, ec); + return ucurr_forLocale(parent.data(), buff, buffCapacity, ec); } if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) { // There is nothing to fallback to. Report the failure/warning if possible. @@ -624,20 +635,22 @@ ucurr_forLocale(const char* locale, * @return true if the fallback happened; false if locale is already * root (""). */ -static UBool fallback(char *loc) { - if (!*loc) { +static UBool fallback(CharString& loc) { + if (loc.isEmpty()) { return false; } UErrorCode status = U_ZERO_ERROR; - if (uprv_strcmp(loc, "en_GB") == 0) { + if (loc == "en_GB") { // HACK: See #13368. We need "en_GB" to fall back to "en_001" instead of "en" // in order to consume the correct data strings. This hack will be removed // when proper data sink loading is implemented here. - // NOTE: "001" adds 1 char over "GB". However, both call sites allocate - // arrays with length ULOC_FULLNAME_CAPACITY (plenty of room for en_001). - uprv_strcpy(loc + 3, "001"); + loc.truncate(3); + loc.append("001", status); } else { - uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status); + CharString tmp; + CharStringByteSink sink(&tmp); + ulocimp_getParent(loc.data(), sink, &status); + loc = std::move(tmp); } /* char *i = uprv_strrchr(loc, '_'); @@ -692,9 +705,12 @@ ucurr_getName(const char16_t* currency, // this function. UErrorCode ec2 = U_ZERO_ERROR; - char loc[ULOC_FULLNAME_CAPACITY]; - uloc_getName(locale, loc, sizeof(loc), &ec2); - if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) { + CharString loc; + { + CharStringByteSink sink(&loc); + ulocimp_getName(locale, sink, &ec2); + } + if (U_FAILURE(ec2)) { *ec = U_ILLEGAL_ARGUMENT_ERROR; return 0; } @@ -707,7 +723,7 @@ ucurr_getName(const char16_t* currency, const char16_t* s = nullptr; ec2 = U_ZERO_ERROR; - LocalUResourceBundlePointer rb(ures_open(U_ICUDATA_CURR, loc, &ec2)); + LocalUResourceBundlePointer rb(ures_open(U_ICUDATA_CURR, loc.data(), &ec2)); if (nameStyle == UCURR_NARROW_SYMBOL_NAME || nameStyle == UCURR_FORMAL_SYMBOL_NAME || nameStyle == UCURR_VARIANT_SYMBOL_NAME) { CharString key; @@ -791,9 +807,12 @@ ucurr_getPluralName(const char16_t* currency, // this function. UErrorCode ec2 = U_ZERO_ERROR; - char loc[ULOC_FULLNAME_CAPACITY]; - uloc_getName(locale, loc, sizeof(loc), &ec2); - if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) { + CharString loc; + { + CharStringByteSink sink(&loc); + ulocimp_getName(locale, sink, &ec2); + } + if (U_FAILURE(ec2)) { *ec = U_ILLEGAL_ARGUMENT_ERROR; return 0; } @@ -803,7 +822,7 @@ ucurr_getPluralName(const char16_t* currency, const char16_t* s = nullptr; ec2 = U_ZERO_ERROR; - UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2); + UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc.data(), &ec2); rb = ures_getByKey(rb, CURRENCYPLURALS, rb, &ec2); @@ -904,13 +923,17 @@ getCurrencyNameCount(const char* loc, int32_t* total_currency_name_count, int32_ *total_currency_name_count = 0; *total_currency_symbol_count = 0; const char16_t* s = nullptr; - char locale[ULOC_FULLNAME_CAPACITY] = ""; - uprv_strcpy(locale, loc); + CharString locale; + { + UErrorCode status = U_ZERO_ERROR; + locale.append(loc, status); + if (U_FAILURE(status)) { return; } + } const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv(); for (;;) { UErrorCode ec2 = U_ZERO_ERROR; // TODO: ures_openDirect? - UResourceBundle* rb = ures_open(U_ICUDATA_CURR, locale, &ec2); + UResourceBundle* rb = ures_open(U_ICUDATA_CURR, locale.data(), &ec2); UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, nullptr, &ec2); int32_t n = ures_getSize(curr); for (int32_t i=0; i<n; ++i) { @@ -979,14 +1002,17 @@ collectCurrencyNames(const char* locale, // Look up the Currencies resource for the given locale. UErrorCode ec2 = U_ZERO_ERROR; - char loc[ULOC_FULLNAME_CAPACITY] = ""; - uloc_getName(locale, loc, sizeof(loc), &ec2); - if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) { + CharString loc; + { + CharStringByteSink sink(&loc); + ulocimp_getName(locale, sink, &ec2); + } + if (U_FAILURE(ec2)) { ec = U_ILLEGAL_ARGUMENT_ERROR; } // Get maximum currency name count first. - getCurrencyNameCount(loc, total_currency_name_count, total_currency_symbol_count); + getCurrencyNameCount(loc.data(), total_currency_name_count, total_currency_symbol_count); *currencyNames = (CurrencyNameStruct*)uprv_malloc (sizeof(CurrencyNameStruct) * (*total_currency_name_count)); @@ -1014,7 +1040,7 @@ collectCurrencyNames(const char* locale, for (int32_t localeLevel = 0; ; ++localeLevel) { ec2 = U_ZERO_ERROR; // TODO: ures_openDirect - UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2); + UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc.data(), &ec2); UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, nullptr, &ec2); int32_t n = ures_getSize(curr); for (int32_t i=0; i<n; ++i) { diff --git a/thirdparty/icu4c/common/udata.cpp b/thirdparty/icu4c/common/udata.cpp index 76d970f3f2..88126fc689 100644 --- a/thirdparty/icu4c/common/udata.cpp +++ b/thirdparty/icu4c/common/udata.cpp @@ -1196,7 +1196,7 @@ doOpenChoice(const char *path, const char *type, const char *name, *p = U_FILE_SEP_CHAR; } #if defined (UDATA_DEBUG) - fprintf(stderr, "Changed path from [%s] to [%s]\n", path, altSepPath.s); + fprintf(stderr, "Changed path from [%s] to [%s]\n", path, altSepPath.data()); #endif path = altSepPath.data(); } diff --git a/thirdparty/icu4c/common/uloc.cpp b/thirdparty/icu4c/common/uloc.cpp index 395df1466e..ce49d6c50e 100644 --- a/thirdparty/icu4c/common/uloc.cpp +++ b/thirdparty/icu4c/common/uloc.cpp @@ -103,12 +103,12 @@ static const char * const LANGUAGES[] = { "ba", "bal", "ban", "bar", "bas", "bax", "bbc", "bbj", "be", "bej", "bem", "bew", "bez", "bfd", "bfq", "bg", "bgc", "bgn", "bho", "bi", "bik", "bin", "bjn", "bkm", "bla", - "bm", "bn", "bo", "bpy", "bqi", "br", "bra", "brh", + "blo", "bm", "bn", "bo", "bpy", "bqi", "br", "bra", "brh", "brx", "bs", "bss", "bua", "bug", "bum", "byn", "byv", "ca", "cad", "car", "cay", "cch", "ccp", "ce", "ceb", "cgg", "ch", "chb", "chg", "chk", "chm", "chn", "cho", "chp", "chr", "chy", "ckb", "co", "cop", "cps", "cr", "crh", - "cs", "csb", "cu", "cv", "cy", + "cs", "csb", "csw", "cu", "cv", "cy", "da", "dak", "dar", "dav", "de", "del", "den", "dgr", "din", "dje", "doi", "dsb", "dtp", "dua", "dum", "dv", "dyo", "dyu", "dz", "dzg", @@ -135,7 +135,7 @@ static const char * const LANGUAGES[] = { "kkj", "kl", "kln", "km", "kmb", "kn", "ko", "koi", "kok", "kos", "kpe", "kr", "krc", "kri", "krj", "krl", "kru", "ks", "ksb", "ksf", "ksh", "ku", "kum", "kut", - "kv", "kw", "ky", + "kv", "kw", "kxv", "ky", "la", "lad", "lag", "lah", "lam", "lb", "lez", "lfn", "lg", "li", "lij", "liv", "lkt", "lmo", "ln", "lo", "lol", "loz", "lrc", "lt", "ltg", "lu", "lua", "lui", @@ -169,14 +169,14 @@ static const char * const LANGUAGES[] = { "sv", "sw", "swb", "syc", "syr", "szl", "ta", "tcy", "te", "tem", "teo", "ter", "tet", "tg", "th", "ti", "tig", "tiv", "tk", "tkl", "tkr", - "tlh", "tli", "tly", "tmh", "tn", "to", "tog", "tpi", + "tlh", "tli", "tly", "tmh", "tn", "to", "tog", "tok", "tpi", "tr", "tru", "trv", "ts", "tsd", "tsi", "tt", "ttt", "tum", "tvl", "tw", "twq", "ty", "tyv", "tzm", "udm", "ug", "uga", "uk", "umb", "und", "ur", "uz", - "vai", "ve", "vec", "vep", "vi", "vls", "vmf", "vo", - "vot", "vro", "vun", + "vai", "ve", "vec", "vep", "vi", "vls", "vmf", "vmw", + "vo", "vot", "vro", "vun", "wa", "wae", "wal", "war", "was", "wbp", "wo", "wuu", - "xal", "xh", "xmf", "xog", + "xal", "xh", "xmf", "xnr", "xog", "yao", "yap", "yav", "ybb", "yi", "yo", "yrl", "yue", "za", "zap", "zbl", "zea", "zen", "zgh", "zh", "zu", "zun", "zxx", "zza", @@ -220,12 +220,12 @@ static const char * const LANGUAGES_3[] = { "bak", "bal", "ban", "bar", "bas", "bax", "bbc", "bbj", "bel", "bej", "bem", "bew", "bez", "bfd", "bfq", "bul", "bgc", "bgn", "bho", "bis", "bik", "bin", "bjn", "bkm", "bla", - "bam", "ben", "bod", "bpy", "bqi", "bre", "bra", "brh", + "blo", "bam", "ben", "bod", "bpy", "bqi", "bre", "bra", "brh", "brx", "bos", "bss", "bua", "bug", "bum", "byn", "byv", "cat", "cad", "car", "cay", "cch", "ccp", "che", "ceb", "cgg", "cha", "chb", "chg", "chk", "chm", "chn", "cho", "chp", "chr", "chy", "ckb", "cos", "cop", "cps", "cre", "crh", - "ces", "csb", "chu", "chv", "cym", + "ces", "csb", "csw", "chu", "chv", "cym", "dan", "dak", "dar", "dav", "deu", "del", "den", "dgr", "din", "dje", "doi", "dsb", "dtp", "dua", "dum", "div", "dyo", "dyu", "dzo", "dzg", @@ -252,7 +252,7 @@ static const char * const LANGUAGES_3[] = { "kkj", "kal", "kln", "khm", "kmb", "kan", "kor", "koi", "kok", "kos", "kpe", "kau", "krc", "kri", "krj", "krl", "kru", "kas", "ksb", "ksf", "ksh", "kur", "kum", "kut", - "kom", "cor", "kir", + "kom", "cor", "kxv", "kir", "lat", "lad", "lag", "lah", "lam", "ltz", "lez", "lfn", "lug", "lim", "lij", "liv", "lkt", "lmo", "lin", "lao", "lol", "loz", "lrc", "lit", "ltg", "lub", "lua", "lui", @@ -286,14 +286,14 @@ static const char * const LANGUAGES_3[] = { "swe", "swa", "swb", "syc", "syr", "szl", "tam", "tcy", "tel", "tem", "teo", "ter", "tet", "tgk", "tha", "tir", "tig", "tiv", "tuk", "tkl", "tkr", - "tlh", "tli", "tly", "tmh", "tsn", "ton", "tog", "tpi", + "tlh", "tli", "tly", "tmh", "tsn", "ton", "tog", "tok", "tpi", "tur", "tru", "trv", "tso", "tsd", "tsi", "tat", "ttt", "tum", "tvl", "twi", "twq", "tah", "tyv", "tzm", "udm", "uig", "uga", "ukr", "umb", "und", "urd", "uzb", - "vai", "ven", "vec", "vep", "vie", "vls", "vmf", "vol", - "vot", "vro", "vun", + "vai", "ven", "vec", "vep", "vie", "vls", "vmf", "vmw", + "vol", "vot", "vro", "vun", "wln", "wae", "wal", "war", "was", "wbp", "wol", "wuu", - "xal", "xho", "xmf", "xog", + "xal", "xho", "xmf", "xnr", "xog", "yao", "yap", "yav", "ybb", "yid", "yor", "yrl", "yue", "zha", "zap", "zbl", "zea", "zen", "zgh", "zho", "zul", "zun", "zxx", "zza", @@ -477,25 +477,6 @@ static const CanonicalizationMap CANONICALIZE_MAP[] = { /* ### BCP47 Conversion *******************************************/ /* Test if the locale id has BCP47 u extension and does not have '@' */ #define _hasBCP47Extension(id) (id && uprv_strstr(id, "@") == nullptr && getShortestSubtagLength(localeID) == 1) -/* Converts the BCP47 id to Unicode id. Does nothing to id if conversion fails */ -static const char* _ConvertBCP47( - const char* id, char* buffer, int32_t length, - UErrorCode* err, int32_t* pLocaleIdSize) { - const char* finalID; - int32_t localeIDSize = uloc_forLanguageTag(id, buffer, length, nullptr, err); - if (localeIDSize <= 0 || U_FAILURE(*err) || *err == U_STRING_NOT_TERMINATED_WARNING) { - finalID=id; - if (*err == U_STRING_NOT_TERMINATED_WARNING) { - *err = U_BUFFER_OVERFLOW_ERROR; - } - } else { - finalID=buffer; - } - if (pLocaleIdSize != nullptr) { - *pLocaleIdSize = localeIDSize; - } - return finalID; -} /* Gets the size of the shortest subtag in the given localeID. */ static int32_t getShortestSubtagLength(const char *localeID) { int32_t localeIDLength = static_cast<int32_t>(uprv_strlen(localeID)); @@ -762,7 +743,7 @@ ulocimp_getKeywordValue(const char* localeID, char localeKeywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN]; if(status && U_SUCCESS(*status) && localeID) { - char tempBuffer[ULOC_FULLNAME_CAPACITY]; + CharString tempBuffer; const char* tmpLocaleID; if (keywordName == nullptr || keywordName[0] == 0) { @@ -776,8 +757,9 @@ ulocimp_getKeywordValue(const char* localeID, } if (_hasBCP47Extension(localeID)) { - tmpLocaleID = _ConvertBCP47(localeID, tempBuffer, - sizeof(tempBuffer), status, nullptr); + CharStringByteSink sink(&tempBuffer); + ulocimp_forLanguageTag(localeID, -1, sink, nullptr, status); + tmpLocaleID = U_SUCCESS(*status) && !tempBuffer.isEmpty() ? tempBuffer.data() : localeID; } else { tmpLocaleID=localeID; } @@ -1406,7 +1388,7 @@ U_CAPI UEnumeration* U_EXPORT2 uloc_openKeywords(const char* localeID, UErrorCode* status) { - char tempBuffer[ULOC_FULLNAME_CAPACITY]; + CharString tempBuffer; const char* tmpLocaleID; if(status==nullptr || U_FAILURE(*status)) { @@ -1414,8 +1396,9 @@ uloc_openKeywords(const char* localeID, } if (_hasBCP47Extension(localeID)) { - tmpLocaleID = _ConvertBCP47(localeID, tempBuffer, - sizeof(tempBuffer), status, nullptr); + CharStringByteSink sink(&tempBuffer); + ulocimp_forLanguageTag(localeID, -1, sink, nullptr, status); + tmpLocaleID = U_SUCCESS(*status) && !tempBuffer.isEmpty() ? tempBuffer.data() : localeID; } else { if (localeID==nullptr) { localeID=uloc_getDefault(); @@ -1489,7 +1472,7 @@ _canonicalize(const char* localeID, } int32_t j, fieldCount=0, scriptSize=0, variantSize=0; - PreflightingLocaleIDBuffer tempBuffer; // if localeID has a BCP47 extension, tmpLocaleID points to this + CharString tempBuffer; // if localeID has a BCP47 extension, tmpLocaleID points to this CharString localeIDWithHyphens; // if localeID has a BPC47 extension and have _, tmpLocaleID points to this const char* origLocaleID; const char* tmpLocaleID; @@ -1512,13 +1495,9 @@ _canonicalize(const char* localeID, } } - do { - // After this call tmpLocaleID may point to localeIDPtr which may - // point to either localeID or localeIDWithHyphens.data(). - tmpLocaleID = _ConvertBCP47(localeIDPtr, tempBuffer.getBuffer(), - tempBuffer.getCapacity(), err, - &(tempBuffer.requestedCapacity)); - } while (tempBuffer.needToTryAgain(err)); + CharStringByteSink tempSink(&tempBuffer); + ulocimp_forLanguageTag(localeIDPtr, -1, tempSink, nullptr, err); + tmpLocaleID = U_SUCCESS(*err) && !tempBuffer.isEmpty() ? tempBuffer.data() : localeIDPtr; } else { if (localeID==nullptr) { localeID=uloc_getDefault(); @@ -1677,11 +1656,38 @@ uloc_getParent(const char* localeID, int32_t parentCapacity, UErrorCode* err) { + if (U_FAILURE(*err)) { + return 0; + } + + CheckedArrayByteSink sink(parent, parentCapacity); + ulocimp_getParent(localeID, sink, err); + + int32_t reslen = sink.NumberOfBytesAppended(); + + if (U_FAILURE(*err)) { + return reslen; + } + + if (sink.Overflowed()) { + *err = U_BUFFER_OVERFLOW_ERROR; + } else { + u_terminateChars(parent, parentCapacity, reslen, err); + } + + return reslen; +} + +U_CAPI void U_EXPORT2 +ulocimp_getParent(const char* localeID, + icu::ByteSink& sink, + UErrorCode* err) +{ const char *lastUnderscore; int32_t i; if (U_FAILURE(*err)) - return 0; + return; if (localeID == nullptr) localeID = uloc_getDefault(); @@ -1697,13 +1703,9 @@ uloc_getParent(const char* localeID, if (uprv_strnicmp(localeID, "und_", 4) == 0) { localeID += 3; i -= 3; - uprv_memmove(parent, localeID, uprv_min(i, parentCapacity)); - } else if (parent != localeID) { - uprv_memcpy(parent, localeID, uprv_min(i, parentCapacity)); } + sink.Append(localeID, i); } - - return u_terminateChars(parent, parentCapacity, i, err); } U_CAPI int32_t U_EXPORT2 @@ -1795,7 +1797,7 @@ uloc_getVariant(const char* localeID, int32_t variantCapacity, UErrorCode* err) { - char tempBuffer[ULOC_FULLNAME_CAPACITY]; + CharString tempBuffer; const char* tmpLocaleID; int32_t i=0; @@ -1804,7 +1806,9 @@ uloc_getVariant(const char* localeID, } if (_hasBCP47Extension(localeID)) { - tmpLocaleID =_ConvertBCP47(localeID, tempBuffer, sizeof(tempBuffer), err, nullptr); + CharStringByteSink sink(&tempBuffer); + ulocimp_forLanguageTag(localeID, -1, sink, nullptr, err); + tmpLocaleID = U_SUCCESS(*err) && !tempBuffer.isEmpty() ? tempBuffer.data() : localeID; } else { if (localeID==nullptr) { localeID=uloc_getDefault(); diff --git a/thirdparty/icu4c/common/uloc_tag.cpp b/thirdparty/icu4c/common/uloc_tag.cpp index 43d597549f..fe3261c75d 100644 --- a/thirdparty/icu4c/common/uloc_tag.cpp +++ b/thirdparty/icu4c/common/uloc_tag.cpp @@ -1326,14 +1326,23 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st attrBufLength = 0; for (; i < len; i++) { if (buf[i] != '-') { - attrBuf[attrBufLength++] = buf[i]; + if (static_cast<size_t>(attrBufLength) < sizeof(attrBuf)) { + attrBuf[attrBufLength++] = buf[i]; + } else { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } } else { i++; break; } } if (attrBufLength > 0) { - attrBuf[attrBufLength] = 0; + if (static_cast<size_t>(attrBufLength) < sizeof(attrBuf)) { + attrBuf[attrBufLength] = 0; + } else { + *status = U_STRING_NOT_TERMINATED_WARNING; + } } else if (i >= len){ break; @@ -1879,11 +1888,8 @@ static void _appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool strict, UBool hadPosix, UErrorCode* status) { (void)hadPosix; char buf[ULOC_FULLNAME_CAPACITY]; - char tmpAppend[ULOC_FULLNAME_CAPACITY]; UErrorCode tmpStatus = U_ZERO_ERROR; int32_t len, i; - int32_t reslen = 0; - int32_t capacity = sizeof tmpAppend; if (U_FAILURE(*status)) { return; @@ -1936,37 +1942,18 @@ _appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool } if (writeValue) { - if (reslen < capacity) { - tmpAppend[reslen++] = SEP; - } + sink.Append("-", 1); if (firstValue) { - if (reslen < capacity) { - tmpAppend[reslen++] = *PRIVATEUSE_KEY; - } - - if (reslen < capacity) { - tmpAppend[reslen++] = SEP; - } - - len = (int32_t)uprv_strlen(PRIVUSE_VARIANT_PREFIX); - if (reslen < capacity) { - uprv_memcpy(tmpAppend + reslen, PRIVUSE_VARIANT_PREFIX, uprv_min(len, capacity - reslen)); - } - reslen += len; - - if (reslen < capacity) { - tmpAppend[reslen++] = SEP; - } - + sink.Append(PRIVATEUSE_KEY, UPRV_LENGTHOF(PRIVATEUSE_KEY) - 1); + sink.Append("-", 1); + sink.Append(PRIVUSE_VARIANT_PREFIX, UPRV_LENGTHOF(PRIVUSE_VARIANT_PREFIX) - 1); + sink.Append("-", 1); firstValue = false; } len = (int32_t)uprv_strlen(pPriv); - if (reslen < capacity) { - uprv_memcpy(tmpAppend + reslen, pPriv, uprv_min(len, capacity - reslen)); - } - reslen += len; + sink.Append(pPriv, len); } } /* reset private use starting position */ @@ -1976,15 +1963,6 @@ _appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool } p++; } - - if (U_FAILURE(*status)) { - return; - } - } - - if (U_SUCCESS(*status)) { - len = reslen; - sink.Append(tmpAppend, len); } } @@ -2092,12 +2070,13 @@ ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* sta int32_t oldTagLength = tagLen; if (tagLen < newTagLength) { uprv_free(tagBuf); - tagBuf = (char*)uprv_malloc(newTagLength + 1); + // Change t->buf after the free and before return to avoid the second double free in + // the destructor of t when t is out of scope. + t->buf = tagBuf = (char*)uprv_malloc(newTagLength + 1); if (tagBuf == nullptr) { *status = U_MEMORY_ALLOCATION_ERROR; return nullptr; } - t->buf = tagBuf; tagLen = newTagLength; } parsedLenDelta = checkLegacyLen - replacementLen; @@ -2646,53 +2625,18 @@ ulocimp_toLanguageTag(const char* localeID, UBool strict, UErrorCode* status) { icu::CharString canonical; - int32_t reslen; UErrorCode tmpStatus = U_ZERO_ERROR; UBool hadPosix = false; const char* pKeywordStart; /* Note: uloc_canonicalize returns "en_US_POSIX" for input locale ID "". See #6835 */ - int32_t resultCapacity = static_cast<int32_t>(uprv_strlen(localeID)); - if (resultCapacity > 0) { - char* buffer; - - for (;;) { - buffer = canonical.getAppendBuffer( - /*minCapacity=*/resultCapacity, - /*desiredCapacityHint=*/resultCapacity, - resultCapacity, - tmpStatus); - - if (U_FAILURE(tmpStatus)) { - *status = tmpStatus; - return; - } - - reslen = - uloc_canonicalize(localeID, buffer, resultCapacity, &tmpStatus); - - if (tmpStatus != U_BUFFER_OVERFLOW_ERROR) { - break; - } - - resultCapacity = reslen; - tmpStatus = U_ZERO_ERROR; - } - - if (U_FAILURE(tmpStatus)) { - *status = U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - canonical.append(buffer, reslen, tmpStatus); - if (tmpStatus == U_STRING_NOT_TERMINATED_WARNING) { - tmpStatus = U_ZERO_ERROR; // Terminators provided by CharString. - } - - if (U_FAILURE(tmpStatus)) { - *status = tmpStatus; - return; - } + { + icu::CharStringByteSink canonicalSink(&canonical); + ulocimp_canonicalize(localeID, canonicalSink, &tmpStatus); + } + if (U_FAILURE(tmpStatus)) { + *status = tmpStatus; + return; } /* For handling special case - private use only tag */ diff --git a/thirdparty/icu4c/common/ulocale.cpp b/thirdparty/icu4c/common/ulocale.cpp new file mode 100644 index 0000000000..471ef0ce79 --- /dev/null +++ b/thirdparty/icu4c/common/ulocale.cpp @@ -0,0 +1,99 @@ +// © 2023 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +// +#include "unicode/errorcode.h" +#include "unicode/stringpiece.h" +#include "unicode/utypes.h" +#include "unicode/ustring.h" +#include "unicode/ulocale.h" +#include "unicode/locid.h" + +#include "charstr.h" +#include "cmemory.h" +#include "ustr_imp.h" + +U_NAMESPACE_USE +#define EXTERNAL(i) (reinterpret_cast<ULocale*>(i)) +#define CONST_INTERNAL(e) (reinterpret_cast<const icu::Locale*>(e)) +#define INTERNAL(e) (reinterpret_cast<icu::Locale*>(e)) + +ULocale* +ulocale_openForLocaleID(const char* localeID, int32_t length, UErrorCode* err) { + CharString str(length < 0 ? StringPiece(localeID) : StringPiece(localeID, length), *err); + if (U_FAILURE(*err)) return nullptr; + return EXTERNAL(icu::Locale::createFromName(str.data()).clone()); +} + +ULocale* +ulocale_openForLanguageTag(const char* tag, int32_t length, UErrorCode* err) { + Locale l = icu::Locale::forLanguageTag(length < 0 ? StringPiece(tag) : StringPiece(tag, length), *err); + if (U_FAILURE(*err)) return nullptr; + return EXTERNAL(l.clone()); +} + +void +ulocale_close(ULocale* locale) { + delete INTERNAL(locale); +} + +#define IMPL_ULOCALE_STRING_GETTER(N1, N2) \ +const char* ulocale_get ## N1(const ULocale* locale) { \ + if (locale == nullptr) return nullptr; \ + return CONST_INTERNAL(locale)->get ## N2(); \ +} + +#define IMPL_ULOCALE_STRING_IDENTICAL_GETTER(N) IMPL_ULOCALE_STRING_GETTER(N, N) + +#define IMPL_ULOCALE_GET_KEYWORD_VALUE(N) \ +int32_t ulocale_get ##N ( \ + const ULocale* locale, const char* keyword, int32_t keywordLength, \ + char* valueBuffer, int32_t bufferCapacity, UErrorCode *err) { \ + if (U_FAILURE(*err)) return 0; \ + if (locale == nullptr) { \ + *err = U_ILLEGAL_ARGUMENT_ERROR; \ + return 0; \ + } \ + CheckedArrayByteSink sink(valueBuffer, bufferCapacity); \ + CONST_INTERNAL(locale)->get ## N( \ + keywordLength < 0 ? StringPiece(keyword) : StringPiece(keyword, keywordLength), \ + sink, *err); \ + int32_t reslen = sink.NumberOfBytesAppended(); \ + if (U_FAILURE(*err)) { \ + return reslen; \ + } \ + if (sink.Overflowed()) { \ + *err = U_BUFFER_OVERFLOW_ERROR; \ + } else { \ + u_terminateChars(valueBuffer, bufferCapacity, reslen, err); \ + } \ + return reslen; \ +} + +#define IMPL_ULOCALE_GET_KEYWORDS(N) \ +UEnumeration* ulocale_get ## N(const ULocale* locale, UErrorCode *err) { \ + if (U_FAILURE(*err)) return nullptr; \ + if (locale == nullptr) { \ + *err = U_ILLEGAL_ARGUMENT_ERROR; \ + return nullptr; \ + } \ + return uenum_openFromStringEnumeration( \ + CONST_INTERNAL(locale)->create ## N(*err), err); \ +} + +IMPL_ULOCALE_STRING_IDENTICAL_GETTER(Language) +IMPL_ULOCALE_STRING_IDENTICAL_GETTER(Script) +IMPL_ULOCALE_STRING_GETTER(Region, Country) +IMPL_ULOCALE_STRING_IDENTICAL_GETTER(Variant) +IMPL_ULOCALE_STRING_GETTER(LocaleID, Name) +IMPL_ULOCALE_STRING_IDENTICAL_GETTER(BaseName) +IMPL_ULOCALE_GET_KEYWORD_VALUE(KeywordValue) +IMPL_ULOCALE_GET_KEYWORD_VALUE(UnicodeKeywordValue) +IMPL_ULOCALE_GET_KEYWORDS(Keywords) +IMPL_ULOCALE_GET_KEYWORDS(UnicodeKeywords) + +bool ulocale_isBogus(const ULocale* locale) { + if (locale == nullptr) return false; + return CONST_INTERNAL(locale)->isBogus(); +} + +/*eof*/ diff --git a/thirdparty/icu4c/common/ulocbuilder.cpp b/thirdparty/icu4c/common/ulocbuilder.cpp new file mode 100644 index 0000000000..a5af73bef4 --- /dev/null +++ b/thirdparty/icu4c/common/ulocbuilder.cpp @@ -0,0 +1,156 @@ +// © 2023 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include <utility> + +#include "unicode/bytestream.h" +#include "unicode/localebuilder.h" +#include "unicode/locid.h" +#include "unicode/stringpiece.h" +#include "unicode/umachine.h" +#include "unicode/ulocbuilder.h" +#include "cstring.h" +#include "ustr_imp.h" + +using icu::CheckedArrayByteSink; +using icu::StringPiece; + +#define EXTERNAL(i) (reinterpret_cast<ULocaleBuilder*>(i)) +#define INTERNAL(e) (reinterpret_cast<icu::LocaleBuilder*>(e)) +#define CONST_INTERNAL(e) (reinterpret_cast<const icu::LocaleBuilder*>(e)) + +ULocaleBuilder* ulocbld_open() { + return EXTERNAL(new icu::LocaleBuilder()); +} + +void ulocbld_close(ULocaleBuilder* builder) { + if (builder == nullptr) return; + delete INTERNAL(builder); +} + +void ulocbld_setLocale(ULocaleBuilder* builder, const char* locale, int32_t length) { + if (builder == nullptr) return; + icu::Locale l; + if (length < 0 || locale[length] == '\0') { + l = icu::Locale(locale); + } else { + if (length >= ULOC_FULLNAME_CAPACITY) { + l.setToBogus(); + } else { + // locale is not null termined but Locale API require one. + // Create a null termined version in buf. + char buf[ULOC_FULLNAME_CAPACITY]; + uprv_memcpy(buf, locale, length); + buf[length] = '\0'; + l = icu::Locale(buf); + } + } + INTERNAL(builder)->setLocale(l); +} + +void +ulocbld_adoptULocale(ULocaleBuilder* builder, ULocale* locale) { + if (builder == nullptr) return; + INTERNAL(builder)->setLocale(*(reinterpret_cast<const icu::Locale*>(locale))); + ulocale_close(locale); +} + +#define STRING_PIECE(s, l) ((l)<0 ? StringPiece(s) : StringPiece((s), (l))) + +#define IMPL_ULOCBLD_SETTER(N) \ +void ulocbld_##N(ULocaleBuilder* bld, const char* s, int32_t l) { \ + if (bld == nullptr) return; \ + INTERNAL(bld)->N(STRING_PIECE(s,l)); \ +} + +IMPL_ULOCBLD_SETTER(setLanguageTag) +IMPL_ULOCBLD_SETTER(setLanguage) +IMPL_ULOCBLD_SETTER(setScript) +IMPL_ULOCBLD_SETTER(setRegion) +IMPL_ULOCBLD_SETTER(setVariant) +IMPL_ULOCBLD_SETTER(addUnicodeLocaleAttribute) +IMPL_ULOCBLD_SETTER(removeUnicodeLocaleAttribute) + +void ulocbld_setExtension(ULocaleBuilder* builder, char key, const char* value, int32_t length) { + if (builder == nullptr) return; + INTERNAL(builder)->setExtension(key, STRING_PIECE(value, length)); +} + +void ulocbld_setUnicodeLocaleKeyword( + ULocaleBuilder* builder, const char* key, int32_t keyLength, + const char* type, int32_t typeLength) { + if (builder == nullptr) return; + INTERNAL(builder)->setUnicodeLocaleKeyword( + STRING_PIECE(key, keyLength), STRING_PIECE(type, typeLength)); +} + +void ulocbld_clear(ULocaleBuilder* builder) { + if (builder == nullptr) return; + INTERNAL(builder)->clear(); +} + +void ulocbld_clearExtensions(ULocaleBuilder* builder) { + if (builder == nullptr) return; + INTERNAL(builder)->clearExtensions(); +} + + +ULocale* ulocbld_buildULocale(ULocaleBuilder* builder, UErrorCode* err) { + if (builder == nullptr) { + *err = U_ILLEGAL_ARGUMENT_ERROR; + return nullptr; + } + icu::Locale l = INTERNAL(builder)->build(*err); + if (U_FAILURE(*err)) return nullptr; + icu::Locale* r = l.clone(); + if (r == nullptr) { + *err = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + return reinterpret_cast<ULocale*>(r); +} + +int32_t ulocbld_buildLocaleID(ULocaleBuilder* builder, + char* buffer, int32_t bufferCapacity, UErrorCode* err) { + if (builder == nullptr) { + *err = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + icu::Locale l = INTERNAL(builder)->build(*err); + if (U_FAILURE(*err)) return 0; + int32_t length = (int32_t)(uprv_strlen(l.getName())); + if (0 < length && length <= bufferCapacity) { + uprv_memcpy(buffer, l.getName(), length); + } + return u_terminateChars(buffer, bufferCapacity, length, err); +} + +int32_t ulocbld_buildLanguageTag(ULocaleBuilder* builder, + char* buffer, int32_t bufferCapacity, UErrorCode* err) { + if (builder == nullptr) { + *err = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + icu::Locale l = INTERNAL(builder)->build(*err); + if (U_FAILURE(*err)) return 0; + CheckedArrayByteSink sink(buffer, bufferCapacity); + l.toLanguageTag(sink, *err); + int32_t reslen = sink.NumberOfBytesAppended(); + if (U_FAILURE(*err)) { + return reslen; + } + if (sink.Overflowed()) { + *err = U_BUFFER_OVERFLOW_ERROR; + } else { + u_terminateChars(buffer, bufferCapacity, reslen, err); + } + return reslen; +} + +UBool ulocbld_copyErrorTo(const ULocaleBuilder* builder, UErrorCode *outErrorCode) { + if (builder == nullptr) { + *outErrorCode = U_ILLEGAL_ARGUMENT_ERROR; + return true; + } + return CONST_INTERNAL(builder)->copyErrorTo(*outErrorCode); +} diff --git a/thirdparty/icu4c/common/ulocimp.h b/thirdparty/icu4c/common/ulocimp.h index 48341054e3..efa0fa72e6 100644 --- a/thirdparty/icu4c/common/ulocimp.h +++ b/thirdparty/icu4c/common/ulocimp.h @@ -92,6 +92,11 @@ ulocimp_getKeywordValue(const char* localeID, icu::ByteSink& sink, UErrorCode* status); +U_CAPI void U_EXPORT2 +ulocimp_getParent(const char* localeID, + icu::ByteSink& sink, + UErrorCode* err); + /** * Writes a well-formed language tag for this locale ID. * @@ -237,6 +242,7 @@ ulocimp_addLikelySubtags(const char* localeID, * * @param localeID The locale to minimize * @param sink The output sink receiving the maximized locale + * @param favorScript favor to keep script if true, region if false. * @param err Error information if minimizing the locale failed. If the length * of the localeID and the null-terminator is greater than the maximum allowed size, * or the localeId is not well-formed, the error code is U_ILLEGAL_ARGUMENT_ERROR. @@ -245,6 +251,7 @@ ulocimp_addLikelySubtags(const char* localeID, U_CAPI void U_EXPORT2 ulocimp_minimizeSubtags(const char* localeID, icu::ByteSink& sink, + bool favorScript, UErrorCode* err); U_CAPI const char * U_EXPORT2 @@ -307,72 +314,4 @@ U_CAPI const char* const* ulocimp_getKnownCanonicalizedLocaleForTest(int32_t* le // Return true if the value is already canonicalized. U_CAPI bool ulocimp_isCanonicalizedLocaleForTest(const char* localeName); -/** - * A utility class for handling locale IDs that may be longer than ULOC_FULLNAME_CAPACITY. - * This encompasses all of the logic to allocate a temporary locale ID buffer on the stack, - * and then, if it's not big enough, reallocate it on the heap and try again. - * - * You use it like this: - * UErrorCode err = U_ZERO_ERROR; - * - * PreflightingLocaleIDBuffer tempBuffer; - * do { - * tempBuffer.requestedCapacity = uloc_doSomething(localeID, tempBuffer.getBuffer(), tempBuffer.getCapacity(), &err); - * } while (tempBuffer.needToTryAgain(&err)); - * if (U_SUCCESS(err)) { - * uloc_doSomethingWithTheResult(tempBuffer.getBuffer()); - * } - */ -class PreflightingLocaleIDBuffer { -private: - char stackBuffer[ULOC_FULLNAME_CAPACITY]; - char* heapBuffer = nullptr; - int32_t capacity = ULOC_FULLNAME_CAPACITY; - -public: - int32_t requestedCapacity = ULOC_FULLNAME_CAPACITY; - - // No heap allocation. Use only on the stack. - static void* U_EXPORT2 operator new(size_t) noexcept = delete; - static void* U_EXPORT2 operator new[](size_t) noexcept = delete; -#if U_HAVE_PLACEMENT_NEW - static void* U_EXPORT2 operator new(size_t, void*) noexcept = delete; -#endif - - PreflightingLocaleIDBuffer() {} - - ~PreflightingLocaleIDBuffer() { uprv_free(heapBuffer); } - - char* getBuffer() { - if (heapBuffer == nullptr) { - return stackBuffer; - } else { - return heapBuffer; - } - } - - int32_t getCapacity() { - return capacity; - } - - bool needToTryAgain(UErrorCode* err) { - if (heapBuffer != nullptr) { - return false; - } - - if (*err == U_BUFFER_OVERFLOW_ERROR || *err == U_STRING_NOT_TERMINATED_WARNING) { - int32_t newCapacity = requestedCapacity + 2; // one for the terminating null, one just for paranoia - heapBuffer = static_cast<char*>(uprv_malloc(newCapacity)); - if (heapBuffer == nullptr) { - *err = U_MEMORY_ALLOCATION_ERROR; - } else { - *err = U_ZERO_ERROR; - capacity = newCapacity; - } - return U_SUCCESS(*err); - } - return false; - } -}; - #endif diff --git a/thirdparty/icu4c/common/unicode/brkiter.h b/thirdparty/icu4c/common/unicode/brkiter.h index 108652799e..1b10e6ef11 100644 --- a/thirdparty/icu4c/common/unicode/brkiter.h +++ b/thirdparty/icu4c/common/unicode/brkiter.h @@ -649,6 +649,7 @@ private: /** @internal (private) */ char actualLocale[ULOC_FULLNAME_CAPACITY]; char validLocale[ULOC_FULLNAME_CAPACITY]; + char requestLocale[ULOC_FULLNAME_CAPACITY]; }; #ifndef U_HIDE_DEPRECATED_API diff --git a/thirdparty/icu4c/common/unicode/docmain.h b/thirdparty/icu4c/common/unicode/docmain.h index 1349f49703..581b2e186d 100644 --- a/thirdparty/icu4c/common/unicode/docmain.h +++ b/thirdparty/icu4c/common/unicode/docmain.h @@ -114,7 +114,7 @@ * </tr> * <tr> * <td>Locales </td> - * <td>uloc.h</a></td> + * <td>uloc.h, ulocale.h, ulocbuilder.h</a></td> * <td>icu::Locale, icu::LocaleBuilder, icu::LocaleMatcher</td> * </tr> * <tr> diff --git a/thirdparty/icu4c/common/unicode/locid.h b/thirdparty/icu4c/common/unicode/locid.h index a6fbbb7041..f0bdc7ca51 100644 --- a/thirdparty/icu4c/common/unicode/locid.h +++ b/thirdparty/icu4c/common/unicode/locid.h @@ -984,7 +984,10 @@ public: static const char* const* U_EXPORT2 getISOCountries(); /** - * Gets a list of all available language codes defined in ISO 639. This is a pointer + * Returns a list of all unique language codes defined in ISO 639. + * They can be 2 or 3 letter codes, as defined by + * <a href="https://www.ietf.org/rfc/bcp/bcp47.html#section-2.2.1"> + * BCP 47, section 2.2.1</a>. This is a pointer * to an array of pointers to arrays of char. All of these pointers are owned * by ICU-- do not delete them, and do not write through them. The array is * terminated with a null pointer. @@ -1110,6 +1113,15 @@ protected: /* only protected for testing purposes. DO NOT USE. */ * @internal */ void setFromPOSIXID(const char *posixID); + /** + * Minimize the subtags for this Locale, per the algorithm described + * @param favorScript favor to keep script if true, to keep region if false. + * @param status error information if maximizing this Locale failed. + * If this Locale is not well-formed, the error code is + * U_ILLEGAL_ARGUMENT_ERROR. + * @internal + */ + void minimizeSubtags(bool favorScript, UErrorCode& status); #endif /* U_HIDE_INTERNAL_API */ private: diff --git a/thirdparty/icu4c/common/unicode/normalizer2.h b/thirdparty/icu4c/common/unicode/normalizer2.h index 972894ec42..6856ff8720 100644 --- a/thirdparty/icu4c/common/unicode/normalizer2.h +++ b/thirdparty/icu4c/common/unicode/normalizer2.h @@ -147,7 +147,10 @@ public: getNFKDInstance(UErrorCode &errorCode); /** - * Returns a Normalizer2 instance for Unicode NFKC_Casefold normalization. + * Returns a Normalizer2 instance for Unicode toNFKC_Casefold() normalization + * which is equivalent to applying the NFKC_Casefold mappings and then NFC. + * See https://www.unicode.org/reports/tr44/#NFKC_Casefold + * * Same as getInstance(nullptr, "nfkc_cf", UNORM2_COMPOSE, errorCode). * Returns an unmodifiable singleton instance. Do not delete it. * @param errorCode Standard ICU error code. Its input value must @@ -160,6 +163,25 @@ public: static const Normalizer2 * getNFKCCasefoldInstance(UErrorCode &errorCode); +#ifndef U_HIDE_DRAFT_API + /** + * Returns a Normalizer2 instance for a variant of Unicode toNFKC_Casefold() normalization + * which is equivalent to applying the NFKC_Simple_Casefold mappings and then NFC. + * See https://www.unicode.org/reports/tr44/#NFKC_Simple_Casefold + * + * Same as getInstance(nullptr, "nfkc_scf", UNORM2_COMPOSE, errorCode). + * Returns an unmodifiable singleton instance. Do not delete it. + * @param errorCode Standard ICU error code. Its input value must + * pass the U_SUCCESS() test, or else the function returns + * immediately. Check for U_FAILURE() on output or use with + * function chaining. (See User Guide for details.) + * @return the requested Normalizer2, if successful + * @draft ICU 74 + */ + static const Normalizer2 * + getNFKCSimpleCasefoldInstance(UErrorCode &errorCode); +#endif // U_HIDE_DRAFT_API + /** * Returns a Normalizer2 instance which uses the specified data file * (packageName/name similar to ucnv_openPackage() and ures_open()/ResourceBundle) @@ -172,7 +194,7 @@ public: * Use name="nfkc_cf" and UNORM2_COMPOSE for Unicode standard NFKC_CF=NFKC_Casefold. * * @param packageName nullptr for ICU built-in data, otherwise application data package name - * @param name "nfc" or "nfkc" or "nfkc_cf" or name of custom data file + * @param name "nfc" or "nfkc" or "nfkc_cf" or "nfkc_scf" or name of custom data file * @param mode normalization mode (compose or decompose etc.) * @param errorCode Standard ICU error code. Its input value must * pass the U_SUCCESS() test, or else the function returns diff --git a/thirdparty/icu4c/common/unicode/rbbi.h b/thirdparty/icu4c/common/unicode/rbbi.h index 418b52e41f..045238ac5d 100644 --- a/thirdparty/icu4c/common/unicode/rbbi.h +++ b/thirdparty/icu4c/common/unicode/rbbi.h @@ -43,6 +43,69 @@ class RBBIDataWrapper; class UnhandledEngine; class UStack; + +#ifndef U_HIDE_DRAFT_API +/** + * The ExternalBreakEngine class define an abstract interface for the host environment + * to provide a low level facility to break text for unicode text in script that the text boundary + * cannot be handled by upper level rule based logic, for example, for Chinese and Japanese + * word breaking, Thai, Khmer, Burmese, Lao and other Southeast Asian scripts. + * The host environment implement one or more subclass of ExternalBreakEngine and + * register them in the initialization time by calling + * RuleBasedBreakIterator::registerExternalBreakEngine(). ICU adopt and own the engine and will + * delete the registered external engine in proper time during the clean up + * event. + * @internal ICU 74 technology preview + */ +class ExternalBreakEngine : public UObject { + public: + /** + * destructor + * @internal ICU 74 technology preview + */ + virtual ~ExternalBreakEngine() {} + + /** + * <p>Indicate whether this engine handles a particular character when + * the RuleBasedBreakIterator is used for a particular locale. This method is used + * by the RuleBasedBreakIterator to find a break engine.</p> + * @param c A character which begins a run that the engine might handle. + * @param locale The locale. + * @return true if this engine handles the particular character for that locale. + * @internal ICU 74 technology preview + */ + virtual bool isFor(UChar32 c, const char* locale) const = 0; + + /** + * <p>Indicate whether this engine handles a particular character.This method is + * used by the RuleBasedBreakIterator after it already find a break engine to see which + * characters after the first one can be handled by this break engine.</p> + * @param c A character that the engine might handle. + * @return true if this engine handles the particular character. + * @internal ICU 74 technology preview + */ + virtual bool handles(UChar32 c) const = 0; + + /** + * <p>Divide up a range of text handled by this break engine.</p> + * + * @param text A UText representing the text + * @param start The start of the range of known characters + * @param end The end of the range of known characters + * @param foundBreaks Output of C array of int32_t break positions, or + * nullptr + * @param foundBreaksCapacity The capacity of foundBreaks + * @param status Information on any errors encountered. + * @return The number of breaks found + * @internal ICU 74 technology preview + */ + virtual int32_t fillBreaks(UText* text, int32_t start, int32_t end, + int32_t* foundBreaks, int32_t foundBreaksCapacity, + UErrorCode& status) const = 0; +}; +#endif /* U_HIDE_DRAFT_API */ + + /** * * A subclass of BreakIterator whose behavior is specified using a list of rules. @@ -716,9 +779,10 @@ private: * This function returns the appropriate LanguageBreakEngine for a * given character c. * @param c A character in the dictionary set + * @param locale The locale. * @internal (private) */ - const LanguageBreakEngine *getLanguageBreakEngine(UChar32 c); + const LanguageBreakEngine *getLanguageBreakEngine(UChar32 c, const char* locale); public: #ifndef U_HIDE_INTERNAL_API @@ -734,8 +798,24 @@ private: */ void dumpTables(); #endif /* U_HIDE_INTERNAL_API */ + +#ifndef U_HIDE_DRAFT_API + /** + * Register a new external break engine. The external break engine will be adopted. + * Because ICU may choose to cache break engine internally, this must + * be called at application startup, prior to any calls to + * object methods of RuleBasedBreakIterator to avoid undefined behavior. + * @param toAdopt the ExternalBreakEngine instance to be adopted + * @param status the in/out status code, no special meanings are assigned + * @internal ICU 74 technology preview + */ + static void U_EXPORT2 registerExternalBreakEngine( + ExternalBreakEngine* toAdopt, UErrorCode& status); +#endif /* U_HIDE_DRAFT_API */ + }; + U_NAMESPACE_END #endif /* #if !UCONFIG_NO_BREAK_ITERATION */ diff --git a/thirdparty/icu4c/common/unicode/uchar.h b/thirdparty/icu4c/common/unicode/uchar.h index 4f82a9fb58..7470891338 100644 --- a/thirdparty/icu4c/common/unicode/uchar.h +++ b/thirdparty/icu4c/common/unicode/uchar.h @@ -60,7 +60,7 @@ U_CDECL_BEGIN * @see u_getUnicodeVersion * @stable ICU 2.0 */ -#define U_UNICODE_VERSION "15.0" +#define U_UNICODE_VERSION "15.1" /** * \file @@ -532,12 +532,33 @@ typedef enum UProperty { * @stable ICU 70 */ UCHAR_RGI_EMOJI=71, +#ifndef U_HIDE_DRAFT_API + /** + * Binary property IDS_Unary_Operator. + * For programmatic determination of Ideographic Description Sequences. + * + * @draft ICU 74 + */ + UCHAR_IDS_UNARY_OPERATOR=72, + /** + * Binary property ID_Compat_Math_Start. + * Used in mathematical identifier profile in UAX #31. + * @draft ICU 74 + */ + UCHAR_ID_COMPAT_MATH_START=73, + /** + * Binary property ID_Compat_Math_Continue. + * Used in mathematical identifier profile in UAX #31. + * @draft ICU 74 + */ + UCHAR_ID_COMPAT_MATH_CONTINUE=74, +#endif // U_HIDE_DRAFT_API #ifndef U_HIDE_DEPRECATED_API /** * One more than the last constant for binary Unicode properties. * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420. */ - UCHAR_BINARY_LIMIT=72, + UCHAR_BINARY_LIMIT=75, #endif // U_HIDE_DEPRECATED_API /** Enumerated property Bidi_Class. @@ -1900,6 +1921,11 @@ enum UBlockCode { /** @stable ICU 72 */ UBLOCK_NAG_MUNDARI = 327, /*[1E4D0]*/ + // New block in Unicode 15.1 + + /** @stable ICU 74 */ + UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_I = 328, /*[2EBF0]*/ + #ifndef U_HIDE_DEPRECATED_API /** * One more than the highest normal UBlockCode value. @@ -1907,7 +1933,7 @@ enum UBlockCode { * * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420. */ - UBLOCK_COUNT = 328, + UBLOCK_COUNT = 329, #endif // U_HIDE_DEPRECATED_API /** @stable ICU 2.0 */ @@ -2439,6 +2465,16 @@ typedef enum ULineBreak { U_LB_E_MODIFIER = 41, /*[EM]*/ /** @stable ICU 58 */ U_LB_ZWJ = 42, /*[ZWJ]*/ + /** @stable ICU 74 */ + U_LB_AKSARA = 43, /*[AK]*/ + /** @stable ICU 74 */ + U_LB_AKSARA_PREBASE = 44, /*[AP]*/ + /** @stable ICU 74 */ + U_LB_AKSARA_START = 45, /*[AS]*/ + /** @stable ICU 74 */ + U_LB_VIRAMA_FINAL = 46, /*[VF]*/ + /** @stable ICU 74 */ + U_LB_VIRAMA = 47, /*[VI]*/ #ifndef U_HIDE_DEPRECATED_API /** * One more than the highest normal ULineBreak value. @@ -2446,7 +2482,7 @@ typedef enum ULineBreak { * * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420. */ - U_LB_COUNT = 43 + U_LB_COUNT = 48 #endif // U_HIDE_DEPRECATED_API } ULineBreak; diff --git a/thirdparty/icu4c/common/unicode/ulocale.h b/thirdparty/icu4c/common/unicode/ulocale.h new file mode 100644 index 0000000000..33e92844bc --- /dev/null +++ b/thirdparty/icu4c/common/unicode/ulocale.h @@ -0,0 +1,229 @@ +// © 2023 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#ifndef ULOCALE_H +#define ULOCALE_H + +#include "unicode/localpointer.h" +#include "unicode/uenum.h" +#include "unicode/utypes.h" + +/** + * \file + * \brief C API: Locale ID functionality similar to C++ class Locale + */ + +#ifndef U_HIDE_DRAFT_API +/** + * Opaque C service object type for the locale API + * @draft ICU 74 + */ +struct ULocale; + +/** + * C typedef for struct ULocale. + * @draft ICU 74 + */ +typedef struct ULocale ULocale; + +/** + * Constructs an ULocale from the locale ID. + * The created ULocale should be destroyed by calling + * ulocale_close(); + * @param localeID the locale, a const char * pointer (need not be terminated when + * the length is non-negative) + * @param length the length of the locale; if negative, then the locale need to be + * null terminated. + * @param err the error code + * @return the locale. + * + * @draft ICU 74 + */ +U_CAPI ULocale* U_EXPORT2 +ulocale_openForLocaleID(const char* localeID, int32_t length, UErrorCode* err); + +/** + * Constructs an ULocale from the provided IETF BCP 47 language tag. + * The created ULocale should be destroyed by calling + * ulocale_close(); + * @param tag the language tag, defined as IETF BCP 47 language tag, const + * char* pointer (need not be terminated when the length is non-negative) + * @param length the length of the tag; if negative, then the tag need to be + * null terminated. + * @param err the error code + * @return the locale. + * + * @draft ICU 74 + */ +U_CAPI ULocale* U_EXPORT2 +ulocale_openForLanguageTag(const char* tag, int32_t length, UErrorCode* err); + +/** + * Close the locale and destroy it's internal states. + * + * @param locale the locale + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocale_close(ULocale* locale); + +/** + * Returns the locale's ISO-639 language code. + * + * @param locale the locale + * @return the language code of the locale. + * @draft ICU 74 + */ +U_CAPI const char* U_EXPORT2 +ulocale_getLanguage(const ULocale* locale); + +/** + * Returns the locale's ISO-15924 abbreviation script code. + * + * @param locale the locale + * @return A pointer to the script. + * @draft ICU 74 + */ +U_CAPI const char* U_EXPORT2 +ulocale_getScript(const ULocale* locale); + +/** + * Returns the locale's ISO-3166 region code. + * + * @param locale the locale + * @return A pointer to the region. + * @draft ICU 74 + */ +U_CAPI const char* U_EXPORT2 +ulocale_getRegion(const ULocale* locale); + +/** + * Returns the locale's variant code. + * + * @param locale the locale + * @return A pointer to the variant. + * @draft ICU 74 + */ +U_CAPI const char* U_EXPORT2 +ulocale_getVariant(const ULocale* locale); + +/** + * Returns the programmatic name of the entire locale, with the language, + * country and variant separated by underbars. If a field is missing, up + * to two leading underbars will occur. Example: "en", "de_DE", "en_US_WIN", + * "de__POSIX", "fr__MAC", "__MAC", "_MT", "_FR_EURO" + * + * @param locale the locale + * @return A pointer to "name". + * @draft ICU 74 + */ +U_CAPI const char* U_EXPORT2 +ulocale_getLocaleID(const ULocale* locale); + +/** + * Returns the programmatic name of the entire locale as ulocale_getLocaleID() + * would return, but without keywords. + * + * @param locale the locale + * @return A pointer to "base name". + * @draft ICU 74 + */ +U_CAPI const char* U_EXPORT2 +ulocale_getBaseName(const ULocale* locale); + +/** + * Gets the bogus state. Locale object can be bogus if it doesn't exist + * + * @param locale the locale + * @return false if it is a real locale, true if it is a bogus locale + * @draft ICU 74 + */ +U_CAPI bool U_EXPORT2 +ulocale_isBogus(const ULocale* locale); + +/** + * Gets the list of keywords for the specified locale. + * + * @param locale the locale + * @param err the error code + * @return pointer to UEnumeration, or nullptr if there are no keywords. + * Client must call uenum_close() to dispose the returned value. + * @draft ICU 74 + */ +U_CAPI UEnumeration* U_EXPORT2 +ulocale_getKeywords(const ULocale* locale, UErrorCode *err); + +/** + * Gets the list of unicode keywords for the specified locale. + * + * @param locale the locale + * @param err the error code + * @return pointer to UEnumeration, or nullptr if there are no keywords. + * Client must call uenum_close() to dispose the returned value. + * @draft ICU 74 + */ +U_CAPI UEnumeration* U_EXPORT2 +ulocale_getUnicodeKeywords(const ULocale* locale, UErrorCode *err); + +/** + * Gets the value for a keyword. + * + * This uses legacy keyword=value pairs, like "collation=phonebook". + * + * @param locale the locale + * @param keyword the keyword, a const char * pointer (need not be + * terminated when the length is non-negative) + * @param keywordLength the length of the keyword; if negative, then the + * keyword need to be null terminated. + * @param valueBuffer The buffer to receive the value. + * @param valueBufferCapacity The capacity of receiving valueBuffer. + * @param err the error code + * @draft ICU 74 + */ +U_CAPI int32_t U_EXPORT2 +ulocale_getKeywordValue( + const ULocale* locale, const char* keyword, int32_t keywordLength, + char* valueBuffer, int32_t valueBufferCapacity, UErrorCode *err); + +/** + * Gets the Unicode value for a Unicode keyword. + * + * This uses Unicode key-value pairs, like "co-phonebk". + * + * @param locale the locale + * @param keyword the Unicode keyword, a const char * pointer (need not be + * terminated when the length is non-negative) + * @param keywordLength the length of the Unicode keyword; if negative, + * then the keyword need to be null terminated. + * @param valueBuffer The buffer to receive the Unicode value. + * @param valueBufferCapacity The capacity of receiving valueBuffer. + * @param err the error code + * @draft ICU 74 + */ +U_CAPI int32_t U_EXPORT2 +ulocale_getUnicodeKeywordValue( + const ULocale* locale, const char* keyword, int32_t keywordLength, + char* valueBuffer, int32_t valueBufferCapacity, UErrorCode *err); + +#if U_SHOW_CPLUSPLUS_API + +U_NAMESPACE_BEGIN + +/** + * \class LocalULocalePointer + * "Smart pointer" class, closes a ULocale via ulocale_close(). + * For most methods see the LocalPointerBase base class. + * + * @see LocalPointerBase + * @see LocalPointer + * @draft ICU 74 + */ +U_DEFINE_LOCAL_OPEN_POINTER(LocalULocalePointer, ULocale, ulocale_close); + +U_NAMESPACE_END + +#endif /* U_SHOW_CPLUSPLUS_API */ + +#endif /* U_HIDE_DRAFT_API */ + +#endif /*_ULOCALE */ diff --git a/thirdparty/icu4c/common/unicode/ulocbuilder.h b/thirdparty/icu4c/common/unicode/ulocbuilder.h new file mode 100644 index 0000000000..f2e98612f0 --- /dev/null +++ b/thirdparty/icu4c/common/unicode/ulocbuilder.h @@ -0,0 +1,441 @@ +// © 2023 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +#ifndef __ULOCBUILDER_H__ +#define __ULOCBUILDER_H__ + +#include "unicode/localpointer.h" +#include "unicode/ulocale.h" +#include "unicode/utypes.h" + +/** + * \file + * \brief C API: Builder API for Locale + */ + +#ifndef U_HIDE_DRAFT_API + +/** + * Opaque C service object type for the locale builder API + * @draft ICU 74 + */ +struct ULocaleBuilder; + +/** + * C typedef for struct ULocaleBuilder. + * @draft ICU 74 + */ +typedef struct ULocaleBuilder ULocaleBuilder; + +/** + * <code>ULocaleBuilder</code> is used to build valid <code>locale</code> id + * string or IETF BCP 47 language tag from values configured by the setters. + * The <code>ULocaleBuilder</code> checks if a value configured by a + * setter satisfies the syntax requirements defined by the <code>Locale</code> + * class. A string of Locale created by a <code>ULocaleBuilder</code> is + * well-formed and can be transformed to a well-formed IETF BCP 47 language tag + * without losing information. + * + * <p>The following example shows how to create a <code>locale</code> string + * with the <code>ULocaleBuilder</code>. + * <blockquote> + * <pre> + * UErrorCode err = U_ZERO_ERROR; + * char buffer[ULOC_FULLNAME_CAPACITY]; + * ULocaleBuilder* builder = ulocbld_open(); + * ulocbld_setLanguage(builder, "sr", -1); + * ulocbld_setScript(builder, "Latn", -1); + * ulocbld_setRegion(builder, "RS", -1); + * int32_t length = ulocbld_buildLocaleID( + * builder, buffer, ULOC_FULLNAME_CAPACITY, &error); + * ulocbld_close(builder); + * </pre> + * </blockquote> + * + * <p>ULocaleBuilders can be reused; <code>ulocbld_clear()</code> resets all + * fields to their default values. + * + * <p>ULocaleBuilder tracks errors in an internal UErrorCode. For all setters, + * except ulocbld_setLanguageTag and ulocbld_setLocale, ULocaleBuilder will return immediately + * if the internal UErrorCode is in error state. + * To reset internal state and error code, call clear method. + * The ulocbld_setLanguageTag and setLocale method will first clear the internal + * UErrorCode, then track the error of the validation of the input parameter + * into the internal UErrorCode. + * + * @draft ICU 74 + */ + +/** + * Constructs an empty ULocaleBuilder. The default value of all + * fields, extensions, and private use information is the + * empty string. The created builder should be destroyed by calling + * ulocbld_close(); + * + * @draft ICU 74 + */ +U_CAPI ULocaleBuilder* U_EXPORT2 +ulocbld_open(); + +/** + * Close the builder and destroy it's internal states. + * @param builder the builder + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_close(ULocaleBuilder* builder); + +/** + * Resets the <code>ULocaleBuilder</code> to match the provided + * <code>locale</code>. Existing state is discarded. + * + * <p>All fields of the locale must be well-formed. + * <p>This method clears the internal UErrorCode. + * + * @param builder the builder + * @param locale the locale, a const char * pointer (need not be terminated when + * the length is non-negative) + * @param length the length of the locale; if negative, then the locale need to be + * null terminated, + * + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_setLocale(ULocaleBuilder* builder, const char* locale, int32_t length); + +/** + * Resets the <code>ULocaleBuilder</code> to match the provided + * <code>ULocale</code>. Existing state is discarded. + * + * <p>The locale must be not bogus. + * <p>This method clears the internal UErrorCode. + * + * @param builder the builder. + * @param locale the locale, a ULocale* pointer. The builder adopts the locale + * after the call and the client must not delete it. + * + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_adoptULocale(ULocaleBuilder* builder, ULocale* locale); + +/** + * Resets the ULocaleBuilder to match the provided IETF BCP 47 language tag. + * Discards the existing state. + * The empty string causes the builder to be reset, like {@link #ulocbld_clear}. + * Legacy language tags (marked as “Type: grandfathered” in BCP 47) + * are converted to their canonical form before being processed. + * Otherwise, the <code>language tag</code> must be well-formed, + * or else the ulocbld_buildLocaleID() and ulocbld_buildLanguageTag() methods + * will later report an U_ILLEGAL_ARGUMENT_ERROR. + * + * <p>This method clears the internal UErrorCode. + * + * @param builder the builder + * @param tag the language tag, defined as IETF BCP 47 language tag, a + * const char * pointer (need not be terminated when + * the length is non-negative) + * @param length the length of the tag; if negative, then the tag need to be + * null terminated, + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_setLanguageTag(ULocaleBuilder* builder, const char* tag, int32_t length); + +/** + * Sets the language. If <code>language</code> is the empty string, the + * language in this <code>ULocaleBuilder</code> is removed. Otherwise, the + * <code>language</code> must be well-formed, or else the ulocbld_buildLocaleID() + * and ulocbld_buildLanguageTag() methods will + * later report an U_ILLEGAL_ARGUMENT_ERROR. + * + * <p>The syntax of language value is defined as + * [unicode_language_subtag](http://www.unicode.org/reports/tr35/tr35.html#unicode_language_subtag). + * + * @param builder the builder + * @param language the language, a const char * pointer (need not be terminated when + * the length is non-negative) + * @param length the length of the language; if negative, then the language need to be + * null terminated, + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_setLanguage(ULocaleBuilder* builder, const char* language, int32_t length); + +/** + * Sets the script. If <code>script</code> is the empty string, the script in + * this <code>ULocaleBuilder</code> is removed. + * Otherwise, the <code>script</code> must be well-formed, or else the + * ulocbld_buildLocaleID() and ulocbld_buildLanguageTag() methods will later + * report an U_ILLEGAL_ARGUMENT_ERROR. + * + * <p>The script value is a four-letter script code as + * [unicode_script_subtag](http://www.unicode.org/reports/tr35/tr35.html#unicode_script_subtag) + * defined by ISO 15924 + * + * @param builder the builder + * @param script the script, a const char * pointer (need not be terminated when + * the length is non-negative) + * @param length the length of the script; if negative, then the script need to be + * null terminated, + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_setScript(ULocaleBuilder* builder, const char* script, int32_t length); + +/** + * Sets the region. If region is the empty string, the region in this + * <code>ULocaleBuilder</code> is removed. Otherwise, the <code>region</code> + * must be well-formed, or else the ulocbld_buildLocaleID() and + * ulocbld_buildLanguageTag() methods will later report an + * U_ILLEGAL_ARGUMENT_ERROR. + * + * <p>The region value is defined by + * [unicode_region_subtag](http://www.unicode.org/reports/tr35/tr35.html#unicode_region_subtag) + * as a two-letter ISO 3166 code or a three-digit UN M.49 area code. + * + * <p>The region value in the <code>Locale</code> created by the + * <code>ULocaleBuilder</code> is always normalized to upper case. + * + * @param builder the builder + * @param region the region, a const char * pointer (need not be terminated when + * the length is non-negative) + * @param length the length of the region; if negative, then the region need to be + * null terminated, + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_setRegion(ULocaleBuilder* builder, const char* region, int32_t length); + +/** + * Sets the variant. If variant is the empty string, the variant in this + * <code>ULocaleBuilder</code> is removed. Otherwise, the <code>variant</code> + * must be well-formed, or else the ulocbld_buildLocaleID() and + * ulocbld_buildLanguageTag() methods will later report an + * U_ILLEGAL_ARGUMENT_ERROR. + * + * <p><b>Note:</b> This method checks if <code>variant</code> + * satisfies the + * [unicode_variant_subtag](http://www.unicode.org/reports/tr35/tr35.html#unicode_variant_subtag) + * syntax requirements, and normalizes the value to lowercase letters. However, + * the <code>Locale</code> class does not impose any syntactic + * restriction on variant. To set an ill-formed variant, use a Locale constructor. + * If there are multiple unicode_variant_subtag, the caller must concatenate + * them with '-' as separator (ex: "foobar-fibar"). + * + * @param builder the builder + * @param variant the variant, a const char * pointer (need not be terminated when + * the length is non-negative) + * @param length the length of the variant; if negative, then the variant need to be + * null terminated, + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_setVariant(ULocaleBuilder* builder, const char* variant, int32_t length); + +/** + * Sets the extension for the given key. If the value is the empty string, + * the extension is removed. Otherwise, the <code>key</code> and + * <code>value</code> must be well-formed, or else the ulocbld_buildLocaleID() + * and ulocbld_buildLanguageTag() methods will + * later report an U_ILLEGAL_ARGUMENT_ERROR. + * + * <p><b>Note:</b> The key ('u') is used for the Unicode locale extension. + * Setting a value for this key replaces any existing Unicode locale key/type + * pairs with those defined in the extension. + * + * <p><b>Note:</b> The key ('x') is used for the private use code. To be + * well-formed, the value for this key needs only to have subtags of one to + * eight alphanumeric characters, not two to eight as in the general case. + * + * @param builder the builder + * @param key the extension key + * @param value the value, a const char * pointer (need not be terminated when + * the length is non-negative) + * @param length the length of the value; if negative, then the value need to be + * null terminated, + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_setExtension(ULocaleBuilder* builder, char key, const char* value, int32_t length); + +/** + * Sets the Unicode locale keyword type for the given key. If the type + * StringPiece is constructed with a nullptr, the keyword is removed. + * If the type is the empty string, the keyword is set without type subtags. + * Otherwise, the key and type must be well-formed, or else the + * ulocbld_buildLocaleID() and ulocbld_buildLanguageTag() methods will later + * report an U_ILLEGAL_ARGUMENT_ERROR. + * + * <p>Keys and types are converted to lower case. + * + * <p><b>Note</b>:Setting the 'u' extension via {@link #ulocbld_setExtension} + * replaces all Unicode locale keywords with those defined in the + * extension. + * + * @param builder the builder + * @param key the Unicode locale key, a const char * pointer (need not be + * terminated when the length is non-negative) + * @param keyLength the length of the key; if negative, then the key need to be + * null terminated, + * @param type the Unicode locale type, a const char * pointer (need not be + * terminated when the length is non-negative) + * @param typeLength the length of the type; if negative, then the type need to + * be null terminated, + * @return This builder. + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_setUnicodeLocaleKeyword(ULocaleBuilder* builder, + const char* key, int32_t keyLength, const char* type, int32_t typeLength); + +/** + * Adds a unicode locale attribute, if not already present, otherwise + * has no effect. The attribute must not be empty string and must be + * well-formed or U_ILLEGAL_ARGUMENT_ERROR will be set to status + * during the ulocbld_buildLocaleID() and ulocbld_buildLanguageTag() calls. + * + * @param builder the builder + * @param attribute the attribute, a const char * pointer (need not be + * terminated when the length is non-negative) + * @param length the length of the attribute; if negative, then the attribute + * need to be null terminated, + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_addUnicodeLocaleAttribute( + ULocaleBuilder* builder, const char* attribute, int32_t length); + +/** + * Removes a unicode locale attribute, if present, otherwise has no + * effect. The attribute must not be empty string and must be well-formed + * or U_ILLEGAL_ARGUMENT_ERROR will be set to status during the ulocbld_buildLocaleID() + * and ulocbld_buildLanguageTag() calls. + * + * <p>Attribute comparison for removal is case-insensitive. + * + * @param builder the builder + * @param attribute the attribute, a const char * pointer (need not be + * terminated when the length is non-negative) + * @param length the length of the attribute; if negative, then the attribute + * need to be null terminated, + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_removeUnicodeLocaleAttribute( + ULocaleBuilder* builder, const char* attribute, int32_t length); + +/** + * Resets the builder to its initial, empty state. + * <p>This method clears the internal UErrorCode. + * + * @param builder the builder + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_clear(ULocaleBuilder* builder); + +/** + * Resets the extensions to their initial, empty state. + * Language, script, region and variant are unchanged. + * + * @param builder the builder + * @draft ICU 74 + */ +U_CAPI void U_EXPORT2 +ulocbld_clearExtensions(ULocaleBuilder* builder); + +/** + * Build the LocaleID string from the fields set on this builder. + * If any set methods or during the ulocbld_buildLocaleID() call require memory + * allocation but fail U_MEMORY_ALLOCATION_ERROR will be set to status. + * If any of the fields set by the setters are not well-formed, the status + * will be set to U_ILLEGAL_ARGUMENT_ERROR. The state of the builder will + * not change after the ulocbld_buildLocaleID() call and the caller is + * free to keep using the same builder to build more locales. + * + * @param builder the builder + * @param locale the locale id + * @param localeCapacity the size of the locale buffer to store the locale id + * @param err the error code + * @return the length of the locale id in buffer + * @draft ICU 74 + */ +U_CAPI int32_t U_EXPORT2 +ulocbld_buildLocaleID(ULocaleBuilder* builder, char* locale, + int32_t localeCapacity, UErrorCode* err); + +/** + * Build the ULocale object from the fields set on this builder. + * If any set methods or during the ulocbld_buildULocale() call require memory + * allocation but fail U_MEMORY_ALLOCATION_ERROR will be set to status. + * If any of the fields set by the setters are not well-formed, the status + * will be set to U_ILLEGAL_ARGUMENT_ERROR. The state of the builder will + * not change after the ulocbld_buildULocale() call and the caller is + * free to keep using the same builder to build more locales. + * + * @param builder the builder. + * @param err the error code. + * @return the locale, a ULocale* pointer. The created ULocale must be + * destroyed by calling {@link ulocale_close}. + * @draft ICU 74 + */ +U_CAPI ULocale* U_EXPORT2 +ulocbld_buildULocale(ULocaleBuilder* builder, UErrorCode* err); + +/** + * Build the IETF BCP 47 language tag string from the fields set on this builder. + * If any set methods or during the ulocbld_buildLanguageTag() call require memory + * allocation but fail U_MEMORY_ALLOCATION_ERROR will be set to status. + * If any of the fields set by the setters are not well-formed, the status + * will be set to U_ILLEGAL_ARGUMENT_ERROR. The state of the builder will + * not change after the ulocbld_buildLanguageTag() call and the caller is free + * to keep using the same builder to build more locales. + * + * @param builder the builder + * @param language the language tag + * @param languageCapacity the size of the language buffer to store the language + * tag + * @param err the error code + * @return the length of the language tag in buffer + * @draft ICU 74 + */ +U_CAPI int32_t U_EXPORT2 +ulocbld_buildLanguageTag(ULocaleBuilder* builder, char* language, + int32_t languageCapacity, UErrorCode* err); + +/** + * Sets the UErrorCode if an error occurred while recording sets. + * Preserves older error codes in the outErrorCode. + * + * @param builder the builder + * @param outErrorCode Set to an error code that occurred while setting subtags. + * Unchanged if there is no such error or if outErrorCode + * already contained an error. + * @return true if U_FAILURE(*outErrorCode) + * @draft ICU 74 + */ +U_CAPI UBool U_EXPORT2 +ulocbld_copyErrorTo(const ULocaleBuilder* builder, UErrorCode *outErrorCode); + +#if U_SHOW_CPLUSPLUS_API + +U_NAMESPACE_BEGIN + +/** + * \class LocalULocaleBuilderPointer + * "Smart pointer" class, closes a ULocaleBuilder via ulocbld_close(). + * For most methods see the LocalPointerBase base class. + * + * @see LocalPointerBase + * @see LocalPointer + * @draft ICU 74 + */ +U_DEFINE_LOCAL_OPEN_POINTER(LocalULocaleBuilderPointer, ULocaleBuilder, ulocbld_close); + +U_NAMESPACE_END + +#endif /* U_SHOW_CPLUSPLUS_API */ + +#endif /* U_HIDE_DRAFT_API */ + +#endif // __ULOCBUILDER_H__ diff --git a/thirdparty/icu4c/common/unicode/unorm2.h b/thirdparty/icu4c/common/unicode/unorm2.h index 24417b7103..3844041f17 100644 --- a/thirdparty/icu4c/common/unicode/unorm2.h +++ b/thirdparty/icu4c/common/unicode/unorm2.h @@ -181,7 +181,10 @@ U_CAPI const UNormalizer2 * U_EXPORT2 unorm2_getNFKDInstance(UErrorCode *pErrorCode); /** - * Returns a UNormalizer2 instance for Unicode NFKC_Casefold normalization. + * Returns a UNormalizer2 instance for Unicode toNFKC_Casefold() normalization + * which is equivalent to applying the NFKC_Casefold mappings and then NFC. + * See https://www.unicode.org/reports/tr44/#NFKC_Casefold + * * Same as unorm2_getInstance(NULL, "nfkc_cf", UNORM2_COMPOSE, pErrorCode). * Returns an unmodifiable singleton instance. Do not delete it. * @param pErrorCode Standard ICU error code. Its input value must @@ -194,6 +197,25 @@ unorm2_getNFKDInstance(UErrorCode *pErrorCode); U_CAPI const UNormalizer2 * U_EXPORT2 unorm2_getNFKCCasefoldInstance(UErrorCode *pErrorCode); +#ifndef U_HIDE_DRAFT_API +/** + * Returns a UNormalizer2 instance for a variant of Unicode toNFKC_Casefold() normalization + * which is equivalent to applying the NFKC_Simple_Casefold mappings and then NFC. + * See https://www.unicode.org/reports/tr44/#NFKC_Simple_Casefold + * + * Same as unorm2_getInstance(NULL, "nfkc_scf", UNORM2_COMPOSE, pErrorCode). + * Returns an unmodifiable singleton instance. Do not delete it. + * @param pErrorCode Standard ICU error code. Its input value must + * pass the U_SUCCESS() test, or else the function returns + * immediately. Check for U_FAILURE() on output or use with + * function chaining. (See User Guide for details.) + * @return the requested Normalizer2, if successful + * @draft ICU 74 + */ +U_CAPI const UNormalizer2 * U_EXPORT2 +unorm2_getNFKCSimpleCasefoldInstance(UErrorCode *pErrorCode); +#endif // U_HIDE_DRAFT_API + /** * Returns a UNormalizer2 instance which uses the specified data file * (packageName/name similar to ucnv_openPackage() and ures_open()/ResourceBundle) @@ -206,7 +228,7 @@ unorm2_getNFKCCasefoldInstance(UErrorCode *pErrorCode); * Use name="nfkc_cf" and UNORM2_COMPOSE for Unicode standard NFKC_CF=NFKC_Casefold. * * @param packageName NULL for ICU built-in data, otherwise application data package name - * @param name "nfc" or "nfkc" or "nfkc_cf" or name of custom data file + * @param name "nfc" or "nfkc" or "nfkc_cf" or "nfkc_scf" or name of custom data file * @param mode normalization mode (compose or decompose etc.) * @param pErrorCode Standard ICU error code. Its input value must * pass the U_SUCCESS() test, or else the function returns diff --git a/thirdparty/icu4c/common/unicode/urename.h b/thirdparty/icu4c/common/unicode/urename.h index b35df45380..74f2cae510 100644 --- a/thirdparty/icu4c/common/unicode/urename.h +++ b/thirdparty/icu4c/common/unicode/urename.h @@ -138,8 +138,8 @@ #define locale_getKeywordsStart U_ICU_ENTRY_POINT_RENAME(locale_getKeywordsStart) #define locale_get_default U_ICU_ENTRY_POINT_RENAME(locale_get_default) #define locale_set_default U_ICU_ENTRY_POINT_RENAME(locale_set_default) +#define mixedMeasuresToMicros U_ICU_ENTRY_POINT_RENAME(mixedMeasuresToMicros) #define numSysCleanup U_ICU_ENTRY_POINT_RENAME(numSysCleanup) -#define rbbi_cleanup U_ICU_ENTRY_POINT_RENAME(rbbi_cleanup) #define pl_addFontRun U_ICU_ENTRY_POINT_RENAME(pl_addFontRun) #define pl_addLocaleRun U_ICU_ENTRY_POINT_RENAME(pl_addLocaleRun) #define pl_addValueRun U_ICU_ENTRY_POINT_RENAME(pl_addValueRun) @@ -193,6 +193,7 @@ #define pl_resetFontRuns U_ICU_ENTRY_POINT_RENAME(pl_resetFontRuns) #define pl_resetLocaleRuns U_ICU_ENTRY_POINT_RENAME(pl_resetLocaleRuns) #define pl_resetValueRuns U_ICU_ENTRY_POINT_RENAME(pl_resetValueRuns) +#define rbbi_cleanup U_ICU_ENTRY_POINT_RENAME(rbbi_cleanup) #define res_countArrayItems U_ICU_ENTRY_POINT_RENAME(res_countArrayItems) #define res_findResource U_ICU_ENTRY_POINT_RENAME(res_findResource) #define res_getAlias U_ICU_ENTRY_POINT_RENAME(res_getAlias) @@ -512,9 +513,6 @@ #define ubrk_setText U_ICU_ENTRY_POINT_RENAME(ubrk_setText) #define ubrk_setUText U_ICU_ENTRY_POINT_RENAME(ubrk_setUText) #define ubrk_swap U_ICU_ENTRY_POINT_RENAME(ubrk_swap) -#define ucache_compareKeys U_ICU_ENTRY_POINT_RENAME(ucache_compareKeys) -#define ucache_deleteKey U_ICU_ENTRY_POINT_RENAME(ucache_deleteKey) -#define ucache_hashKeys U_ICU_ENTRY_POINT_RENAME(ucache_hashKeys) #define ucal_add U_ICU_ENTRY_POINT_RENAME(ucal_add) #define ucal_clear U_ICU_ENTRY_POINT_RENAME(ucal_clear) #define ucal_clearField U_ICU_ENTRY_POINT_RENAME(ucal_clearField) @@ -532,6 +530,7 @@ #define ucal_getFieldDifference U_ICU_ENTRY_POINT_RENAME(ucal_getFieldDifference) #define ucal_getGregorianChange U_ICU_ENTRY_POINT_RENAME(ucal_getGregorianChange) #define ucal_getHostTimeZone U_ICU_ENTRY_POINT_RENAME(ucal_getHostTimeZone) +#define ucal_getIanaTimeZoneID U_ICU_ENTRY_POINT_RENAME(ucal_getIanaTimeZoneID) #define ucal_getKeywordValuesForLocale U_ICU_ENTRY_POINT_RENAME(ucal_getKeywordValuesForLocale) #define ucal_getLimit U_ICU_ENTRY_POINT_RENAME(ucal_getLimit) #define ucal_getLocaleByType U_ICU_ENTRY_POINT_RENAME(ucal_getLocaleByType) @@ -587,6 +586,7 @@ #define ucasemap_getLocale U_ICU_ENTRY_POINT_RENAME(ucasemap_getLocale) #define ucasemap_getOptions U_ICU_ENTRY_POINT_RENAME(ucasemap_getOptions) #define ucasemap_internalUTF8ToTitle U_ICU_ENTRY_POINT_RENAME(ucasemap_internalUTF8ToTitle) +#define ucasemap_mapUTF8 U_ICU_ENTRY_POINT_RENAME(ucasemap_mapUTF8) #define ucasemap_open U_ICU_ENTRY_POINT_RENAME(ucasemap_open) #define ucasemap_setBreakIterator U_ICU_ENTRY_POINT_RENAME(ucasemap_setBreakIterator) #define ucasemap_setLocale U_ICU_ENTRY_POINT_RENAME(ucasemap_setLocale) @@ -955,9 +955,16 @@ #define ufieldpositer_close U_ICU_ENTRY_POINT_RENAME(ufieldpositer_close) #define ufieldpositer_next U_ICU_ENTRY_POINT_RENAME(ufieldpositer_next) #define ufieldpositer_open U_ICU_ENTRY_POINT_RENAME(ufieldpositer_open) +#define ufile_close_translit U_ICU_ENTRY_POINT_RENAME(ufile_close_translit) +#define ufile_fill_uchar_buffer U_ICU_ENTRY_POINT_RENAME(ufile_fill_uchar_buffer) +#define ufile_flush_io U_ICU_ENTRY_POINT_RENAME(ufile_flush_io) +#define ufile_flush_translit U_ICU_ENTRY_POINT_RENAME(ufile_flush_translit) #define ufile_getch U_ICU_ENTRY_POINT_RENAME(ufile_getch) #define ufile_getch32 U_ICU_ENTRY_POINT_RENAME(ufile_getch32) +#define ufmt_64tou U_ICU_ENTRY_POINT_RENAME(ufmt_64tou) #define ufmt_close U_ICU_ENTRY_POINT_RENAME(ufmt_close) +#define ufmt_defaultCPToUnicode U_ICU_ENTRY_POINT_RENAME(ufmt_defaultCPToUnicode) +#define ufmt_digitvalue U_ICU_ENTRY_POINT_RENAME(ufmt_digitvalue) #define ufmt_getArrayItemByIndex U_ICU_ENTRY_POINT_RENAME(ufmt_getArrayItemByIndex) #define ufmt_getArrayLength U_ICU_ENTRY_POINT_RENAME(ufmt_getArrayLength) #define ufmt_getDate U_ICU_ENTRY_POINT_RENAME(ufmt_getDate) @@ -969,7 +976,11 @@ #define ufmt_getType U_ICU_ENTRY_POINT_RENAME(ufmt_getType) #define ufmt_getUChars U_ICU_ENTRY_POINT_RENAME(ufmt_getUChars) #define ufmt_isNumeric U_ICU_ENTRY_POINT_RENAME(ufmt_isNumeric) +#define ufmt_isdigit U_ICU_ENTRY_POINT_RENAME(ufmt_isdigit) #define ufmt_open U_ICU_ENTRY_POINT_RENAME(ufmt_open) +#define ufmt_ptou U_ICU_ENTRY_POINT_RENAME(ufmt_ptou) +#define ufmt_uto64 U_ICU_ENTRY_POINT_RENAME(ufmt_uto64) +#define ufmt_utop U_ICU_ENTRY_POINT_RENAME(ufmt_utop) #define ufmtval_getString U_ICU_ENTRY_POINT_RENAME(ufmtval_getString) #define ufmtval_nextPosition U_ICU_ENTRY_POINT_RENAME(ufmtval_nextPosition) #define ugender_getInstance U_ICU_ENTRY_POINT_RENAME(ugender_getInstance) @@ -1133,6 +1144,39 @@ #define uloc_toLegacyType U_ICU_ENTRY_POINT_RENAME(uloc_toLegacyType) #define uloc_toUnicodeLocaleKey U_ICU_ENTRY_POINT_RENAME(uloc_toUnicodeLocaleKey) #define uloc_toUnicodeLocaleType U_ICU_ENTRY_POINT_RENAME(uloc_toUnicodeLocaleType) +#define ulocale_close U_ICU_ENTRY_POINT_RENAME(ulocale_close) +#define ulocale_getBaseName U_ICU_ENTRY_POINT_RENAME(ulocale_getBaseName) +#define ulocale_getKeywordValue U_ICU_ENTRY_POINT_RENAME(ulocale_getKeywordValue) +#define ulocale_getKeywords U_ICU_ENTRY_POINT_RENAME(ulocale_getKeywords) +#define ulocale_getLanguage U_ICU_ENTRY_POINT_RENAME(ulocale_getLanguage) +#define ulocale_getLocaleID U_ICU_ENTRY_POINT_RENAME(ulocale_getLocaleID) +#define ulocale_getRegion U_ICU_ENTRY_POINT_RENAME(ulocale_getRegion) +#define ulocale_getScript U_ICU_ENTRY_POINT_RENAME(ulocale_getScript) +#define ulocale_getUnicodeKeywordValue U_ICU_ENTRY_POINT_RENAME(ulocale_getUnicodeKeywordValue) +#define ulocale_getUnicodeKeywords U_ICU_ENTRY_POINT_RENAME(ulocale_getUnicodeKeywords) +#define ulocale_getVariant U_ICU_ENTRY_POINT_RENAME(ulocale_getVariant) +#define ulocale_isBogus U_ICU_ENTRY_POINT_RENAME(ulocale_isBogus) +#define ulocale_openForLanguageTag U_ICU_ENTRY_POINT_RENAME(ulocale_openForLanguageTag) +#define ulocale_openForLocaleID U_ICU_ENTRY_POINT_RENAME(ulocale_openForLocaleID) +#define ulocbld_addUnicodeLocaleAttribute U_ICU_ENTRY_POINT_RENAME(ulocbld_addUnicodeLocaleAttribute) +#define ulocbld_adoptULocale U_ICU_ENTRY_POINT_RENAME(ulocbld_adoptULocale) +#define ulocbld_buildLanguageTag U_ICU_ENTRY_POINT_RENAME(ulocbld_buildLanguageTag) +#define ulocbld_buildLocaleID U_ICU_ENTRY_POINT_RENAME(ulocbld_buildLocaleID) +#define ulocbld_buildULocale U_ICU_ENTRY_POINT_RENAME(ulocbld_buildULocale) +#define ulocbld_clear U_ICU_ENTRY_POINT_RENAME(ulocbld_clear) +#define ulocbld_clearExtensions U_ICU_ENTRY_POINT_RENAME(ulocbld_clearExtensions) +#define ulocbld_close U_ICU_ENTRY_POINT_RENAME(ulocbld_close) +#define ulocbld_copyErrorTo U_ICU_ENTRY_POINT_RENAME(ulocbld_copyErrorTo) +#define ulocbld_open U_ICU_ENTRY_POINT_RENAME(ulocbld_open) +#define ulocbld_removeUnicodeLocaleAttribute U_ICU_ENTRY_POINT_RENAME(ulocbld_removeUnicodeLocaleAttribute) +#define ulocbld_setExtension U_ICU_ENTRY_POINT_RENAME(ulocbld_setExtension) +#define ulocbld_setLanguage U_ICU_ENTRY_POINT_RENAME(ulocbld_setLanguage) +#define ulocbld_setLanguageTag U_ICU_ENTRY_POINT_RENAME(ulocbld_setLanguageTag) +#define ulocbld_setLocale U_ICU_ENTRY_POINT_RENAME(ulocbld_setLocale) +#define ulocbld_setRegion U_ICU_ENTRY_POINT_RENAME(ulocbld_setRegion) +#define ulocbld_setScript U_ICU_ENTRY_POINT_RENAME(ulocbld_setScript) +#define ulocbld_setUnicodeLocaleKeyword U_ICU_ENTRY_POINT_RENAME(ulocbld_setUnicodeLocaleKeyword) +#define ulocbld_setVariant U_ICU_ENTRY_POINT_RENAME(ulocbld_setVariant) #define ulocdata_close U_ICU_ENTRY_POINT_RENAME(ulocdata_close) #define ulocdata_getCLDRVersion U_ICU_ENTRY_POINT_RENAME(ulocdata_getCLDRVersion) #define ulocdata_getDelimiter U_ICU_ENTRY_POINT_RENAME(ulocdata_getDelimiter) @@ -1213,6 +1257,7 @@ #define unorm2_getNFDInstance U_ICU_ENTRY_POINT_RENAME(unorm2_getNFDInstance) #define unorm2_getNFKCCasefoldInstance U_ICU_ENTRY_POINT_RENAME(unorm2_getNFKCCasefoldInstance) #define unorm2_getNFKCInstance U_ICU_ENTRY_POINT_RENAME(unorm2_getNFKCInstance) +#define unorm2_getNFKCSimpleCasefoldInstance U_ICU_ENTRY_POINT_RENAME(unorm2_getNFKCSimpleCasefoldInstance) #define unorm2_getNFKDInstance U_ICU_ENTRY_POINT_RENAME(unorm2_getNFKDInstance) #define unorm2_getRawDecomposition U_ICU_ENTRY_POINT_RENAME(unorm2_getRawDecomposition) #define unorm2_hasBoundaryAfter U_ICU_ENTRY_POINT_RENAME(unorm2_hasBoundaryAfter) @@ -1349,6 +1394,7 @@ #define uprv_convertToPosix U_ICU_ENTRY_POINT_RENAME(uprv_convertToPosix) #define uprv_copyAscii U_ICU_ENTRY_POINT_RENAME(uprv_copyAscii) #define uprv_copyEbcdic U_ICU_ENTRY_POINT_RENAME(uprv_copyEbcdic) +#define uprv_currencyLeads U_ICU_ENTRY_POINT_RENAME(uprv_currencyLeads) #define uprv_decContextClearStatus U_ICU_ENTRY_POINT_RENAME(uprv_decContextClearStatus) #define uprv_decContextDefault U_ICU_ENTRY_POINT_RENAME(uprv_decContextDefault) #define uprv_decContextGetRounding U_ICU_ENTRY_POINT_RENAME(uprv_decContextGetRounding) @@ -1367,6 +1413,7 @@ #define uprv_decNumberAbs U_ICU_ENTRY_POINT_RENAME(uprv_decNumberAbs) #define uprv_decNumberAdd U_ICU_ENTRY_POINT_RENAME(uprv_decNumberAdd) #define uprv_decNumberAnd U_ICU_ENTRY_POINT_RENAME(uprv_decNumberAnd) +#define uprv_decNumberClass U_ICU_ENTRY_POINT_RENAME(uprv_decNumberClass) #define uprv_decNumberClassToString U_ICU_ENTRY_POINT_RENAME(uprv_decNumberClassToString) #define uprv_decNumberCompare U_ICU_ENTRY_POINT_RENAME(uprv_decNumberCompare) #define uprv_decNumberCompareSignal U_ICU_ENTRY_POINT_RENAME(uprv_decNumberCompareSignal) @@ -1763,6 +1810,9 @@ #define usnumf_formatInt64 U_ICU_ENTRY_POINT_RENAME(usnumf_formatInt64) #define usnumf_openForLocale U_ICU_ENTRY_POINT_RENAME(usnumf_openForLocale) #define usnumf_openForLocaleAndGroupingStrategy U_ICU_ENTRY_POINT_RENAME(usnumf_openForLocaleAndGroupingStrategy) +#define uspoof_areBidiConfusable U_ICU_ENTRY_POINT_RENAME(uspoof_areBidiConfusable) +#define uspoof_areBidiConfusableUTF8 U_ICU_ENTRY_POINT_RENAME(uspoof_areBidiConfusableUTF8) +#define uspoof_areBidiConfusableUnicodeString U_ICU_ENTRY_POINT_RENAME(uspoof_areBidiConfusableUnicodeString) #define uspoof_areConfusable U_ICU_ENTRY_POINT_RENAME(uspoof_areConfusable) #define uspoof_areConfusableUTF8 U_ICU_ENTRY_POINT_RENAME(uspoof_areConfusableUTF8) #define uspoof_areConfusableUnicodeString U_ICU_ENTRY_POINT_RENAME(uspoof_areConfusableUnicodeString) @@ -1778,6 +1828,9 @@ #define uspoof_getAllowedChars U_ICU_ENTRY_POINT_RENAME(uspoof_getAllowedChars) #define uspoof_getAllowedLocales U_ICU_ENTRY_POINT_RENAME(uspoof_getAllowedLocales) #define uspoof_getAllowedUnicodeSet U_ICU_ENTRY_POINT_RENAME(uspoof_getAllowedUnicodeSet) +#define uspoof_getBidiSkeleton U_ICU_ENTRY_POINT_RENAME(uspoof_getBidiSkeleton) +#define uspoof_getBidiSkeletonUTF8 U_ICU_ENTRY_POINT_RENAME(uspoof_getBidiSkeletonUTF8) +#define uspoof_getBidiSkeletonUnicodeString U_ICU_ENTRY_POINT_RENAME(uspoof_getBidiSkeletonUnicodeString) #define uspoof_getCheckResultChecks U_ICU_ENTRY_POINT_RENAME(uspoof_getCheckResultChecks) #define uspoof_getCheckResultNumerics U_ICU_ENTRY_POINT_RENAME(uspoof_getCheckResultNumerics) #define uspoof_getCheckResultRestrictionLevel U_ICU_ENTRY_POINT_RENAME(uspoof_getCheckResultRestrictionLevel) diff --git a/thirdparty/icu4c/common/unicode/uvernum.h b/thirdparty/icu4c/common/unicode/uvernum.h index fc784b2492..9fc98e7380 100644 --- a/thirdparty/icu4c/common/unicode/uvernum.h +++ b/thirdparty/icu4c/common/unicode/uvernum.h @@ -53,13 +53,13 @@ * This value will change in the subsequent releases of ICU * @stable ICU 2.4 */ -#define U_ICU_VERSION_MAJOR_NUM 73 +#define U_ICU_VERSION_MAJOR_NUM 74 /** The current ICU minor version as an integer. * This value will change in the subsequent releases of ICU * @stable ICU 2.6 */ -#define U_ICU_VERSION_MINOR_NUM 2 +#define U_ICU_VERSION_MINOR_NUM 1 /** The current ICU patchlevel version as an integer. * This value will change in the subsequent releases of ICU @@ -79,7 +79,7 @@ * This value will change in the subsequent releases of ICU * @stable ICU 2.6 */ -#define U_ICU_VERSION_SUFFIX _73 +#define U_ICU_VERSION_SUFFIX _74 /** * \def U_DEF2_ICU_ENTRY_POINT_RENAME @@ -132,7 +132,7 @@ * This value will change in the subsequent releases of ICU * @stable ICU 2.4 */ -#define U_ICU_VERSION "73.2" +#define U_ICU_VERSION "74.1" /** * The current ICU library major version number as a string, for library name suffixes. @@ -145,13 +145,13 @@ * * @stable ICU 2.6 */ -#define U_ICU_VERSION_SHORT "73" +#define U_ICU_VERSION_SHORT "74" #ifndef U_HIDE_INTERNAL_API /** Data version in ICU4C. * @internal ICU 4.4 Internal Use Only **/ -#define U_ICU_DATA_VERSION "73.2" +#define U_ICU_DATA_VERSION "74.1" #endif /* U_HIDE_INTERNAL_API */ /*=========================================================================== diff --git a/thirdparty/icu4c/common/uniquecharstr.h b/thirdparty/icu4c/common/uniquecharstr.h index 10cc924f7f..e5d3b73418 100644 --- a/thirdparty/icu4c/common/uniquecharstr.h +++ b/thirdparty/icu4c/common/uniquecharstr.h @@ -10,6 +10,7 @@ #include "charstr.h" #include "uassert.h" #include "uhash.h" +#include "cmemory.h" U_NAMESPACE_BEGIN @@ -47,22 +48,20 @@ public: } /** - * Adds a string and returns a unique number for it. - * The string's buffer contents must not change, nor move around in memory, + * Adds a NUL-terminated string and returns a unique number for it. + * The string must not change, nor move around in memory, * while this UniqueCharStrings is in use. - * The string contents must be NUL-terminated exactly at s.length(). * - * Best used with read-only-alias UnicodeString objects that point to - * stable storage, such as strings returned by resource bundle functions. + * Best used with string data in a stable storage, such as strings returned + * by resource bundle functions. */ - int32_t add(const UnicodeString &s, UErrorCode &errorCode) { - if (U_FAILURE(errorCode)) { return 0; } + int32_t add(const char16_t*p, UErrorCode &errorCode) { + if (U_FAILURE(errorCode)) { return -1; } if (isFrozen) { errorCode = U_NO_WRITE_PERMISSION; - return 0; + return -1; } // The string points into the resource bundle. - const char16_t *p = s.getBuffer(); int32_t oldIndex = uhash_geti(&map, p); if (oldIndex != 0) { // found duplicate return oldIndex; @@ -71,11 +70,33 @@ public: // The strings object is also terminated with one implicit NUL. strings->append(0, errorCode); int32_t newIndex = strings->length(); - strings->appendInvariantChars(s, errorCode); + strings->appendInvariantChars(p, u_strlen(p), errorCode); uhash_puti(&map, const_cast<char16_t *>(p), newIndex, &errorCode); return newIndex; } + /** + * Adds a unicode string by value and returns a unique number for it. + */ + int32_t addByValue(UnicodeString s, UErrorCode &errorCode) { + if (U_FAILURE(errorCode)) { return -1; } + if (isFrozen) { + errorCode = U_NO_WRITE_PERMISSION; + return -1; + } + int32_t oldIndex = uhash_geti(&map, s.getTerminatedBuffer()); + if (oldIndex != 0) { // found duplicate + return oldIndex; + } + // We need to store the string content of the UnicodeString. + UnicodeString *key = keyStore.create(s); + if (key == nullptr) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + return -1; + } + return add(key->getTerminatedBuffer(), errorCode); + } + void freeze() { isFrozen = true; } /** @@ -90,6 +111,7 @@ public: private: UHashtable map; CharString *strings; + MemoryPool<UnicodeString> keyStore; bool isFrozen = false; }; diff --git a/thirdparty/icu4c/common/uprops.cpp b/thirdparty/icu4c/common/uprops.cpp index 28540186c6..314fa6fb86 100644 --- a/thirdparty/icu4c/common/uprops.cpp +++ b/thirdparty/icu4c/common/uprops.cpp @@ -328,6 +328,53 @@ static UBool hasEmojiProperty(const BinaryProperty &/*prop*/, UChar32 c, UProper return EmojiProps::hasBinaryProperty(c, which); } +static UBool isIDSUnaryOperator(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { + // New in Unicode 15.1 for just two characters. + return 0x2FFE<=c && c<=0x2FFF; +} + +/** Ranges (start/limit pairs) of ID_Compat_Math_Continue (only), from UCD PropList.txt. */ +static constexpr UChar32 ID_COMPAT_MATH_CONTINUE[] = { + 0x00B2, 0x00B3 + 1, + 0x00B9, 0x00B9 + 1, + 0x2070, 0x2070 + 1, + 0x2074, 0x207E + 1, + 0x2080, 0x208E + 1 +}; + +/** ID_Compat_Math_Start characters, from UCD PropList.txt. */ +static constexpr UChar32 ID_COMPAT_MATH_START[] = { + 0x2202, + 0x2207, + 0x221E, + 0x1D6C1, + 0x1D6DB, + 0x1D6FB, + 0x1D715, + 0x1D735, + 0x1D74F, + 0x1D76F, + 0x1D789, + 0x1D7A9, + 0x1D7C3 +}; + +static UBool isIDCompatMathStart(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { + if (c < ID_COMPAT_MATH_START[0]) { return false; } // fastpath for common scripts + for (UChar32 startChar : ID_COMPAT_MATH_START) { + if (c == startChar) { return true; } + } + return false; +} + +static UBool isIDCompatMathContinue(const BinaryProperty &prop, UChar32 c, UProperty /*which*/) { + for (int32_t i = 0; i < UPRV_LENGTHOF(ID_COMPAT_MATH_CONTINUE); i += 2) { + if (c < ID_COMPAT_MATH_CONTINUE[i]) { return false; } // below range start + if (c < ID_COMPAT_MATH_CONTINUE[i + 1]) { return true; } // below range limit + } + return isIDCompatMathStart(prop, c, UCHAR_ID_COMPAT_MATH_START); +} + static const BinaryProperty binProps[UCHAR_BINARY_LIMIT]={ /* * column and mask values for binary properties from u_getUnicodeProperties(). @@ -409,6 +456,9 @@ static const BinaryProperty binProps[UCHAR_BINARY_LIMIT]={ { UPROPS_SRC_EMOJI, 0, hasEmojiProperty }, // UCHAR_RGI_EMOJI_TAG_SEQUENCE { UPROPS_SRC_EMOJI, 0, hasEmojiProperty }, // UCHAR_RGI_EMOJI_ZWJ_SEQUENCE { UPROPS_SRC_EMOJI, 0, hasEmojiProperty }, // UCHAR_RGI_EMOJI + { UPROPS_SRC_IDSU, 0, isIDSUnaryOperator }, // UCHAR_IDS_UNARY_OPERATOR + { UPROPS_SRC_ID_COMPAT_MATH, 0, isIDCompatMathStart }, // UCHAR_ID_COMPAT_MATH_START + { UPROPS_SRC_ID_COMPAT_MATH, 0, isIDCompatMathContinue }, // UCHAR_ID_COMPAT_MATH_CONTINUE }; U_CAPI UBool U_EXPORT2 @@ -759,6 +809,19 @@ uprops_getSource(UProperty which) { U_CFUNC void U_EXPORT2 uprops_addPropertyStarts(UPropertySource src, const USetAdder *sa, UErrorCode *pErrorCode) { + if (U_FAILURE(*pErrorCode)) { return; } + if (src == UPROPS_SRC_ID_COMPAT_MATH) { + // range limits + for (UChar32 c : ID_COMPAT_MATH_CONTINUE) { + sa->add(sa->set, c); + } + // single characters + for (UChar32 c : ID_COMPAT_MATH_START) { + sa->add(sa->set, c); + sa->add(sa->set, c + 1); + } + return; + } if (!ulayout_ensureData(*pErrorCode)) { return; } const UCPTrie *trie; switch (src) { diff --git a/thirdparty/icu4c/common/uprops.h b/thirdparty/icu4c/common/uprops.h index 1e06d03519..80347eab57 100644 --- a/thirdparty/icu4c/common/uprops.h +++ b/thirdparty/icu4c/common/uprops.h @@ -379,6 +379,8 @@ enum UPropertySource { UPROPS_SRC_INSC, UPROPS_SRC_VO, UPROPS_SRC_EMOJI, + UPROPS_SRC_IDSU, + UPROPS_SRC_ID_COMPAT_MATH, /** One more than the highest UPropertySource (UPROPS_SRC_) constant. */ UPROPS_SRC_COUNT }; diff --git a/thirdparty/icu4c/common/uresbund.cpp b/thirdparty/icu4c/common/uresbund.cpp index d02bba8921..5aa1c5fa2f 100644 --- a/thirdparty/icu4c/common/uresbund.cpp +++ b/thirdparty/icu4c/common/uresbund.cpp @@ -24,6 +24,7 @@ #include "unicode/ures.h" #include "unicode/ustring.h" #include "unicode/ucnv.h" +#include "bytesinkutil.h" #include "charstr.h" #include "uresimp.h" #include "ustr_imp.h" @@ -2351,7 +2352,66 @@ struct GetAllChildrenSink : public ResourceSink { aliasedValue.setData(aliasRB->getResData()); aliasedValue.setValidLocaleDataEntry(aliasRB->fValidLocaleDataEntry); aliasedValue.setResource(aliasRB->fRes, ResourceTracer(aliasRB)); - dest.put(key, aliasedValue, isRoot, errorCode); + + if (aliasedValue.getType() != URES_TABLE) { + dest.put(key, aliasedValue, isRoot, errorCode); + } else { + // if the resource we're aliasing over to is a table, the sink might iterate over its contents. + // If it does, it'll get only the things defined in the actual alias target, not the things + // the target inherits from its parent resources. So we walk the parent chain for the *alias target*, + // calling dest.put() for each of the parent tables we could be inheriting from. This means + // that dest.put() has to iterate over the children of multiple tables to get all of the inherited + // resource values, but it already has to do that to handle normal vertical inheritance. + UResType aliasedValueType = URES_TABLE; + CharString tablePath; + tablePath.append(aliasRB->fResPath, errorCode); + const char* parentKey = key; // dest.put() changes the key + dest.put(parentKey, aliasedValue, isRoot, errorCode); + UResourceDataEntry* entry = aliasRB->fData; + Resource res = aliasRB->fRes; + while (aliasedValueType == URES_TABLE && entry->fParent != nullptr) { + CharString localPath; + localPath.copyFrom(tablePath, errorCode); + char* localPathAsCharPtr = localPath.data(); + const char* childKey; + entry = entry->fParent; + res = entry->fData.rootRes; + Resource newRes = res_findResource(&entry->fData, res, &localPathAsCharPtr, &childKey); + if (newRes != RES_BOGUS) { + aliasedValue.setData(entry->fData); + // TODO: do I also need to call aliasedValue.setValueLocaleDataEntry() ? + aliasedValue.setResource(newRes, ResourceTracer(aliasRB)); // probably wrong to use aliasRB here + aliasedValueType = aliasedValue.getType(); + if (aliasedValueType == URES_ALIAS) { + // in a few rare cases, when we get to the root resource bundle, the resource in question + // won't be an actual table, but will instead be an alias to a table. That is, we have + // two aliases in the inheritance path. (For some locales, such as Zulu, we see this with + // children of the "fields" resource: "day-narrow" aliases to "day-short", which aliases + // to "day".) When this happens, we need to make sure we follow all the aliases. + ResourceDataValue& rdv2 = static_cast<ResourceDataValue&>(aliasedValue); + aliasRB = getAliasTargetAsResourceBundle(rdv2.getData(), rdv2.getResource(), nullptr, -1, + rdv2.getValidLocaleDataEntry(), nullptr, 0, + stackTempBundle.getAlias(), &errorCode); + tablePath.clear(); + tablePath.append(aliasRB->fResPath, errorCode); + entry = aliasRB->fData; + res = aliasRB->fRes; + aliasedValue.setData(entry->fData); + // TODO: do I also need to call aliasedValue.setValueLocaleDataEntry() ? + aliasedValue.setResource(res, ResourceTracer(aliasRB)); // probably wrong to use aliasRB here + aliasedValueType = aliasedValue.getType(); + } + if (aliasedValueType == URES_TABLE) { + dest.put(parentKey, aliasedValue, isRoot, errorCode); + } else { + // once we've followed the alias, the resource we're looking at really should + // be a table + errorCode = U_INTERNAL_PROGRAM_ERROR; + return; + } + } + } + } } } else { dest.put(key, value, isRoot, errorCode); @@ -2657,13 +2717,16 @@ ures_openWithType(UResourceBundle *r, const char* path, const char* localeID, UResourceDataEntry *entry; if(openType != URES_OPEN_DIRECT) { /* first "canonicalize" the locale ID */ - char canonLocaleID[ULOC_FULLNAME_CAPACITY]; - uloc_getBaseName(localeID, canonLocaleID, UPRV_LENGTHOF(canonLocaleID), status); - if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) { + CharString canonLocaleID; + { + CharStringByteSink sink(&canonLocaleID); + ulocimp_getBaseName(localeID, sink, status); + } + if(U_FAILURE(*status)) { *status = U_ILLEGAL_ARGUMENT_ERROR; return nullptr; } - entry = entryOpen(path, canonLocaleID, openType, status); + entry = entryOpen(path, canonLocaleID.data(), openType, status); } else { entry = entryOpenDirect(path, localeID, status); } @@ -2974,15 +3037,39 @@ static UBool isLocaleInList(UEnumeration *locEnum, const char *locToSearch, UErr return false; } +static void getParentForFunctionalEquivalent(const char* localeID, + UResourceBundle* res, + UResourceBundle* bund1, + char* parent, + int32_t parentCapacity) { + // Get parent. + // First check for a parent from %%Parent resource (Note that in resource trees + // such as collation, data may have different parents than in parentLocales). + UErrorCode subStatus = U_ZERO_ERROR; + parent[0] = '\0'; + if (res != NULL) { + ures_getByKey(res, "%%Parent", bund1, &subStatus); + if (U_SUCCESS(subStatus)) { + int32_t parentLen = parentCapacity; + ures_getUTF8String(bund1, parent, &parentLen, true, &subStatus); + } + } + + // If none there, use normal truncation parent + if (U_FAILURE(subStatus) || parent[0] == 0) { + subStatus = U_ZERO_ERROR; + uloc_getParent(localeID, parent, parentCapacity, &subStatus); + } +} + U_CAPI int32_t U_EXPORT2 ures_getFunctionalEquivalent(char *result, int32_t resultCapacity, const char *path, const char *resName, const char *keyword, const char *locid, UBool *isAvailable, UBool omitDefault, UErrorCode *status) { - char kwVal[1024] = ""; /* value of keyword 'keyword' */ char defVal[1024] = ""; /* default value for given locale */ char defLoc[1024] = ""; /* default value for given locale */ - char base[1024] = ""; /* base locale */ + CharString base; /* base locale */ char found[1024] = ""; char parent[1024] = ""; char full[1024] = ""; @@ -2991,23 +3078,29 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity, UErrorCode subStatus = U_ZERO_ERROR; int32_t length = 0; if(U_FAILURE(*status)) return 0; - uloc_getKeywordValue(locid, keyword, kwVal, 1024-1,&subStatus); - if(!uprv_strcmp(kwVal, DEFAULT_TAG)) { - kwVal[0]=0; + CharString kwVal; + { + CharStringByteSink sink(&kwVal); + ulocimp_getKeywordValue(locid, keyword, sink, &subStatus); + } + if(kwVal == DEFAULT_TAG) { + kwVal.clear(); + } + { + CharStringByteSink sink(&base); + ulocimp_getBaseName(locid, sink, &subStatus); } - uloc_getBaseName(locid, base, 1024-1,&subStatus); #if defined(URES_TREE_DEBUG) fprintf(stderr, "getFunctionalEquivalent: \"%s\" [%s=%s] in %s - %s\n", - locid, keyword, kwVal, base, u_errorName(subStatus)); + locid, keyword, kwVal.data(), base.data(), u_errorName(subStatus)); #endif ures_initStackObject(&bund1); ures_initStackObject(&bund2); - - - uprv_strcpy(parent, base); - uprv_strcpy(found, base); - if(isAvailable) { + base.extract(parent, UPRV_LENGTHOF(parent), subStatus); + base.extract(found, UPRV_LENGTHOF(found), subStatus); + + if(isAvailable) { UEnumeration *locEnum = ures_openAvailableLocales(path, &subStatus); *isAvailable = true; if (U_SUCCESS(subStatus)) { @@ -3054,11 +3147,11 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity, path?path:"ICUDATA", parent, keyword, defVal, u_errorName(subStatus)); #endif uprv_strcpy(defLoc, parent); - if(kwVal[0]==0) { - uprv_strcpy(kwVal, defVal); + if(kwVal.isEmpty()) { + kwVal.append(defVal, defLen, subStatus); #if defined(URES_TREE_DEBUG) fprintf(stderr, "%s;%s -> kwVal = %s\n", - path?path:"ICUDATA", parent, keyword, kwVal); + path?path:"ICUDATA", parent, keyword, kwVal.data()); #endif } } @@ -3071,16 +3164,19 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity, uprv_strcpy(found, ures_getLocaleByType(res, ULOC_VALID_LOCALE, &subStatus)); } - uloc_getParent(found,parent,sizeof(parent),&subStatus); + if (uprv_strcmp(found, parent) != 0) { + uprv_strcpy(parent, found); + } else { + getParentForFunctionalEquivalent(found,res,&bund1,parent,sizeof(parent)); + } ures_close(res); } while(!defVal[0] && *found && uprv_strcmp(found, "root") != 0 && U_SUCCESS(*status)); /* Now, see if we can find the kwVal collator.. start the search over.. */ - uprv_strcpy(parent, base); - uprv_strcpy(found, base); - + base.extract(parent, UPRV_LENGTHOF(parent), subStatus); + base.extract(found, UPRV_LENGTHOF(found), subStatus); + do { - subStatus = U_ZERO_ERROR; res = ures_open(path, parent, &subStatus); if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) { *isAvailable = false; @@ -3089,7 +3185,7 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity, #if defined(URES_TREE_DEBUG) fprintf(stderr, "%s;%s -> %s (looking for %s)\n", - path?path:"ICUDATA", parent, u_errorName(subStatus), kwVal); + path?path:"ICUDATA", parent, u_errorName(subStatus), kwVal.data()); #endif if(U_FAILURE(subStatus)) { *status = subStatus; @@ -3099,14 +3195,14 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity, /**/ fprintf(stderr,"@%d [%s] %s\n", __LINE__, resName, u_errorName(subStatus)); #endif if(subStatus == U_ZERO_ERROR) { - ures_getByKey(&bund1, kwVal, &bund2, &subStatus); + ures_getByKey(&bund1, kwVal.data(), &bund2, &subStatus); #if defined(URES_TREE_DEBUG) -/**/ fprintf(stderr,"@%d [%s] %s\n", __LINE__, kwVal, u_errorName(subStatus)); +/**/ fprintf(stderr,"@%d [%s] %s\n", __LINE__, kwVal.data(), u_errorName(subStatus)); #endif if(subStatus == U_ZERO_ERROR) { #if defined(URES_TREE_DEBUG) fprintf(stderr, "%s;%s -> full0 %s=%s, %s\n", - path?path:"ICUDATA", parent, keyword, kwVal, u_errorName(subStatus)); + path?path:"ICUDATA", parent, keyword, kwVal.data(), u_errorName(subStatus)); #endif uprv_strcpy(full, parent); if(*full == 0) { @@ -3139,29 +3235,52 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity, } else { #if defined(URES_TREE_DEBUG) fprintf(stderr, "err=%s in %s looking for %s\n", - u_errorName(subStatus), parent, kwVal); + u_errorName(subStatus), parent, kwVal.data()); #endif } } } - subStatus = U_ZERO_ERROR; - - uprv_strcpy(found, parent); - uloc_getParent(found,parent,1023,&subStatus); + UBool haveFound = false; + // At least for collations which may be aliased, we need to use the VALID locale + // as the parent instead of just truncating, as long as the VALID locale is not + // root and has a different language than the parent. Use of the VALID locale + // here is similar to the procedure used at the end of the previous do-while loop + // for all resource types. + if (res != NULL && uprv_strcmp(resName, "collations") == 0) { + subStatus = U_ZERO_ERROR; + const char *validLoc = ures_getLocaleByType(res, ULOC_VALID_LOCALE, &subStatus); + if (U_SUCCESS(subStatus) && validLoc != NULL && validLoc[0] != 0 && uprv_strcmp(validLoc, "root") != 0) { + char validLang[ULOC_LANG_CAPACITY]; + char parentLang[ULOC_LANG_CAPACITY]; + uloc_getLanguage(validLoc, validLang, ULOC_LANG_CAPACITY, &subStatus); + uloc_getLanguage(parent, parentLang, ULOC_LANG_CAPACITY, &subStatus); + if (U_SUCCESS(subStatus) && uprv_strcmp(validLang, parentLang) != 0) { + // validLoc is not root and has a different language than parent, use it instead + uprv_strcpy(found, validLoc); + haveFound = true; + } + } + subStatus = U_ZERO_ERROR; + } + if (!haveFound) { + uprv_strcpy(found, parent); + } + + getParentForFunctionalEquivalent(found,res,&bund1,parent,1023); ures_close(res); + subStatus = U_ZERO_ERROR; } while(!full[0] && *found && U_SUCCESS(*status)); - - if((full[0]==0) && uprv_strcmp(kwVal, defVal)) { + + if((full[0]==0) && kwVal != defVal) { #if defined(URES_TREE_DEBUG) - fprintf(stderr, "Failed to locate kw %s - try default %s\n", kwVal, defVal); + fprintf(stderr, "Failed to locate kw %s - try default %s\n", kwVal.data(), defVal); #endif - uprv_strcpy(kwVal, defVal); - uprv_strcpy(parent, base); - uprv_strcpy(found, base); - + kwVal.clear().append(defVal, subStatus); + base.extract(parent, UPRV_LENGTHOF(parent), subStatus); + base.extract(found, UPRV_LENGTHOF(found), subStatus); + do { /* search for 'default' named item */ - subStatus = U_ZERO_ERROR; res = ures_open(path, parent, &subStatus); if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) { *isAvailable = false; @@ -3170,18 +3289,18 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity, #if defined(URES_TREE_DEBUG) fprintf(stderr, "%s;%s -> %s (looking for default %s)\n", - path?path:"ICUDATA", parent, u_errorName(subStatus), kwVal); + path?path:"ICUDATA", parent, u_errorName(subStatus), kwVal.data()); #endif if(U_FAILURE(subStatus)) { *status = subStatus; } else if(subStatus == U_ZERO_ERROR) { ures_getByKey(res,resName,&bund1, &subStatus); if(subStatus == U_ZERO_ERROR) { - ures_getByKey(&bund1, kwVal, &bund2, &subStatus); + ures_getByKey(&bund1, kwVal.data(), &bund2, &subStatus); if(subStatus == U_ZERO_ERROR) { #if defined(URES_TREE_DEBUG) fprintf(stderr, "%s;%s -> full1 %s=%s, %s\n", path?path:"ICUDATA", - parent, keyword, kwVal, u_errorName(subStatus)); + parent, keyword, kwVal.data(), u_errorName(subStatus)); #endif uprv_strcpy(full, parent); if(*full == 0) { @@ -3215,18 +3334,18 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity, } } } - subStatus = U_ZERO_ERROR; uprv_strcpy(found, parent); - uloc_getParent(found,parent,1023,&subStatus); + getParentForFunctionalEquivalent(found,res,&bund1,parent,1023); ures_close(res); + subStatus = U_ZERO_ERROR; } while(!full[0] && *found && U_SUCCESS(*status)); } if(U_SUCCESS(*status)) { if(!full[0]) { #if defined(URES_TREE_DEBUG) - fprintf(stderr, "Still could not load keyword %s=%s\n", keyword, kwVal); + fprintf(stderr, "Still could not load keyword %s=%s\n", keyword, kwVal.data()); #endif *status = U_MISSING_RESOURCE_ERROR; } else if(omitDefault) { @@ -3235,21 +3354,21 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity, #endif if(uprv_strlen(defLoc) <= uprv_strlen(full)) { /* found the keyword in a *child* of where the default tag was present. */ - if(!uprv_strcmp(kwVal, defVal)) { /* if the requested kw is default, */ + if(kwVal == defVal) { /* if the requested kw is default, */ /* and the default is in or in an ancestor of the current locale */ #if defined(URES_TREE_DEBUG) - fprintf(stderr, "Removing unneeded var %s=%s\n", keyword, kwVal); + fprintf(stderr, "Removing unneeded var %s=%s\n", keyword, kwVal.data()); #endif - kwVal[0]=0; + kwVal.clear(); } } } uprv_strcpy(found, full); - if(kwVal[0]) { + if(!kwVal.isEmpty()) { uprv_strcat(found, "@"); uprv_strcat(found, keyword); uprv_strcat(found, "="); - uprv_strcat(found, kwVal); + uprv_strcat(found, kwVal.data()); } else if(!omitDefault) { uprv_strcat(found, "@"); uprv_strcat(found, keyword); diff --git a/thirdparty/icu4c/common/ustrcase.cpp b/thirdparty/icu4c/common/ustrcase.cpp index 537b5ba857..e4aec8a1c7 100644 --- a/thirdparty/icu4c/common/ustrcase.cpp +++ b/thirdparty/icu4c/common/ustrcase.cpp @@ -1130,14 +1130,18 @@ int32_t toUpper(uint32_t options, // Adding one only to the final vowel in a longer sequence // (which does not occur in normal writing) would require lookahead. // Set the same flag as for preserving an existing dialytika. - if ((data & HAS_VOWEL) != 0 && (state & AFTER_VOWEL_WITH_ACCENT) != 0 && - (upper == 0x399 || upper == 0x3A5)) { - data |= HAS_DIALYTIKA; + if ((data & HAS_VOWEL) != 0 && + (state & (AFTER_VOWEL_WITH_PRECOMPOSED_ACCENT | AFTER_VOWEL_WITH_COMBINING_ACCENT)) != + 0 && + (upper == 0x399 || upper == 0x3A5)) { + data |= (state & AFTER_VOWEL_WITH_PRECOMPOSED_ACCENT) ? HAS_DIALYTIKA + : HAS_COMBINING_DIALYTIKA; } int32_t numYpogegrammeni = 0; // Map each one to a trailing, spacing, capital iota. if ((data & HAS_YPOGEGRAMMENI) != 0) { numYpogegrammeni = 1; } + const UBool hasPrecomposedAccent = (data & HAS_ACCENT) != 0; // Skip combining diacritics after this Greek letter. while (nextIndex < srcLength) { uint32_t diacriticData = getDiacriticData(src[nextIndex]); @@ -1152,7 +1156,8 @@ int32_t toUpper(uint32_t options, } } if ((data & HAS_VOWEL_AND_ACCENT_AND_DIALYTIKA) == HAS_VOWEL_AND_ACCENT) { - nextState |= AFTER_VOWEL_WITH_ACCENT; + nextState |= hasPrecomposedAccent ? AFTER_VOWEL_WITH_PRECOMPOSED_ACCENT + : AFTER_VOWEL_WITH_COMBINING_ACCENT; } // Map according to Greek rules. UBool addTonos = false; @@ -1163,7 +1168,7 @@ int32_t toUpper(uint32_t options, !isFollowedByCasedLetter(src, nextIndex, srcLength)) { // Keep disjunctive "or" with (only) a tonos. // We use the same "word boundary" conditions as for the Final_Sigma test. - if (i == nextIndex) { + if (hasPrecomposedAccent) { upper = 0x389; // Preserve the precomposed form. } else { addTonos = true; diff --git a/thirdparty/icu4c/common/uts46.cpp b/thirdparty/icu4c/common/uts46.cpp index fce2af4130..28f15f7175 100644 --- a/thirdparty/icu4c/common/uts46.cpp +++ b/thirdparty/icu4c/common/uts46.cpp @@ -669,14 +669,6 @@ UTS46::mapDevChars(UnicodeString &dest, int32_t labelStart, int32_t mappingStart return length; } -// Some non-ASCII characters are equivalent to sequences with -// non-LDH ASCII characters. To find them: -// grep disallowed_STD3_valid IdnaMappingTable.txt (or uts46.txt) -static inline UBool -isNonASCIIDisallowedSTD3Valid(UChar32 c) { - return c==0x2260 || c==0x226E || c==0x226F; -} - // Replace the label in dest with the label string, if the label was modified. // If &label==&dest then the label was modified in-place and labelLength // is the new label length, different from label.length(). @@ -820,10 +812,7 @@ UTS46::processLabel(UnicodeString &dest, } } else { oredChars|=c; - if(disallowNonLDHDot && isNonASCIIDisallowedSTD3Valid(c)) { - info.labelErrors|=UIDNA_ERROR_DISALLOWED; - *s=0xfffd; - } else if(c==0xfffd) { + if(c==0xfffd) { info.labelErrors|=UIDNA_ERROR_DISALLOWED; } } diff --git a/thirdparty/icu4c/i18n/unicode/uspoof.h b/thirdparty/icu4c/i18n/unicode/uspoof.h index 442655bb54..20d29d62b2 100644 --- a/thirdparty/icu4c/i18n/unicode/uspoof.h +++ b/thirdparty/icu4c/i18n/unicode/uspoof.h @@ -19,6 +19,7 @@ #ifndef USPOOF_H #define USPOOF_H +#include "unicode/ubidi.h" #include "unicode/utypes.h" #include "unicode/uset.h" #include "unicode/parseerr.h" @@ -83,6 +84,25 @@ * the instance should be created once (e.g., upon application startup), and the efficient * {@link uspoof_areConfusable} method can be used at runtime. * + * If the paragraph direction used to display the strings is known, the bidi function should be used instead: + * + * \code{.c} + * UErrorCode status = U_ZERO_ERROR; + * // These strings look identical when rendered in a left-to-right context. + * // They look distinct in a right-to-left context. + * UChar* str1 = (UChar*) u"A1\u05D0"; // A1א + * UChar* str2 = (UChar*) u"A\u05D01"; // Aא1 + * + * USpoofChecker* sc = uspoof_open(&status); + * uspoof_setChecks(sc, USPOOF_CONFUSABLE, &status); + * + * int32_t bitmask = uspoof_areBidiConfusable(sc, UBIDI_LTR, str1, -1, str2, -1, &status); + * UBool result = bitmask != 0; + * // areBidiConfusable: 1 (status: U_ZERO_ERROR) + * printf("areBidiConfusable: %d (status: %s)\n", result, u_errorName(status)); + * uspoof_close(sc); + * \endcode + * * <p> * The type {@link LocalUSpoofCheckerPointer} is exposed for C++ programmers. It will automatically call * {@link uspoof_close} when the object goes out of scope: @@ -339,6 +359,51 @@ * COMMON or INHERITED, such as numbers and punctuation, are ignored when computing whether a string has multiple * scripts. * + * <h2>Advanced bidirectional usage</h2> + * If the paragraph direction with which the identifiers will be displayed is not known, there are + * multiple options for confusable detection depending on the circumstances. + * + * <p> + * In some circumstances, the only concern is confusion between identifiers displayed with the same + * paragraph direction. + * + * <p> + * An example is the case where identifiers are usernames prefixed with the @ symbol. + * That symbol will appear to the left in a left-to-right context, and to the right in a + * right-to-left context, so that an identifier displayed in a left-to-right context can never be + * confused with an identifier displayed in a right-to-left context: + * <ul> + * <li> + * The usernames "A1א" (A one aleph) and "Aא1" (A aleph 1) + * would be considered confusable, since they both appear as \@A1א in a left-to-right context, and the + * usernames "אA_1" (aleph A underscore one) and "א1_A" (aleph one underscore A) would be considered + * confusable, since they both appear as A_1א@ in a right-to-left context. + * </li> + * <li> + * The username "Mark_" would not be considered confusable with the username "_Mark", + * even though the latter would appear as Mark_@ in a right-to-left context, and the + * former as \@Mark_ in a left-to-right context. + * </li> + * </ul> + * <p> + * In that case, the caller should check for both LTR-confusability and RTL-confusability: + * + * \code{.cpp} + * bool confusableInEitherDirection = + * uspoof_areBidiConfusableUnicodeString(sc, UBIDI_LTR, id1, id2, &status) || + * uspoof_areBidiConfusableUnicodeString(sc, UBIDI_RTL, id1, id2, &status); + * \endcode + * + * If the bidiSkeleton is used, the LTR and RTL skeleta should be kept separately and compared, LTR + * with LTR and RTL with RTL. + * + * <p> + * In cases where confusability between the visual appearances of an identifier displayed in a + * left-to-right context with another identifier displayed in a right-to-left context is a concern, + * the LTR skeleton of one can be compared with the RTL skeleton of the other. However, this + * very broad definition of confusability may have unexpected results; for instance, it treats the + * ASCII identifiers "Mark_" and "_Mark" as confusable. + * * <h2>Additional Information</h2> * * A <code>USpoofChecker</code> instance may be used repeatedly to perform checks on any number of identifiers. @@ -519,7 +584,7 @@ typedef enum USpoofChecks { /** - * Constants from UAX #39 for use in {@link uspoof_setRestrictionLevel}, and + * Constants from UTS #39 for use in {@link uspoof_setRestrictionLevel}, and * for returned identifier restriction levels in check results. * * @stable ICU 51 @@ -633,8 +698,8 @@ uspoof_openFromSerialized(const void *data, int32_t length, int32_t *pActualLeng /** * Open a Spoof Checker from the source form of the spoof data. * The input corresponds to the Unicode data file confusables.txt - * as described in Unicode UAX #39. The syntax of the source data - * is as described in UAX #39 for this file, and the content of + * as described in Unicode Technical Standard #39. The syntax of the source data + * is as described in UTS #39 for this file, and the content of * this file is acceptable input. * * The character encoding of the (char *) input text is UTF-8. @@ -1111,7 +1176,7 @@ uspoof_getCheckResultNumerics(const USpoofCheckResult *checkResult, UErrorCode * /** - * Check the whether two specified strings are visually confusable. + * Check whether two specified strings are visually confusable. * * If the strings are confusable, the return value will be nonzero, as long as * {@link USPOOF_CONFUSABLE} was enabled in uspoof_setChecks(). @@ -1159,7 +1224,58 @@ uspoof_areConfusable(const USpoofChecker *sc, const UChar *id2, int32_t length2, UErrorCode *status); - +#ifndef U_HIDE_DRAFT_API +/** + * Check whether two specified strings are visually confusable when + * displayed in a context with the given paragraph direction. + * + * If the strings are confusable, the return value will be nonzero, as long as + * {@link USPOOF_CONFUSABLE} was enabled in uspoof_setChecks(). + * + * The bits in the return value correspond to flags for each of the classes of + * confusables applicable to the two input strings. According to UTS 39 + * section 4, the possible flags are: + * + * <ul> + * <li>{@link USPOOF_SINGLE_SCRIPT_CONFUSABLE}</li> + * <li>{@link USPOOF_MIXED_SCRIPT_CONFUSABLE}</li> + * <li>{@link USPOOF_WHOLE_SCRIPT_CONFUSABLE}</li> + * </ul> + * + * If one or more of the above flags were not listed in uspoof_setChecks(), this + * function will never report that class of confusable. The check + * {@link USPOOF_CONFUSABLE} enables all three flags. + * + * + * @param sc The USpoofChecker + * @param direction The paragraph direction with which the identifiers are + * displayed. Must be either UBIDI_LTR or UBIDI_RTL. + * @param id1 The first of the two identifiers to be compared for + * confusability. The strings are in UTF-16 format. + * @param length1 the length of the first identifier, expressed in + * 16 bit UTF-16 code units, or -1 if the string is + * nul terminated. + * @param id2 The second of the two identifiers to be compared for + * confusability. The identifiers are in UTF-16 format. + * @param length2 The length of the second identifiers, expressed in + * 16 bit UTF-16 code units, or -1 if the string is + * nul terminated. + * @param status The error code, set if an error occurred while attempting to + * perform the check. + * Confusability of the identifiers is not reported here, + * but through this function's return value. + * @return An integer value with bit(s) set corresponding to + * the type of confusability found, as defined by + * enum USpoofChecks. Zero is returned if the identifiers + * are not confusable. + * + * @draft ICU 74 + */ +U_CAPI uint32_t U_EXPORT2 uspoof_areBidiConfusable(const USpoofChecker *sc, UBiDiDirection direction, + const UChar *id1, int32_t length1, + const UChar *id2, int32_t length2, + UErrorCode *status); +#endif /* U_HIDE_DRAFT_API */ /** * A version of {@link uspoof_areConfusable} accepting strings in UTF-8 format. @@ -1192,14 +1308,45 @@ uspoof_areConfusableUTF8(const USpoofChecker *sc, const char *id2, int32_t length2, UErrorCode *status); - - +#ifndef U_HIDE_DRAFT_API +/** + * A version of {@link uspoof_areBidiConfusable} accepting strings in UTF-8 format. + * + * @param sc The USpoofChecker + * @param direction The paragraph direction with which the identifiers are + * displayed. Must be either UBIDI_LTR or UBIDI_RTL. + * @param id1 The first of the two identifiers to be compared for + * confusability. The strings are in UTF-8 format. + * @param length1 the length of the first identifiers, in bytes, or -1 + * if the string is nul terminated. + * @param id2 The second of the two identifiers to be compared for + * confusability. The strings are in UTF-8 format. + * @param length2 The length of the second string in bytes, or -1 + * if the string is nul terminated. + * @param status The error code, set if an error occurred while attempting to + * perform the check. + * Confusability of the strings is not reported here, + * but through this function's return value. + * @return An integer value with bit(s) set corresponding to + * the type of confusability found, as defined by + * enum USpoofChecks. Zero is returned if the strings + * are not confusable. + * + * @draft ICU 74 + * + * @see uspoof_areBidiConfusable + */ +U_CAPI uint32_t U_EXPORT2 uspoof_areBidiConfusableUTF8(const USpoofChecker *sc, UBiDiDirection direction, + const char *id1, int32_t length1, + const char *id2, int32_t length2, + UErrorCode *status); +#endif /* U_HIDE_DRAFT_API */ /** * Get the "skeleton" for an identifier. * Skeletons are a transformation of the input identifier; * Two identifiers are confusable if their skeletons are identical. - * See Unicode UAX #39 for additional information. + * See Unicode Technical Standard #39 for additional information. * * Using skeletons directly makes it possible to quickly check * whether an identifier is confusable with any of some large @@ -1233,11 +1380,50 @@ uspoof_getSkeleton(const USpoofChecker *sc, UChar *dest, int32_t destCapacity, UErrorCode *status); +#ifndef U_HIDE_DRAFT_API +/** + * Get the "bidiSkeleton" for an identifier and a direction. + * Skeletons are a transformation of the input identifier; + * Two identifiers are LTR-confusable if their LTR bidiSkeletons are identical; + * they are RTL-confusable if their RTL bidiSkeletons are identical. + * See Unicode Technical Standard #39 for additional information: + * https://www.unicode.org/reports/tr39/#Confusable_Detection. + * + * Using skeletons directly makes it possible to quickly check + * whether an identifier is confusable with any of some large + * set of existing identifiers, by creating an efficiently + * searchable collection of the skeletons. + * + * @param sc The USpoofChecker. + * @param direction The context direction with which the identifier will be + * displayed. Must be either UBIDI_LTR or UBIDI_RTL. + * @param id The input identifier whose skeleton will be computed. + * @param length The length of the input identifier, expressed in 16 bit + * UTF-16 code units, or -1 if the string is zero terminated. + * @param dest The output buffer, to receive the skeleton string. + * @param destCapacity The length of the output buffer, in 16 bit units. + * The destCapacity may be zero, in which case the function will + * return the actual length of the skeleton. + * @param status The error code, set if an error occurred while attempting to + * perform the check. + * @return The length of the skeleton string. The returned length + * is always that of the complete skeleton, even when the + * supplied buffer is too small (or of zero length) + * + * @draft ICU 74 + * @see uspoof_areBidiConfusable + */ +U_CAPI int32_t U_EXPORT2 uspoof_getBidiSkeleton(const USpoofChecker *sc, + UBiDiDirection direction, + const UChar *id, int32_t length, + UChar *dest, int32_t destCapacity, UErrorCode *status); +#endif /* U_HIDE_DRAFT_API */ + /** * Get the "skeleton" for an identifier. * Skeletons are a transformation of the input identifier; * Two identifiers are confusable if their skeletons are identical. - * See Unicode UAX #39 for additional information. + * See Unicode Technical Standard #39 for additional information. * * Using skeletons directly makes it possible to quickly check * whether an identifier is confusable with any of some large @@ -1273,6 +1459,46 @@ uspoof_getSkeletonUTF8(const USpoofChecker *sc, char *dest, int32_t destCapacity, UErrorCode *status); +#ifndef U_HIDE_DRAFT_API +/** + * Get the "bidiSkeleton" for an identifier and a direction. + * Skeletons are a transformation of the input identifier; + * Two identifiers are LTR-confusable if their LTR bidiSkeletons are identical; + * they are RTL-confusable if their RTL bidiSkeletons are identical. + * See Unicode Technical Standard #39 for additional information: + * https://www.unicode.org/reports/tr39/#Confusable_Detection. + * + * Using skeletons directly makes it possible to quickly check + * whether an identifier is confusable with any of some large + * set of existing identifiers, by creating an efficiently + * searchable collection of the skeletons. + * + * @param sc The USpoofChecker + * @param direction The context direction with which the identifier will be + * displayed. Must be either UBIDI_LTR or UBIDI_RTL. + * @param id The UTF-8 format identifier whose skeleton will be computed. + * @param length The length of the input string, in bytes, + * or -1 if the string is zero terminated. + * @param dest The output buffer, to receive the skeleton string. + * @param destCapacity The length of the output buffer, in bytes. + * The destCapacity may be zero, in which case the function will + * return the actual length of the skeleton. + * @param status The error code, set if an error occurred while attempting to + * perform the check. Possible Errors include U_INVALID_CHAR_FOUND + * for invalid UTF-8 sequences, and + * U_BUFFER_OVERFLOW_ERROR if the destination buffer is too small + * to hold the complete skeleton. + * @return The length of the skeleton string, in bytes. The returned length + * is always that of the complete skeleton, even when the + * supplied buffer is too small (or of zero length) + * + * @draft ICU 74 + */ +U_CAPI int32_t U_EXPORT2 uspoof_getBidiSkeletonUTF8(const USpoofChecker *sc, UBiDiDirection direction, + const char *id, int32_t length, char *dest, + int32_t destCapacity, UErrorCode *status); +#endif /* U_HIDE_DRAFT_API */ + /** * Get the set of Candidate Characters for Inclusion in Identifiers, as defined * in http://unicode.org/Public/security/latest/xidmodifications.txt @@ -1510,11 +1736,42 @@ uspoof_areConfusableUnicodeString(const USpoofChecker *sc, const icu::UnicodeString &s2, UErrorCode *status); +#ifndef U_HIDE_DRAFT_API +/** + * A version of {@link uspoof_areBidiConfusable} accepting UnicodeStrings. + * + * @param sc The USpoofChecker + * @param direction The paragraph direction with which the identifiers are + * displayed. Must be either UBIDI_LTR or UBIDI_RTL. + * @param s1 The first of the two identifiers to be compared for + * confusability. The strings are in UTF-8 format. + * @param s2 The second of the two identifiers to be compared for + * confusability. The strings are in UTF-8 format. + * @param status The error code, set if an error occurred while attempting to + * perform the check. + * Confusability of the identifiers is not reported here, + * but through this function's return value. + * @return An integer value with bit(s) set corresponding to + * the type of confusability found, as defined by + * enum USpoofChecks. Zero is returned if the identifiers + * are not confusable. + * + * @draft ICU 74 + * + * @see uspoof_areBidiConfusable + */ +U_CAPI uint32_t U_EXPORT2 uspoof_areBidiConfusableUnicodeString(const USpoofChecker *sc, + UBiDiDirection direction, + const icu::UnicodeString &s1, + const icu::UnicodeString &s2, + UErrorCode *status); +#endif /* U_HIDE_DRAFT_API */ + /** * Get the "skeleton" for an identifier. * Skeletons are a transformation of the input identifier; * Two identifiers are confusable if their skeletons are identical. - * See Unicode UAX #39 for additional information. + * See Unicode Technical Standard #39 for additional information. * * Using skeletons directly makes it possible to quickly check * whether an identifier is confusable with any of some large @@ -1540,6 +1797,36 @@ uspoof_getSkeletonUnicodeString(const USpoofChecker *sc, icu::UnicodeString &dest, UErrorCode *status); +#ifndef U_HIDE_DRAFT_API +/** + * Get the "bidiSkeleton" for an identifier and a direction. + * Skeletons are a transformation of the input identifier; + * Two identifiers are LTR-confusable if their LTR bidiSkeletons are identical; + * they are RTL-confusable if their RTL bidiSkeletons are identical. + * See Unicode Technical Standard #39 for additional information. + * https://www.unicode.org/reports/tr39/#Confusable_Detection. + * + * Using skeletons directly makes it possible to quickly check + * whether an identifier is confusable with any of some large + * set of existing identifiers, by creating an efficiently + * searchable collection of the skeletons. + * + * @param sc The USpoofChecker. + * @param direction The context direction with which the identifier will be + * displayed. Must be either UBIDI_LTR or UBIDI_RTL. + * @param id The input identifier whose bidiSkeleton will be computed. + * @param dest The output identifier, to receive the skeleton string. + * @param status The error code, set if an error occurred while attempting to + * perform the check. + * @return A reference to the destination (skeleton) string. + * + * @draft ICU 74 + */ +U_I18N_API icu::UnicodeString &U_EXPORT2 uspoof_getBidiSkeletonUnicodeString( + const USpoofChecker *sc, UBiDiDirection direction, const icu::UnicodeString &id, + icu::UnicodeString &dest, UErrorCode *status); +#endif /* U_HIDE_DRAFT_API */ + /** * Get the set of Candidate Characters for Inclusion in Identifiers, as defined * in http://unicode.org/Public/security/latest/xidmodifications.txt diff --git a/thirdparty/icu4c/i18n/uspoof.cpp b/thirdparty/icu4c/i18n/uspoof.cpp index 271caeafff..47dac8418e 100644 --- a/thirdparty/icu4c/i18n/uspoof.cpp +++ b/thirdparty/icu4c/i18n/uspoof.cpp @@ -15,6 +15,7 @@ * * Unicode Spoof Detection */ +#include "unicode/ubidi.h" #include "unicode/utypes.h" #include "unicode/normalizer2.h" #include "unicode/uspoof.h" @@ -141,8 +142,8 @@ void U_CALLCONV initializeStatics(UErrorCode &status) { u"\\U0001DF00-\\U0001DF1E\\U0001DF25-\\U0001DF2A\\U0001E08F\\U0001E7E0-" u"\\U0001E7E6\\U0001E7E8-\\U0001E7EB\\U0001E7ED\\U0001E7EE\\U0001E7F0-" u"\\U0001E7FE\\U00020000-\\U0002A6DF\\U0002A700-\\U0002B739\\U0002B740-" - u"\\U0002B81D\\U0002B820-\\U0002CEA1\\U0002CEB0-\\U0002EBE0\\U00030000-" - u"\\U0003134A\\U00031350-\\U000323AF]"; + u"\\U0002B81D\\U0002B820-\\U0002CEA1\\U0002CEB0-\\U0002EBE0\\U0002EBF0-" + u"\\U0002EE5D\\U00030000-\\U0003134A\\U00031350-\\U000323AF]"; gRecommendedSet = new UnicodeSet(UnicodeString(recommendedPat), status); if (gRecommendedSet == nullptr) { @@ -538,6 +539,90 @@ uspoof_areConfusableUnicodeString(const USpoofChecker *sc, return result; } +U_CAPI uint32_t U_EXPORT2 uspoof_areBidiConfusable(const USpoofChecker *sc, UBiDiDirection direction, + const char16_t *id1, int32_t length1, + const char16_t *id2, int32_t length2, + UErrorCode *status) { + UnicodeString id1Str((length1 == -1), id1, length1); // Aliasing constructor + UnicodeString id2Str((length2 == -1), id2, length2); // Aliasing constructor + if (id1Str.isBogus() || id2Str.isBogus()) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + return uspoof_areBidiConfusableUnicodeString(sc, direction, id1Str, id2Str, status); +} + +U_CAPI uint32_t U_EXPORT2 uspoof_areBidiConfusableUTF8(const USpoofChecker *sc, UBiDiDirection direction, + const char *id1, int32_t length1, const char *id2, + int32_t length2, UErrorCode *status) { + if (length1 < -1 || length2 < -1) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + UnicodeString id1Str = UnicodeString::fromUTF8( + StringPiece(id1, length1 >= 0 ? length1 : static_cast<int32_t>(uprv_strlen(id1)))); + UnicodeString id2Str = UnicodeString::fromUTF8( + StringPiece(id2, length2 >= 0 ? length2 : static_cast<int32_t>(uprv_strlen(id2)))); + return uspoof_areBidiConfusableUnicodeString(sc, direction, id1Str, id2Str, status); +} + +U_CAPI uint32_t U_EXPORT2 uspoof_areBidiConfusableUnicodeString(const USpoofChecker *sc, + UBiDiDirection direction, + const icu::UnicodeString &id1, + const icu::UnicodeString &id2, + UErrorCode *status) { + const SpoofImpl *This = SpoofImpl::validateThis(sc, *status); + if (U_FAILURE(*status)) { + return 0; + } + // + // See section 4 of UTS 39 for the algorithm for checking whether two strings are confusable, + // and for definitions of the types (single, whole, mixed-script) of confusables. + + // We only care about a few of the check flags. Ignore the others. + // If no tests relevant to this function have been specified, return an error. + // TODO: is this really the right thing to do? It's probably an error on the caller's part, + // but logically we would just return 0 (no error). + if ((This->fChecks & USPOOF_CONFUSABLE) == 0) { + *status = U_INVALID_STATE_ERROR; + return 0; + } + + // Compute the skeletons and check for confusability. + UnicodeString id1Skeleton; + uspoof_getBidiSkeletonUnicodeString(sc, direction, id1, id1Skeleton, status); + UnicodeString id2Skeleton; + uspoof_getBidiSkeletonUnicodeString(sc, direction, id2, id2Skeleton, status); + if (U_FAILURE(*status)) { + return 0; + } + if (id1Skeleton != id2Skeleton) { + return 0; + } + + // If we get here, the strings are confusable. Now we just need to set the flags for the appropriate + // classes of confusables according to UTS 39 section 4. Start by computing the resolved script sets + // of id1 and id2. + ScriptSet id1RSS; + This->getResolvedScriptSet(id1, id1RSS, *status); + ScriptSet id2RSS; + This->getResolvedScriptSet(id2, id2RSS, *status); + + // Turn on all applicable flags + uint32_t result = 0; + if (id1RSS.intersects(id2RSS)) { + result |= USPOOF_SINGLE_SCRIPT_CONFUSABLE; + } else { + result |= USPOOF_MIXED_SCRIPT_CONFUSABLE; + if (!id1RSS.isEmpty() && !id2RSS.isEmpty()) { + result |= USPOOF_WHOLE_SCRIPT_CONFUSABLE; + } + } + + // Turn off flags that the user doesn't want + return result & This->fChecks; +} + U_CAPI int32_t U_EXPORT2 uspoof_checkUnicodeString(const USpoofChecker *sc, @@ -697,6 +782,60 @@ uspoof_getSkeleton(const USpoofChecker *sc, return destStr.length(); } +U_CAPI int32_t U_EXPORT2 uspoof_getBidiSkeleton(const USpoofChecker *sc, UBiDiDirection direction, + const UChar *id, int32_t length, UChar *dest, + int32_t destCapacity, UErrorCode *status) { + UnicodeString idStr((length == -1), id, length); // Aliasing constructor + if (idStr.isBogus()) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + UnicodeString destStr; + uspoof_getBidiSkeletonUnicodeString(sc, direction, idStr, destStr, status); + return destStr.extract(dest, destCapacity, *status); +} + + + +U_I18N_API UnicodeString &U_EXPORT2 uspoof_getBidiSkeletonUnicodeString(const USpoofChecker *sc, + UBiDiDirection direction, + const UnicodeString &id, + UnicodeString &dest, + UErrorCode *status) { + dest.remove(); + if (direction != UBIDI_LTR && direction != UBIDI_RTL) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return dest; + } + UBiDi *bidi = ubidi_open(); + ubidi_setPara(bidi, id.getBuffer(), id.length(), direction, + /*embeddingLevels*/ nullptr, status); + if (U_FAILURE(*status)) { + ubidi_close(bidi); + return dest; + } + UnicodeString reordered; + int32_t const size = ubidi_getProcessedLength(bidi); + UChar* const reorderedBuffer = reordered.getBuffer(size); + if (reorderedBuffer == nullptr) { + *status = U_MEMORY_ALLOCATION_ERROR; + ubidi_close(bidi); + return dest; + } + ubidi_writeReordered(bidi, reorderedBuffer, size, + UBIDI_KEEP_BASE_COMBINING | UBIDI_DO_MIRRORING, status); + reordered.releaseBuffer(size); + ubidi_close(bidi); + + if (U_FAILURE(*status)) { + return dest; + } + + // The type parameter is deprecated since ICU 58; any number may be passed. + constexpr uint32_t deprecatedType = 58; + return uspoof_getSkeletonUnicodeString(sc, deprecatedType, reordered, dest, status); +} + U_I18N_API UnicodeString & U_EXPORT2 @@ -721,19 +860,17 @@ uspoof_getSkeletonUnicodeString(const USpoofChecker *sc, for (inputIndex=0; inputIndex < normalizedLen; ) { UChar32 c = nfdId.char32At(inputIndex); inputIndex += U16_LENGTH(c); - This->fSpoofData->confusableLookup(c, skelStr); + if (!u_hasBinaryProperty(c, UCHAR_DEFAULT_IGNORABLE_CODE_POINT)) { + This->fSpoofData->confusableLookup(c, skelStr); + } } gNfdNormalizer->normalize(skelStr, dest, *status); return dest; } - -U_CAPI int32_t U_EXPORT2 -uspoof_getSkeletonUTF8(const USpoofChecker *sc, - uint32_t type, - const char *id, int32_t length, - char *dest, int32_t destCapacity, +U_CAPI int32_t U_EXPORT2 uspoof_getSkeletonUTF8(const USpoofChecker *sc, uint32_t type, const char *id, + int32_t length, char *dest, int32_t destCapacity, UErrorCode *status) { SpoofImpl::validateThis(sc, *status); if (U_FAILURE(*status)) { @@ -744,7 +881,8 @@ uspoof_getSkeletonUTF8(const USpoofChecker *sc, return 0; } - UnicodeString srcStr = UnicodeString::fromUTF8(StringPiece(id, length>=0 ? length : static_cast<int32_t>(uprv_strlen(id)))); + UnicodeString srcStr = UnicodeString::fromUTF8( + StringPiece(id, length >= 0 ? length : static_cast<int32_t>(uprv_strlen(id)))); UnicodeString destStr; uspoof_getSkeletonUnicodeString(sc, type, srcStr, destStr, status); if (U_FAILURE(*status)) { @@ -752,8 +890,28 @@ uspoof_getSkeletonUTF8(const USpoofChecker *sc, } int32_t lengthInUTF8 = 0; - u_strToUTF8(dest, destCapacity, &lengthInUTF8, - destStr.getBuffer(), destStr.length(), status); + u_strToUTF8(dest, destCapacity, &lengthInUTF8, destStr.getBuffer(), destStr.length(), status); + return lengthInUTF8; +} + +U_CAPI int32_t U_EXPORT2 uspoof_getBidiSkeletonUTF8(const USpoofChecker *sc, UBiDiDirection direction, + const char *id, int32_t length, char *dest, + int32_t destCapacity, UErrorCode *status) { + if (length < -1) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + + UnicodeString srcStr = UnicodeString::fromUTF8( + StringPiece(id, length >= 0 ? length : static_cast<int32_t>(uprv_strlen(id)))); + UnicodeString destStr; + uspoof_getBidiSkeletonUnicodeString(sc, direction, srcStr, destStr, status); + if (U_FAILURE(*status)) { + return 0; + } + + int32_t lengthInUTF8 = 0; + u_strToUTF8(dest, destCapacity, &lengthInUTF8, destStr.getBuffer(), destStr.length(), status); return lengthInUTF8; } diff --git a/thirdparty/icu4c/icudt73l.dat b/thirdparty/icu4c/icudt74l.dat Binary files differindex fc007e5f96..8576067fd0 100644 --- a/thirdparty/icu4c/icudt73l.dat +++ b/thirdparty/icu4c/icudt74l.dat diff --git a/thirdparty/linuxbsd_headers/README.md b/thirdparty/linuxbsd_headers/README.md index af902aa97a..225dd62ad0 100644 --- a/thirdparty/linuxbsd_headers/README.md +++ b/thirdparty/linuxbsd_headers/README.md @@ -9,20 +9,21 @@ readability. - Upstream: https://www.alsa-project.org/ - Version: 1.1.3-5 -- License: LPGL-2.1+ +- License: LGPL-2.1+ Patches in the `patches` directory should be re-applied after updates. + ## dbus -- Upstream: https://www.freedesktop.org/wiki/software/dbus/ +- Upstream: https://www.freedesktop.org/wiki/Software/dbus/ - Version: 1.12.2 - License: AFL-2.1 ## fontconfig -- Upstream: https://www.freedesktop.org/wiki/software/fontconfig/ +- Upstream: https://www.freedesktop.org/wiki/Software/fontconfig/ - Version: 2.12.6 - License: fontconfig @@ -31,21 +32,21 @@ Patches in the `patches` directory should be re-applied after updates. - Upstream: http://pulseaudio.org/ - Version: 1.11.1 -- License: LPGL-2.1+ +- License: LGPL-2.1+ -# speechd +## speechd - Upstream: https://www.freebsoft.org/pub/projects/speechd/ - Version: 0.8.8 -- License: LPGL-2.1+ +- License: LGPL-2.1+ -# udev +## udev -- Upstream: https://www.freedesktop.org/wiki/software/systemd/ +- Upstream: https://www.freedesktop.org/wiki/Software/systemd/ - Version: 237 -- License: LPGL-2.1+ +- License: LGPL-2.1+ ## X11 diff --git a/thirdparty/openxr/COPYING.adoc b/thirdparty/openxr/COPYING.adoc index 473e7fdc5d..18c85fa6c7 100644 --- a/thirdparty/openxr/COPYING.adoc +++ b/thirdparty/openxr/COPYING.adoc @@ -1,6 +1,6 @@ = COPYING.adoc for the Khronos Group OpenXR projects -// Copyright (c) 2020-2023, The Khronos Group Inc. +// Copyright (c) 2020-2024, The Khronos Group Inc. // // SPDX-License-Identifier: CC-BY-4.0 diff --git a/thirdparty/openxr/include/openxr/openxr.h b/thirdparty/openxr/include/openxr/openxr.h index 9ba17cbe06..3e9d6599bb 100644 --- a/thirdparty/openxr/include/openxr/openxr.h +++ b/thirdparty/openxr/include/openxr/openxr.h @@ -2,7 +2,7 @@ #define OPENXR_H_ 1 /* -** Copyright 2017-2023 The Khronos Group Inc. +** Copyright 2017-2024, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -25,7 +25,7 @@ extern "C" { ((((major) & 0xffffULL) << 48) | (((minor) & 0xffffULL) << 32) | ((patch) & 0xffffffffULL)) // OpenXR current version number. -#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 31) +#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 33) #define XR_VERSION_MAJOR(version) (uint16_t)(((uint64_t)(version) >> 48)& 0xffffULL) #define XR_VERSION_MINOR(version) (uint16_t)(((uint64_t)(version) >> 32) & 0xffffULL) @@ -218,6 +218,18 @@ typedef enum XrResult { XR_RENDER_MODEL_UNAVAILABLE_FB = 1000119020, XR_ERROR_MARKER_NOT_TRACKED_VARJO = -1000124000, XR_ERROR_MARKER_ID_INVALID_VARJO = -1000124001, + XR_ERROR_MARKER_DETECTOR_PERMISSION_DENIED_ML = -1000138000, + XR_ERROR_MARKER_DETECTOR_LOCATE_FAILED_ML = -1000138001, + XR_ERROR_MARKER_DETECTOR_INVALID_DATA_QUERY_ML = -1000138002, + XR_ERROR_MARKER_DETECTOR_INVALID_CREATE_INFO_ML = -1000138003, + XR_ERROR_MARKER_INVALID_ML = -1000138004, + XR_ERROR_LOCALIZATION_MAP_INCOMPATIBLE_ML = -1000139000, + XR_ERROR_LOCALIZATION_MAP_UNAVAILABLE_ML = -1000139001, + XR_ERROR_LOCALIZATION_MAP_FAIL_ML = -1000139002, + XR_ERROR_LOCALIZATION_MAP_IMPORT_EXPORT_PERMISSION_DENIED_ML = -1000139003, + XR_ERROR_LOCALIZATION_MAP_PERMISSION_DENIED_ML = -1000139004, + XR_ERROR_LOCALIZATION_MAP_ALREADY_EXISTS_ML = -1000139005, + XR_ERROR_LOCALIZATION_MAP_CANNOT_EXPORT_CLOUD_MAP_ML = -1000139006, XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT = -1000142001, XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT = -1000142002, XR_SCENE_MARKER_DATA_NOT_STRING_MSFT = 1000147000, @@ -228,6 +240,7 @@ typedef enum XrResult { XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB = -1000169004, XR_ERROR_PASSTHROUGH_COLOR_LUT_BUFFER_SIZE_MISMATCH_META = -1000266000, XR_ERROR_HINT_ALREADY_SET_QCOM = -1000306000, + XR_ERROR_NOT_AN_ANCHOR_HTC = -1000319000, XR_ERROR_SPACE_NOT_LOCATABLE_EXT = -1000429000, XR_ERROR_PLANE_DETECTION_PERMISSION_DENIED_EXT = -1000429001, XR_RESULT_MAX_ENUM = 0x7FFFFFFF @@ -445,6 +458,20 @@ typedef enum XrStructureType { XR_TYPE_FRAME_END_INFO_ML = 1000135000, XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML = 1000136000, XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML = 1000137000, + XR_TYPE_SYSTEM_MARKER_UNDERSTANDING_PROPERTIES_ML = 1000138000, + XR_TYPE_MARKER_DETECTOR_CREATE_INFO_ML = 1000138001, + XR_TYPE_MARKER_DETECTOR_ARUCO_INFO_ML = 1000138002, + XR_TYPE_MARKER_DETECTOR_SIZE_INFO_ML = 1000138003, + XR_TYPE_MARKER_DETECTOR_APRIL_TAG_INFO_ML = 1000138004, + XR_TYPE_MARKER_DETECTOR_CUSTOM_PROFILE_INFO_ML = 1000138005, + XR_TYPE_MARKER_DETECTOR_SNAPSHOT_INFO_ML = 1000138006, + XR_TYPE_MARKER_DETECTOR_STATE_ML = 1000138007, + XR_TYPE_MARKER_SPACE_CREATE_INFO_ML = 1000138008, + XR_TYPE_LOCALIZATION_MAP_ML = 1000139000, + XR_TYPE_EVENT_DATA_LOCALIZATION_CHANGED_ML = 1000139001, + XR_TYPE_MAP_LOCALIZATION_REQUEST_INFO_ML = 1000139002, + XR_TYPE_LOCALIZATION_MAP_IMPORT_INFO_ML = 1000139003, + XR_TYPE_LOCALIZATION_ENABLE_EVENTS_INFO_ML = 1000139004, XR_TYPE_EVENT_DATA_HEADSET_FIT_CHANGED_ML = 1000472000, XR_TYPE_EVENT_DATA_EYE_CALIBRATION_CHANGED_ML = 1000472001, XR_TYPE_USER_CALIBRATION_ENABLE_EVENTS_INFO_ML = 1000472002, @@ -534,6 +561,8 @@ typedef enum XrStructureType { XR_TYPE_FOVEATION_APPLY_INFO_HTC = 1000318000, XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC = 1000318001, XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC = 1000318002, + XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC = 1000319000, + XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_HTC = 1000319001, XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT = 1000373000, XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX = 1000375000, XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX = 1000375001, @@ -580,6 +609,7 @@ typedef enum XrReferenceSpaceType { XR_REFERENCE_SPACE_TYPE_STAGE = 3, XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT = 1000038000, XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO = 1000121000, + XR_REFERENCE_SPACE_TYPE_LOCALIZATION_MAP_ML = 1000139000, XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT = 1000426000, XR_REFERENCE_SPACE_TYPE_MAX_ENUM = 0x7FFFFFFF } XrReferenceSpaceType; @@ -634,6 +664,8 @@ typedef enum XrObjectType { XR_OBJECT_TYPE_PASSTHROUGH_FB = 1000118000, XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB = 1000118002, XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB = 1000118004, + XR_OBJECT_TYPE_MARKER_DETECTOR_ML = 1000138000, + XR_OBJECT_TYPE_EXPORTED_LOCALIZATION_MAP_ML = 1000139000, XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT = 1000142000, XR_OBJECT_TYPE_FACE_TRACKER_FB = 1000201000, XR_OBJECT_TYPE_EYE_TRACKER_FB = 1000202000, @@ -1677,7 +1709,7 @@ typedef struct XrCompositionLayerColorScaleBiasKHR { #define XR_KHR_loader_init 1 -#define XR_KHR_loader_init_SPEC_VERSION 1 +#define XR_KHR_loader_init_SPEC_VERSION 2 #define XR_KHR_LOADER_INIT_EXTENSION_NAME "XR_KHR_loader_init" typedef struct XR_MAY_ALIAS XrLoaderInitInfoBaseHeaderKHR { XrStructureType type; @@ -4342,6 +4374,360 @@ typedef struct XrGlobalDimmerFrameEndInfoML { +#define XR_ML_marker_understanding 1 +XR_DEFINE_ATOM(XrMarkerML) +XR_DEFINE_HANDLE(XrMarkerDetectorML) +#define XR_ML_marker_understanding_SPEC_VERSION 1 +#define XR_ML_MARKER_UNDERSTANDING_EXTENSION_NAME "XR_ML_marker_understanding" + +typedef enum XrMarkerDetectorProfileML { + XR_MARKER_DETECTOR_PROFILE_DEFAULT_ML = 0, + XR_MARKER_DETECTOR_PROFILE_SPEED_ML = 1, + XR_MARKER_DETECTOR_PROFILE_ACCURACY_ML = 2, + XR_MARKER_DETECTOR_PROFILE_SMALL_TARGETS_ML = 3, + XR_MARKER_DETECTOR_PROFILE_LARGE_FOV_ML = 4, + XR_MARKER_DETECTOR_PROFILE_CUSTOM_ML = 5, + XR_MARKER_DETECTOR_PROFILE_MAX_ENUM_ML = 0x7FFFFFFF +} XrMarkerDetectorProfileML; + +typedef enum XrMarkerTypeML { + XR_MARKER_TYPE_ARUCO_ML = 0, + XR_MARKER_TYPE_APRIL_TAG_ML = 1, + XR_MARKER_TYPE_QR_ML = 2, + XR_MARKER_TYPE_EAN_13_ML = 3, + XR_MARKER_TYPE_UPC_A_ML = 4, + XR_MARKER_TYPE_CODE_128_ML = 5, + XR_MARKER_TYPE_MAX_ENUM_ML = 0x7FFFFFFF +} XrMarkerTypeML; + +typedef enum XrMarkerArucoDictML { + XR_MARKER_ARUCO_DICT_4X4_50_ML = 0, + XR_MARKER_ARUCO_DICT_4X4_100_ML = 1, + XR_MARKER_ARUCO_DICT_4X4_250_ML = 2, + XR_MARKER_ARUCO_DICT_4X4_1000_ML = 3, + XR_MARKER_ARUCO_DICT_5X5_50_ML = 4, + XR_MARKER_ARUCO_DICT_5X5_100_ML = 5, + XR_MARKER_ARUCO_DICT_5X5_250_ML = 6, + XR_MARKER_ARUCO_DICT_5X5_1000_ML = 7, + XR_MARKER_ARUCO_DICT_6X6_50_ML = 8, + XR_MARKER_ARUCO_DICT_6X6_100_ML = 9, + XR_MARKER_ARUCO_DICT_6X6_250_ML = 10, + XR_MARKER_ARUCO_DICT_6X6_1000_ML = 11, + XR_MARKER_ARUCO_DICT_7X7_50_ML = 12, + XR_MARKER_ARUCO_DICT_7X7_100_ML = 13, + XR_MARKER_ARUCO_DICT_7X7_250_ML = 14, + XR_MARKER_ARUCO_DICT_7X7_1000_ML = 15, + XR_MARKER_ARUCO_DICT_MAX_ENUM_ML = 0x7FFFFFFF +} XrMarkerArucoDictML; + +typedef enum XrMarkerAprilTagDictML { + XR_MARKER_APRIL_TAG_DICT_16H5_ML = 0, + XR_MARKER_APRIL_TAG_DICT_25H9_ML = 1, + XR_MARKER_APRIL_TAG_DICT_36H10_ML = 2, + XR_MARKER_APRIL_TAG_DICT_36H11_ML = 3, + XR_MARKER_APRIL_TAG_DICT_MAX_ENUM_ML = 0x7FFFFFFF +} XrMarkerAprilTagDictML; + +typedef enum XrMarkerDetectorFpsML { + XR_MARKER_DETECTOR_FPS_LOW_ML = 0, + XR_MARKER_DETECTOR_FPS_MEDIUM_ML = 1, + XR_MARKER_DETECTOR_FPS_HIGH_ML = 2, + XR_MARKER_DETECTOR_FPS_MAX_ML = 3, + XR_MARKER_DETECTOR_FPS_MAX_ENUM_ML = 0x7FFFFFFF +} XrMarkerDetectorFpsML; + +typedef enum XrMarkerDetectorResolutionML { + XR_MARKER_DETECTOR_RESOLUTION_LOW_ML = 0, + XR_MARKER_DETECTOR_RESOLUTION_MEDIUM_ML = 1, + XR_MARKER_DETECTOR_RESOLUTION_HIGH_ML = 2, + XR_MARKER_DETECTOR_RESOLUTION_MAX_ENUM_ML = 0x7FFFFFFF +} XrMarkerDetectorResolutionML; + +typedef enum XrMarkerDetectorCameraML { + XR_MARKER_DETECTOR_CAMERA_RGB_CAMERA_ML = 0, + XR_MARKER_DETECTOR_CAMERA_WORLD_CAMERAS_ML = 1, + XR_MARKER_DETECTOR_CAMERA_MAX_ENUM_ML = 0x7FFFFFFF +} XrMarkerDetectorCameraML; + +typedef enum XrMarkerDetectorCornerRefineMethodML { + XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_NONE_ML = 0, + XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_SUBPIX_ML = 1, + XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_CONTOUR_ML = 2, + XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_APRIL_TAG_ML = 3, + XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_MAX_ENUM_ML = 0x7FFFFFFF +} XrMarkerDetectorCornerRefineMethodML; + +typedef enum XrMarkerDetectorFullAnalysisIntervalML { + XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_MAX_ML = 0, + XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_FAST_ML = 1, + XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_MEDIUM_ML = 2, + XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_SLOW_ML = 3, + XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_MAX_ENUM_ML = 0x7FFFFFFF +} XrMarkerDetectorFullAnalysisIntervalML; + +typedef enum XrMarkerDetectorStatusML { + XR_MARKER_DETECTOR_STATUS_PENDING_ML = 0, + XR_MARKER_DETECTOR_STATUS_READY_ML = 1, + XR_MARKER_DETECTOR_STATUS_ERROR_ML = 2, + XR_MARKER_DETECTOR_STATUS_MAX_ENUM_ML = 0x7FFFFFFF +} XrMarkerDetectorStatusML; +// XrSystemMarkerUnderstandingPropertiesML extends XrSystemProperties +typedef struct XrSystemMarkerUnderstandingPropertiesML { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsMarkerUnderstanding; +} XrSystemMarkerUnderstandingPropertiesML; + +typedef struct XrMarkerDetectorCreateInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrMarkerDetectorProfileML profile; + XrMarkerTypeML markerType; +} XrMarkerDetectorCreateInfoML; + +// XrMarkerDetectorArucoInfoML extends XrMarkerDetectorCreateInfoML +typedef struct XrMarkerDetectorArucoInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrMarkerArucoDictML arucoDict; +} XrMarkerDetectorArucoInfoML; + +// XrMarkerDetectorSizeInfoML extends XrMarkerDetectorCreateInfoML +typedef struct XrMarkerDetectorSizeInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float markerLength; +} XrMarkerDetectorSizeInfoML; + +// XrMarkerDetectorAprilTagInfoML extends XrMarkerDetectorCreateInfoML +typedef struct XrMarkerDetectorAprilTagInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrMarkerAprilTagDictML aprilTagDict; +} XrMarkerDetectorAprilTagInfoML; + +// XrMarkerDetectorCustomProfileInfoML extends XrMarkerDetectorCreateInfoML +typedef struct XrMarkerDetectorCustomProfileInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrMarkerDetectorFpsML fpsHint; + XrMarkerDetectorResolutionML resolutionHint; + XrMarkerDetectorCameraML cameraHint; + XrMarkerDetectorCornerRefineMethodML cornerRefineMethod; + XrBool32 useEdgeRefinement; + XrMarkerDetectorFullAnalysisIntervalML fullAnalysisIntervalHint; +} XrMarkerDetectorCustomProfileInfoML; + +typedef struct XrMarkerDetectorSnapshotInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrMarkerDetectorSnapshotInfoML; + +typedef struct XrMarkerDetectorStateML { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrMarkerDetectorStatusML state; +} XrMarkerDetectorStateML; + +typedef struct XrMarkerSpaceCreateInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrMarkerDetectorML markerDetector; + XrMarkerML marker; + XrPosef poseInMarkerSpace; +} XrMarkerSpaceCreateInfoML; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateMarkerDetectorML)(XrSession session, const XrMarkerDetectorCreateInfoML* createInfo, XrMarkerDetectorML* markerDetector); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyMarkerDetectorML)(XrMarkerDetectorML markerDetector); +typedef XrResult (XRAPI_PTR *PFN_xrSnapshotMarkerDetectorML)(XrMarkerDetectorML markerDetector, XrMarkerDetectorSnapshotInfoML* snapshotInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerDetectorStateML)(XrMarkerDetectorML markerDetector, XrMarkerDetectorStateML* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetMarkersML)(XrMarkerDetectorML markerDetector, uint32_t markerCapacityInput, uint32_t* markerCountOutput, XrMarkerML* markers); +typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerReprojectionErrorML)(XrMarkerDetectorML markerDetector, XrMarkerML marker, float* reprojectionErrorMeters); +typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerLengthML)(XrMarkerDetectorML markerDetector, XrMarkerML marker, float* meters); +typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerNumberML)(XrMarkerDetectorML markerDetector, XrMarkerML marker, uint64_t* number); +typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerStringML)(XrMarkerDetectorML markerDetector, XrMarkerML marker, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrCreateMarkerSpaceML)(XrSession session, const XrMarkerSpaceCreateInfoML* createInfo, XrSpace* space); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateMarkerDetectorML( + XrSession session, + const XrMarkerDetectorCreateInfoML* createInfo, + XrMarkerDetectorML* markerDetector); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyMarkerDetectorML( + XrMarkerDetectorML markerDetector); + +XRAPI_ATTR XrResult XRAPI_CALL xrSnapshotMarkerDetectorML( + XrMarkerDetectorML markerDetector, + XrMarkerDetectorSnapshotInfoML* snapshotInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerDetectorStateML( + XrMarkerDetectorML markerDetector, + XrMarkerDetectorStateML* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkersML( + XrMarkerDetectorML markerDetector, + uint32_t markerCapacityInput, + uint32_t* markerCountOutput, + XrMarkerML* markers); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerReprojectionErrorML( + XrMarkerDetectorML markerDetector, + XrMarkerML marker, + float* reprojectionErrorMeters); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerLengthML( + XrMarkerDetectorML markerDetector, + XrMarkerML marker, + float* meters); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerNumberML( + XrMarkerDetectorML markerDetector, + XrMarkerML marker, + uint64_t* number); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerStringML( + XrMarkerDetectorML markerDetector, + XrMarkerML marker, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateMarkerSpaceML( + XrSession session, + const XrMarkerSpaceCreateInfoML* createInfo, + XrSpace* space); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_ML_localization_map 1 +XR_DEFINE_HANDLE(XrExportedLocalizationMapML) +#define XR_MAX_LOCALIZATION_MAP_NAME_LENGTH_ML 64 +#define XR_ML_localization_map_SPEC_VERSION 1 +#define XR_ML_LOCALIZATION_MAP_EXTENSION_NAME "XR_ML_localization_map" + +typedef enum XrLocalizationMapStateML { + XR_LOCALIZATION_MAP_STATE_NOT_LOCALIZED_ML = 0, + XR_LOCALIZATION_MAP_STATE_LOCALIZED_ML = 1, + XR_LOCALIZATION_MAP_STATE_LOCALIZATION_PENDING_ML = 2, + XR_LOCALIZATION_MAP_STATE_LOCALIZATION_SLEEPING_BEFORE_RETRY_ML = 3, + XR_LOCALIZATION_MAP_STATE_MAX_ENUM_ML = 0x7FFFFFFF +} XrLocalizationMapStateML; + +typedef enum XrLocalizationMapTypeML { + XR_LOCALIZATION_MAP_TYPE_ON_DEVICE_ML = 0, + XR_LOCALIZATION_MAP_TYPE_CLOUD_ML = 1, + XR_LOCALIZATION_MAP_TYPE_MAX_ENUM_ML = 0x7FFFFFFF +} XrLocalizationMapTypeML; + +typedef enum XrLocalizationMapConfidenceML { + XR_LOCALIZATION_MAP_CONFIDENCE_POOR_ML = 0, + XR_LOCALIZATION_MAP_CONFIDENCE_FAIR_ML = 1, + XR_LOCALIZATION_MAP_CONFIDENCE_GOOD_ML = 2, + XR_LOCALIZATION_MAP_CONFIDENCE_EXCELLENT_ML = 3, + XR_LOCALIZATION_MAP_CONFIDENCE_MAX_ENUM_ML = 0x7FFFFFFF +} XrLocalizationMapConfidenceML; +typedef XrFlags64 XrLocalizationMapErrorFlagsML; + +// Flag bits for XrLocalizationMapErrorFlagsML +static const XrLocalizationMapErrorFlagsML XR_LOCALIZATION_MAP_ERROR_UNKNOWN_BIT_ML = 0x00000001; +static const XrLocalizationMapErrorFlagsML XR_LOCALIZATION_MAP_ERROR_OUT_OF_MAPPED_AREA_BIT_ML = 0x00000002; +static const XrLocalizationMapErrorFlagsML XR_LOCALIZATION_MAP_ERROR_LOW_FEATURE_COUNT_BIT_ML = 0x00000004; +static const XrLocalizationMapErrorFlagsML XR_LOCALIZATION_MAP_ERROR_EXCESSIVE_MOTION_BIT_ML = 0x00000008; +static const XrLocalizationMapErrorFlagsML XR_LOCALIZATION_MAP_ERROR_LOW_LIGHT_BIT_ML = 0x00000010; +static const XrLocalizationMapErrorFlagsML XR_LOCALIZATION_MAP_ERROR_HEADPOSE_BIT_ML = 0x00000020; + +typedef struct XrLocalizationMapML { + XrStructureType type; + void* XR_MAY_ALIAS next; + char name[XR_MAX_LOCALIZATION_MAP_NAME_LENGTH_ML]; + XrUuidEXT mapUuid; + XrLocalizationMapTypeML mapType; +} XrLocalizationMapML; + +typedef struct XrEventDataLocalizationChangedML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; + XrLocalizationMapStateML state; + XrLocalizationMapML map; + XrLocalizationMapConfidenceML confidence; + XrLocalizationMapErrorFlagsML errorFlags; +} XrEventDataLocalizationChangedML; + +typedef struct XrLocalizationMapQueryInfoBaseHeaderML { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrLocalizationMapQueryInfoBaseHeaderML; + +typedef struct XrMapLocalizationRequestInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidEXT mapUuid; +} XrMapLocalizationRequestInfoML; + +typedef struct XrLocalizationMapImportInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t size; + char* data; +} XrLocalizationMapImportInfoML; + +typedef struct XrLocalizationEnableEventsInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 enabled; +} XrLocalizationEnableEventsInfoML; + +typedef XrResult (XRAPI_PTR *PFN_xrEnableLocalizationEventsML)(XrSession session, const XrLocalizationEnableEventsInfoML * info); +typedef XrResult (XRAPI_PTR *PFN_xrQueryLocalizationMapsML)(XrSession session, const XrLocalizationMapQueryInfoBaseHeaderML* queryInfo, uint32_t mapCapacityInput, uint32_t * mapCountOutput, XrLocalizationMapML* maps); +typedef XrResult (XRAPI_PTR *PFN_xrRequestMapLocalizationML)(XrSession session, const XrMapLocalizationRequestInfoML* requestInfo); +typedef XrResult (XRAPI_PTR *PFN_xrImportLocalizationMapML)(XrSession session, const XrLocalizationMapImportInfoML* importInfo, XrUuidEXT* mapUuid); +typedef XrResult (XRAPI_PTR *PFN_xrCreateExportedLocalizationMapML)(XrSession session, const XrUuidEXT* mapUuid, XrExportedLocalizationMapML* map); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyExportedLocalizationMapML)(XrExportedLocalizationMapML map); +typedef XrResult (XRAPI_PTR *PFN_xrGetExportedLocalizationMapDataML)(XrExportedLocalizationMapML map, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnableLocalizationEventsML( + XrSession session, + const XrLocalizationEnableEventsInfoML * info); + +XRAPI_ATTR XrResult XRAPI_CALL xrQueryLocalizationMapsML( + XrSession session, + const XrLocalizationMapQueryInfoBaseHeaderML* queryInfo, + uint32_t mapCapacityInput, + uint32_t * mapCountOutput, + XrLocalizationMapML* maps); + +XRAPI_ATTR XrResult XRAPI_CALL xrRequestMapLocalizationML( + XrSession session, + const XrMapLocalizationRequestInfoML* requestInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrImportLocalizationMapML( + XrSession session, + const XrLocalizationMapImportInfoML* importInfo, + XrUuidEXT* mapUuid); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateExportedLocalizationMapML( + XrSession session, + const XrUuidEXT* mapUuid, + XrExportedLocalizationMapML* map); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyExportedLocalizationMapML( + XrExportedLocalizationMapML map); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetExportedLocalizationMapDataML( + XrExportedLocalizationMapML map, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + #define XR_MSFT_spatial_anchor_persistence 1 XR_DEFINE_HANDLE(XrSpatialAnchorStoreConnectionMSFT) #define XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT 256 @@ -5814,6 +6200,11 @@ XRAPI_ATTR XrResult XRAPI_CALL xrUpdatePassthroughColorLutMETA( #endif /* !XR_NO_PROTOTYPES */ +#define XR_META_touch_controller_plus 1 +#define XR_META_touch_controller_plus_SPEC_VERSION 1 +#define XR_META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME "XR_META_touch_controller_plus" + + #define XR_EXT_uuid 1 #define XR_EXT_uuid_SPEC_VERSION 1 #define XR_EXT_UUID_EXTENSION_NAME "XR_EXT_uuid" @@ -5980,6 +6371,46 @@ XRAPI_ATTR XrResult XRAPI_CALL xrApplyFoveationHTC( #endif /* !XR_NO_PROTOTYPES */ +#define XR_HTC_anchor 1 +#define XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC 256 +#define XR_HTC_anchor_SPEC_VERSION 1 +#define XR_HTC_ANCHOR_EXTENSION_NAME "XR_HTC_anchor" +// XrSystemAnchorPropertiesHTC extends XrSystemProperties +typedef struct XrSystemAnchorPropertiesHTC { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsAnchor; +} XrSystemAnchorPropertiesHTC; + +typedef struct XrSpatialAnchorNameHTC { + char name[XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC]; +} XrSpatialAnchorNameHTC; + +typedef struct XrSpatialAnchorCreateInfoHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrPosef poseInSpace; + XrSpatialAnchorNameHTC name; +} XrSpatialAnchorCreateInfoHTC; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorHTC)(XrSession session, const XrSpatialAnchorCreateInfoHTC* createInfo, XrSpace* anchor); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpatialAnchorNameHTC)(XrSpace anchor, XrSpatialAnchorNameHTC* name); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorHTC( + XrSession session, + const XrSpatialAnchorCreateInfoHTC* createInfo, + XrSpace* anchor); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpatialAnchorNameHTC( + XrSpace anchor, + XrSpatialAnchorNameHTC* name); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + #define XR_EXT_active_action_set_priority 1 #define XR_EXT_active_action_set_priority_SPEC_VERSION 1 #define XR_EXT_ACTIVE_ACTION_SET_PRIORITY_EXTENSION_NAME "XR_EXT_active_action_set_priority" @@ -6274,7 +6705,7 @@ typedef struct XrUserCalibrationEnableEventsInfoML { XrBool32 enabled; } XrUserCalibrationEnableEventsInfoML; -typedef XrResult (XRAPI_PTR *PFN_xrEnableUserCalibrationEventsML)(XrInstance instance, const XrUserCalibrationEnableEventsInfoML* enableInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEnableUserCalibrationEventsML)(XrInstance instance, const XrUserCalibrationEnableEventsInfoML* enableInfo); #ifndef XR_NO_PROTOTYPES #ifdef XR_EXTENSION_PROTOTYPES diff --git a/thirdparty/openxr/include/openxr/openxr_loader_negotiation.h b/thirdparty/openxr/include/openxr/openxr_loader_negotiation.h new file mode 100644 index 0000000000..619b226760 --- /dev/null +++ b/thirdparty/openxr/include/openxr/openxr_loader_negotiation.h @@ -0,0 +1,140 @@ +#ifndef OPENXR_LOADER_NEGOTIATION_H_ +#define OPENXR_LOADER_NEGOTIATION_H_ 1 + +/* +** Copyright 2017-2024, The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos OpenXR XML API Registry. +** +*/ + +#include "openxr.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +#define XR_LOADER_VERSION_1_0 1 + +#define XR_CURRENT_LOADER_API_LAYER_VERSION 1 + + +#define XR_CURRENT_LOADER_RUNTIME_VERSION 1 + + +#define XR_LOADER_INFO_STRUCT_VERSION 1 + + +#define XR_API_LAYER_INFO_STRUCT_VERSION 1 + + +#define XR_RUNTIME_INFO_STRUCT_VERSION 1 + + +#define XR_API_LAYER_NEXT_INFO_STRUCT_VERSION 1 + + +#define XR_API_LAYER_CREATE_INFO_STRUCT_VERSION 1 + + +#define XR_API_LAYER_MAX_SETTINGS_PATH_SIZE 512 + + +typedef enum XrLoaderInterfaceStructs { + XR_LOADER_INTERFACE_STRUCT_UNINTIALIZED = 0, + XR_LOADER_INTERFACE_STRUCT_LOADER_INFO = 1, + XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST = 2, + XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST = 3, + XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO = 4, + XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO = 5, + XR_LOADER_INTERFACE_STRUCTS_MAX_ENUM = 0x7FFFFFFF +} XrLoaderInterfaceStructs; +typedef XrResult (XRAPI_PTR *PFN_xrGetInstanceProcAddr)(XrInstance instance, const char* name, PFN_xrVoidFunction* function); + +typedef struct XrApiLayerCreateInfo XrApiLayerCreateInfo; +typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( + const XrInstanceCreateInfo* info, + const XrApiLayerCreateInfo* apiLayerInfo, + XrInstance* instance); + +typedef struct XrApiLayerNextInfo { + XrLoaderInterfaceStructs structType; + uint32_t structVersion; + size_t structSize; + char layerName[XR_MAX_API_LAYER_NAME_SIZE]; + PFN_xrGetInstanceProcAddr nextGetInstanceProcAddr; + PFN_xrCreateApiLayerInstance nextCreateApiLayerInstance; + struct XrApiLayerNextInfo* next; +} XrApiLayerNextInfo; + +typedef struct XrApiLayerCreateInfo { + XrLoaderInterfaceStructs structType; + uint32_t structVersion; + size_t structSize; + void* XR_MAY_ALIAS loaderInstance; + char settings_file_location[XR_API_LAYER_MAX_SETTINGS_PATH_SIZE]; + XrApiLayerNextInfo* nextInfo; +} XrApiLayerCreateInfo; + +typedef struct XrNegotiateLoaderInfo { + XrLoaderInterfaceStructs structType; + uint32_t structVersion; + size_t structSize; + uint32_t minInterfaceVersion; + uint32_t maxInterfaceVersion; + XrVersion minApiVersion; + XrVersion maxApiVersion; +} XrNegotiateLoaderInfo; + +typedef struct XrNegotiateRuntimeRequest { + XrLoaderInterfaceStructs structType; + uint32_t structVersion; + size_t structSize; + uint32_t runtimeInterfaceVersion; + XrVersion runtimeApiVersion; + PFN_xrGetInstanceProcAddr getInstanceProcAddr; +} XrNegotiateRuntimeRequest; + +typedef struct XrNegotiateApiLayerRequest { + XrLoaderInterfaceStructs structType; + uint32_t structVersion; + size_t structSize; + uint32_t layerInterfaceVersion; + XrVersion layerApiVersion; + PFN_xrGetInstanceProcAddr getInstanceProcAddr; + PFN_xrCreateApiLayerInstance createApiLayerInstance; +} XrNegotiateApiLayerRequest; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)(const XrInstanceCreateInfo* info, const XrApiLayerCreateInfo* layerInfo, XrInstance* instance); +typedef XrResult (XRAPI_PTR *PFN_xrNegotiateLoaderRuntimeInterface)(const XrNegotiateLoaderInfo* loaderInfo, XrNegotiateRuntimeRequest* runtimeRequest); +typedef XrResult (XRAPI_PTR *PFN_xrNegotiateLoaderApiLayerInterface)(const XrNegotiateLoaderInfo* loaderInfo, const char* layerName, XrNegotiateApiLayerRequest* apiLayerRequest); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateApiLayerInstance( + const XrInstanceCreateInfo* info, + const XrApiLayerCreateInfo* layerInfo, + XrInstance* instance); + +XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderRuntimeInterface( + const XrNegotiateLoaderInfo* loaderInfo, + XrNegotiateRuntimeRequest* runtimeRequest); + +XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderApiLayerInterface( + const XrNegotiateLoaderInfo* loaderInfo, + const char* layerName, + XrNegotiateApiLayerRequest* apiLayerRequest); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/openxr/include/openxr/openxr_platform.h b/thirdparty/openxr/include/openxr/openxr_platform.h index e4ddfcbb7d..1f47428676 100644 --- a/thirdparty/openxr/include/openxr/openxr_platform.h +++ b/thirdparty/openxr/include/openxr/openxr_platform.h @@ -2,7 +2,7 @@ #define OPENXR_PLATFORM_H_ 1 /* -** Copyright 2017-2023 The Khronos Group Inc. +** Copyright 2017-2024, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -22,7 +22,7 @@ extern "C" { #ifdef XR_USE_PLATFORM_ANDROID #define XR_KHR_android_thread_settings 1 -#define XR_KHR_android_thread_settings_SPEC_VERSION 5 +#define XR_KHR_android_thread_settings_SPEC_VERSION 6 #define XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME "XR_KHR_android_thread_settings" typedef enum XrAndroidThreadTypeKHR { @@ -489,7 +489,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirements2KHR( #ifdef XR_USE_PLATFORM_EGL #define XR_MNDX_egl_enable 1 -#define XR_MNDX_egl_enable_SPEC_VERSION 1 +#define XR_MNDX_egl_enable_SPEC_VERSION 2 #define XR_MNDX_EGL_ENABLE_EXTENSION_NAME "XR_MNDX_egl_enable" typedef PFN_xrVoidFunction (*PFN_xrEglGetProcAddressMNDX)(const char *name); // XrGraphicsBindingEGLMNDX extends XrSessionCreateInfo diff --git a/thirdparty/openxr/include/openxr/openxr_platform_defines.h b/thirdparty/openxr/include/openxr/openxr_platform_defines.h index 820b7b3e1e..cd07c91360 100644 --- a/thirdparty/openxr/include/openxr/openxr_platform_defines.h +++ b/thirdparty/openxr/include/openxr/openxr_platform_defines.h @@ -1,5 +1,5 @@ /* -** Copyright (c) 2017-2023, The Khronos Group Inc. +** Copyright (c) 2017-2024, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ diff --git a/thirdparty/openxr/include/openxr/openxr_reflection.h b/thirdparty/openxr/include/openxr/openxr_reflection.h index 8f49323417..f6d66363bf 100644 --- a/thirdparty/openxr/include/openxr/openxr_reflection.h +++ b/thirdparty/openxr/include/openxr/openxr_reflection.h @@ -2,7 +2,7 @@ #define OPENXR_REFLECTION_H_ 1 /* -** Copyright (c) 2017-2023, The Khronos Group Inc. +** Copyright (c) 2017-2024, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -114,6 +114,18 @@ XR_ENUM_STR(XrResult); _(XR_RENDER_MODEL_UNAVAILABLE_FB, 1000119020) \ _(XR_ERROR_MARKER_NOT_TRACKED_VARJO, -1000124000) \ _(XR_ERROR_MARKER_ID_INVALID_VARJO, -1000124001) \ + _(XR_ERROR_MARKER_DETECTOR_PERMISSION_DENIED_ML, -1000138000) \ + _(XR_ERROR_MARKER_DETECTOR_LOCATE_FAILED_ML, -1000138001) \ + _(XR_ERROR_MARKER_DETECTOR_INVALID_DATA_QUERY_ML, -1000138002) \ + _(XR_ERROR_MARKER_DETECTOR_INVALID_CREATE_INFO_ML, -1000138003) \ + _(XR_ERROR_MARKER_INVALID_ML, -1000138004) \ + _(XR_ERROR_LOCALIZATION_MAP_INCOMPATIBLE_ML, -1000139000) \ + _(XR_ERROR_LOCALIZATION_MAP_UNAVAILABLE_ML, -1000139001) \ + _(XR_ERROR_LOCALIZATION_MAP_FAIL_ML, -1000139002) \ + _(XR_ERROR_LOCALIZATION_MAP_IMPORT_EXPORT_PERMISSION_DENIED_ML, -1000139003) \ + _(XR_ERROR_LOCALIZATION_MAP_PERMISSION_DENIED_ML, -1000139004) \ + _(XR_ERROR_LOCALIZATION_MAP_ALREADY_EXISTS_ML, -1000139005) \ + _(XR_ERROR_LOCALIZATION_MAP_CANNOT_EXPORT_CLOUD_MAP_ML, -1000139006) \ _(XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT, -1000142001) \ _(XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT, -1000142002) \ _(XR_SCENE_MARKER_DATA_NOT_STRING_MSFT, 1000147000) \ @@ -124,6 +136,7 @@ XR_ENUM_STR(XrResult); _(XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB, -1000169004) \ _(XR_ERROR_PASSTHROUGH_COLOR_LUT_BUFFER_SIZE_MISMATCH_META, -1000266000) \ _(XR_ERROR_HINT_ALREADY_SET_QCOM, -1000306000) \ + _(XR_ERROR_NOT_AN_ANCHOR_HTC, -1000319000) \ _(XR_ERROR_SPACE_NOT_LOCATABLE_EXT, -1000429000) \ _(XR_ERROR_PLANE_DETECTION_PERMISSION_DENIED_EXT, -1000429001) \ _(XR_RESULT_MAX_ENUM, 0x7FFFFFFF) @@ -340,6 +353,20 @@ XR_ENUM_STR(XrResult); _(XR_TYPE_FRAME_END_INFO_ML, 1000135000) \ _(XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML, 1000136000) \ _(XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML, 1000137000) \ + _(XR_TYPE_SYSTEM_MARKER_UNDERSTANDING_PROPERTIES_ML, 1000138000) \ + _(XR_TYPE_MARKER_DETECTOR_CREATE_INFO_ML, 1000138001) \ + _(XR_TYPE_MARKER_DETECTOR_ARUCO_INFO_ML, 1000138002) \ + _(XR_TYPE_MARKER_DETECTOR_SIZE_INFO_ML, 1000138003) \ + _(XR_TYPE_MARKER_DETECTOR_APRIL_TAG_INFO_ML, 1000138004) \ + _(XR_TYPE_MARKER_DETECTOR_CUSTOM_PROFILE_INFO_ML, 1000138005) \ + _(XR_TYPE_MARKER_DETECTOR_SNAPSHOT_INFO_ML, 1000138006) \ + _(XR_TYPE_MARKER_DETECTOR_STATE_ML, 1000138007) \ + _(XR_TYPE_MARKER_SPACE_CREATE_INFO_ML, 1000138008) \ + _(XR_TYPE_LOCALIZATION_MAP_ML, 1000139000) \ + _(XR_TYPE_EVENT_DATA_LOCALIZATION_CHANGED_ML, 1000139001) \ + _(XR_TYPE_MAP_LOCALIZATION_REQUEST_INFO_ML, 1000139002) \ + _(XR_TYPE_LOCALIZATION_MAP_IMPORT_INFO_ML, 1000139003) \ + _(XR_TYPE_LOCALIZATION_ENABLE_EVENTS_INFO_ML, 1000139004) \ _(XR_TYPE_EVENT_DATA_HEADSET_FIT_CHANGED_ML, 1000472000) \ _(XR_TYPE_EVENT_DATA_EYE_CALIBRATION_CHANGED_ML, 1000472001) \ _(XR_TYPE_USER_CALIBRATION_ENABLE_EVENTS_INFO_ML, 1000472002) \ @@ -429,6 +456,8 @@ XR_ENUM_STR(XrResult); _(XR_TYPE_FOVEATION_APPLY_INFO_HTC, 1000318000) \ _(XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC, 1000318001) \ _(XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC, 1000318002) \ + _(XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC, 1000319000) \ + _(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_HTC, 1000319001) \ _(XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT, 1000373000) \ _(XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX, 1000375000) \ _(XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX, 1000375001) \ @@ -467,6 +496,7 @@ XR_ENUM_STR(XrResult); _(XR_REFERENCE_SPACE_TYPE_STAGE, 3) \ _(XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT, 1000038000) \ _(XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO, 1000121000) \ + _(XR_REFERENCE_SPACE_TYPE_LOCALIZATION_MAP_ML, 1000139000) \ _(XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT, 1000426000) \ _(XR_REFERENCE_SPACE_TYPE_MAX_ENUM, 0x7FFFFFFF) @@ -517,6 +547,8 @@ XR_ENUM_STR(XrResult); _(XR_OBJECT_TYPE_PASSTHROUGH_FB, 1000118000) \ _(XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB, 1000118002) \ _(XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB, 1000118004) \ + _(XR_OBJECT_TYPE_MARKER_DETECTOR_ML, 1000138000) \ + _(XR_OBJECT_TYPE_EXPORTED_LOCALIZATION_MAP_ML, 1000139000) \ _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT, 1000142000) \ _(XR_OBJECT_TYPE_FACE_TRACKER_FB, 1000201000) \ _(XR_OBJECT_TYPE_EYE_TRACKER_FB, 1000202000) \ @@ -527,6 +559,15 @@ XR_ENUM_STR(XrResult); _(XR_OBJECT_TYPE_PLANE_DETECTOR_EXT, 1000429000) \ _(XR_OBJECT_TYPE_MAX_ENUM, 0x7FFFFFFF) +#define XR_LIST_ENUM_XrLoaderInterfaceStructs(_) \ + _(XR_LOADER_INTERFACE_STRUCT_UNINTIALIZED, 0) \ + _(XR_LOADER_INTERFACE_STRUCT_LOADER_INFO, 1) \ + _(XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST, 2) \ + _(XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST, 3) \ + _(XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO, 4) \ + _(XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO, 5) \ + _(XR_LOADER_INTERFACE_STRUCTS_MAX_ENUM, 0x7FFFFFFF) + #define XR_LIST_ENUM_XrAndroidThreadTypeKHR(_) \ _(XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR, 1) \ _(XR_ANDROID_THREAD_TYPE_APPLICATION_WORKER_KHR, 2) \ @@ -877,6 +918,107 @@ XR_ENUM_STR(XrResult); _(XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS_FB, 1000203002) \ _(XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB, 0x7FFFFFFF) +#define XR_LIST_ENUM_XrMarkerDetectorProfileML(_) \ + _(XR_MARKER_DETECTOR_PROFILE_DEFAULT_ML, 0) \ + _(XR_MARKER_DETECTOR_PROFILE_SPEED_ML, 1) \ + _(XR_MARKER_DETECTOR_PROFILE_ACCURACY_ML, 2) \ + _(XR_MARKER_DETECTOR_PROFILE_SMALL_TARGETS_ML, 3) \ + _(XR_MARKER_DETECTOR_PROFILE_LARGE_FOV_ML, 4) \ + _(XR_MARKER_DETECTOR_PROFILE_CUSTOM_ML, 5) \ + _(XR_MARKER_DETECTOR_PROFILE_MAX_ENUM_ML, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMarkerTypeML(_) \ + _(XR_MARKER_TYPE_ARUCO_ML, 0) \ + _(XR_MARKER_TYPE_APRIL_TAG_ML, 1) \ + _(XR_MARKER_TYPE_QR_ML, 2) \ + _(XR_MARKER_TYPE_EAN_13_ML, 3) \ + _(XR_MARKER_TYPE_UPC_A_ML, 4) \ + _(XR_MARKER_TYPE_CODE_128_ML, 5) \ + _(XR_MARKER_TYPE_MAX_ENUM_ML, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMarkerArucoDictML(_) \ + _(XR_MARKER_ARUCO_DICT_4X4_50_ML, 0) \ + _(XR_MARKER_ARUCO_DICT_4X4_100_ML, 1) \ + _(XR_MARKER_ARUCO_DICT_4X4_250_ML, 2) \ + _(XR_MARKER_ARUCO_DICT_4X4_1000_ML, 3) \ + _(XR_MARKER_ARUCO_DICT_5X5_50_ML, 4) \ + _(XR_MARKER_ARUCO_DICT_5X5_100_ML, 5) \ + _(XR_MARKER_ARUCO_DICT_5X5_250_ML, 6) \ + _(XR_MARKER_ARUCO_DICT_5X5_1000_ML, 7) \ + _(XR_MARKER_ARUCO_DICT_6X6_50_ML, 8) \ + _(XR_MARKER_ARUCO_DICT_6X6_100_ML, 9) \ + _(XR_MARKER_ARUCO_DICT_6X6_250_ML, 10) \ + _(XR_MARKER_ARUCO_DICT_6X6_1000_ML, 11) \ + _(XR_MARKER_ARUCO_DICT_7X7_50_ML, 12) \ + _(XR_MARKER_ARUCO_DICT_7X7_100_ML, 13) \ + _(XR_MARKER_ARUCO_DICT_7X7_250_ML, 14) \ + _(XR_MARKER_ARUCO_DICT_7X7_1000_ML, 15) \ + _(XR_MARKER_ARUCO_DICT_MAX_ENUM_ML, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMarkerAprilTagDictML(_) \ + _(XR_MARKER_APRIL_TAG_DICT_16H5_ML, 0) \ + _(XR_MARKER_APRIL_TAG_DICT_25H9_ML, 1) \ + _(XR_MARKER_APRIL_TAG_DICT_36H10_ML, 2) \ + _(XR_MARKER_APRIL_TAG_DICT_36H11_ML, 3) \ + _(XR_MARKER_APRIL_TAG_DICT_MAX_ENUM_ML, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMarkerDetectorFpsML(_) \ + _(XR_MARKER_DETECTOR_FPS_LOW_ML, 0) \ + _(XR_MARKER_DETECTOR_FPS_MEDIUM_ML, 1) \ + _(XR_MARKER_DETECTOR_FPS_HIGH_ML, 2) \ + _(XR_MARKER_DETECTOR_FPS_MAX_ML, 3) \ + _(XR_MARKER_DETECTOR_FPS_MAX_ENUM_ML, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMarkerDetectorResolutionML(_) \ + _(XR_MARKER_DETECTOR_RESOLUTION_LOW_ML, 0) \ + _(XR_MARKER_DETECTOR_RESOLUTION_MEDIUM_ML, 1) \ + _(XR_MARKER_DETECTOR_RESOLUTION_HIGH_ML, 2) \ + _(XR_MARKER_DETECTOR_RESOLUTION_MAX_ENUM_ML, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMarkerDetectorCameraML(_) \ + _(XR_MARKER_DETECTOR_CAMERA_RGB_CAMERA_ML, 0) \ + _(XR_MARKER_DETECTOR_CAMERA_WORLD_CAMERAS_ML, 1) \ + _(XR_MARKER_DETECTOR_CAMERA_MAX_ENUM_ML, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMarkerDetectorCornerRefineMethodML(_) \ + _(XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_NONE_ML, 0) \ + _(XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_SUBPIX_ML, 1) \ + _(XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_CONTOUR_ML, 2) \ + _(XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_APRIL_TAG_ML, 3) \ + _(XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_MAX_ENUM_ML, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMarkerDetectorFullAnalysisIntervalML(_) \ + _(XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_MAX_ML, 0) \ + _(XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_FAST_ML, 1) \ + _(XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_MEDIUM_ML, 2) \ + _(XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_SLOW_ML, 3) \ + _(XR_MARKER_DETECTOR_FULL_ANALYSIS_INTERVAL_MAX_ENUM_ML, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMarkerDetectorStatusML(_) \ + _(XR_MARKER_DETECTOR_STATUS_PENDING_ML, 0) \ + _(XR_MARKER_DETECTOR_STATUS_READY_ML, 1) \ + _(XR_MARKER_DETECTOR_STATUS_ERROR_ML, 2) \ + _(XR_MARKER_DETECTOR_STATUS_MAX_ENUM_ML, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrLocalizationMapStateML(_) \ + _(XR_LOCALIZATION_MAP_STATE_NOT_LOCALIZED_ML, 0) \ + _(XR_LOCALIZATION_MAP_STATE_LOCALIZED_ML, 1) \ + _(XR_LOCALIZATION_MAP_STATE_LOCALIZATION_PENDING_ML, 2) \ + _(XR_LOCALIZATION_MAP_STATE_LOCALIZATION_SLEEPING_BEFORE_RETRY_ML, 3) \ + _(XR_LOCALIZATION_MAP_STATE_MAX_ENUM_ML, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrLocalizationMapTypeML(_) \ + _(XR_LOCALIZATION_MAP_TYPE_ON_DEVICE_ML, 0) \ + _(XR_LOCALIZATION_MAP_TYPE_CLOUD_ML, 1) \ + _(XR_LOCALIZATION_MAP_TYPE_MAX_ENUM_ML, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrLocalizationMapConfidenceML(_) \ + _(XR_LOCALIZATION_MAP_CONFIDENCE_POOR_ML, 0) \ + _(XR_LOCALIZATION_MAP_CONFIDENCE_FAIR_ML, 1) \ + _(XR_LOCALIZATION_MAP_CONFIDENCE_GOOD_ML, 2) \ + _(XR_LOCALIZATION_MAP_CONFIDENCE_EXCELLENT_ML, 3) \ + _(XR_LOCALIZATION_MAP_CONFIDENCE_MAX_ENUM_ML, 0x7FFFFFFF) + #define XR_LIST_ENUM_XrSceneMarkerTypeMSFT(_) \ _(XR_SCENE_MARKER_TYPE_QR_CODE_MSFT, 1) \ _(XR_SCENE_MARKER_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) @@ -1281,6 +1423,14 @@ XR_ENUM_STR(XrResult); #define XR_LIST_BITS_XrGlobalDimmerFrameEndInfoFlagsML(_) \ _(XR_GLOBAL_DIMMER_FRAME_END_INFO_ENABLED_BIT_ML, 0x00000001) \ +#define XR_LIST_BITS_XrLocalizationMapErrorFlagsML(_) \ + _(XR_LOCALIZATION_MAP_ERROR_UNKNOWN_BIT_ML, 0x00000001) \ + _(XR_LOCALIZATION_MAP_ERROR_OUT_OF_MAPPED_AREA_BIT_ML, 0x00000002) \ + _(XR_LOCALIZATION_MAP_ERROR_LOW_FEATURE_COUNT_BIT_ML, 0x00000004) \ + _(XR_LOCALIZATION_MAP_ERROR_EXCESSIVE_MOTION_BIT_ML, 0x00000008) \ + _(XR_LOCALIZATION_MAP_ERROR_LOW_LIGHT_BIT_ML, 0x00000010) \ + _(XR_LOCALIZATION_MAP_ERROR_HEADPOSE_BIT_ML, 0x00000020) \ + #define XR_LIST_BITS_XrCompositionLayerSpaceWarpInfoFlagsFB(_) \ _(XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0x00000001) \ @@ -1851,6 +2001,54 @@ XR_ENUM_STR(XrResult); _(b) \ _(a) \ +/// Calls your macro with the name of each member of XrApiLayerNextInfo, in order. +#define XR_LIST_STRUCT_XrApiLayerNextInfo(_) \ + _(structType) \ + _(structVersion) \ + _(structSize) \ + _(layerName) \ + _(nextGetInstanceProcAddr) \ + _(nextCreateApiLayerInstance) \ + _(next) \ + +/// Calls your macro with the name of each member of XrApiLayerCreateInfo, in order. +#define XR_LIST_STRUCT_XrApiLayerCreateInfo(_) \ + _(structType) \ + _(structVersion) \ + _(structSize) \ + _(loaderInstance) \ + _(settings_file_location) \ + _(nextInfo) \ + +/// Calls your macro with the name of each member of XrNegotiateLoaderInfo, in order. +#define XR_LIST_STRUCT_XrNegotiateLoaderInfo(_) \ + _(structType) \ + _(structVersion) \ + _(structSize) \ + _(minInterfaceVersion) \ + _(maxInterfaceVersion) \ + _(minApiVersion) \ + _(maxApiVersion) \ + +/// Calls your macro with the name of each member of XrNegotiateRuntimeRequest, in order. +#define XR_LIST_STRUCT_XrNegotiateRuntimeRequest(_) \ + _(structType) \ + _(structVersion) \ + _(structSize) \ + _(runtimeInterfaceVersion) \ + _(runtimeApiVersion) \ + _(getInstanceProcAddr) \ + +/// Calls your macro with the name of each member of XrNegotiateApiLayerRequest, in order. +#define XR_LIST_STRUCT_XrNegotiateApiLayerRequest(_) \ + _(structType) \ + _(structVersion) \ + _(structSize) \ + _(layerInterfaceVersion) \ + _(layerApiVersion) \ + _(getInstanceProcAddr) \ + _(createApiLayerInstance) \ + /// Calls your macro with the name of each member of XrCompositionLayerCubeKHR, in order. #define XR_LIST_STRUCT_XrCompositionLayerCubeKHR(_) \ _(type) \ @@ -3212,6 +3410,109 @@ XR_ENUM_STR(XrResult); _(cfuid) \ _(poseInCoordinateSpace) \ +/// Calls your macro with the name of each member of XrSystemMarkerUnderstandingPropertiesML, in order. +#define XR_LIST_STRUCT_XrSystemMarkerUnderstandingPropertiesML(_) \ + _(type) \ + _(next) \ + _(supportsMarkerUnderstanding) \ + +/// Calls your macro with the name of each member of XrMarkerDetectorCreateInfoML, in order. +#define XR_LIST_STRUCT_XrMarkerDetectorCreateInfoML(_) \ + _(type) \ + _(next) \ + _(profile) \ + _(markerType) \ + +/// Calls your macro with the name of each member of XrMarkerDetectorArucoInfoML, in order. +#define XR_LIST_STRUCT_XrMarkerDetectorArucoInfoML(_) \ + _(type) \ + _(next) \ + _(arucoDict) \ + +/// Calls your macro with the name of each member of XrMarkerDetectorSizeInfoML, in order. +#define XR_LIST_STRUCT_XrMarkerDetectorSizeInfoML(_) \ + _(type) \ + _(next) \ + _(markerLength) \ + +/// Calls your macro with the name of each member of XrMarkerDetectorAprilTagInfoML, in order. +#define XR_LIST_STRUCT_XrMarkerDetectorAprilTagInfoML(_) \ + _(type) \ + _(next) \ + _(aprilTagDict) \ + +/// Calls your macro with the name of each member of XrMarkerDetectorCustomProfileInfoML, in order. +#define XR_LIST_STRUCT_XrMarkerDetectorCustomProfileInfoML(_) \ + _(type) \ + _(next) \ + _(fpsHint) \ + _(resolutionHint) \ + _(cameraHint) \ + _(cornerRefineMethod) \ + _(useEdgeRefinement) \ + _(fullAnalysisIntervalHint) \ + +/// Calls your macro with the name of each member of XrMarkerDetectorSnapshotInfoML, in order. +#define XR_LIST_STRUCT_XrMarkerDetectorSnapshotInfoML(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrMarkerDetectorStateML, in order. +#define XR_LIST_STRUCT_XrMarkerDetectorStateML(_) \ + _(type) \ + _(next) \ + _(state) \ + +/// Calls your macro with the name of each member of XrMarkerSpaceCreateInfoML, in order. +#define XR_LIST_STRUCT_XrMarkerSpaceCreateInfoML(_) \ + _(type) \ + _(next) \ + _(markerDetector) \ + _(marker) \ + _(poseInMarkerSpace) \ + +/// Calls your macro with the name of each member of XrLocalizationMapML, in order. +#define XR_LIST_STRUCT_XrLocalizationMapML(_) \ + _(type) \ + _(next) \ + _(name) \ + _(mapUuid) \ + _(mapType) \ + +/// Calls your macro with the name of each member of XrEventDataLocalizationChangedML, in order. +#define XR_LIST_STRUCT_XrEventDataLocalizationChangedML(_) \ + _(type) \ + _(next) \ + _(session) \ + _(state) \ + _(map) \ + _(confidence) \ + _(errorFlags) \ + +/// Calls your macro with the name of each member of XrLocalizationMapQueryInfoBaseHeaderML, in order. +#define XR_LIST_STRUCT_XrLocalizationMapQueryInfoBaseHeaderML(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrMapLocalizationRequestInfoML, in order. +#define XR_LIST_STRUCT_XrMapLocalizationRequestInfoML(_) \ + _(type) \ + _(next) \ + _(mapUuid) \ + +/// Calls your macro with the name of each member of XrLocalizationMapImportInfoML, in order. +#define XR_LIST_STRUCT_XrLocalizationMapImportInfoML(_) \ + _(type) \ + _(next) \ + _(size) \ + _(data) \ + +/// Calls your macro with the name of each member of XrLocalizationEnableEventsInfoML, in order. +#define XR_LIST_STRUCT_XrLocalizationEnableEventsInfoML(_) \ + _(type) \ + _(next) \ + _(enabled) \ + /// Calls your macro with the name of each member of XrSpatialAnchorPersistenceNameMSFT, in order. #define XR_LIST_STRUCT_XrSpatialAnchorPersistenceNameMSFT(_) \ _(name) \ @@ -3941,6 +4242,24 @@ XR_ENUM_STR(XrResult); _(configCount) \ _(configs) \ +/// Calls your macro with the name of each member of XrSystemAnchorPropertiesHTC, in order. +#define XR_LIST_STRUCT_XrSystemAnchorPropertiesHTC(_) \ + _(type) \ + _(next) \ + _(supportsAnchor) \ + +/// Calls your macro with the name of each member of XrSpatialAnchorNameHTC, in order. +#define XR_LIST_STRUCT_XrSpatialAnchorNameHTC(_) \ + _(name) \ + +/// Calls your macro with the name of each member of XrSpatialAnchorCreateInfoHTC, in order. +#define XR_LIST_STRUCT_XrSpatialAnchorCreateInfoHTC(_) \ + _(type) \ + _(next) \ + _(space) \ + _(poseInSpace) \ + _(name) \ + /// Calls your macro with the name of each member of XrActiveActionSetPriorityEXT, in order. #define XR_LIST_STRUCT_XrActiveActionSetPriorityEXT(_) \ _(actionSet) \ @@ -4278,6 +4597,20 @@ XR_ENUM_STR(XrResult); _(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \ _(XrFrameEndInfoML, XR_TYPE_FRAME_END_INFO_ML) \ _(XrGlobalDimmerFrameEndInfoML, XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML) \ + _(XrSystemMarkerUnderstandingPropertiesML, XR_TYPE_SYSTEM_MARKER_UNDERSTANDING_PROPERTIES_ML) \ + _(XrMarkerDetectorCreateInfoML, XR_TYPE_MARKER_DETECTOR_CREATE_INFO_ML) \ + _(XrMarkerDetectorArucoInfoML, XR_TYPE_MARKER_DETECTOR_ARUCO_INFO_ML) \ + _(XrMarkerDetectorSizeInfoML, XR_TYPE_MARKER_DETECTOR_SIZE_INFO_ML) \ + _(XrMarkerDetectorAprilTagInfoML, XR_TYPE_MARKER_DETECTOR_APRIL_TAG_INFO_ML) \ + _(XrMarkerDetectorCustomProfileInfoML, XR_TYPE_MARKER_DETECTOR_CUSTOM_PROFILE_INFO_ML) \ + _(XrMarkerDetectorSnapshotInfoML, XR_TYPE_MARKER_DETECTOR_SNAPSHOT_INFO_ML) \ + _(XrMarkerDetectorStateML, XR_TYPE_MARKER_DETECTOR_STATE_ML) \ + _(XrMarkerSpaceCreateInfoML, XR_TYPE_MARKER_SPACE_CREATE_INFO_ML) \ + _(XrLocalizationMapML, XR_TYPE_LOCALIZATION_MAP_ML) \ + _(XrEventDataLocalizationChangedML, XR_TYPE_EVENT_DATA_LOCALIZATION_CHANGED_ML) \ + _(XrMapLocalizationRequestInfoML, XR_TYPE_MAP_LOCALIZATION_REQUEST_INFO_ML) \ + _(XrLocalizationMapImportInfoML, XR_TYPE_LOCALIZATION_MAP_IMPORT_INFO_ML) \ + _(XrLocalizationEnableEventsInfoML, XR_TYPE_LOCALIZATION_ENABLE_EVENTS_INFO_ML) \ _(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \ _(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \ _(XrSceneMarkersMSFT, XR_TYPE_SCENE_MARKERS_MSFT) \ @@ -4359,6 +4692,8 @@ XR_ENUM_STR(XrResult); _(XrFoveationApplyInfoHTC, XR_TYPE_FOVEATION_APPLY_INFO_HTC) \ _(XrFoveationDynamicModeInfoHTC, XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC) \ _(XrFoveationCustomModeInfoHTC, XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC) \ + _(XrSystemAnchorPropertiesHTC, XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC) \ + _(XrSpatialAnchorCreateInfoHTC, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_HTC) \ _(XrActiveActionSetPrioritiesEXT, XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT) \ _(XrSystemForceFeedbackCurlPropertiesMNDX, XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX) \ _(XrForceFeedbackCurlApplyLocationsMNDX, XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX) \ @@ -4629,6 +4964,8 @@ XR_ENUM_STR(XrResult); _(XR_ML_frame_end_info, 136) \ _(XR_ML_global_dimmer, 137) \ _(XR_ML_compat, 138) \ + _(XR_ML_marker_understanding, 139) \ + _(XR_ML_localization_map, 140) \ _(XR_MSFT_spatial_anchor_persistence, 143) \ _(XR_MSFT_scene_marker, 148) \ _(XR_ULTRALEAP_hand_tracking_forearm, 150) \ @@ -4667,11 +5004,13 @@ XR_ENUM_STR(XrResult); _(XR_FB_spatial_entity_user, 242) \ _(XR_META_headset_id, 246) \ _(XR_META_passthrough_color_lut, 267) \ + _(XR_META_touch_controller_plus, 280) \ _(XR_EXT_uuid, 300) \ _(XR_EXT_hand_interaction, 303) \ _(XR_QCOM_tracking_optimization_settings, 307) \ _(XR_HTC_passthrough, 318) \ _(XR_HTC_foveation, 319) \ + _(XR_HTC_anchor, 320) \ _(XR_EXT_active_action_set_priority, 374) \ _(XR_MNDX_force_feedback_curl, 376) \ _(XR_BD_controller_interaction, 385) \ diff --git a/thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h b/thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h index f410ddcf79..4241682e0b 100644 --- a/thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h +++ b/thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h @@ -2,7 +2,7 @@ #define OPENXR_REFLECTION_PARENT_STRUCTS_H_ 1 /* -** Copyright (c) 2017-2023, The Khronos Group Inc. +** Copyright (c) 2017-2024, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -58,6 +58,7 @@ This file contains expansion macros (X Macros) for OpenXR structures that have a _avail(XrEventDataSpatialAnchorCreateCompleteFB, XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB) \ _avail(XrEventDataSpaceSetStatusCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB) \ _avail(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \ + _avail(XrEventDataLocalizationChangedML, XR_TYPE_EVENT_DATA_LOCALIZATION_CHANGED_ML) \ _avail(XrEventDataSpaceQueryResultsAvailableFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB) \ _avail(XrEventDataSpaceQueryCompleteFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB) \ _avail(XrEventDataSpaceSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB) \ diff --git a/thirdparty/openxr/include/openxr/openxr_reflection_structs.h b/thirdparty/openxr/include/openxr/openxr_reflection_structs.h index 2d23ac15ca..bcc1333e29 100644 --- a/thirdparty/openxr/include/openxr/openxr_reflection_structs.h +++ b/thirdparty/openxr/include/openxr/openxr_reflection_structs.h @@ -2,7 +2,7 @@ #define OPENXR_REFLECTION_STRUCTS_H_ 1 /* -** Copyright (c) 2017-2023, The Khronos Group Inc. +** Copyright (c) 2017-2024, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -225,6 +225,20 @@ This file contains expansion macros (X Macros) for OpenXR structures. _avail(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \ _avail(XrFrameEndInfoML, XR_TYPE_FRAME_END_INFO_ML) \ _avail(XrGlobalDimmerFrameEndInfoML, XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML) \ + _avail(XrSystemMarkerUnderstandingPropertiesML, XR_TYPE_SYSTEM_MARKER_UNDERSTANDING_PROPERTIES_ML) \ + _avail(XrMarkerDetectorCreateInfoML, XR_TYPE_MARKER_DETECTOR_CREATE_INFO_ML) \ + _avail(XrMarkerDetectorArucoInfoML, XR_TYPE_MARKER_DETECTOR_ARUCO_INFO_ML) \ + _avail(XrMarkerDetectorSizeInfoML, XR_TYPE_MARKER_DETECTOR_SIZE_INFO_ML) \ + _avail(XrMarkerDetectorAprilTagInfoML, XR_TYPE_MARKER_DETECTOR_APRIL_TAG_INFO_ML) \ + _avail(XrMarkerDetectorCustomProfileInfoML, XR_TYPE_MARKER_DETECTOR_CUSTOM_PROFILE_INFO_ML) \ + _avail(XrMarkerDetectorSnapshotInfoML, XR_TYPE_MARKER_DETECTOR_SNAPSHOT_INFO_ML) \ + _avail(XrMarkerDetectorStateML, XR_TYPE_MARKER_DETECTOR_STATE_ML) \ + _avail(XrMarkerSpaceCreateInfoML, XR_TYPE_MARKER_SPACE_CREATE_INFO_ML) \ + _avail(XrLocalizationMapML, XR_TYPE_LOCALIZATION_MAP_ML) \ + _avail(XrEventDataLocalizationChangedML, XR_TYPE_EVENT_DATA_LOCALIZATION_CHANGED_ML) \ + _avail(XrMapLocalizationRequestInfoML, XR_TYPE_MAP_LOCALIZATION_REQUEST_INFO_ML) \ + _avail(XrLocalizationMapImportInfoML, XR_TYPE_LOCALIZATION_MAP_IMPORT_INFO_ML) \ + _avail(XrLocalizationEnableEventsInfoML, XR_TYPE_LOCALIZATION_ENABLE_EVENTS_INFO_ML) \ _avail(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \ _avail(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \ _avail(XrSceneMarkersMSFT, XR_TYPE_SCENE_MARKERS_MSFT) \ @@ -306,6 +320,8 @@ This file contains expansion macros (X Macros) for OpenXR structures. _avail(XrFoveationApplyInfoHTC, XR_TYPE_FOVEATION_APPLY_INFO_HTC) \ _avail(XrFoveationDynamicModeInfoHTC, XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC) \ _avail(XrFoveationCustomModeInfoHTC, XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC) \ + _avail(XrSystemAnchorPropertiesHTC, XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC) \ + _avail(XrSpatialAnchorCreateInfoHTC, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_HTC) \ _avail(XrActiveActionSetPrioritiesEXT, XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT) \ _avail(XrSystemForceFeedbackCurlPropertiesMNDX, XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX) \ _avail(XrForceFeedbackCurlApplyLocationsMNDX, XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX) \ diff --git a/thirdparty/openxr/src/common/extra_algorithms.h b/thirdparty/openxr/src/common/extra_algorithms.h index eec429e12a..bdaa420e9f 100644 --- a/thirdparty/openxr/src/common/extra_algorithms.h +++ b/thirdparty/openxr/src/common/extra_algorithms.h @@ -1,11 +1,11 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // Copyright (c) 2019 Collabora, Ltd. // // SPDX-License-Identifier: Apache-2.0 OR MIT // -// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com> +// Initial Author: Rylie Pavlik <rylie.pavlik@collabora.com> // /*! diff --git a/thirdparty/openxr/src/common/filesystem_utils.cpp b/thirdparty/openxr/src/common/filesystem_utils.cpp index 16e6ff3292..063c4c4cee 100644 --- a/thirdparty/openxr/src/common/filesystem_utils.cpp +++ b/thirdparty/openxr/src/common/filesystem_utils.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017 Valve Corporation // Copyright (c) 2017 LunarG, Inc. // diff --git a/thirdparty/openxr/src/common/filesystem_utils.hpp b/thirdparty/openxr/src/common/filesystem_utils.hpp index 3dea1b2c3e..2a923fac4c 100644 --- a/thirdparty/openxr/src/common/filesystem_utils.hpp +++ b/thirdparty/openxr/src/common/filesystem_utils.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017 Valve Corporation // Copyright (c) 2017 LunarG, Inc. // diff --git a/thirdparty/openxr/src/common/hex_and_handles.h b/thirdparty/openxr/src/common/hex_and_handles.h index 300669033f..12bdb3670c 100644 --- a/thirdparty/openxr/src/common/hex_and_handles.h +++ b/thirdparty/openxr/src/common/hex_and_handles.h @@ -1,11 +1,11 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // Copyright (c) 2019 Collabora, Ltd. // // SPDX-License-Identifier: Apache-2.0 OR MIT // -// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com> +// Initial Author: Rylie Pavlik <rylie.pavlik@collabora.com> // /*! diff --git a/thirdparty/openxr/src/common/loader_interfaces.h b/thirdparty/openxr/src/common/loader_interfaces.h deleted file mode 100644 index 020c3456ea..0000000000 --- a/thirdparty/openxr/src/common/loader_interfaces.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. -// Copyright (c) 2017 Valve Corporation -// Copyright (c) 2017 LunarG, Inc. -// -// SPDX-License-Identifier: Apache-2.0 OR MIT -// -// Initial Author: Mark Young <marky@lunarg.com> -// - -#pragma once - -#include <openxr/openxr.h> - -#ifdef __cplusplus -extern "C" { -#endif - -// Forward declare. -typedef struct XrApiLayerCreateInfo XrApiLayerCreateInfo; - -// Function pointer prototype for the xrCreateApiLayerInstance function used in place of xrCreateInstance. -// This function allows us to pass special API layer information to each layer during the process of creating an Instance. -typedef XrResult(XRAPI_PTR *PFN_xrCreateApiLayerInstance)(const XrInstanceCreateInfo *info, - const XrApiLayerCreateInfo *apiLayerInfo, XrInstance *instance); - -// Loader/API Layer Interface versions -// 1 - First version, introduces negotiation structure and functions -#define XR_CURRENT_LOADER_API_LAYER_VERSION 1 - -// Loader/Runtime Interface versions -// 1 - First version, introduces negotiation structure and functions -#define XR_CURRENT_LOADER_RUNTIME_VERSION 1 - -// Version negotiation values -typedef enum XrLoaderInterfaceStructs { - XR_LOADER_INTERFACE_STRUCT_UNINTIALIZED = 0, - XR_LOADER_INTERFACE_STRUCT_LOADER_INFO, - XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST, - XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST, - XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO, - XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO, -} XrLoaderInterfaceStructs; - -#define XR_LOADER_INFO_STRUCT_VERSION 1 -typedef struct XrNegotiateLoaderInfo { - XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_LOADER_INFO - uint32_t structVersion; // XR_LOADER_INFO_STRUCT_VERSION - size_t structSize; // sizeof(XrNegotiateLoaderInfo) - uint32_t minInterfaceVersion; - uint32_t maxInterfaceVersion; - XrVersion minApiVersion; - XrVersion maxApiVersion; -} XrNegotiateLoaderInfo; - -#define XR_API_LAYER_INFO_STRUCT_VERSION 1 -typedef struct XrNegotiateApiLayerRequest { - XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST - uint32_t structVersion; // XR_API_LAYER_INFO_STRUCT_VERSION - size_t structSize; // sizeof(XrNegotiateApiLayerRequest) - uint32_t layerInterfaceVersion; // CURRENT_LOADER_API_LAYER_VERSION - XrVersion layerApiVersion; - PFN_xrGetInstanceProcAddr getInstanceProcAddr; - PFN_xrCreateApiLayerInstance createApiLayerInstance; -} XrNegotiateApiLayerRequest; - -#define XR_RUNTIME_INFO_STRUCT_VERSION 1 -typedef struct XrNegotiateRuntimeRequest { - XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST - uint32_t structVersion; // XR_RUNTIME_INFO_STRUCT_VERSION - size_t structSize; // sizeof(XrNegotiateRuntimeRequest) - uint32_t runtimeInterfaceVersion; // CURRENT_LOADER_RUNTIME_VERSION - XrVersion runtimeApiVersion; - PFN_xrGetInstanceProcAddr getInstanceProcAddr; -} XrNegotiateRuntimeRequest; - -// Function used to negotiate an interface betewen the loader and an API layer. Each library exposing one or -// more API layers needs to expose at least this function. -typedef XrResult(XRAPI_PTR *PFN_xrNegotiateLoaderApiLayerInterface)(const XrNegotiateLoaderInfo *loaderInfo, - const char *apiLayerName, - XrNegotiateApiLayerRequest *apiLayerRequest); - -// Function used to negotiate an interface betewen the loader and a runtime. Each runtime should expose -// at least this function. -typedef XrResult(XRAPI_PTR *PFN_xrNegotiateLoaderRuntimeInterface)(const XrNegotiateLoaderInfo *loaderInfo, - XrNegotiateRuntimeRequest *runtimeRequest); - -// Forward declare. -typedef struct XrApiLayerNextInfo XrApiLayerNextInfo; - -#define XR_API_LAYER_NEXT_INFO_STRUCT_VERSION 1 -struct XrApiLayerNextInfo { - XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO - uint32_t structVersion; // XR_API_LAYER_NEXT_INFO_STRUCT_VERSION - size_t structSize; // sizeof(XrApiLayerNextInfo) - char layerName[XR_MAX_API_LAYER_NAME_SIZE]; // Name of API layer which should receive this info - PFN_xrGetInstanceProcAddr nextGetInstanceProcAddr; // Pointer to next API layer's xrGetInstanceProcAddr - PFN_xrCreateApiLayerInstance nextCreateApiLayerInstance; // Pointer to next API layer's xrCreateApiLayerInstance - XrApiLayerNextInfo *next; // Pointer to the next API layer info in the sequence -}; - -#define XR_API_LAYER_MAX_SETTINGS_PATH_SIZE 512 -#define XR_API_LAYER_CREATE_INFO_STRUCT_VERSION 1 -typedef struct XrApiLayerCreateInfo { - XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO - uint32_t structVersion; // XR_API_LAYER_CREATE_INFO_STRUCT_VERSION - size_t structSize; // sizeof(XrApiLayerCreateInfo) - void *loaderInstance; // Pointer to the LoaderInstance class - char settings_file_location[XR_API_LAYER_MAX_SETTINGS_PATH_SIZE]; // Location to the found settings file (or empty '\0') - XrApiLayerNextInfo *nextInfo; // Pointer to the next API layer's Info -} XrApiLayerCreateInfo; - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/thirdparty/openxr/src/common/object_info.cpp b/thirdparty/openxr/src/common/object_info.cpp index 3f8f96bc6e..d45430a609 100644 --- a/thirdparty/openxr/src/common/object_info.cpp +++ b/thirdparty/openxr/src/common/object_info.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // Copyright (c) 2019 Collabora, Ltd. @@ -6,7 +6,7 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT // // Initial Authors: Mark Young <marky@lunarg.com> -// Ryan Pavlik <ryan.pavlik@collabora.com> +// Rylie Pavlik <rylie.pavlik@collabora.com> // Dave Houlton <daveh@lunarg.com> // diff --git a/thirdparty/openxr/src/common/object_info.h b/thirdparty/openxr/src/common/object_info.h index 247ede0dcc..572f06ab15 100644 --- a/thirdparty/openxr/src/common/object_info.h +++ b/thirdparty/openxr/src/common/object_info.h @@ -1,11 +1,11 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // Copyright (c) 2019 Collabora, Ltd. // // SPDX-License-Identifier: Apache-2.0 OR MIT // -// Initial Authors: Mark Young <marky@lunarg.com>, Ryan Pavlik <ryan.pavlik@collabora.com +// Initial Authors: Mark Young <marky@lunarg.com>, Rylie Pavlik <rylie.pavlik@collabora.com // /*! * @file diff --git a/thirdparty/openxr/src/common/platform_utils.hpp b/thirdparty/openxr/src/common/platform_utils.hpp index 0b295f5cc9..c4d75bf259 100644 --- a/thirdparty/openxr/src/common/platform_utils.hpp +++ b/thirdparty/openxr/src/common/platform_utils.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // diff --git a/thirdparty/openxr/src/common/stdfs_conditions.h b/thirdparty/openxr/src/common/stdfs_conditions.h index 0a551f08cd..9e2ba70d42 100644 --- a/thirdparty/openxr/src/common/stdfs_conditions.h +++ b/thirdparty/openxr/src/common/stdfs_conditions.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017 Valve Corporation // Copyright (c) 2017 LunarG, Inc. // diff --git a/thirdparty/openxr/src/common/unique_asset.h b/thirdparty/openxr/src/common/unique_asset.h index a8ae8077bc..fd5f8868e3 100644 --- a/thirdparty/openxr/src/common/unique_asset.h +++ b/thirdparty/openxr/src/common/unique_asset.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // // SPDX-License-Identifier: Apache-2.0 OR MIT #pragma once diff --git a/thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp b/thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp index 451219d20f..885389ce8e 100644 --- a/thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp +++ b/thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // // SPDX-License-Identifier: Apache-2.0 diff --git a/thirdparty/openxr/src/common/xr_dependencies.h b/thirdparty/openxr/src/common/xr_dependencies.h index 6c9cf2d05f..55d93bfbac 100644 --- a/thirdparty/openxr/src/common/xr_dependencies.h +++ b/thirdparty/openxr/src/common/xr_dependencies.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023, The Khronos Group Inc. +// Copyright (c) 2018-2024, The Khronos Group Inc. // // SPDX-License-Identifier: Apache-2.0 OR MIT // diff --git a/thirdparty/openxr/src/common/xr_linear.h b/thirdparty/openxr/src/common/xr_linear.h index ce65f8ddfb..2b295ed304 100644 --- a/thirdparty/openxr/src/common/xr_linear.h +++ b/thirdparty/openxr/src/common/xr_linear.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2016, Oculus VR, LLC. // // SPDX-License-Identifier: Apache-2.0 diff --git a/thirdparty/openxr/src/loader/android_utilities.cpp b/thirdparty/openxr/src/loader/android_utilities.cpp index 9a3ad76ce0..5c9b846b5a 100644 --- a/thirdparty/openxr/src/loader/android_utilities.cpp +++ b/thirdparty/openxr/src/loader/android_utilities.cpp @@ -1,9 +1,9 @@ -// Copyright (c) 2020-2023, The Khronos Group Inc. +// Copyright (c) 2020-2024, The Khronos Group Inc. // Copyright (c) 2020-2021, Collabora, Ltd. // // SPDX-License-Identifier: Apache-2.0 OR MIT // -// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com> +// Initial Author: Rylie Pavlik <rylie.pavlik@collabora.com> #include "android_utilities.h" @@ -245,18 +245,38 @@ static int populateFunctions(wrap::android::content::Context const &context, boo return 0; } +// The current file relies on android-jni-wrappers and jnipp, which may throw on failure. +// This is problematic when the loader is compiled with exception handling disabled - the consumers can reasonably +// expect that the compilation with -fno-exceptions will succeed, but the compiler will not accept the code that +// uses `try` & `catch` keywords. We cannot use the `exception_handling.hpp` here since we're not at an ABI boundary, +// so we define helper macros here. This is fine for now since the only occurrence of exception-handling code is in this file. +#ifdef XRLOADER_DISABLE_EXCEPTION_HANDLING + +#define ANDROID_UTILITIES_TRY +#define ANDROID_UTILITIES_CATCH_FALLBACK(...) + +#else + +#define ANDROID_UTILITIES_TRY try +#define ANDROID_UTILITIES_CATCH_FALLBACK(...) \ + catch (const std::exception &e) { \ + __VA_ARGS__ \ + } + +#endif // XRLOADER_DISABLE_EXCEPTION_HANDLING + /// Get cursor for active runtime, parameterized by whether or not we use the system broker static bool getActiveRuntimeCursor(wrap::android::content::Context const &context, jni::Array<std::string> const &projection, bool systemBroker, Cursor &cursor) { auto uri = active_runtime::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), ABI); ALOGI("getActiveRuntimeCursor: Querying URI: %s", uri.toString().c_str()); - try { - cursor = context.getContentResolver().query(uri, projection); - } catch (const std::exception &e) { + + ANDROID_UTILITIES_TRY { cursor = context.getContentResolver().query(uri, projection); } + ANDROID_UTILITIES_CATCH_FALLBACK({ ALOGW("Exception when querying %s content resolver: %s", getBrokerTypeName(systemBroker), e.what()); cursor = {}; return false; - } + }) if (cursor.isNull()) { ALOGW("Null cursor when querying %s content resolver.", getBrokerTypeName(systemBroker)); diff --git a/thirdparty/openxr/src/loader/android_utilities.h b/thirdparty/openxr/src/loader/android_utilities.h index f66c9bf1d0..582a65056e 100644 --- a/thirdparty/openxr/src/loader/android_utilities.h +++ b/thirdparty/openxr/src/loader/android_utilities.h @@ -1,9 +1,9 @@ -// Copyright (c) 2020-2023, The Khronos Group Inc. +// Copyright (c) 2020-2024, The Khronos Group Inc. // Copyright (c) 2020-2021, Collabora, Ltd. // // SPDX-License-Identifier: Apache-2.0 OR MIT // -// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com> +// Initial Author: Rylie Pavlik <rylie.pavlik@collabora.com> #pragma once #ifdef __ANDROID__ diff --git a/thirdparty/openxr/src/loader/api_layer_interface.cpp b/thirdparty/openxr/src/loader/api_layer_interface.cpp index c9e24ec40b..fb509de270 100644 --- a/thirdparty/openxr/src/loader/api_layer_interface.cpp +++ b/thirdparty/openxr/src/loader/api_layer_interface.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // @@ -9,13 +9,14 @@ #include "api_layer_interface.hpp" -#include "loader_interfaces.h" +#include "loader_init_data.hpp" #include "loader_logger.hpp" #include "loader_platform.hpp" #include "manifest_file.hpp" #include "platform_utils.hpp" #include <openxr/openxr.h> +#include <openxr/openxr_loader_negotiation.h> #include <cstring> #include <memory> @@ -282,6 +283,38 @@ XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uin LoaderLogger::LogWarningMessage(openxr_command, warning_message); continue; } +#ifdef XR_KHR_LOADER_INIT_SUPPORT + if (!LoaderInitData::instance().initialized()) { + LoaderLogger::LogErrorMessage(openxr_command, "ApiLayerInterface::LoadApiLayers skipping manifest file " + + manifest_file->Filename() + + " because xrInitializeLoaderKHR was not yet called."); + + LoaderPlatformLibraryClose(layer_library); + return XR_ERROR_VALIDATION_FAILURE; + } + bool forwardedInitLoader = false; + { + // If we have xrInitializeLoaderKHR exposed as an export, forward call to it. + const auto function_name = manifest_file->GetFunctionName("xrInitializeLoaderKHR"); + auto initLoader = + reinterpret_cast<PFN_xrInitializeLoaderKHR>(LoaderPlatformLibraryGetProcAddr(layer_library, function_name)); + if (initLoader != nullptr) { + // we found the entry point one way or another. + LoaderLogger::LogInfoMessage(openxr_command, + "ApiLayerInterface::LoadApiLayers forwarding xrInitializeLoaderKHR call to API layer " + "before calling xrNegotiateLoaderApiLayerInterface."); + XrResult res = initLoader(LoaderInitData::instance().getParam()); + if (!XR_SUCCEEDED(res)) { + LoaderLogger::LogErrorMessage( + openxr_command, "ApiLayerInterface::LoadApiLayers forwarded call to xrInitializeLoaderKHR failed."); + + LoaderPlatformLibraryClose(layer_library); + return res; + } + forwardedInitLoader = true; + } + } +#endif // Get and settle on an layer interface version (using any provided name if required). std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderApiLayerInterface"); @@ -324,6 +357,38 @@ XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uin LoaderLogger::LogWarningMessage(openxr_command, warning_message); res = XR_ERROR_FILE_CONTENTS_INVALID; } + +#ifdef XR_KHR_LOADER_INIT_SUPPORT + if (XR_SUCCEEDED(res) && !forwardedInitLoader) { + // Forward initialize loader call, where possible and if we did not do so before. + PFN_xrVoidFunction initializeVoid = nullptr; + PFN_xrInitializeLoaderKHR initialize = nullptr; + + // Now we may try asking xrGetInstanceProcAddr on the API layer + if (XR_SUCCEEDED(api_layer_info.getInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", &initializeVoid))) { + if (initializeVoid == nullptr) { + LoaderLogger::LogErrorMessage(openxr_command, + "ApiLayerInterface::LoadApiLayers got success from xrGetInstanceProcAddr " + "for xrInitializeLoaderKHR, but output a null pointer."); + res = XR_ERROR_RUNTIME_FAILURE; + } else { + initialize = reinterpret_cast<PFN_xrInitializeLoaderKHR>(initializeVoid); + } + } + if (initialize != nullptr) { + // we found the entry point one way or another. + LoaderLogger::LogInfoMessage(openxr_command, + "ApiLayerInterface::LoadApiLayers forwarding xrInitializeLoaderKHR call to API layer " + "after calling xrNegotiateLoaderApiLayerInterface."); + res = initialize(LoaderInitData::instance().getParam()); + if (!XR_SUCCEEDED(res)) { + LoaderLogger::LogErrorMessage( + openxr_command, "ApiLayerInterface::LoadApiLayers forwarded call to xrInitializeLoaderKHR failed."); + } + } + } +#endif + if (XR_FAILED(res)) { if (!any_loaded) { last_error = res; diff --git a/thirdparty/openxr/src/loader/api_layer_interface.hpp b/thirdparty/openxr/src/loader/api_layer_interface.hpp index 98685b0c32..43758b31a4 100644 --- a/thirdparty/openxr/src/loader/api_layer_interface.hpp +++ b/thirdparty/openxr/src/loader/api_layer_interface.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // @@ -14,9 +14,9 @@ #include <memory> #include <openxr/openxr.h> +#include <openxr/openxr_loader_negotiation.h> #include "loader_platform.hpp" -#include "loader_interfaces.h" struct XrGeneratedDispatchTable; diff --git a/thirdparty/openxr/src/loader/exception_handling.hpp b/thirdparty/openxr/src/loader/exception_handling.hpp index bc0d9b65e3..62395fdf69 100644 --- a/thirdparty/openxr/src/loader/exception_handling.hpp +++ b/thirdparty/openxr/src/loader/exception_handling.hpp @@ -1,8 +1,8 @@ -// Copyright (c) 2019-2023, The Khronos Group Inc. +// Copyright (c) 2019-2024, The Khronos Group Inc. // // SPDX-License-Identifier: Apache-2.0 OR MIT // -// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com> +// Initial Author: Rylie Pavlik <rylie.pavlik@collabora.com> // // Provides protection for C ABI functions if standard library functions may throw. diff --git a/thirdparty/openxr/src/loader/loader_core.cpp b/thirdparty/openxr/src/loader/loader_core.cpp index 06e6870053..8bf2609a08 100644 --- a/thirdparty/openxr/src/loader/loader_core.cpp +++ b/thirdparty/openxr/src/loader/loader_core.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // @@ -14,6 +14,7 @@ #include "api_layer_interface.hpp" #include "exception_handling.hpp" #include "hex_and_handles.h" +#include "loader_init_data.hpp" #include "loader_instance.hpp" #include "loader_logger_recorders.hpp" #include "loader_logger.hpp" @@ -77,7 +78,7 @@ inline bool IsMissingNullTerminator(const char (&str)[max_length]) { #ifdef XR_KHR_LOADER_INIT_SUPPORT // platforms that support XR_KHR_loader_init. XRAPI_ATTR XrResult XRAPI_CALL LoaderXrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) XRLOADER_ABI_TRY { LoaderLogger::LogVerboseMessage("xrInitializeLoaderKHR", "Entering loader trampoline"); - return InitializeLoader(loaderInitInfo); + return InitializeLoaderInitData(loaderInitInfo); } XRLOADER_ABI_CATCH_FALLBACK #endif diff --git a/thirdparty/openxr/src/loader/loader_init_data.cpp b/thirdparty/openxr/src/loader/loader_init_data.cpp new file mode 100644 index 0000000000..11d3c4e77b --- /dev/null +++ b/thirdparty/openxr/src/loader/loader_init_data.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2017-2024, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#include "loader_init_data.hpp" + +#ifdef XR_KHR_LOADER_INIT_SUPPORT + +#ifdef XR_USE_PLATFORM_ANDROID +// Check and copy the Android-specific init data. +XrResult LoaderInitData::initialize(const XrLoaderInitInfoBaseHeaderKHR* info) { + if (info->type != XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) { + return XR_ERROR_VALIDATION_FAILURE; + } + auto cast_info = reinterpret_cast<XrLoaderInitInfoAndroidKHR const*>(info); + + if (cast_info->applicationVM == nullptr) { + return XR_ERROR_VALIDATION_FAILURE; + } + if (cast_info->applicationContext == nullptr) { + return XR_ERROR_VALIDATION_FAILURE; + } + + // Copy and store the JVM pointer and Android Context, ensuring the JVM is initialised. + _data = *cast_info; + _data.next = nullptr; + jni::init(static_cast<jni::JavaVM*>(_data.applicationVM)); + const jni::Object context = jni::Object{static_cast<jni::jobject>(_data.applicationContext)}; + + // Retrieve a reference to the Android AssetManager. + const auto assetManager = context.call<jni::Object>("getAssets()Landroid/content/res/AssetManager;"); + _android_asset_manager = AAssetManager_fromJava(jni::env(), assetManager.getHandle()); + + // Retrieve the path to the native libraries. + const auto applicationContext = context.call<jni::Object>("getApplicationContext()Landroid/content/Context;"); + const auto applicationInfo = context.call<jni::Object>("getApplicationInfo()Landroid/content/pm/ApplicationInfo;"); + _native_library_path = applicationInfo.get<std::string>("nativeLibraryDir"); + + _initialized = true; + return XR_SUCCESS; +} +#endif // XR_USE_PLATFORM_ANDROID + +XrResult InitializeLoaderInitData(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo) { + return LoaderInitData::instance().initialize(loaderInitInfo); +} + +#ifdef XR_USE_PLATFORM_ANDROID +std::string GetAndroidNativeLibraryDir() { return LoaderInitData::instance()._native_library_path; } + +void* Android_Get_Asset_Manager() { return LoaderInitData::instance()._android_asset_manager; } +#endif // XR_USE_PLATFORM_ANDROID + +#endif // XR_KHR_LOADER_INIT_SUPPORT diff --git a/thirdparty/openxr/src/loader/loader_init_data.hpp b/thirdparty/openxr/src/loader/loader_init_data.hpp new file mode 100644 index 0000000000..fe6bc134d3 --- /dev/null +++ b/thirdparty/openxr/src/loader/loader_init_data.hpp @@ -0,0 +1,92 @@ +// Copyright (c) 2017-2024, The Khronos Group Inc. +// Copyright (c) 2017-2019 Valve Corporation +// Copyright (c) 2017-2019 LunarG, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Initial Author: Mark Young <marky@lunarg.com> +// + +#pragma once + +#include <xr_dependencies.h> +#include <openxr/openxr_platform.h> + +#ifdef XR_USE_PLATFORM_ANDROID +#include <json/value.h> +#include <android/asset_manager_jni.h> +#include "android_utilities.h" +#endif // XR_USE_PLATFORM_ANDROID + +#ifdef XR_KHR_LOADER_INIT_SUPPORT + +/*! + * Stores a copy of the data passed to the xrInitializeLoaderKHR function in a singleton. + */ +class LoaderInitData { + public: + /*! + * Singleton accessor. + */ + static LoaderInitData& instance() { + static LoaderInitData obj; + return obj; + } + +#ifdef XR_USE_PLATFORM_ANDROID + /*! + * Type alias for the platform-specific structure type. + */ + using StructType = XrLoaderInitInfoAndroidKHR; + /*! + * Native library path. + */ + std::string _native_library_path; + /*! + * Android asset manager. + */ + AAssetManager* _android_asset_manager; +#else +#error "Platform specific XR_KHR_loader_init structure is not defined for this platform." +#endif + + /*! + * Get our copy of the data, casted to pass to the runtime's matching method. + */ + const XrLoaderInitInfoBaseHeaderKHR* getParam() const { return reinterpret_cast<const XrLoaderInitInfoBaseHeaderKHR*>(&_data); } + + /*! + * Get the data via its real structure type. + */ + const StructType& getData() const { return _data; } + + /*! + * Has this been correctly initialized? + */ + bool initialized() const noexcept { return _initialized; } + + /*! + * Initialize loader data - called by InitializeLoaderInitData() and thus ultimately by the loader's xrInitializeLoaderKHR + * implementation. Each platform that needs this extension will provide an implementation of this. + */ + XrResult initialize(const XrLoaderInitInfoBaseHeaderKHR* info); + + private: + //! Private constructor, forces use of singleton accessor. + LoaderInitData() = default; + //! Platform-specific init data + StructType _data = {}; + //! Flag for indicating whether _data is valid. + bool _initialized = false; +}; + +//! Initialize loader init data, where required. +XrResult InitializeLoaderInitData(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); + +#ifdef XR_USE_PLATFORM_ANDROID +XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest); +std::string GetAndroidNativeLibraryDir(); +void* Android_Get_Asset_Manager(); +#endif // XR_USE_PLATFORM_ANDROID + +#endif // XR_KHR_LOADER_INIT_SUPPORT diff --git a/thirdparty/openxr/src/loader/loader_instance.cpp b/thirdparty/openxr/src/loader/loader_instance.cpp index ce5c205505..f18230087f 100644 --- a/thirdparty/openxr/src/loader/loader_instance.cpp +++ b/thirdparty/openxr/src/loader/loader_instance.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // @@ -15,13 +15,13 @@ #include "api_layer_interface.hpp" #include "hex_and_handles.h" -#include "loader_interfaces.h" #include "loader_logger.hpp" #include "runtime_interface.hpp" #include "xr_generated_dispatch_table_core.h" #include "xr_generated_loader.hpp" #include <openxr/openxr.h> +#include <openxr/openxr_loader_negotiation.h> #include <cstring> #include <memory> @@ -60,7 +60,7 @@ XrResult Get(LoaderInstance** loader_instance, const char* log_function_name) { bool IsAvailable() { return GetSetCurrentLoaderInstance() != nullptr; } -void Remove() { GetSetCurrentLoaderInstance().release(); } +void Remove() { GetSetCurrentLoaderInstance().reset(nullptr); } } // namespace ActiveLoaderInstance // Extensions that are supported by the loader, but may not be supported diff --git a/thirdparty/openxr/src/loader/loader_instance.hpp b/thirdparty/openxr/src/loader/loader_instance.hpp index a0268a855c..b99e6b047f 100644 --- a/thirdparty/openxr/src/loader/loader_instance.hpp +++ b/thirdparty/openxr/src/loader/loader_instance.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // @@ -10,9 +10,9 @@ #pragma once #include "extra_algorithms.h" -#include "loader_interfaces.h" #include <openxr/openxr.h> +#include <openxr/openxr_loader_negotiation.h> #include <array> #include <cmath> diff --git a/thirdparty/openxr/src/loader/loader_logger.cpp b/thirdparty/openxr/src/loader/loader_logger.cpp index 1c8d64f394..593e19a3ba 100644 --- a/thirdparty/openxr/src/loader/loader_logger.cpp +++ b/thirdparty/openxr/src/loader/loader_logger.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // diff --git a/thirdparty/openxr/src/loader/loader_logger.hpp b/thirdparty/openxr/src/loader/loader_logger.hpp index d31fac093a..964aa47962 100644 --- a/thirdparty/openxr/src/loader/loader_logger.hpp +++ b/thirdparty/openxr/src/loader/loader_logger.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // diff --git a/thirdparty/openxr/src/loader/loader_logger_recorders.cpp b/thirdparty/openxr/src/loader/loader_logger_recorders.cpp index 32e4687b2f..00392c27bd 100644 --- a/thirdparty/openxr/src/loader/loader_logger_recorders.cpp +++ b/thirdparty/openxr/src/loader/loader_logger_recorders.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // diff --git a/thirdparty/openxr/src/loader/loader_logger_recorders.hpp b/thirdparty/openxr/src/loader/loader_logger_recorders.hpp index 7b934202d5..b676c37e93 100644 --- a/thirdparty/openxr/src/loader/loader_logger_recorders.hpp +++ b/thirdparty/openxr/src/loader/loader_logger_recorders.hpp @@ -1,10 +1,10 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // // SPDX-License-Identifier: Apache-2.0 OR MIT // -// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com> +// Initial Author: Rylie Pavlik <rylie.pavlik@collabora.com> // #pragma once diff --git a/thirdparty/openxr/src/loader/loader_platform.hpp b/thirdparty/openxr/src/loader/loader_platform.hpp index 0ea80c05b8..964116caa4 100644 --- a/thirdparty/openxr/src/loader/loader_platform.hpp +++ b/thirdparty/openxr/src/loader/loader_platform.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // diff --git a/thirdparty/openxr/src/loader/manifest_file.cpp b/thirdparty/openxr/src/loader/manifest_file.cpp index 0683bc166a..f9699ece40 100644 --- a/thirdparty/openxr/src/loader/manifest_file.cpp +++ b/thirdparty/openxr/src/loader/manifest_file.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // @@ -18,6 +18,7 @@ #endif // OPENXR_HAVE_COMMON_CONFIG #include "filesystem_utils.hpp" +#include "loader_init_data.hpp" #include "loader_platform.hpp" #include "platform_utils.hpp" #include "loader_logger.hpp" @@ -666,14 +667,14 @@ XrResult RuntimeManifestFile::FindManifestFiles(std::vector<std::unique_ptr<Runt } #else -#if defined(XR_KHR_LOADER_INIT_SUPPORT) +#if defined(XR_USE_PLATFORM_ANDROID) Json::Value virtualManifest; result = GetPlatformRuntimeVirtualManifest(virtualManifest); if (XR_SUCCESS == result) { RuntimeManifestFile::CreateIfValid(virtualManifest, "", manifest_files); return result; } -#endif // defined(XR_KHR_LOADER_INIT_SUPPORT) +#endif // defined(XR_USE_PLATFORM_ANDROID) if (!PlatformGetGlobalRuntimeFileName(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), filename)) { LoaderLogger::LogErrorMessage( "", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment"); diff --git a/thirdparty/openxr/src/loader/manifest_file.hpp b/thirdparty/openxr/src/loader/manifest_file.hpp index 46b842c663..52fe3134b0 100644 --- a/thirdparty/openxr/src/loader/manifest_file.hpp +++ b/thirdparty/openxr/src/loader/manifest_file.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017 Valve Corporation // Copyright (c) 2017 LunarG, Inc. // diff --git a/thirdparty/openxr/src/loader/runtime_interface.cpp b/thirdparty/openxr/src/loader/runtime_interface.cpp index 8312b15ba4..7812aca987 100644 --- a/thirdparty/openxr/src/loader/runtime_interface.cpp +++ b/thirdparty/openxr/src/loader/runtime_interface.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // @@ -9,14 +9,15 @@ #include "runtime_interface.hpp" +#include <openxr/openxr.h> +#include <openxr/openxr_loader_negotiation.h> + #include "manifest_file.hpp" -#include "loader_interfaces.h" +#include "loader_init_data.hpp" #include "loader_logger.hpp" #include "loader_platform.hpp" #include "xr_generated_dispatch_table_core.h" -#include <openxr/openxr.h> - #include <cstring> #include <memory> #include <mutex> @@ -26,8 +27,6 @@ #include <vector> #ifdef XR_USE_PLATFORM_ANDROID -#include "android_utilities.h" -#include <android/asset_manager_jni.h> #include <json/value.h> // Needed for the loader init struct @@ -35,112 +34,6 @@ #include <openxr/openxr_platform.h> #endif // XR_USE_PLATFORM_ANDROID -#ifdef XR_KHR_LOADER_INIT_SUPPORT -namespace { -/*! - * Stores a copy of the data passed to the xrInitializeLoaderKHR function in a singleton. - */ -class LoaderInitData { - public: - /*! - * Singleton accessor. - */ - static LoaderInitData& instance() { - static LoaderInitData obj; - return obj; - } - -#ifdef XR_USE_PLATFORM_ANDROID - /*! - * Type alias for the platform-specific structure type. - */ - using StructType = XrLoaderInitInfoAndroidKHR; - /*! - * Native library path. - */ - std::string _native_library_path; - /*! - * Android asset manager. - */ - AAssetManager* _android_asset_manager; -#endif - - /*! - * Get our copy of the data, casted to pass to the runtime's matching method. - */ - const XrLoaderInitInfoBaseHeaderKHR* getParam() const { return reinterpret_cast<const XrLoaderInitInfoBaseHeaderKHR*>(&_data); } - - /*! - * Get the data via its real structure type. - */ - const StructType& getData() const { return _data; } - - /*! - * Has this been correctly initialized? - */ - bool initialized() const noexcept { return _initialized; } - - /*! - * Initialize loader data - called by InitializeLoader() and thus ultimately by the loader's xrInitializeLoaderKHR - * implementation. Each platform that needs this extension will provide an implementation of this. - */ - XrResult initialize(const XrLoaderInitInfoBaseHeaderKHR* info); - - private: - //! Private constructor, forces use of singleton accessor. - LoaderInitData() = default; - //! Platform-specific init data - StructType _data = {}; - //! Flag for indicating whether _data is valid. - bool _initialized = false; -}; - -#ifdef XR_USE_PLATFORM_ANDROID -// Check and copy the Android-specific init data. -XrResult LoaderInitData::initialize(const XrLoaderInitInfoBaseHeaderKHR* info) { - if (info->type != XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) { - return XR_ERROR_VALIDATION_FAILURE; - } - auto cast_info = reinterpret_cast<XrLoaderInitInfoAndroidKHR const*>(info); - - if (cast_info->applicationVM == nullptr) { - return XR_ERROR_VALIDATION_FAILURE; - } - if (cast_info->applicationContext == nullptr) { - return XR_ERROR_VALIDATION_FAILURE; - } - - // Copy and store the JVM pointer and Android Context, ensuring the JVM is initialised. - _data = *cast_info; - _data.next = nullptr; - jni::init(static_cast<jni::JavaVM*>(_data.applicationVM)); - const jni::Object context = jni::Object{static_cast<jni::jobject>(_data.applicationContext)}; - - // Retrieve a reference to the Android AssetManager. - const auto assetManager = context.call<jni::Object>("getAssets()Landroid/content/res/AssetManager;"); - _android_asset_manager = AAssetManager_fromJava(jni::env(), assetManager.getHandle()); - - // Retrieve the path to the native libraries. - const auto applicationContext = context.call<jni::Object>("getApplicationContext()Landroid/content/Context;"); - const auto applicationInfo = context.call<jni::Object>("getApplicationInfo()Landroid/content/pm/ApplicationInfo;"); - _native_library_path = applicationInfo.get<std::string>("nativeLibraryDir"); - - _initialized = true; - return XR_SUCCESS; -} -#endif // XR_USE_PLATFORM_ANDROID -} // namespace - -XrResult InitializeLoader(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo) { - return LoaderInitData::instance().initialize(loaderInitInfo); -} - -std::string GetAndroidNativeLibraryDir() { return LoaderInitData::instance()._native_library_path; } - -void* Android_Get_Asset_Manager() { return LoaderInitData::instance()._android_asset_manager; } - -#endif // XR_KHR_LOADER_INIT_SUPPORT - #ifdef XR_USE_PLATFORM_ANDROID XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest) { using wrap::android::content::Context; diff --git a/thirdparty/openxr/src/loader/runtime_interface.hpp b/thirdparty/openxr/src/loader/runtime_interface.hpp index 8d55ec674a..093f8ba767 100644 --- a/thirdparty/openxr/src/loader/runtime_interface.hpp +++ b/thirdparty/openxr/src/loader/runtime_interface.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // @@ -19,22 +19,10 @@ #include <mutex> #include <memory> -#ifdef XR_USE_PLATFORM_ANDROID -#define XR_KHR_LOADER_INIT_SUPPORT -#endif - namespace Json { class Value; } -#ifdef XR_KHR_LOADER_INIT_SUPPORT -//! Initialize loader, where required. -XrResult InitializeLoader(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); -XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest); -std::string GetAndroidNativeLibraryDir(); -void* Android_Get_Asset_Manager(); -#endif - class RuntimeManifestFile; struct XrGeneratedDispatchTable; diff --git a/thirdparty/openxr/src/loader/xr_generated_loader.cpp b/thirdparty/openxr/src/loader/xr_generated_loader.cpp index 8c79afddc5..7bddbdc3ea 100644 --- a/thirdparty/openxr/src/loader/xr_generated_loader.cpp +++ b/thirdparty/openxr/src/loader/xr_generated_loader.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // SPDX-License-Identifier: Apache-2.0 OR MIT @@ -6,7 +6,7 @@ // See loader_source_generator.py for modifications // ************************************************************ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // diff --git a/thirdparty/openxr/src/loader/xr_generated_loader.hpp b/thirdparty/openxr/src/loader/xr_generated_loader.hpp index e28e35bbcf..68a6b9470d 100644 --- a/thirdparty/openxr/src/loader/xr_generated_loader.hpp +++ b/thirdparty/openxr/src/loader/xr_generated_loader.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // SPDX-License-Identifier: Apache-2.0 OR MIT @@ -6,7 +6,7 @@ // See loader_source_generator.py for modifications // ************************************************************ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // @@ -34,10 +34,9 @@ #include "xr_dependencies.h" #include "openxr/openxr.h" +#include "openxr/openxr_loader_negotiation.h" #include "openxr/openxr_platform.h" -#include "loader_interfaces.h" - #include "loader_instance.hpp" #include "loader_platform.hpp" diff --git a/thirdparty/openxr/src/xr_generated_dispatch_table_core.c b/thirdparty/openxr/src/xr_generated_dispatch_table_core.c index de88ef7e6c..e73e8b2b95 100644 --- a/thirdparty/openxr/src/xr_generated_dispatch_table_core.c +++ b/thirdparty/openxr/src/xr_generated_dispatch_table_core.c @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019, Valve Corporation // Copyright (c) 2017-2019, LunarG, Inc. @@ -8,7 +8,7 @@ // See utility_source_generator.py for modifications // ************************************************************ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // diff --git a/thirdparty/openxr/src/xr_generated_dispatch_table_core.h b/thirdparty/openxr/src/xr_generated_dispatch_table_core.h index 0f3e7e0502..5871231267 100644 --- a/thirdparty/openxr/src/xr_generated_dispatch_table_core.h +++ b/thirdparty/openxr/src/xr_generated_dispatch_table_core.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019, Valve Corporation // Copyright (c) 2017-2019, LunarG, Inc. @@ -8,7 +8,7 @@ // See utility_source_generator.py for modifications // ************************************************************ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017-2024, The Khronos Group Inc. // Copyright (c) 2017-2019 Valve Corporation // Copyright (c) 2017-2019 LunarG, Inc. // diff --git a/thirdparty/thorvg/AUTHORS b/thirdparty/thorvg/AUTHORS index 3a459e9bb4..d5d5e9be97 100644 --- a/thirdparty/thorvg/AUTHORS +++ b/thirdparty/thorvg/AUTHORS @@ -23,3 +23,5 @@ Rafał Mikrut <mikrutrafal@protonmail.com> Martin Capitanio <capnm@capitanio.org> RuiwenTang <tangruiwen1989@gmail.com> YouJin Lee <ol-of@naver.com> +SergeyLebedkin <sergii@lottiefiles.com> +Jinny You <jinny@lottiefiles.com> diff --git a/thirdparty/thorvg/LICENSE b/thirdparty/thorvg/LICENSE index d056ff6cbf..f97be65005 100644 --- a/thirdparty/thorvg/LICENSE +++ b/thirdparty/thorvg/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2020 - 2023 notice for the ThorVG Project (see AUTHORS) +Copyright (c) 2020 - 2024 notice for the ThorVG Project (see AUTHORS) 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: diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h index 818739b113..d1abc5a290 100644 --- a/thirdparty/thorvg/inc/config.h +++ b/thirdparty/thorvg/inc/config.h @@ -9,5 +9,5 @@ // For internal debugging: //#define THORVG_LOG_ENABLED -#define THORVG_VERSION_STRING "0.11.2" +#define THORVG_VERSION_STRING "0.12.0" #endif diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h index 1b9c2d70d3..6aee53f7e0 100644 --- a/thirdparty/thorvg/inc/thorvg.h +++ b/thirdparty/thorvg/inc/thorvg.h @@ -1,17 +1,3 @@ -/*! - * @file thorvg.h - * - * The main APIs enabling the TVG initialization, preparation of the canvas and provisioning of its content: - * - drawing shapes: line, arc, curve, path, polygon... - * - drawing pictures: tvg, svg, png, jpg, bitmap... - * - drawing fillings: solid, linear and radial gradient... - * - drawing stroking: continuous stroking with arbitrary width, join, cap, dash styles. - * - drawing composition: blending, masking, path clipping... - * - drawing scene graph & affine transformation (translation, rotation, scale, ...) - * and finally drawing the canvas and TVG termination. - */ - - #ifndef _THORVG_H_ #define _THORVG_H_ @@ -172,10 +158,10 @@ enum class CompositeMethod InvAlphaMask, ///< Alpha Masking using the complement to the compositing target's pixels as an alpha value. LumaMask, ///< Alpha Masking using the grayscale (0.2125R + 0.7154G + 0.0721*B) of the compositing target's pixels. @since 0.9 InvLumaMask, ///< Alpha Masking using the grayscale (0.2125R + 0.7154G + 0.0721*B) of the complement to the compositing target's pixels. - AddMask, ///< Combines the target and source objects pixels using target alpha. (T * TA) + (S * (255 - TA)) @BETA_API - SubtractMask, ///< Subtracts the source color from the target color while considering their respective target alpha. (T * TA) - (S * (255 - TA)) @BETA_API - IntersectMask, ///< Computes the result by taking the minimum value between the target alpha and the source alpha and multiplies it with the target color. (T * min(TA, SA)) @BETA_API - DifferenceMask ///< Calculates the absolute difference between the target color and the source color multiplied by the complement of the target alpha. abs(T - S * (255 - TA)) @BETA_API + AddMask, ///< Combines the target and source objects pixels using target alpha. (T * TA) + (S * (255 - TA)) (Experimental API) + SubtractMask, ///< Subtracts the source color from the target color while considering their respective target alpha. (T * TA) - (S * (255 - TA)) (Experimental API) + IntersectMask, ///< Computes the result by taking the minimum value between the target alpha and the source alpha and multiplies it with the target color. (T * min(TA, SA)) (Experimental API) + DifferenceMask ///< Calculates the absolute difference between the target color and the source color multiplied by the complement of the target alpha. abs(T - S * (255 - TA)) (Experimental API) }; @@ -186,7 +172,7 @@ enum class CompositeMethod * * @see Paint::blend() * - * @BETA_API + * @note Experimental API */ enum class BlendMethod : uint8_t { @@ -213,7 +199,8 @@ enum class BlendMethod : uint8_t enum class CanvasEngine { Sw = (1 << 1), ///< CPU rasterizer. - Gl = (1 << 2) ///< OpenGL rasterizer. + Gl = (1 << 2), ///< OpenGL rasterizer. + Wg = (1 << 3), ///< WebGPU rasterizer. (Experimental API) }; @@ -247,7 +234,7 @@ struct Matrix * @param pt The vertex coordinate * @param uv The normalized texture coordinate in the range (0.0..1.0, 0.0..1.0) * - * @BETA_API + * @note Experimental API */ struct Vertex { @@ -261,7 +248,7 @@ struct Vertex * * @param vertex The three vertices that make up the polygon * - * @BETA_API + * @note Experimental API */ struct Polygon { @@ -291,7 +278,7 @@ public: * * @param[in] degree The value of the angle in degrees. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result rotate(float degree) noexcept; @@ -300,7 +287,7 @@ public: * * @param[in] factor The value of the scaling factor. The default value is 1. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result scale(float factor) noexcept; @@ -313,7 +300,7 @@ public: * @param[in] x The value of the horizontal shift. * @param[in] y The value of the vertical shift. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result translate(float x, float y) noexcept; @@ -324,7 +311,7 @@ public: * * @param[in] m The 3x3 augmented matrix. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result transform(const Matrix& m) noexcept; @@ -345,7 +332,7 @@ public: * * @param[in] o The opacity value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note Setting the opacity with this API may require multiple render pass for composition. It is recommended to avoid changing the opacity if possible. * @note ClipPath won't use the opacity value. (see: enum class CompositeMethod::ClipPath) @@ -358,7 +345,7 @@ public: * @param[in] target The paint of the target object. * @param[in] method The method used to composite the source object with the target. * - * @return Result::Success when succeed, Result::InvalidArguments otherwise. + * @retval Result::Success when succeed, Result::InvalidArguments otherwise. */ Result composite(std::unique_ptr<Paint> target, CompositeMethod method) noexcept; @@ -371,9 +358,9 @@ public: * * @param[in] method The blending method to be set. * - * @return Result::Success when the blending method is successfully set. + * @retval Result::Success when the blending method is successfully set. * - * @BETA_API + * @note Experimental API */ Result blend(BlendMethod method) const noexcept; @@ -404,7 +391,7 @@ public: * @param[out] h The height of the object. * @param[in] transformed If @c true, the paint's transformations are taken into account, otherwise they aren't. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. * * @note The bounding box doesn't indicate the actual drawing region. It's the smallest rectangle that encloses the object. */ @@ -442,7 +429,7 @@ public: * * @return The blending method * - * @BETA_API + * @note Experimental API */ BlendMethod blend() const noexcept; @@ -493,7 +480,7 @@ public: * @param[in] colorStops An array of ColorStop data structure. * @param[in] cnt The count of the @p colorStops array equal to the colors number used in the gradient. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept; @@ -502,7 +489,7 @@ public: * * @param[in] s The FillSpread value. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result spread(FillSpread s) noexcept; @@ -513,7 +500,7 @@ public: * * @param[in] m The 3x3 augmented matrix. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result transform(const Matrix& m) noexcept; @@ -538,7 +525,7 @@ public: * * In case no transformation was applied, the identity matrix is returned. * - * @retval The augmented transformation matrix. + * @return The augmented transformation matrix. */ Matrix transform() const noexcept; @@ -600,7 +587,7 @@ public: * @warning Please avoid accessing the paints during Canvas update/draw. You can access them after calling sync(). * @see Canvas::sync() * - * @BETA_API + * @note Experimental API */ std::list<Paint*>& paints() noexcept; @@ -631,7 +618,7 @@ public: * * @param[in] free If @c true, the memory occupied by paints is deallocated, otherwise it is not. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. * * @see Canvas::push() * @see Canvas::paints() @@ -646,7 +633,7 @@ public: * * @param[in] paint A pointer to the Paint object or @c nullptr. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. * * @note The Update behavior can be asynchronous if the assigned thread number is greater than zero. */ @@ -655,7 +642,7 @@ public: /** * @brief Requests the canvas to draw the Paint objects. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. * * @note Drawing can be asynchronous if the assigned thread number is greater than zero. To guarantee the drawing is done, call sync() afterwards. * @see Canvas::sync() @@ -668,7 +655,7 @@ public: * The Canvas rendering can be performed asynchronously. To make sure that rendering is finished, * the sync() must be called after the draw() regardless of threading. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. * @see Canvas::draw() */ virtual Result sync() noexcept; @@ -702,7 +689,7 @@ public: * @param[in] x2 The horizontal coordinate of the second point used to determine the gradient bounds. * @param[in] y2 The vertical coordinate of the second point used to determine the gradient bounds. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note In case the first and the second points are equal, an object filled with such a gradient fill is not rendered. */ @@ -720,7 +707,7 @@ public: * @param[out] x2 The horizontal coordinate of the second point used to determine the gradient bounds. * @param[out] y2 The vertical coordinate of the second point used to determine the gradient bounds. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result linear(float* x1, float* y1, float* x2, float* y2) const noexcept; @@ -764,7 +751,7 @@ public: * @param[in] cy The vertical coordinate of the center of the bounding circle. * @param[in] radius The radius of the bounding circle. * - * @return Result::Success when succeed, Result::InvalidArguments in case the @p radius value is zero or less. + * @retval Result::Success when succeed, Result::InvalidArguments in case the @p radius value is zero or less. */ Result radial(float cx, float cy, float radius) noexcept; @@ -777,7 +764,7 @@ public: * @param[out] cy The vertical coordinate of the center of the bounding circle. * @param[out] radius The radius of the bounding circle. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result radial(float* cx, float* cy, float* radius) const noexcept; @@ -823,7 +810,7 @@ public: * * The transformation matrix, the color, the fill and the stroke properties are retained. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note The memory, where the path data is stored, is not deallocated at this stage for caching effect. */ @@ -837,7 +824,7 @@ public: * @param[in] x The horizontal coordinate of the initial point of the sub-path. * @param[in] y The vertical coordinate of the initial point of the sub-path. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result moveTo(float x, float y) noexcept; @@ -849,7 +836,7 @@ public: * @param[in] x The horizontal coordinate of the end-point of the line. * @param[in] y The vertical coordinate of the end-point of the line. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note In case this is the first command in the path, it corresponds to the moveTo() call. */ @@ -868,7 +855,7 @@ public: * @param[in] x The horizontal coordinate of the end-point of the curve. * @param[in] y The vertical coordinate of the end-point of the curve. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note In case this is the first command in the path, no data from the path are rendered. */ @@ -879,7 +866,7 @@ public: * * The value of the current point is set to the initial point of the closed sub-path. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note In case the sub-path does not contain any points, this function has no effect. */ @@ -905,7 +892,7 @@ public: * @param[in] rx The x-axis radius of the ellipse defining the rounded corners of the rectangle. * @param[in] ry The y-axis radius of the ellipse defining the rounded corners of the rectangle. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note For @p rx and @p ry greater than or equal to the half of @p w and the half of @p h, respectively, the shape become an ellipse. */ @@ -925,7 +912,7 @@ public: * @param[in] rx The x-axis radius of the ellipse. * @param[in] ry The y-axis radius of the ellipse. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result appendCircle(float cx, float cy, float rx, float ry) noexcept; @@ -942,7 +929,7 @@ public: * @param[in] sweep The central angle of the arc given in degrees, measured counter-clockwise from @p startAngle. * @param[in] pie Specifies whether to draw radii from the arc's center to both of its end-point - drawn if @c true. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note Setting @p sweep value greater than 360 degrees, is equivalent to calling appendCircle(cx, cy, radius, radius). */ @@ -960,7 +947,7 @@ public: * @param[in] pts The array of the two-dimensional points. * @param[in] ptsCnt The number of the points in the @p pts array. * - * @return Result::Success when succeed, Result::InvalidArguments otherwise. + * @retval Result::Success when succeed, Result::InvalidArguments otherwise. * * @note The interface is designed for optimal path setting if the caller has a completed path commands already. */ @@ -971,7 +958,7 @@ public: * * @param[in] width The width of the stroke. The default value is 0. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result stroke(float width) noexcept; @@ -983,7 +970,7 @@ public: * @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0. * @param[in] a The alpha channel value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque. The default value is 0. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255) noexcept; @@ -1018,7 +1005,7 @@ public: * * @param[in] cap The cap style value. The default value is @c StrokeCap::Square. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result stroke(StrokeCap cap) noexcept; @@ -1029,7 +1016,7 @@ public: * * @param[in] join The join style value. The default value is @c StrokeJoin::Bevel. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result stroke(StrokeJoin join) noexcept; @@ -1039,7 +1026,7 @@ public: * * @param[in] miterlimit The miterlimit imposes a limit on the extent of the stroke join, when the @c StrokeJoin::Miter join style is set. The default value is 4. * - * @return Result::Success when succeed, Result::NonSupport unsupported value, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::NonSupport unsupported value, Result::FailedAllocation otherwise. * * @since 0.11 */ @@ -1055,7 +1042,7 @@ public: * @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0. * @param[in] a The alpha channel value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque. The default value is 0. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note Either a solid color or a gradient fill is applied, depending on what was set as last. * @note ClipPath won't use the fill values. (see: enum class CompositeMethod::ClipPath) @@ -1069,7 +1056,7 @@ public: * * @param[in] f The unique pointer to the gradient fill. * - * @return Result::Success when succeed, Result::MemoryCorruption otherwise. + * @retval Result::Success when succeed, Result::MemoryCorruption otherwise. * * @note Either a solid color or a gradient fill is applied, depending on what was set as last. */ @@ -1080,7 +1067,7 @@ public: * * @param[in] r The fill rule value. The default value is @c FillRule::Winding. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result fill(FillRule r) noexcept; @@ -1090,7 +1077,7 @@ public: * * @param[in] strokeFirst If @c true the stroke is rendered before the fill, otherwise the stroke is rendered as the second one (the default option). * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. * * @since 0.10 */ @@ -1156,7 +1143,7 @@ public: * @param[out] b The blue color channel value in the range [0 ~ 255]. * @param[out] a The alpha channel value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. */ Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a = nullptr) const noexcept; @@ -1295,7 +1282,7 @@ public: * @param[in] w A new width of the image in pixels. * @param[in] h A new height of the image in pixels. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. */ Result size(float w, float h) noexcept; @@ -1305,13 +1292,20 @@ public: * @param[out] w The width of the image in pixels. * @param[out] h The height of the image in pixels. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result size(float* w, float* h) const noexcept; /** * @brief Loads a raw data from a memory block with a given size. * + * @param[in] paint A Tvg_Paint pointer to the picture object. + * @param[in] data A pointer to a memory location where the content of the picture raw data is stored. + * @param[in] w The width of the image @p data in pixels. + * @param[in] h The height of the image @p data in pixels. + * @param[in] premultiplied If @c true, the given image data is alpha-premultiplied. + * @param[in] copy If @c true the data are copied into the engine local buffer, otherwise they are not. + * * @retval Result::Success When succeed, Result::InsufficientCondition otherwise. * @retval Result::FailedAllocation An internal error possibly with memory allocation. * @@ -1339,7 +1333,7 @@ public: * @note The Polygons are copied internally, so modifying them after calling Mesh::mesh has no affect. * @warning Please do not use it, this API is not official one. It could be modified in the next version. * - * @BETA_API + * @note Experimental API */ Result mesh(const Polygon* triangles, uint32_t triangleCnt) noexcept; @@ -1348,12 +1342,12 @@ public: * * @param[out] triangles Optional. A pointer to the array of Polygons used by this mesh. * - * @return uint32_t The number of polygons in the array. + * @return The number of polygons in the array. * * @note Modifying the triangles returned by this method will modify them directly within the mesh. * @warning Please do not use it, this API is not official one. It could be modified in the next version. * - * @BETA_API + * @note Experimental API */ uint32_t mesh(const Polygon** triangles) const noexcept; @@ -1402,7 +1396,7 @@ public: * * @param[in] paint A Paint object to be drawn. * - * @return Result::Success when succeed, Result::MemoryCorruption otherwise. + * @retval Result::Success when succeed, Result::MemoryCorruption otherwise. * * @note The rendering order of the paints is the same as the order as they were pushed. Consider sorting the paints before pushing them if you intend to use layering. * @see Scene::paints() @@ -1432,7 +1426,7 @@ public: * @see Scene::push() * @see Scene::clear() * - * @BETA_API + * @note Experimental API */ std::list<Paint*>& paints() noexcept; @@ -1442,7 +1436,7 @@ public: * * @param[in] free If @c true, the memory occupied by paints is deallocated, otherwise it is not. * - * @return Result::Success when succeed + * @retval Result::Success when succeed * * @warning If you don't free the paints they become dangled. They are supposed to be reused, otherwise you are responsible for their lives. Thus please use the @p free argument only when you know how it works, otherwise it's not recommended. * @@ -1471,6 +1465,138 @@ public: /** + * @class Text + * + * @brief A class to represent text objects in a graphical context, allowing for rendering and manipulation of unicode text. + * + * @note Experimental API + */ +class TVG_API Text final : public Paint +{ +public: + ~Text(); + + /** + * @brief Sets the font properties for the text. + * + * This function allows you to define the font characteristics used for text rendering. + * It sets the font name, size and optionally the style. + * + * @param[in] name The name of the font. This should correspond to a font available in the canvas. + * @param[in] size The size of the font in points. This determines how large the text will appear. + * @param[in] style The style of the font. It can be used to set the font to 'italic'. + * If not specified, the default style is used. Only 'italic' style is supported currently. + * + * @retval Result::Success when the font properties are set successfully. + * @retval Result::InsufficientCondition when the specified @p name cannot be found. + * + * @note Experimental API + */ + Result font(const char* name, float size, const char* style = nullptr) noexcept; + + /** + * @brief Assigns the given unicode text to be rendered. + * + * This function sets the unicode string that will be displayed by the rendering system. + * The text is set according to the specified UTF encoding method, which defaults to UTF-8. + * + * @param[in] text The multi-byte text encoded with utf8 string to be rendered. + * + * @retval Result::Success when succeed. + * + * @note Experimental API + */ + Result text(const char* text) noexcept; + + /** + * @brief Sets the text color. + * + * @param[in] r The red color channel value in the range [0 ~ 255]. The default value is 0. + * @param[in] g The green color channel value in the range [0 ~ 255]. The default value is 0. + * @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0. + * + * @retval Result::Success when succeed. + * @retval Result::InsufficientCondition when the font has not been set up prior to this operation. + * + * @see Text::font() + * + * @note Experimental API + */ + Result fill(uint8_t r, uint8_t g, uint8_t b) noexcept; + + /** + * @brief Sets the gradient fill for all of the figures from the text. + * + * The parts of the text defined as inner are filled. + * + * @param[in] f The unique pointer to the gradient fill. + * + * @retval Result::Success when succeed, Result::MemoryCorruption otherwise. + * @retval Result::InsufficientCondition when the font has not been set up prior to this operation. + * + * @note Either a solid color or a gradient fill is applied, depending on what was set as last. + * @note Experimental API + * + * @see Text::font() + */ + Result fill(std::unique_ptr<Fill> f) noexcept; + + /** + * @brief Loads a scalable font data(ttf) from a file. + * + * @param[in] path The path to the font file. + * + * @retval Result::Success When succeed. + * @retval Result::InvalidArguments In case the @p path is invalid. + * @retval Result::NonSupport When trying to load a file with an unknown extension. + * @retval Result::Unknown If an error occurs at a later stage. + * + * @note Experimental API + * + * @see Text::unload(const std::string& path) + */ + static Result load(const std::string& path) noexcept; + + /** + * @brief Unloads the specified scalable font data (TTF) that was previously loaded. + * + * This function is used to release resources associated with a font file that has been loaded into memory. + * + * @param[in] path The file path of the loaded font. + * + * @retval Result::Success Successfully unloads the font data. + * @retval Result::InsufficientCondition Fails if the loader is not initialized. + * + * @note If the font data is currently in use, it will not be immediately unloaded. + * @note Experimental API + * + * @see Text::load(const std::string& path) + */ + static Result unload(const std::string& path) noexcept; + + /** + * @brief Creates a new Text object. + * + * @return A new Text object. + * + * @note Experimental API + */ + static std::unique_ptr<Text> gen() noexcept; + + /** + * @brief Return the unique id value of this class. + * + * This method can be referred for identifying the Text class type. + * + * @return The type id of the Text class. + */ + static uint32_t identifier() noexcept; + + _TVG_DECLARE_PRIVATE(Text); +}; + + +/** * @class SwCanvas * * @brief A class for the rendering graphical elements with a software raster engine. @@ -1487,8 +1613,8 @@ public: { ABGR8888 = 0, ///< The channels are joined in the order: alpha, blue, green, red. Colors are alpha-premultiplied. (a << 24 | b << 16 | g << 8 | r) ARGB8888, ///< The channels are joined in the order: alpha, red, green, blue. Colors are alpha-premultiplied. (a << 24 | r << 16 | g << 8 | b) - ABGR8888S, ///< @BETA_API The channels are joined in the order: alpha, blue, green, red. Colors are un-alpha-premultiplied. - ARGB8888S, ///< @BETA_API The channels are joined in the order: alpha, red, green, blue. Colors are un-alpha-premultiplied. + ABGR8888S, ///< The channels are joined in the order: alpha, blue, green, red. Colors are un-alpha-premultiplied. @since 0.12 + ARGB8888S, ///< The channels are joined in the order: alpha, red, green, blue. Colors are un-alpha-premultiplied. @since 0.12 }; /** @@ -1564,7 +1690,7 @@ public: * * @warning Please do not use it. This class is not fully supported yet. * - * @BETA_API + * @note Experimental API */ class TVG_API GlCanvas final : public Canvas { @@ -1576,7 +1702,7 @@ public: * * @warning Please do not use it, this API is not official one. It could be modified in the next version. * - * @BETA_API + * @note Experimental API */ Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; @@ -1585,7 +1711,7 @@ public: * * @return A new GlCanvas object. * - * @BETA_API + * @note Experimental API */ static std::unique_ptr<GlCanvas> gen() noexcept; @@ -1594,6 +1720,42 @@ public: /** + * @class WgCanvas + * + * @brief A class for the rendering graphic elements with a WebGPU raster engine. + * + * @warning Please do not use it. This class is not fully supported yet. + * + * @note Experimental API + */ +class TVG_API WgCanvas final : public Canvas +{ +public: + ~WgCanvas(); + + /** + * @brief Sets the target window for the rasterization. + * + * @warning Please do not use it, this API is not official one. It could be modified in the next version. + * + * @note Experimental API + */ + Result target(void* window, uint32_t w, uint32_t h) noexcept; + + /** + * @brief Creates a new WgCanvas object. + * + * @return A new WgCanvas object. + * + * @note Experimental API + */ + static std::unique_ptr<WgCanvas> gen() noexcept; + + _TVG_DECLARE_PRIVATE(WgCanvas); +}; + + +/** * @class Initializer * * @brief A class that enables initialization and termination of the TVG engines. @@ -1650,7 +1812,7 @@ public: * * This class supports the display and control of animation frames. * - * @BETA_API + * @note Experimental API */ class TVG_API Animation @@ -1664,14 +1826,14 @@ public: * @param[in] no The index of the animation frame to be displayed. The index should be less than the totalFrame(). * * @retval Result::Success Successfully set the frame. - * @retval Result::InsufficientCondition No animatable data loaded from the Picture. - * @retval Result::NonSupport The Picture data does not support animations. + * @retval Result::InsufficientCondition if the given @p no is the same as the current frame value. + * @retval Result::NonSupport The current Picture data does not support animations. * * @see totalFrame() * - * @BETA_API + * @note Experimental API */ - Result frame(uint32_t no) noexcept; + Result frame(float no) noexcept; /** * @brief Retrieves a picture instance associated with this animation instance. @@ -1684,7 +1846,7 @@ public: * * @warning The picture instance is owned by Animation. It should not be deleted manually. * - * @BETA_API + * @note Experimental API */ Picture* picture() const noexcept; @@ -1695,12 +1857,12 @@ public: * * @note If the Picture is not properly configured, this function will return 0. * - * @see Animation::frame(uint32_t no) + * @see Animation::frame(float no) * @see Animation::totalFrame() * - * @BETA_API + * @note Experimental API */ - uint32_t curFrame() const noexcept; + float curFrame() const noexcept; /** * @brief Retrieves the total number of frames in the animation. @@ -1710,9 +1872,9 @@ public: * @note Frame numbering starts from 0. * @note If the Picture is not properly configured, this function will return 0. * - * @BETA_API + * @note Experimental API */ - uint32_t totalFrame() const noexcept; + float totalFrame() const noexcept; /** * @brief Retrieves the duration of the animation in seconds. @@ -1721,7 +1883,7 @@ public: * * @note If the Picture is not properly configured, this function will return 0. * - * @BETA_API + * @% Experimental API */ float duration() const noexcept; @@ -1730,7 +1892,7 @@ public: * * @return A new Animation object. * - * @BETA_API + * @note Experimental API */ static std::unique_ptr<Animation> gen() noexcept; @@ -1761,6 +1923,15 @@ public: ~Saver(); /** + * @brief Sets the base background content for the saved image. + * + * @param[in] paint The paint to be drawn as the background image for the saving paint. + * + * @note Experimental API + */ + Result background(std::unique_ptr<Paint> paint) noexcept; + + /** * @brief Exports the given @p paint data to the given @p path * * If the saver module supports any compression mechanism, it will optimize the data size. @@ -1785,6 +1956,31 @@ public: Result save(std::unique_ptr<Paint> paint, const std::string& path, bool compress = true) noexcept; /** + * @brief Export the provided animation data to the specified file path. + * + * This function exports the given animation data to the provided file path. You can also specify the desired frame rate in frames per second (FPS) by providing the fps parameter. + * + * @param[in] animation The animation to be saved, including all associated properties. + * @param[in] path The path to the file where the animation will be saved. + * @param[in] quality The encoded quality level. @c 0 is the minimum, @c 100 is the maximum value(recommended). + * @param[in] fps The desired frames per second (FPS). For example, to encode data at 60 FPS, pass 60. Pass 0 to keep the original frame data. + * + * @retval Result::Success if the export succeeds. + * @retval Result::InsufficientCondition if there are ongoing resource-saving operations. + * @retval Result::NonSupport if an attempt is made to save the file with an unknown extension or in an unsupported format. + * @retval Result::MemoryCorruption in case of an internal error. + * @retval Result::Unknown if attempting to save an empty paint. + * + * @note A higher frames per second (FPS) would result in a larger file size. It is recommended to use the default value. + * @note Saving can be asynchronous if the assigned thread number is greater than zero. To guarantee the saving is done, call sync() afterwards. + * + * @see Saver::sync() + * + * @note Experimental API + */ + Result save(std::unique_ptr<Animation> animation, const std::string& path, uint32_t quality = 100, uint32_t fps = 0) noexcept; + + /** * @brief Guarantees that the saving task is finished. * * The behavior of the Saver works on a sync/async basis, depending on the threading setting of the Initializer. @@ -1857,7 +2053,7 @@ public: * @brief The cast() function is a utility function used to cast a 'Paint' to type 'T'. * @since 0.11 */ -template<typename T> +template<typename T = tvg::Paint> std::unique_ptr<T> cast(Paint* paint) { return std::unique_ptr<T>(static_cast<T*>(paint)); @@ -1868,7 +2064,7 @@ std::unique_ptr<T> cast(Paint* paint) * @brief The cast() function is a utility function used to cast a 'Fill' to type 'T'. * @since 0.11 */ -template<typename T> +template<typename T = tvg::Fill> std::unique_ptr<T> cast(Fill* fill) { return std::unique_ptr<T>(static_cast<T*>(fill)); diff --git a/thirdparty/thorvg/src/common/tvgArray.h b/thirdparty/thorvg/src/common/tvgArray.h index 08eb25329c..acb3a41b97 100644 --- a/thirdparty/thorvg/src/common/tvgArray.h +++ b/thirdparty/thorvg/src/common/tvgArray.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,7 @@ #include <memory.h> #include <cstdint> +#include <cstdlib> namespace tvg { @@ -38,6 +39,11 @@ struct Array Array(){} + Array(int32_t size) + { + reserve(size); + } + Array(const Array& rhs) { reset(); diff --git a/thirdparty/thorvg/src/common/tvgBezier.cpp b/thirdparty/thorvg/src/common/tvgBezier.cpp index f9daf07b84..5fb501721e 100644 --- a/thirdparty/thorvg/src/common/tvgBezier.cpp +++ b/thirdparty/thorvg/src/common/tvgBezier.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/common/tvgBezier.h b/thirdparty/thorvg/src/common/tvgBezier.h index 539a63bdd3..cb2766c505 100644 --- a/thirdparty/thorvg/src/common/tvgBezier.h +++ b/thirdparty/thorvg/src/common/tvgBezier.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/common/tvgCompressor.cpp b/thirdparty/thorvg/src/common/tvgCompressor.cpp index e38940f3d0..778fc4d0a2 100644 --- a/thirdparty/thorvg/src/common/tvgCompressor.cpp +++ b/thirdparty/thorvg/src/common/tvgCompressor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/common/tvgCompressor.h b/thirdparty/thorvg/src/common/tvgCompressor.h index 05d23f4293..0756127ec6 100644 --- a/thirdparty/thorvg/src/common/tvgCompressor.h +++ b/thirdparty/thorvg/src/common/tvgCompressor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/common/tvgInlist.h b/thirdparty/thorvg/src/common/tvgInlist.h new file mode 100644 index 0000000000..ff28cfd48e --- /dev/null +++ b/thirdparty/thorvg/src/common/tvgInlist.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. + + * 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 _TVG_INLIST_H_ +#define _TVG_INLIST_H_ + +namespace tvg { + +//NOTE: declare this in your list item +#define INLIST_ITEM(T) \ + T* prev; \ + T* next + +template<typename T> +struct Inlist +{ + T* head = nullptr; + T* tail = nullptr; + + void free() + { + while (head) { + auto t = head; + head = t->next; + delete(t); + } + head = tail = nullptr; + } + + void back(T* element) + { + if (tail) { + tail->next = element; + element->prev = tail; + element->next = nullptr; + tail = element; + } else { + head = tail = element; + element->prev = nullptr; + element->next = nullptr; + } + } + + void front(T* element) + { + if (head) { + head->prev = element; + element->prev = nullptr; + element->next = head; + head = element; + } else { + head = tail = element; + element->prev = nullptr; + element->next = nullptr; + } + } + + T* back() + { + if (!tail) return nullptr; + auto t = tail; + tail = t->prev; + if (!tail) head = nullptr; + return t; + } + + T* front() + { + if (!head) return nullptr; + auto t = head; + head = t->next; + if (!head) tail = nullptr; + return t; + } + + void remove(T* element) + { + if (element->prev) element->prev->next = element->next; + if (element->next) element->next->prev = element->prev; + if (element == head) head = element->next; + if (element == tail) tail = element->prev; + } + + bool empty() + { + return head ? false : true; + } +}; + +} + +#endif // _TVG_INLIST_H_ diff --git a/thirdparty/thorvg/src/common/tvgList.h b/thirdparty/thorvg/src/common/tvgList.h deleted file mode 100644 index 01e87a840f..0000000000 --- a/thirdparty/thorvg/src/common/tvgList.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2023 the ThorVG project. All rights reserved. - - * 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 _TVG_LIST_H_ -#define _TVG_LIST_H_ - -namespace tvg { - -template<typename T> -struct LinkedList -{ - T *head = nullptr; - T *tail = nullptr; - - LinkedList() = default; - LinkedList(T *head, T *tail) : head(head), tail(tail) - { - } - - template<T *T::*Prev, T *T::*Next> - static void insert(T *t, T *prev, T *next, T **head, T **tail) - { - t->*Prev = prev; - t->*Next = next; - - if (prev) { - prev->*Next = t; - } else if (head) { - *head = t; - } - - if (next) { - next->*Prev = t; - } else if (tail) { - *tail = t; - } - } - - template<T *T::*Prev, T *T::*Next> - static void remove(T *t, T **head, T **tail) - { - if (t->*Prev) { - t->*Prev->*Next = t->*Next; - } else if (head) { - *head = t->*Next; - } - - if (t->*Next) { - t->*Next->*Prev = t->*Prev; - } else if (tail) { - *tail = t->*Prev; - } - - t->*Prev = t->*Next = nullptr; - } - - template <T* T::*Next> - static bool contains(T *t, T **head, T **tail) { - for (T *it = *head; it; it = it->*Next) { - if (it == t) { - return true; - } - } - - return false; - } -}; - -} - -#endif // _TVG_LIST_H_ diff --git a/thirdparty/thorvg/src/common/tvgMath.cpp b/thirdparty/thorvg/src/common/tvgMath.cpp index a9463c8077..42bc2cf4aa 100644 --- a/thirdparty/thorvg/src/common/tvgMath.cpp +++ b/thirdparty/thorvg/src/common/tvgMath.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/common/tvgMath.h b/thirdparty/thorvg/src/common/tvgMath.h index 004fff1e7b..50c3458efc 100644 --- a/thirdparty/thorvg/src/common/tvgMath.h +++ b/thirdparty/thorvg/src/common/tvgMath.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -174,6 +174,18 @@ static inline Point operator*(const Point& lhs, float rhs) } +static inline Point operator*(const float& lhs, const Point& rhs) +{ + return {lhs * rhs.x, lhs * rhs.y}; +} + + +static inline Point operator/(const Point& lhs, const float rhs) +{ + return {lhs.x / rhs, lhs.y / rhs}; +} + + template <typename T> static inline T mathLerp(const T &start, const T &end, float t) { diff --git a/thirdparty/thorvg/src/common/tvgStr.cpp b/thirdparty/thorvg/src/common/tvgStr.cpp index eeed4fc404..311b986511 100644 --- a/thirdparty/thorvg/src/common/tvgStr.cpp +++ b/thirdparty/thorvg/src/common/tvgStr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/common/tvgStr.h b/thirdparty/thorvg/src/common/tvgStr.h index 448cc69336..9e5f9ba9b5 100644 --- a/thirdparty/thorvg/src/common/tvgStr.h +++ b/thirdparty/thorvg/src/common/tvgStr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp index b0a9fdd579..10277f846d 100644 --- a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp +++ b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,19 +20,25 @@ * SOFTWARE. */ -#include "tvgLoader.h" #include "tvgPngLoader.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +void PngLoader::clear() +{ + png_image_free(image); + free(image); + image = nullptr; +} + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -PngLoader::PngLoader() +PngLoader::PngLoader() : ImageLoader(FileType::Png) { image = static_cast<png_imagep>(calloc(1, sizeof(png_image))); image->version = PNG_IMAGE_VERSION; @@ -41,13 +47,11 @@ PngLoader::PngLoader() PngLoader::~PngLoader() { - if (content) { - free((void*)content); - content = nullptr; - } - free(image); + clear(); + free((void*)surface.buf32); } + bool PngLoader::open(const string& path) { image->opaque = NULL; @@ -56,11 +60,11 @@ bool PngLoader::open(const string& path) w = (float)image->width; h = (float)image->height; - cs = ColorSpace::ARGB8888; return true; } + bool PngLoader::open(const char* data, uint32_t size, bool copy) { image->opaque = NULL; @@ -69,7 +73,6 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) w = (float)image->width; h = (float)image->height; - cs = ColorSpace::ARGB8888; return true; } @@ -77,6 +80,10 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) bool PngLoader::read() { + if (!LoadModule::read()) return true; + + if (w == 0 || h == 0) return false; + png_bytep buffer; image->format = PNG_FORMAT_BGRA; buffer = static_cast<png_bytep>(malloc(PNG_IMAGE_SIZE((*image)))); @@ -89,32 +96,17 @@ bool PngLoader::read() free(buffer); return false; } - content = reinterpret_cast<uint32_t*>(buffer); - return true; -} + //setup the surface + surface.buf32 = reinterpret_cast<uint32_t*>(buffer); + surface.stride = (uint32_t)w; + surface.w = (uint32_t)w; + surface.h = (uint32_t)h; + surface.channelSize = sizeof(uint32_t); + surface.cs = ColorSpace::ARGB8888; + surface.premultiplied = false; -bool PngLoader::close() -{ - png_image_free(image); - return true; -} + clear(); -unique_ptr<Surface> PngLoader::bitmap() -{ - if (!content) return nullptr; - - //TODO: It's better to keep this surface instance in the loader side - auto surface = new Surface; - surface->buf32 = content; - surface->stride = w; - surface->w = w; - surface->h = h; - surface->cs = cs; - surface->channelSize = sizeof(uint32_t); - surface->owner = true; - surface->premultiplied = false; - - return unique_ptr<Surface>(surface); + return true; } - diff --git a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h index 5354e1bdd6..c45544eb07 100644 --- a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h +++ b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,24 +24,22 @@ #define _TVG_PNG_LOADER_H_ #include <png.h> +#include "tvgLoader.h" -class PngLoader : public LoadModule +class PngLoader : public ImageLoader { public: PngLoader(); ~PngLoader(); - using LoadModule::open; bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; bool read() override; - bool close() override; - - unique_ptr<Surface> bitmap() override; private: + void clear(); + png_imagep image = nullptr; - uint32_t* content = nullptr; }; #endif //_TVG_PNG_LOADER_H_ diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp index 6edda86cc1..86a46245d9 100644 --- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp +++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,7 +21,6 @@ */ #include <memory.h> -#include "tvgLoader.h" #include "tvgJpgLoader.h" /************************************************************************/ @@ -38,30 +37,45 @@ void JpgLoader::clear() } +void JpgLoader::run(unsigned tid) +{ + surface.buf8 = jpgdDecompress(decoder); + surface.stride = static_cast<uint32_t>(w); + surface.w = static_cast<uint32_t>(w); + surface.h = static_cast<uint32_t>(h); + surface.cs = ColorSpace::ARGB8888; + surface.channelSize = sizeof(uint32_t); + surface.premultiplied = true; + + clear(); +} + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ +JpgLoader::JpgLoader() : ImageLoader(FileType::Jpg) +{ + +} + JpgLoader::~JpgLoader() { - jpgdDelete(decoder); - if (freeData) free(data); - free(image); + clear(); + free(surface.buf8); } bool JpgLoader::open(const string& path) { - clear(); - int width, height; decoder = jpgdHeader(path.c_str(), &width, &height); if (!decoder) return false; w = static_cast<float>(width); h = static_cast<float>(height); - cs = ColorSpace::ARGB8888; return true; } @@ -69,8 +83,6 @@ bool JpgLoader::open(const string& path) bool JpgLoader::open(const char* data, uint32_t size, bool copy) { - clear(); - if (copy) { this->data = (char *) malloc(size); if (!this->data) return false; @@ -87,7 +99,6 @@ bool JpgLoader::open(const char* data, uint32_t size, bool copy) w = static_cast<float>(width); h = static_cast<float>(height); - cs = ColorSpace::ARGB8888; return true; } @@ -96,7 +107,9 @@ bool JpgLoader::open(const char* data, uint32_t size, bool copy) bool JpgLoader::read() { - if (!decoder || w <= 0 || h <= 0) return false; + if (!LoadModule::read()) return true; + + if (!decoder || w == 0 || h == 0) return false; TaskScheduler::request(this); @@ -106,38 +119,14 @@ bool JpgLoader::read() bool JpgLoader::close() { + if (!LoadModule::close()) return false; this->done(); - clear(); return true; } -unique_ptr<Surface> JpgLoader::bitmap() +Surface* JpgLoader::bitmap() { this->done(); - - if (!image) return nullptr; - - //TODO: It's better to keep this surface instance in the loader side - auto surface = new Surface; - surface->buf8 = image; - surface->stride = static_cast<uint32_t>(w); - surface->w = static_cast<uint32_t>(w); - surface->h = static_cast<uint32_t>(h); - surface->cs = cs; - surface->channelSize = sizeof(uint32_t); - surface->premultiplied = true; - surface->owner = true; - - return unique_ptr<Surface>(surface); -} - - -void JpgLoader::run(unsigned tid) -{ - if (image) { - free(image); - image = nullptr; - } - image = jpgdDecompress(decoder); + return ImageLoader::bitmap(); } diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h index 6d2febe94f..05cbb54c85 100644 --- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h +++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,30 +23,30 @@ #ifndef _TVG_JPG_LOADER_H_ #define _TVG_JPG_LOADER_H_ +#include "tvgLoader.h" #include "tvgTaskScheduler.h" #include "tvgJpgd.h" -class JpgLoader : public LoadModule, public Task +class JpgLoader : public ImageLoader, public Task { private: jpeg_decoder* decoder = nullptr; char* data = nullptr; - unsigned char *image = nullptr; bool freeData = false; void clear(); + void run(unsigned tid) override; public: + JpgLoader(); ~JpgLoader(); - using LoadModule::open; bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; bool read() override; bool close() override; - unique_ptr<Surface> bitmap() override; - void run(unsigned tid) override; + Surface* bitmap() override; }; #endif //_TVG_JPG_LOADER_H_ diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp index 61a5dc1c0f..6f2bd916d5 100644 --- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp +++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -1456,7 +1456,11 @@ void jpeg_decoder::locate_sof_marker() int c = process_markers(); switch (c) { - case M_SOF2: m_progressive_flag = true; + case M_SOF2: { + m_progressive_flag = true; + read_sof_marker(); + break; + } case M_SOF0: /* baseline DCT */ case M_SOF1: { /* extended sequential DCT */ read_sof_marker(); diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h index 030fdc2946..e1fe35f488 100644 --- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h +++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp b/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp index fc4cce4061..fb7527f045 100644 --- a/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp +++ b/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/png/tvgLodePng.h b/thirdparty/thorvg/src/loaders/png/tvgLodePng.h index 7254a55477..cd3efacf98 100644 --- a/thirdparty/thorvg/src/loaders/png/tvgLodePng.h +++ b/thirdparty/thorvg/src/loaders/png/tvgLodePng.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp index 32ff57c5c3..111180b657 100644 --- a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp +++ b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,14 +29,22 @@ /* Internal Class Implementation */ /************************************************************************/ -void PngLoader::clear() + +void PngLoader::run(unsigned tid) { - lodepng_state_cleanup(&state); + auto width = static_cast<unsigned>(w); + auto height = static_cast<unsigned>(h); - if (freeData) free(data); - data = nullptr; - size = 0; - freeData = false; + if (lodepng_decode(&surface.buf8, &width, &height, &state, data, size)) { + TVGERR("PNG", "Failed to decode image"); + } + + //setup the surface + surface.stride = width; + surface.w = width; + surface.h = height; + surface.channelSize = sizeof(uint32_t); + surface.premultiplied = false; } @@ -44,7 +52,7 @@ void PngLoader::clear() /* External Class Implementation */ /************************************************************************/ -PngLoader::PngLoader() +PngLoader::PngLoader() : ImageLoader(FileType::Png) { lodepng_state_init(&state); } @@ -53,14 +61,13 @@ PngLoader::PngLoader() PngLoader::~PngLoader() { if (freeData) free(data); - free(image); + free(surface.buf8); + lodepng_state_cleanup(&state); } bool PngLoader::open(const string& path) { - clear(); - auto pngFile = fopen(path.c_str(), "rb"); if (!pngFile) return false; @@ -76,26 +83,23 @@ bool PngLoader::open(const string& path) freeData = true; - if (fread(data, size, 1, pngFile) < 1) goto failure; + if (fread(data, size, 1, pngFile) < 1) goto finalize; lodepng_state_init(&state); unsigned int width, height; - if (lodepng_inspect(&width, &height, &state, data, size) > 0) goto failure; + if (lodepng_inspect(&width, &height, &state, data, size) > 0) goto finalize; w = static_cast<float>(width); h = static_cast<float>(height); - if (state.info_png.color.colortype == LCT_RGBA) cs = ColorSpace::ABGR8888; - else cs = ColorSpace::ARGB8888; + if (state.info_png.color.colortype == LCT_RGBA) surface.cs = ColorSpace::ABGR8888; + else surface.cs = ColorSpace::ARGB8888; ret = true; goto finalize; -failure: - clear(); - finalize: fclose(pngFile); return ret; @@ -104,10 +108,6 @@ finalize: bool PngLoader::open(const char* data, uint32_t size, bool copy) { - clear(); - - lodepng_state_init(&state); - unsigned int width, height; if (lodepng_inspect(&width, &height, &state, (unsigned char*)(data), size) > 0) return false; @@ -125,7 +125,7 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) h = static_cast<float>(height); this->size = size; - cs = ColorSpace::ABGR8888; + surface.cs = ColorSpace::ABGR8888; return true; } @@ -133,53 +133,18 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) bool PngLoader::read() { - if (!data || w <= 0 || h <= 0) return false; - - TaskScheduler::request(this); + if (!data || w == 0 || h == 0) return false; - return true; -} + if (!LoadModule::read()) return true; + TaskScheduler::request(this); -bool PngLoader::close() -{ - this->done(); - clear(); return true; } -unique_ptr<Surface> PngLoader::bitmap() +Surface* PngLoader::bitmap() { this->done(); - - if (!image) return nullptr; - - //TODO: It's better to keep this surface instance in the loader side - auto surface = new Surface; - surface->buf8 = image; - surface->stride = static_cast<uint32_t>(w); - surface->w = static_cast<uint32_t>(w); - surface->h = static_cast<uint32_t>(h); - surface->cs = cs; - surface->channelSize = sizeof(uint32_t); - surface->premultiplied = false; - surface->owner = true; - - return unique_ptr<Surface>(surface); -} - - -void PngLoader::run(unsigned tid) -{ - if (image) { - free(image); - image = nullptr; - } - auto width = static_cast<unsigned>(w); - auto height = static_cast<unsigned>(h); - - if (lodepng_decode(&image, &width, &height, &state, data, size)) { - TVGERR("PNG", "Failed to decode image"); - } + return ImageLoader::bitmap(); } diff --git a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h index 579d197ad6..06fbbf7349 100644 --- a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h +++ b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,29 +27,25 @@ #include "tvgTaskScheduler.h" -class PngLoader : public LoadModule, public Task +class PngLoader : public ImageLoader, public Task { private: LodePNGState state; unsigned char* data = nullptr; - unsigned char *image = nullptr; unsigned long size = 0; bool freeData = false; - void clear(); + void run(unsigned tid) override; public: PngLoader(); ~PngLoader(); - using LoadModule::open; bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; bool read() override; - bool close() override; - unique_ptr<Surface> bitmap() override; - void run(unsigned tid) override; + Surface* bitmap() override; }; #endif //_TVG_PNG_LOADER_H_ diff --git a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp index 5f5e72b0dd..b797f98218 100644 --- a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp +++ b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,17 +34,21 @@ /* External Class Implementation */ /************************************************************************/ +RawLoader::RawLoader() : ImageLoader(FileType::Raw) +{ +} + + RawLoader::~RawLoader() { - if (copy && content) { - free((void*)content); - content = nullptr; - } + if (copy) free(surface.buf32); } bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) { + if (!LoadModule::read()) return true; + if (!data || w == 0 || h == 0) return false; this->w = (float)w; @@ -52,13 +56,19 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) this->copy = copy; if (copy) { - content = (uint32_t*)malloc(sizeof(uint32_t) * w * h); - if (!content) return false; - memcpy((void*)content, data, sizeof(uint32_t) * w * h); + surface.buf32 = (uint32_t*)malloc(sizeof(uint32_t) * w * h); + if (!surface.buf32) return false; + memcpy((void*)surface.buf32, data, sizeof(uint32_t) * w * h); } - else content = const_cast<uint32_t*>(data); + else surface.buf32 = const_cast<uint32_t*>(data); - cs = ColorSpace::ARGB8888; + //setup the surface + surface.stride = w; + surface.w = w; + surface.h = h; + surface.cs = ColorSpace::ARGB8888; + surface.channelSize = sizeof(uint32_t); + surface.premultiplied = true; return true; } @@ -66,30 +76,7 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) bool RawLoader::read() { - return true; -} - + LoadModule::read(); -bool RawLoader::close() -{ return true; } - - -unique_ptr<Surface> RawLoader::bitmap() -{ - if (!content) return nullptr; - - //TODO: It's better to keep this surface instance in the loader side - auto surface = new Surface; - surface->buf32 = content; - surface->stride = static_cast<uint32_t>(w); - surface->w = static_cast<uint32_t>(w); - surface->h = static_cast<uint32_t>(h); - surface->cs = cs; - surface->channelSize = sizeof(uint32_t); - surface->premultiplied = true; - surface->owner = true; - - return unique_ptr<Surface>(surface); -} diff --git a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h index 69f9bdc47a..970cdd9c83 100644 --- a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h +++ b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,20 +23,17 @@ #ifndef _TVG_RAW_LOADER_H_ #define _TVG_RAW_LOADER_H_ -class RawLoader : public LoadModule +class RawLoader : public ImageLoader { public: - uint32_t* content = nullptr; bool copy = false; + RawLoader(); ~RawLoader(); using LoadModule::open; - bool open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) override; + bool open(const uint32_t* data, uint32_t w, uint32_t h, bool copy); bool read() override; - bool close() override; - - unique_ptr<Surface> bitmap() override; }; diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp index c3c477a263..2826dc9134 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2022 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h index 228c5996da..7d8dcfa94a 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2022 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp index be99ec085c..6e52476625 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -3528,6 +3528,10 @@ void SvgLoader::clear(bool all) loaderData.images.reset(); if (copy) free((char*)content); + + delete(root); + root = nullptr; + size = 0; content = nullptr; copy = false; @@ -3538,14 +3542,15 @@ void SvgLoader::clear(bool all) /* External Class Implementation */ /************************************************************************/ -SvgLoader::SvgLoader() +SvgLoader::SvgLoader() : ImageLoader(FileType::Svg) { } SvgLoader::~SvgLoader() { - close(); + this->done(); + clear(); } @@ -3554,7 +3559,7 @@ void SvgLoader::run(unsigned tid) //According to the SVG standard the value of the width/height of the viewbox set to 0 disables rendering if ((viewFlag & SvgViewFlag::Viewbox) && (fabsf(vw) <= FLT_EPSILON || fabsf(vh) <= FLT_EPSILON)) { TVGLOG("SVG", "The <viewBox> width and/or height set to 0 - rendering disabled."); - root = Scene::gen(); + root = Scene::gen().release(); return; } @@ -3727,6 +3732,8 @@ bool SvgLoader::read() { if (!content || size == 0) return false; + if (!LoadModule::read()) return true; + //the loading has been already completed in header() if (root) return true; @@ -3738,16 +3745,17 @@ bool SvgLoader::read() bool SvgLoader::close() { + if (!LoadModule::close()) return false; this->done(); - clear(); - return true; } -unique_ptr<Paint> SvgLoader::paint() +Paint* SvgLoader::paint() { this->done(); - return std::move(root); + auto ret = root; + root = nullptr; + return ret; } diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h index 4bac52e0b9..e0cba8b11e 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,7 @@ #include "tvgTaskScheduler.h" #include "tvgSvgLoaderCommon.h" -class SvgLoader : public LoadModule, public Task +class SvgLoader : public ImageLoader, public Task { public: string filePath; @@ -35,21 +35,20 @@ public: uint32_t size = 0; SvgLoaderData loaderData; - unique_ptr<Scene> root; + Scene* root = nullptr; bool copy = false; SvgLoader(); ~SvgLoader(); - using LoadModule::open; bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; bool resize(Paint* paint, float w, float h) override; bool read() override; bool close() override; - unique_ptr<Paint> paint() override; + Paint* paint() override; private: SvgViewFlag viewFlag = SvgViewFlag::None; diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h index b4ee3e8e0d..d6febd6825 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp index 79a9c0771d..f618a3c827 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -53,6 +53,7 @@ #include <cstring> #include <math.h> #include <ctype.h> +#include "tvgShape.h" #include "tvgSvgLoaderCommon.h" #include "tvgSvgPath.h" #include "tvgStr.h" @@ -534,7 +535,7 @@ static char* _nextCommand(char* path, char* cmd, float* arr, int* count) /************************************************************************/ -bool svgPathToTvgPath(const char* svgPath, Array<PathCommand>& cmds, Array<Point>& pts) +bool svgPathToShape(const char* svgPath, Shape* shape) { float numberArray[7]; int numberCount = 0; @@ -545,11 +546,16 @@ bool svgPathToTvgPath(const char* svgPath, Array<PathCommand>& cmds, Array<Point bool isQuadratic = false; char* path = (char*)svgPath; + auto& pts = P(shape)->rs.path.pts; + auto& cmds = P(shape)->rs.path.cmds; + auto lastCmds = cmds.count; + while ((path[0] != '\0')) { path = _nextCommand(path, &cmd, numberArray, &numberCount); if (!path) break; if (!_processCommand(&cmds, &pts, cmd, numberArray, numberCount, &cur, &curCtl, &startPoint, &isQuadratic)) break; } + if (cmds.count > lastCmds && cmds[lastCmds] != PathCommand::MoveTo) return false; return true; } diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h index 4199088dc1..b8641dd165 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,6 @@ #include <tvgCommon.h> -bool svgPathToTvgPath(const char* svgPath, Array<PathCommand>& cmds, Array<Point>& pts); +bool svgPathToShape(const char* svgPath, Shape* shape); #endif //_TVG_SVG_PATH_H_ diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp index 1791df57f0..674c30f5bd 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -396,10 +396,9 @@ static bool _recognizeShape(SvgNode* node, Shape* shape) switch (node->type) { case SvgNodeType::Path: { if (node->node.path.path) { - Array<PathCommand> cmds; - Array<Point> pts; - if (svgPathToTvgPath(node->node.path.path, cmds, pts)) { - shape->appendPath(cmds.data, cmds.count, pts.data, pts.count); + if (!svgPathToShape(node->node.path.path, shape)) { + TVGERR("SVG", "Invalid path information."); + return false; } } break; @@ -845,7 +844,7 @@ static void _updateInvalidViewSize(const Scene* scene, Box& vBox, float& w, floa /* External Class Implementation */ /************************************************************************/ -unique_ptr<Scene> svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag) +Scene* svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag) { //TODO: aspect ratio is valid only if viewBox was set @@ -863,8 +862,7 @@ unique_ptr<Scene> svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, fl } auto viewBoxClip = Shape::gen(); - viewBoxClip->appendRect(0, 0, w, h, 0, 0); - viewBoxClip->fill(0, 0, 0); + viewBoxClip->appendRect(0, 0, w, h); auto compositeLayer = Scene::gen(); compositeLayer->composite(std::move(viewBoxClip), CompositeMethod::ClipPath); @@ -880,5 +878,5 @@ unique_ptr<Scene> svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, fl loaderData.doc->node.doc.w = w; loaderData.doc->node.doc.h = h; - return root; + return root.release(); } diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h index f6a60f850d..0663a37f05 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,6 @@ #include "tvgCommon.h" -unique_ptr<Scene> svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag); +Scene* svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag); #endif //_TVG_SVG_SCENE_BUILDER_H_ diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp index 7940188ade..32affd04c6 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h index ee0e3f8861..220a4b3e55 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp index dbc3b17b70..aec30d2384 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h index 7333bb09fb..30ca23b565 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h index c6dcf79a48..3d73075a4a 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -43,11 +43,16 @@ static double timeStamp() #define SW_ANGLE_PI (180L << 16) #define SW_ANGLE_2PI (SW_ANGLE_PI << 1) #define SW_ANGLE_PI2 (SW_ANGLE_PI >> 1) -#define SW_ANGLE_PI4 (SW_ANGLE_PI >> 2) using SwCoord = signed long; using SwFixed = signed long long; + +static inline float TO_FLOAT(SwCoord val) +{ + return static_cast<float>(val) / 64.0f; +} + struct SwPoint { SwCoord x, y; @@ -92,6 +97,10 @@ struct SwPoint else return false; } + Point toPoint() const + { + return {TO_FLOAT(x), TO_FLOAT(y)}; + } }; struct SwSize @@ -252,13 +261,26 @@ struct SwSurface : Surface SwAlpha alphas[4]; //Alpha:2, InvAlpha:3, Luma:4, InvLuma:5 SwBlender blender = nullptr; //blender (optional) SwCompositor* compositor = nullptr; //compositor (optional) - BlendMethod blendMethod; //blending method (uint8_t) + BlendMethod blendMethod; //blending method (uint8_t) SwAlpha alpha(CompositeMethod method) { auto idx = (int)(method) - 2; //0: None, 1: ClipPath return alphas[idx > 3 ? 0 : idx]; //CompositeMethod has only four Matting methods. } + + SwSurface() + { + } + + SwSurface(const SwSurface* rhs) : Surface(rhs) + { + join = rhs->join; + memcpy(alphas, rhs->alphas, sizeof(alphas)); + blender = rhs->blender; + compositor = rhs->compositor; + blendMethod = rhs->blendMethod; + } }; struct SwCompositor : Compositor diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp index cede9e6eb7..8956cd9f24 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -167,7 +167,6 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr fill->linear.dy = dx * invTransform.e12 + fill->linear.dy * invTransform.e22; fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy; - if (fill->linear.len < FLT_EPSILON) return true; } return true; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp index b1624037bc..c162945501 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp index dbcfa754f3..42e405195e 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,7 +20,7 @@ * SOFTWARE. */ -#include <math.h> +#include "tvgMath.h" #include "tvgSwCommon.h" @@ -28,173 +28,9 @@ /* Internal Class Implementation */ /************************************************************************/ -//clz: count leading zero’s -#if defined(_MSC_VER) && !defined(__clang__) - #include <intrin.h> - static uint32_t __inline _clz(uint32_t value) - { - unsigned long leadingZero = 0; - if (_BitScanReverse(&leadingZero, value)) return 31 - leadingZero; - else return 32; - } -#else - #define _clz(x) __builtin_clz((x)) -#endif - - -constexpr SwFixed CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32 - -//this table was generated for SW_FT_PI = 180L << 16, i.e. degrees -constexpr static auto ATAN_MAX = 23; -constexpr static SwFixed ATAN_TBL[] = { - 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, - 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, - 57L, 29L, 14L, 7L, 4L, 2L, 1L}; - -static inline SwCoord SATURATE(const SwCoord x) -{ - return (x >> (sizeof(SwCoord) * 8 - 1)); -} - - -static inline SwFixed PAD_ROUND(const SwFixed x, int32_t n) -{ - return (((x) + ((n)/2)) & ~((n)-1)); -} - - -static SwCoord _downscale(SwFixed x) +static float TO_RADIAN(SwFixed angle) { - //multiply a give value by the CORDIC shrink factor - auto s = abs(x); - int64_t t = (s * static_cast<int64_t>(CORDIC_FACTOR)) + 0x100000000UL; - s = static_cast<SwFixed>(t >> 32); - if (x < 0) s = -s; - return s; -} - - -static int32_t _normalize(SwPoint& pt) -{ - /* the highest bit in overflow-safe vector components - MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */ - constexpr auto SAFE_MSB = 29; - - auto v = pt; - - //High order bit(MSB) - int32_t shift = 31 - _clz(abs(v.x) | abs(v.y)); - - if (shift <= SAFE_MSB) { - shift = SAFE_MSB - shift; - pt.x = static_cast<SwCoord>((unsigned long)v.x << shift); - pt.y = static_cast<SwCoord>((unsigned long)v.y << shift); - } else { - shift -= SAFE_MSB; - pt.x = v.x >> shift; - pt.y = v.y >> shift; - shift = -shift; - } - return shift; -} - - -static void _polarize(SwPoint& pt) -{ - auto v = pt; - SwFixed theta; - - //Get the vector into [-PI/4, PI/4] sector - if (v.y > v.x) { - if (v.y > -v.x) { - auto tmp = v.y; - v.y = -v.x; - v.x = tmp; - theta = SW_ANGLE_PI2; - } else { - theta = v.y > 0 ? SW_ANGLE_PI : -SW_ANGLE_PI; - v.x = -v.x; - v.y = -v.y; - } - } else { - if (v.y < -v.x) { - theta = -SW_ANGLE_PI2; - auto tmp = -v.y; - v.y = v.x; - v.x = tmp; - } else { - theta = 0; - } - } - - auto atan = ATAN_TBL; - uint32_t i; - SwFixed j; - - //Pseudorotations. with right shifts - for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) { - if (v.y > 0) { - auto tmp = v.x + ((v.y + j) >> i); - v.y = v.y - ((v.x + j) >> i); - v.x = tmp; - theta += *atan++; - } else { - auto tmp = v.x - ((v.y + j) >> i); - v.y = v.y + ((v.x + j) >> i); - v.x = tmp; - theta -= *atan++; - } - } - - //round theta - if (theta >= 0) theta = PAD_ROUND(theta, 32); - else theta = -PAD_ROUND(-theta, 32); - - pt.x = v.x; - pt.y = theta; -} - - -static void _rotate(SwPoint& pt, SwFixed theta) -{ - SwFixed x = pt.x; - SwFixed y = pt.y; - - //Rotate inside [-PI/4, PI/4] sector - while (theta < -SW_ANGLE_PI4) { - auto tmp = y; - y = -x; - x = tmp; - theta += SW_ANGLE_PI2; - } - - while (theta > SW_ANGLE_PI4) { - auto tmp = -y; - y = x; - x = tmp; - theta -= SW_ANGLE_PI2; - } - - auto atan = ATAN_TBL; - uint32_t i; - SwFixed j; - - for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) { - if (theta < 0) { - auto tmp = x + ((y + j) >> i); - y = y - ((x + j) >> i); - x = tmp; - theta += *atan++; - } else { - auto tmp = x - ((y + j) >> i); - y = y + ((x + j) >> i); - x = tmp; - theta -= *atan++; - } - } - - pt.x = static_cast<SwCoord>(x); - pt.y = static_cast<SwCoord>(y); + return (float(angle) / 65536.0f) * (MATH_PI / 180.0f); } @@ -214,11 +50,17 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw auto d2 = base[1] - base[2]; auto d3 = base[0] - base[1]; + if (d1 == d2 || d2 == d3) { + if (d3.small()) angleIn = angleMid = angleOut = 0; + else angleIn = angleMid = angleOut = mathAtan(d3); + return true; + } + if (d1.small()) { if (d2.small()) { if (d3.small()) { - //basically a point. - //do nothing to retain original direction + angleIn = angleMid = angleOut = 0; + return true; } else { angleIn = angleMid = angleOut = mathAtan(d3); } @@ -320,77 +162,63 @@ int64_t mathMulDiv(int64_t a, int64_t b, int64_t c) void mathRotate(SwPoint& pt, SwFixed angle) { - if (angle == 0 || (pt.x == 0 && pt.y == 0)) return; - - auto v = pt; - auto shift = _normalize(v); + if (angle == 0 || pt.zero()) return; - auto theta = angle; - _rotate(v, theta); + Point v = pt.toPoint(); - v.x = _downscale(v.x); - v.y = _downscale(v.y); + auto radian = TO_RADIAN(angle); + auto cosv = cosf(radian); + auto sinv = sinf(radian); - if (shift > 0) { - auto half = static_cast<int32_t>(1L << (shift - 1)); - pt.x = (v.x + half + SATURATE(v.x)) >> shift; - pt.y = (v.y + half + SATURATE(v.y)) >> shift; - } else { - shift = -shift; - pt.x = static_cast<SwCoord>((unsigned long)v.x << shift); - pt.y = static_cast<SwCoord>((unsigned long)v.y << shift); - } + pt.x = SwCoord(roundf((v.x * cosv - v.y * sinv) * 64.0f)); + pt.y = SwCoord(roundf((v.x * sinv + v.y * cosv) * 64.0f)); } + SwFixed mathTan(SwFixed angle) { - SwPoint v = {CORDIC_FACTOR >> 8, 0}; - _rotate(v, angle); - return mathDivide(v.y, v.x); + if (angle == 0) return 0; + return SwFixed(tanf(TO_RADIAN(angle)) * 65536.0f); } SwFixed mathAtan(const SwPoint& pt) { - if (pt.x == 0 && pt.y == 0) return 0; - - auto v = pt; - _normalize(v); - _polarize(v); - - return v.y; + if (pt.zero()) return 0; + return SwFixed(atan2f(TO_FLOAT(pt.y), TO_FLOAT(pt.x)) * (180.0f / MATH_PI) * 65536.0f); } SwFixed mathSin(SwFixed angle) { + if (angle == 0) return 0; return mathCos(SW_ANGLE_PI2 - angle); } SwFixed mathCos(SwFixed angle) { - SwPoint v = {CORDIC_FACTOR >> 8, 0}; - _rotate(v, angle); - return (v.x + 0x80L) >> 8; + return SwFixed(cosf(TO_RADIAN(angle)) * 65536.0f); } SwFixed mathLength(const SwPoint& pt) { - auto v = pt; + if (pt.zero()) return 0; //trivial case - if (v.x == 0) return abs(v.y); - if (v.y == 0) return abs(v.x); - - //general case - auto shift = _normalize(v); - _polarize(v); - v.x = _downscale(v.x); - - if (shift > 0) return (v.x + (static_cast<SwFixed>(1) << (shift -1))) >> shift; - return static_cast<SwFixed>((uint32_t)v.x << -shift); + if (pt.x == 0) return abs(pt.y); + if (pt.y == 0) return abs(pt.x); + + auto v = pt.toPoint(); + //return static_cast<SwFixed>(sqrtf(v.x * v.x + v.y * v.y) * 65536.0f); + + /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. + With alpha = 1, beta = 3/8, giving results with the largest error less + than 7% compared to the exact value. */ + if (v.x < 0) v.x = -v.x; + if (v.y < 0) v.y = -v.y; + return static_cast<SwFixed>((v.x > v.y) ? (v.x + v.y * 0.375f) : (v.y + v.x * 0.375f)); } @@ -401,22 +229,22 @@ void mathSplitCubic(SwPoint* base) base[6].x = base[3].x; c = base[1].x; d = base[2].x; - base[1].x = a = (base[0].x + c) / 2; - base[5].x = b = (base[3].x + d) / 2; - c = (c + d) / 2; - base[2].x = a = (a + c) / 2; - base[4].x = b = (b + c) / 2; - base[3].x = (a + b) / 2; + base[1].x = a = (base[0].x + c) >> 1; + base[5].x = b = (base[3].x + d) >> 1; + c = (c + d) >> 1; + base[2].x = a = (a + c) >> 1; + base[4].x = b = (b + c) >> 1; + base[3].x = (a + b) >> 1; base[6].y = base[3].y; c = base[1].y; d = base[2].y; - base[1].y = a = (base[0].y + c) / 2; - base[5].y = b = (base[3].y + d) / 2; - c = (c + d) / 2; - base[2].y = a = (a + c) / 2; - base[4].y = b = (b + c) / 2; - base[3].y = (a + b) / 2; + base[1].y = a = (base[0].y + c) >> 1; + base[5].y = b = (base[3].y + d) >> 1; + c = (c + d) >> 1; + base[2].y = a = (a + c) >> 1; + base[4].y = b = (b + c) >> 1; + base[3].y = (a + b) >> 1; } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp index 54ae594bff..68eb7a5a6f 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp index 4b1ba59100..9a6dc45950 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -248,17 +248,17 @@ static inline uint32_t _sampleSize(float scale) //Bilinear Interpolation //OPTIMIZE_ME: Skip the function pointer access -static uint32_t _interpUpScaler(const uint32_t *img, TVG_UNUSED uint32_t stride, uint32_t w, uint32_t h, float sx, float sy, TVG_UNUSED uint32_t n, TVG_UNUSED uint32_t n2) +static uint32_t _interpUpScaler(const uint32_t *img, TVG_UNUSED uint32_t stride, uint32_t w, uint32_t h, float sx, float sy, TVG_UNUSED int32_t miny, TVG_UNUSED int32_t maxy, TVG_UNUSED int32_t n) { - auto rx = (uint32_t)(sx); - auto ry = (uint32_t)(sy); + auto rx = (size_t)(sx); + auto ry = (size_t)(sy); auto rx2 = rx + 1; if (rx2 >= w) rx2 = w - 1; auto ry2 = ry + 1; if (ry2 >= h) ry2 = h - 1; - auto dx = static_cast<uint32_t>((sx - rx) * 255.0f); - auto dy = static_cast<uint32_t>((sy - ry) * 255.0f); + auto dx = static_cast<size_t>((sx - rx) * 255.0f); + auto dy = static_cast<size_t>((sy - ry) * 255.0f); auto c1 = img[rx + ry * w]; auto c2 = img[rx2 + ry * w]; @@ -271,18 +271,21 @@ static uint32_t _interpUpScaler(const uint32_t *img, TVG_UNUSED uint32_t stride, //2n x 2n Mean Kernel //OPTIMIZE_ME: Skip the function pointer access -static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t w, uint32_t h, float sx, float sy, uint32_t n, uint32_t n2) +static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t w, uint32_t h, float sx, TVG_UNUSED float sy, int32_t miny, int32_t maxy, int32_t n) { - uint32_t rx = lroundf(sx); - uint32_t ry = lroundf(sy); - uint32_t c[4] = {0, 0, 0, 0}; - auto src = img + rx - n + (ry - n) * stride; + size_t c[4] = {0, 0, 0, 0}; - for (auto y = ry - n; y < ry + n; ++y) { - if (y >= h) continue; + int32_t minx = (int32_t)sx - n; + if (minx < 0) minx = 0; + + int32_t maxx = (int32_t)sx + n; + if (maxx >= (int32_t)w) maxx = w; + + auto src = img + minx + miny * stride; + + for (auto y = miny; y < maxy; ++y) { auto p = src; - for (auto x = rx - n; x < rx + n; ++x, ++p) { - if (x >= w) continue; + for (auto x = minx; x < maxx; ++x, ++p) { c[0] += *p >> 24; c[1] += (*p >> 16) & 0xff; c[2] += (*p >> 8) & 0xff; @@ -290,9 +293,14 @@ static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t } src += stride; } - for (auto i = 0; i < 4; ++i) { - c[i] = (c[i] >> 2) / n2; - } + + n = (maxy - miny) * (maxx - minx); + + c[0] /= n; + c[1] /= n; + c[2] /= n; + c[3] /= n; + return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; } @@ -660,34 +668,39 @@ static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g, /* RLE Scaled Image */ /************************************************************************/ +#define SCALED_IMAGE_RANGE_Y(y) \ + auto sy = (y) * itransform->e22 + itransform->e23; \ + auto my = (int32_t)round(sy); \ + if (my < 0 || (uint32_t)sy >= image->h) continue; \ + if (scaleMethod == _interpDownScaler) { \ + miny = my - (int32_t)sampleSize; \ + if (miny < 0) miny = 0; \ + maxy = my + (int32_t)sampleSize; \ + if (maxy >= (int32_t)image->h) maxy = (int32_t)image->h; \ + } + +#define SCALED_IMAGE_RANGE_X \ + auto sx = x * itransform->e11 + itransform->e13; \ + if ((int32_t)round(sx) < 0 || (uint32_t) sx >= image->w) continue; + + #if 0 //Enable it when GRAYSCALE image is supported static bool _rasterCompositeScaledMaskedRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, SwMask maskOp, uint8_t opacity) { auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; auto span = image->rle->spans; + int32_t miny = 0, maxy = 0; for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto sy = span->y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(span->y) auto cmp = &surface->compositor->image.buf8[span->y * surface->compositor->image.stride + span->x]; auto a = MULTIPLY(span->coverage, opacity); - if (a == 255) { - for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++cmp) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - *cmp = maskOp(src, *cmp, ~src); - } - } else { - for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++cmp) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = MULTIPLY(src, a); - *cmp = maskOp(tmp, *cmp, ~tmp); - } + for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++cmp) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (a < 255) src = MULTIPLY(src, a); + *cmp = maskOp(src, *cmp, ~src); } } return true; @@ -698,31 +711,20 @@ static bool _rasterDirectScaledMaskedRleImage(SwSurface* surface, const SwImage* { auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; auto span = image->rle->spans; + int32_t miny = 0, maxy = 0; - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto sy = span->y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { + SCALED_IMAGE_RANGE_Y(span->y) auto cmp = &surface->compositor->image.buf8[span->y * surface->compositor->image.stride + span->x]; auto dst = &surface->buf8[span->y * surface->stride + span->x]; auto a = MULTIPLY(span->coverage, opacity); - if (a == 255) { - for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++cmp, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = maskOp(src, *cmp, 0); //not use alpha - *dst = tmp + MULTIPLY(*dst, ~tmp); - } - } else { - for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++cmp, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = maskOp(MULTIPLY(src, a), *cmp, 0); //not use alpha - *dst = tmp + MULTIPLY(*dst, ~tmp); - } + for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++cmp, ++dst) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (a < 255) src = MULTIPLY(src, a); + src = maskOp(src, *cmp, 0); //not use alpha + *dst = src + MULTIPLY(*dst, ~src); } } return _compositeMaskImage(surface, &surface->compositor->image, surface->compositor->bbox); @@ -752,32 +754,20 @@ static bool _rasterScaledMattedRleImage(SwSurface* surface, const SwImage* image auto span = image->rle->spans; auto csize = surface->compositor->image.channelSize; auto alpha = surface->alpha(surface->compositor->method); - auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; + int32_t miny = 0, maxy = 0; for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto sy = span->y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(span->y) auto dst = &surface->buf32[span->y * surface->stride + span->x]; auto cmp = &surface->compositor->image.buf8[(span->y * surface->compositor->image.stride + span->x) * csize]; auto a = MULTIPLY(span->coverage, opacity); - if (a == 255) { - for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto tmp = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), alpha(cmp)); - *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); - } - } else { - for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = ALPHA_BLEND(src, MULTIPLY(alpha(cmp), a)); - *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); - } + for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + src = ALPHA_BLEND(src, (a == 255) ? alpha(cmp) : MULTIPLY(alpha(cmp), a)); + *dst = src + ALPHA_BLEND(*dst, IA(src)); } } @@ -790,34 +780,24 @@ static bool _rasterScaledBlendingRleImage(SwSurface* surface, const SwImage* ima auto span = image->rle->spans; auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; + int32_t miny = 0, maxy = 0; for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto sy = span->y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(span->y) auto dst = &surface->buf32[span->y * surface->stride + span->x]; auto alpha = MULTIPLY(span->coverage, opacity); if (alpha == 255) { for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); auto tmp = surface->blender(src, *dst, 255); *dst = INTERPOLATE(tmp, *dst, A(src)); } - } else if (opacity == 255) { - for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = surface->blender(src, *dst, 255); - *dst = INTERPOLATE(tmp, *dst, MULTIPLY(span->coverage, A(src))); - } } else { for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity); + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (opacity < 255) src = ALPHA_BLEND(src, opacity); auto tmp = surface->blender(src, *dst, 255); *dst = INTERPOLATE(tmp, *dst, MULTIPLY(span->coverage, A(src))); } @@ -832,27 +812,17 @@ static bool _rasterScaledRleImage(SwSurface* surface, const SwImage* image, cons auto span = image->rle->spans; auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; + int32_t miny = 0, maxy = 0; for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto sy = span->y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(span->y) auto dst = &surface->buf32[span->y * surface->stride + span->x]; auto alpha = MULTIPLY(span->coverage, opacity); - if (alpha == 255) { - for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - *dst = src + ALPHA_BLEND(*dst, IA(src)); - } - } else { - for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), alpha); - *dst = src + ALPHA_BLEND(*dst, IA(src)); - } + for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (alpha < 255) src = ALPHA_BLEND(src, alpha); + *dst = src + ALPHA_BLEND(*dst, IA(src)); } } return true; @@ -1067,29 +1037,18 @@ static bool _rasterCompositeScaledMaskedImage(SwSurface* surface, const SwImage* { auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; auto cstride = surface->compositor->image.stride; auto cbuffer = surface->compositor->image.buf8 + (region.min.y * cstride + region.min.x); + int32_t miny = 0, maxy = 0; for (auto y = region.min.y; y < region.max.y; ++y) { - auto sy = y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(y) auto cmp = cbuffer; - if (opacity == 255) { - for (auto x = region.min.x; x < region.max.x; ++x, ++cmp) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - *cmp = maskOp(src, *cmp, ~src); - } - } else { - for (auto x = region.min.x; x < region.max.x; ++x, ++cmp) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = MULTIPLY(src, opacity); - *cmp = maskOp(tmp, *cmp, ~tmp); - } + for (auto x = region.min.x; x < region.max.x; ++x, ++cmp) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (opacity < 255) src = MULTIPLY(src, opacity); + *cmp = maskOp(src, *cmp, ~src); } cbuffer += cstride; } @@ -1101,33 +1060,21 @@ static bool _rasterDirectScaledMaskedImage(SwSurface* surface, const SwImage* im { auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; auto cstride = surface->compositor->image.stride; auto cbuffer = surface->compositor->image.buf8 + (region.min.y * cstride + region.min.x); auto dbuffer = surface->buf8 + (region.min.y * surface->stride + region.min.x); + int32_t miny = 0, maxy = 0; for (auto y = region.min.y; y < region.max.y; ++y) { - auto sy = y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(y) auto cmp = cbuffer; auto dst = dbuffer; - if (opacity == 255) { - for (auto x = region.min.x; x < region.max.x; ++x, ++cmp, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = maskOp(src, *cmp, 0); //not use alpha - *dst = tmp + MULTIPLY(*dst, ~tmp); - } - } else { - for (auto x = region.min.x; x < region.max.x; ++x, ++cmp, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = MULTIPLY(src, opacity); - auto tmp2 = maskOp(tmp, *cmp, 0); //not use alpha - *dst = tmp2 + MULTIPLY(*dst, ~tmp2); - } + for (auto x = region.min.x; x < region.max.x; ++x, ++cmp, ++dst) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (opacity < 255) src = MULTIPLY(src, opacity); + src = maskOp(src, *cmp, 0); //not use alpha + *dst = src + MULTIPLY(*dst, ~src); } cbuffer += cstride; dbuffer += surface->stride; @@ -1160,29 +1107,17 @@ static bool _rasterScaledMattedImage(SwSurface* surface, const SwImage* image, c auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; + int32_t miny = 0, maxy = 0; for (auto y = region.min.y; y < region.max.y; ++y) { - auto sy = y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(y) auto dst = dbuffer; auto cmp = cbuffer; - if (opacity == 255) { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto temp = ALPHA_BLEND(src, alpha(cmp)); - *dst = temp + ALPHA_BLEND(*dst, IA(temp)); - } - } else { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto temp = ALPHA_BLEND(src, MULTIPLY(opacity, alpha(cmp))); - *dst = temp + ALPHA_BLEND(*dst, IA(temp)); - } + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + auto tmp = ALPHA_BLEND(src, opacity == 255 ? alpha(cmp) : MULTIPLY(opacity, alpha(cmp))); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); } dbuffer += surface->stride; cbuffer += surface->compositor->image.stride * csize; @@ -1196,28 +1131,17 @@ static bool _rasterScaledBlendingImage(SwSurface* surface, const SwImage* image, auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x); auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; + int32_t miny = 0, maxy = 0; for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) { - auto sy = y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(y) auto dst = dbuffer; - if (opacity == 255) { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = surface->blender(src, *dst, 255); - *dst = INTERPOLATE(tmp, *dst, A(src)); - } - } else { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity); - auto tmp = surface->blender(src, *dst, 255); - *dst = INTERPOLATE(tmp, *dst, A(src)); - } + for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (opacity < 255) ALPHA_BLEND(src, opacity); + auto tmp = surface->blender(src, *dst, 255); + *dst = INTERPOLATE(tmp, *dst, A(src)); } } return true; @@ -1229,26 +1153,16 @@ static bool _rasterScaledImage(SwSurface* surface, const SwImage* image, const M auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x); auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; + int32_t miny = 0, maxy = 0; for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) { - auto sy = y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(y) auto dst = dbuffer; - if (opacity == 255) { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - *dst = src + ALPHA_BLEND(*dst, IA(src)); - } - } else { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity); - *dst = src + ALPHA_BLEND(*dst, IA(src)); - } + for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (opacity < 255) src = ALPHA_BLEND(src, opacity); + *dst = src + ALPHA_BLEND(*dst, IA(src)); } } return true; @@ -1800,7 +1714,7 @@ static bool _rasterSolidGradientRle(SwSurface* surface, const SwRleData* rle, co static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { - if (!rle || fill->linear.len < FLT_EPSILON) return false; + if (!rle) return false; if (_compositing(surface)) { if (_matting(surface)) return _rasterGradientMattedRle<FillLinear>(surface, rle, fill); @@ -1941,7 +1855,9 @@ void rasterUnpremultiply(Surface* surface) void rasterPremultiply(Surface* surface) { - if (surface->channelSize != sizeof(uint32_t)) return; + unique_lock<mutex> lock{surface->mtx}; + if (surface->premultiplied || (surface->channelSize != sizeof(uint32_t))) return; + surface->premultiplied = true; TVGLOG("SW_ENGINE", "Premultiply [Size: %d x %d]", surface->w, surface->h); @@ -1955,7 +1871,6 @@ void rasterPremultiply(Surface* surface) *dst = (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff); } } - surface->premultiplied = true; } @@ -2021,6 +1936,9 @@ bool rasterImage(SwSurface* surface, SwImage* image, const RenderMesh* mesh, con bool rasterConvertCS(Surface* surface, ColorSpace to) { + unique_lock<mutex> lock{surface->mtx}; + if (surface->cs == to) return true; + //TOOD: Support SIMD accelerations auto from = surface->cs; @@ -2032,6 +1950,5 @@ bool rasterConvertCS(Surface* surface, ColorSpace to) surface->cs = to; return cRasterARGBtoABGR(surface); } - return false; } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h index 090fa29a7a..177c7b847f 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h index da3c7077e8..6d0bd9383d 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h index ba77ed53cf..cfbeb0caca 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h index 698ab37da2..04e382b842 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp index 049aa3d1d0..c9c543fbb5 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -45,8 +45,11 @@ struct SwTask : Task bool pushed = false; //Pushed into task list? bool disposed = false; //Disposed task? - RenderRegion bounds() const + RenderRegion bounds() { + //Can we skip the synchronization? + done(); + RenderRegion region; //Range over? @@ -139,7 +142,9 @@ struct SwShapeTask : SwTask visibleFill = (alpha > 0 || rshape->fill); if (visibleFill || clipper) { shapeReset(&shape); - if (!shapePrepare(&shape, rshape, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err; + if (!shapePrepare(&shape, rshape, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) { + visibleFill = false; + } } } //Fill @@ -276,10 +281,8 @@ struct SwImageTask : SwTask auto clipRegion = bbox; //Convert colorspace if it's not aligned. - if (source->owner) { - if (source->cs != surface->cs) rasterConvertCS(source, surface->cs); - if (!source->premultiplied) rasterPremultiply(source); - } + rasterConvertCS(source, surface->cs); + rasterPremultiply(source); image.data = source->data; image.w = source->w; @@ -431,7 +434,6 @@ bool SwRenderer::target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h, surface->cs = cs; surface->channelSize = CHANNEL_SIZE(cs); surface->premultiplied = true; - surface->owner = true; vport.x = vport.y = 0; vport.w = surface->w; @@ -633,11 +635,8 @@ Compositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs) //New Composition if (!cmp) { - cmp = new SwSurface; - //Inherits attributes from main surface - *cmp = *surface; - + cmp = new SwSurface(surface); cmp->compositor = new SwCompositor; //TODO: We can optimize compositor surface size from (surface->stride x surface->h) to Parameter(w x h) diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h index 4393740bd9..83d942388f 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp index a4a7fabdee..33c94e1063 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp index 4f66cdacc0..e001ced2a8 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -558,11 +558,15 @@ void shapeReset(SwShape* shape) void shapeFree(SwShape* shape) { rleFree(shape->rle); + shape->rle = nullptr; + shapeDelFill(shape); if (shape->stroke) { rleFree(shape->strokeRle); + shape->strokeRle = nullptr; strokeFree(shape->stroke); + shape->stroke = nullptr; } } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp index 75c5fa5667..8f44cf3616 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgAccessor.cpp b/thirdparty/thorvg/src/renderer/tvgAccessor.cpp index 0c636979b5..903437f29d 100644 --- a/thirdparty/thorvg/src/renderer/tvgAccessor.cpp +++ b/thirdparty/thorvg/src/renderer/tvgAccessor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp index 7a29ecf973..995eca7f41 100644 --- a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp +++ b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -62,9 +62,9 @@ Animation::Animation() : pImpl(new Impl) } -Result Animation::frame(uint32_t no) noexcept +Result Animation::frame(float no) noexcept { - auto loader = pImpl->picture->pImpl->loader.get(); + auto loader = pImpl->picture->pImpl->loader; if (!loader) return Result::InsufficientCondition; if (!loader->animatable()) return Result::NonSupport; @@ -80,9 +80,9 @@ Picture* Animation::picture() const noexcept } -uint32_t Animation::curFrame() const noexcept +float Animation::curFrame() const noexcept { - auto loader = pImpl->picture->pImpl->loader.get(); + auto loader = pImpl->picture->pImpl->loader; if (!loader) return 0; if (!loader->animatable()) return 0; @@ -91,9 +91,9 @@ uint32_t Animation::curFrame() const noexcept } -uint32_t Animation::totalFrame() const noexcept +float Animation::totalFrame() const noexcept { - auto loader = pImpl->picture->pImpl->loader.get(); + auto loader = pImpl->picture->pImpl->loader; if (!loader) return 0; if (!loader->animatable()) return 0; @@ -104,7 +104,7 @@ uint32_t Animation::totalFrame() const noexcept float Animation::duration() const noexcept { - auto loader = pImpl->picture->pImpl->loader.get(); + auto loader = pImpl->picture->pImpl->loader; if (!loader) return 0; if (!loader->animatable()) return 0; diff --git a/thirdparty/thorvg/src/renderer/tvgBinaryDesc.h b/thirdparty/thorvg/src/renderer/tvgBinaryDesc.h index b1468148d6..29f84eb82a 100644 --- a/thirdparty/thorvg/src/renderer/tvgBinaryDesc.h +++ b/thirdparty/thorvg/src/renderer/tvgBinaryDesc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,7 +36,7 @@ using TvgBinFlag = TvgBinByte; #define TVG_HEADER_SIZE 33 //TVG_HEADER_SIGNATURE_LENGTH + TVG_HEADER_VERSION_LENGTH + 2*SIZE(float) + TVG_HEADER_RESERVED_LENGTH + TVG_HEADER_COMPRESS_SIZE #define TVG_HEADER_SIGNATURE "ThorVG" #define TVG_HEADER_SIGNATURE_LENGTH 6 -#define TVG_HEADER_VERSION "001100" //Major 00, Minor 11, Micro 00 +#define TVG_HEADER_VERSION "001200" //Major 00, Minor 12, Micro 00 #define TVG_HEADER_VERSION_LENGTH 6 #define TVG_HEADER_RESERVED_LENGTH 1 //Storing flags for extensions #define TVG_HEADER_COMPRESS_SIZE 12 //TVG_HEADER_UNCOMPRESSED_SIZE + TVG_HEADER_COMPRESSED_SIZE + TVG_HEADER_COMPRESSED_SIZE_BITS diff --git a/thirdparty/thorvg/src/renderer/tvgCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgCanvas.cpp index 2d4cbd048f..11d6b778f7 100644 --- a/thirdparty/thorvg/src/renderer/tvgCanvas.cpp +++ b/thirdparty/thorvg/src/renderer/tvgCanvas.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -63,9 +63,9 @@ Result Canvas::clear(bool free) noexcept Result Canvas::draw() noexcept { - TVGLOG("COMMON", "Draw S. -------------------------------- Canvas(%p)", this); + TVGLOG("RENDERER", "Draw S. -------------------------------- Canvas(%p)", this); auto ret = pImpl->draw(); - TVGLOG("COMMON", "Draw E. -------------------------------- Canvas(%p)", this); + TVGLOG("RENDERER", "Draw E. -------------------------------- Canvas(%p)", this); return ret; } @@ -73,9 +73,9 @@ Result Canvas::draw() noexcept Result Canvas::update(Paint* paint) noexcept { - TVGLOG("COMMON", "Update S. ------------------------------ Canvas(%p)", this); + TVGLOG("RENDERER", "Update S. ------------------------------ Canvas(%p)", this); auto ret = pImpl->update(paint, false); - TVGLOG("COMMON", "Update E. ------------------------------ Canvas(%p)", this); + TVGLOG("RENDERER", "Update E. ------------------------------ Canvas(%p)", this); return ret; } diff --git a/thirdparty/thorvg/src/renderer/tvgCanvas.h b/thirdparty/thorvg/src/renderer/tvgCanvas.h index f893f9f7c0..25181de47e 100644 --- a/thirdparty/thorvg/src/renderer/tvgCanvas.h +++ b/thirdparty/thorvg/src/renderer/tvgCanvas.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,14 +20,11 @@ * SOFTWARE. */ -#ifndef _TVG_CANVAS_IMPL_H_ -#define _TVG_CANVAS_IMPL_H_ +#ifndef _TVG_CANVAS_H_ +#define _TVG_CANVAS_H_ #include "tvgPaint.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ struct Canvas::Impl { @@ -143,4 +140,4 @@ struct Canvas::Impl } }; -#endif /* _TVG_CANVAS_IMPL_H_ */ +#endif /* _TVG_CANVAS_H_ */ diff --git a/thirdparty/thorvg/src/renderer/tvgCommon.h b/thirdparty/thorvg/src/renderer/tvgCommon.h index f36b4b9b30..deb419bc65 100644 --- a/thirdparty/thorvg/src/renderer/tvgCommon.h +++ b/thirdparty/thorvg/src/renderer/tvgCommon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -61,8 +61,9 @@ using namespace tvg; #define TVG_CLASS_ID_PICTURE 3 #define TVG_CLASS_ID_LINEAR 4 #define TVG_CLASS_ID_RADIAL 5 +#define TVG_CLASS_ID_TEXT 6 -enum class FileType { Tvg = 0, Svg, Lottie, Raw, Png, Jpg, Webp, Unknown }; +enum class FileType { Tvg = 0, Svg, Ttf, Lottie, Raw, Png, Jpg, Webp, Gif, Unknown }; using Size = Point; diff --git a/thirdparty/thorvg/src/renderer/tvgFill.cpp b/thirdparty/thorvg/src/renderer/tvgFill.cpp index 9215882c8d..ea1010051e 100644 --- a/thirdparty/thorvg/src/renderer/tvgFill.cpp +++ b/thirdparty/thorvg/src/renderer/tvgFill.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgFill.h b/thirdparty/thorvg/src/renderer/tvgFill.h index ff3dd48c49..47f0c051c0 100644 --- a/thirdparty/thorvg/src/renderer/tvgFill.h +++ b/thirdparty/thorvg/src/renderer/tvgFill.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgFrameModule.h b/thirdparty/thorvg/src/renderer/tvgFrameModule.h index 857c6caeb9..df97ccb894 100644 --- a/thirdparty/thorvg/src/renderer/tvgFrameModule.h +++ b/thirdparty/thorvg/src/renderer/tvgFrameModule.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,15 +28,15 @@ namespace tvg { -class FrameModule: public LoadModule +class FrameModule: public ImageLoader { public: + FrameModule(FileType type) : ImageLoader(type) {} virtual ~FrameModule() {} - virtual bool frame(uint32_t frameNo) = 0; //set the current frame number - - virtual uint32_t totalFrame() = 0; //return the total frame count - virtual uint32_t curFrame() = 0; //return the current frame number + virtual bool frame(float no) = 0; //set the current frame number + virtual float totalFrame() = 0; //return the total frame count + virtual float curFrame() = 0; //return the current frame number virtual float duration() = 0; //return the animation duration in seconds virtual bool animatable() override { return true; } diff --git a/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp index aa7f8dbe2a..f6f0d354d1 100644 --- a/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp +++ b/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgInitializer.cpp b/thirdparty/thorvg/src/renderer/tvgInitializer.cpp index b7326a9fbc..76d89b40ed 100644 --- a/thirdparty/thorvg/src/renderer/tvgInitializer.cpp +++ b/thirdparty/thorvg/src/renderer/tvgInitializer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,6 +36,10 @@ #include "tvgGlRenderer.h" #endif +#ifdef THORVG_WG_RASTER_SUPPORT + #include "tvgWgRenderer.h" +#endif + /************************************************************************/ /* Internal Class Implementation */ @@ -91,19 +95,27 @@ static bool _buildVersionInfo() Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept { auto nonSupport = true; + if (static_cast<int>(engine) == 0) return Result::InvalidArguments; if (engine & CanvasEngine::Sw) { #ifdef THORVG_SW_RASTER_SUPPORT if (!SwRenderer::init(threads)) return Result::FailedAllocation; nonSupport = false; #endif - } else if (engine & CanvasEngine::Gl) { + } + + if (engine & CanvasEngine::Gl) { #ifdef THORVG_GL_RASTER_SUPPORT if (!GlRenderer::init(threads)) return Result::FailedAllocation; nonSupport = false; #endif - } else { - return Result::InvalidArguments; + } + + if (engine & CanvasEngine::Wg) { + #ifdef THORVG_WG_RASTER_SUPPORT + if (!WgRenderer::init(threads)) return Result::FailedAllocation; + nonSupport = false; + #endif } if (nonSupport) return Result::NonSupport; @@ -125,19 +137,27 @@ Result Initializer::term(CanvasEngine engine) noexcept if (_initCnt == 0) return Result::InsufficientCondition; auto nonSupport = true; + if (static_cast<int>(engine) == 0) return Result::InvalidArguments; if (engine & CanvasEngine::Sw) { #ifdef THORVG_SW_RASTER_SUPPORT if (!SwRenderer::term()) return Result::InsufficientCondition; nonSupport = false; #endif - } else if (engine & CanvasEngine::Gl) { + } + + if (engine & CanvasEngine::Gl) { #ifdef THORVG_GL_RASTER_SUPPORT if (!GlRenderer::term()) return Result::InsufficientCondition; nonSupport = false; #endif - } else { - return Result::InvalidArguments; + } + + if (engine & CanvasEngine::Wg) { + #ifdef THORVG_WG_RASTER_SUPPORT + if (!WgRenderer::term()) return Result::InsufficientCondition; + nonSupport = false; + #endif } if (nonSupport) return Result::NonSupport; @@ -156,3 +176,4 @@ uint16_t THORVG_VERSION_NUMBER() { return _version; } + diff --git a/thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h b/thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h index 2347613ed8..46e900a582 100644 --- a/thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h +++ b/thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgLoadModule.h b/thirdparty/thorvg/src/renderer/tvgLoadModule.h index 29ceba3fcc..0ea766395e 100644 --- a/thirdparty/thorvg/src/renderer/tvgLoadModule.h +++ b/thirdparty/thorvg/src/renderer/tvgLoadModule.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,35 +24,73 @@ #define _TVG_LOAD_MODULE_H_ #include "tvgRender.h" +#include "tvgInlist.h" -namespace tvg -{ -class LoadModule +struct LoadModule { -public: - float w = 0, h = 0; //default image size - ColorSpace cs = ColorSpace::Unsupported; //must be clarified at open() + INLIST_ITEM(LoadModule); + + //Use either hashkey(data) or hashpath(path) + uint64_t hashkey; + char* hashpath = nullptr; - virtual ~LoadModule() {} + FileType type; //current loader file type + uint16_t sharing = 0; //reference count + bool readied = false; //read done already. + + LoadModule(FileType type) : type(type) {} + virtual ~LoadModule() + { + free(hashpath); + } virtual bool open(const string& path) { return false; } virtual bool open(const char* data, uint32_t size, bool copy) { return false; } - virtual bool open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) { return false; } - - //Override this if the vector-format has own resizing policy. virtual bool resize(Paint* paint, float w, float h) { return false; } - - virtual bool animatable() { return false; } //true if this loader supports animation. virtual void sync() {}; //finish immediately if any async update jobs. - virtual bool read() = 0; - virtual bool close() = 0; + virtual bool read() + { + if (readied) return false; + readied = true; + return true; + } - virtual unique_ptr<Surface> bitmap() { return nullptr; } - virtual unique_ptr<Paint> paint() { return nullptr; } + virtual bool close() + { + if (sharing == 0) return true; + --sharing; + return false; + } }; -} + +struct ImageLoader : LoadModule +{ + float w = 0, h = 0; //default image size + Surface surface; + + ImageLoader(FileType type) : LoadModule(type) {} + + virtual bool animatable() { return false; } //true if this loader supports animation. + virtual Paint* paint() { return nullptr; } + + virtual Surface* bitmap() + { + if (surface.data) return &surface; + return nullptr; + } +}; + + +struct FontLoader : LoadModule +{ + float scale = 1.0f; + + FontLoader(FileType type) : LoadModule(type) {} + + virtual bool request(Shape* shape, char* text, bool italic = false) = 0; +}; #endif //_TVG_LOAD_MODULE_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgLoader.cpp b/thirdparty/thorvg/src/renderer/tvgLoader.cpp index 52bdb91d6a..628b0fa17f 100644 --- a/thirdparty/thorvg/src/renderer/tvgLoader.cpp +++ b/thirdparty/thorvg/src/renderer/tvgLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,6 +20,9 @@ * SOFTWARE. */ +#include <string.h> + +#include "tvgInlist.h" #include "tvgLoader.h" #ifdef THORVG_SVG_LOADER_SUPPORT @@ -42,16 +45,30 @@ #include "tvgWebpLoader.h" #endif +#ifdef THORVG_TTF_LOADER_SUPPORT + #include "tvgTtfLoader.h" +#endif + #ifdef THORVG_LOTTIE_LOADER_SUPPORT #include "tvgLottieLoader.h" #endif #include "tvgRawLoader.h" + +uint64_t HASH_KEY(const char* data, uint64_t size) +{ + return (((uint64_t) data) << 32) | size; +} + /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +static mutex mtx; +static Inlist<LoadModule> _activeLoaders; + + static LoadModule* _find(FileType type) { switch(type) { @@ -67,6 +84,12 @@ static LoadModule* _find(FileType type) #endif break; } + case FileType::Ttf: { +#ifdef THORVG_TTF_LOADER_SUPPORT + return new TtfLoader; +#endif + break; + } case FileType::Lottie: { #ifdef THORVG_LOTTIE_LOADER_SUPPORT return new LottieLoader; @@ -111,6 +134,10 @@ static LoadModule* _find(FileType type) format = "SVG"; break; } + case FileType::Ttf: { + format = "TTF"; + break; + } case FileType::Lottie: { format = "lottie(json)"; break; @@ -136,7 +163,7 @@ static LoadModule* _find(FileType type) break; } } - TVGLOG("LOADER", "%s format is not supported", format); + TVGLOG("RENDERER", "%s format is not supported", format); #endif return nullptr; } @@ -152,29 +179,71 @@ static LoadModule* _findByPath(const string& path) if (!ext.compare("png")) return _find(FileType::Png); if (!ext.compare("jpg")) return _find(FileType::Jpg); if (!ext.compare("webp")) return _find(FileType::Webp); + if (!ext.compare("ttf") || !ext.compare("ttc")) return _find(FileType::Ttf); + if (!ext.compare("otf") || !ext.compare("otc")) return _find(FileType::Ttf); return nullptr; } -static LoadModule* _findByType(const string& mimeType) +static FileType _convert(const string& mimeType) { - if (mimeType.empty()) return nullptr; - auto type = FileType::Unknown; if (mimeType == "tvg") type = FileType::Tvg; else if (mimeType == "svg" || mimeType == "svg+xml") type = FileType::Svg; + else if (mimeType == "ttf" || mimeType == "otf") type = FileType::Ttf; else if (mimeType == "lottie") type = FileType::Lottie; else if (mimeType == "raw") type = FileType::Raw; else if (mimeType == "png") type = FileType::Png; else if (mimeType == "jpg" || mimeType == "jpeg") type = FileType::Jpg; else if (mimeType == "webp") type = FileType::Webp; - else { - TVGLOG("LOADER", "Given mimetype is unknown = \"%s\".", mimeType.c_str()); - return nullptr; + else TVGLOG("RENDERER", "Given mimetype is unknown = \"%s\".", mimeType.c_str()); + + return type; +} + + +static LoadModule* _findByType(const string& mimeType) +{ + return _find(_convert(mimeType)); +} + + +static LoadModule* _findFromCache(const string& path) +{ + unique_lock<mutex> lock{mtx}; + + auto loader = _activeLoaders.head; + + while (loader) { + if (loader->hashpath && !strcmp(loader->hashpath, path.c_str())) { + ++loader->sharing; + return loader; + } + loader = loader->next; } + return nullptr; +} + + +static LoadModule* _findFromCache(const char* data, uint32_t size, const string& mimeType) +{ + auto type = _convert(mimeType); + if (type == FileType::Unknown) return nullptr; - return _find(type); + unique_lock<mutex> lock{mtx}; + auto loader = _activeLoaders.head; + + auto key = HASH_KEY(data, size); + + while (loader) { + if (loader->type == type && loader->hashkey == key) { + ++loader->sharing; + return loader; + } + loader = loader->next; + } + return nullptr; } @@ -185,40 +254,95 @@ static LoadModule* _findByType(const string& mimeType) bool LoaderMgr::init() { - //TODO: - return true; } bool LoaderMgr::term() { - //TODO: + auto loader = _activeLoaders.head; + + //clean up the remained font loaders which is globally used. + while (loader && loader->type == FileType::Ttf) { + auto ret = loader->close(); + auto tmp = loader; + loader = loader->next; + _activeLoaders.remove(tmp); + if (ret) delete(loader); + } + return true; +} + +bool LoaderMgr::retrieve(LoadModule* loader) +{ + if (!loader) return false; + if (loader->close()) { + { + unique_lock<mutex> lock{mtx}; + _activeLoaders.remove(loader); + } + delete(loader); + } return true; } -shared_ptr<LoadModule> LoaderMgr::loader(const string& path, bool* invalid) +LoadModule* LoaderMgr::loader(const string& path, bool* invalid) { *invalid = false; + if (auto loader = _findFromCache(path)) return loader; + if (auto loader = _findByPath(path)) { - if (loader->open(path)) return shared_ptr<LoadModule>(loader); - else delete(loader); + if (loader->open(path)) { + loader->hashpath = strdup(path.c_str()); + { + unique_lock<mutex> lock{mtx}; + _activeLoaders.back(loader); + } + return loader; + } + delete(loader); *invalid = true; } return nullptr; } -shared_ptr<LoadModule> LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, bool copy) +bool LoaderMgr::retrieve(const string& path) +{ + return retrieve(_findFromCache(path)); +} + + +LoadModule* LoaderMgr::loader(const char* key) +{ + auto loader = _activeLoaders.head; + + while (loader) { + if (loader->hashpath && strstr(loader->hashpath, key)) { + ++loader->sharing; + return loader; + } + loader = loader->next; + } + return nullptr; +} + + +LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, bool copy) { + if (auto loader = _findFromCache(data, size, mimeType)) return loader; + //Try with the given MimeType if (!mimeType.empty()) { if (auto loader = _findByType(mimeType)) { if (loader->open(data, size, copy)) { - return shared_ptr<LoadModule>(loader); + loader->hashkey = HASH_KEY(data, size); + unique_lock<mutex> lock{mtx}; + _activeLoaders.back(loader); + return loader; } else { TVGLOG("LOADER", "Given mimetype \"%s\" seems incorrect or not supported.", mimeType.c_str()); delete(loader); @@ -229,8 +353,15 @@ shared_ptr<LoadModule> LoaderMgr::loader(const char* data, uint32_t size, const for (int i = 0; i < static_cast<int>(FileType::Unknown); i++) { auto loader = _find(static_cast<FileType>(i)); if (loader) { - if (loader->open(data, size, copy)) return shared_ptr<LoadModule>(loader); - else delete(loader); + if (loader->open(data, size, copy)) { + loader->hashkey = HASH_KEY(data, size); + { + unique_lock<mutex> lock{mtx}; + _activeLoaders.back(loader); + } + return loader; + } + delete(loader); } } } @@ -238,12 +369,21 @@ shared_ptr<LoadModule> LoaderMgr::loader(const char* data, uint32_t size, const } -shared_ptr<LoadModule> LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool copy) +LoadModule* LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool copy) { + //TODO: should we check premultiplied?? + if (auto loader = _findFromCache((const char*)(data), w * h, "raw")) return loader; + //function is dedicated for raw images only auto loader = new RawLoader; - if (loader->open(data, w, h, copy)) return shared_ptr<LoadModule>(loader); - else delete(loader); - + if (loader->open(data, w, h, copy)) { + loader->hashkey = HASH_KEY((const char*)data, w * h); + { + unique_lock<mutex> lock{mtx}; + _activeLoaders.back(loader); + } + return loader; + } + delete(loader); return nullptr; } diff --git a/thirdparty/thorvg/src/renderer/tvgLoader.h b/thirdparty/thorvg/src/renderer/tvgLoader.h index 17ff9e2637..b15032df27 100644 --- a/thirdparty/thorvg/src/renderer/tvgLoader.h +++ b/thirdparty/thorvg/src/renderer/tvgLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,9 +29,12 @@ struct LoaderMgr { static bool init(); static bool term(); - static shared_ptr<LoadModule> loader(const string& path, bool* invalid); - static shared_ptr<LoadModule> loader(const char* data, uint32_t size, const string& mimeType, bool copy); - static shared_ptr<LoadModule> loader(const uint32_t* data, uint32_t w, uint32_t h, bool copy); + static LoadModule* loader(const string& path, bool* invalid); + static LoadModule* loader(const char* data, uint32_t size, const string& mimeType, bool copy); + static LoadModule* loader(const uint32_t* data, uint32_t w, uint32_t h, bool copy); + static LoadModule* loader(const char* key); + static bool retrieve(const string& path); + static bool retrieve(LoadModule* loader); }; #endif //_TVG_LOADER_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.cpp b/thirdparty/thorvg/src/renderer/tvgPaint.cpp index 37df906dac..563db3b44a 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPaint.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,24 @@ #include "tvgMath.h" #include "tvgPaint.h" +#include "tvgShape.h" +#include "tvgPicture.h" +#include "tvgScene.h" +#include "tvgText.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +#define PAINT_METHOD(ret, METHOD) \ + switch (id) { \ + case TVG_CLASS_ID_SHAPE: ret = P((Shape*)paint)->METHOD; break; \ + case TVG_CLASS_ID_SCENE: ret = P((Scene*)paint)->METHOD; break; \ + case TVG_CLASS_ID_PICTURE: ret = P((Picture*)paint)->METHOD; break; \ + case TVG_CLASS_ID_TEXT: ret = P((Text*)paint)->METHOD; break; \ + default: ret = {}; \ + } + static bool _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& viewport) { @@ -93,9 +106,36 @@ static bool _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, } +RenderRegion Paint::Impl::bounds(RenderMethod& renderer) const +{ + RenderRegion ret; + PAINT_METHOD(ret, bounds(renderer)); + return ret; +} + + +bool Paint::Impl::dispose(RenderMethod& renderer) +{ + if (compData) compData->target->pImpl->dispose(renderer); + + bool ret; + PAINT_METHOD(ret, dispose(renderer)); + return ret; +} + + +Iterator* Paint::Impl::iterator() +{ + Iterator* ret; + PAINT_METHOD(ret, iterator()); + return ret; +} + + Paint* Paint::Impl::duplicate() { - auto ret = smethod->duplicate(); + Paint* ret; + PAINT_METHOD(ret, duplicate()); //duplicate Transform if (rTransform) { @@ -165,8 +205,10 @@ bool Paint::Impl::render(RenderMethod& renderer) /* Note: only ClipPath is processed in update() step. Create a composition image. */ if (compData && compData->method != CompositeMethod::ClipPath && !(compData->target->pImpl->ctxFlag & ContextFlag::FastTrack)) { - auto region = smethod->bounds(renderer); - if (MASK_REGION_MERGING(compData->method)) region.add(compData->target->pImpl->smethod->bounds(renderer)); + RenderRegion region; + PAINT_METHOD(region, bounds(renderer)); + + if (MASK_REGION_MERGING(compData->method)) region.add(P(compData->target)->bounds(renderer)); if (region.w == 0 || region.h == 0) return true; cmp = renderer.target(region, COMPOSITE_TO_COLORSPACE(renderer, compData->method)); if (renderer.beginComposite(cmp, CompositeMethod::None, 255)) { @@ -177,7 +219,9 @@ bool Paint::Impl::render(RenderMethod& renderer) if (cmp) renderer.beginComposite(cmp, compData->method, compData->target->pImpl->opacity); renderer.blend(blendMethod); - auto ret = smethod->render(renderer); + + bool ret; + PAINT_METHOD(ret, render(renderer)); if (cmp) renderer.endComposite(cmp); @@ -189,10 +233,7 @@ RenderData Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pT { if (renderFlag & RenderUpdateFlag::Transform) { if (!rTransform) return nullptr; - if (!rTransform->update()) { - delete(rTransform); - rTransform = nullptr; - } + rTransform->update(); } /* 1. Composition Pre Processing */ @@ -239,18 +280,13 @@ RenderData Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pT } /* 2. Main Update */ - RenderData rd = nullptr; auto newFlag = static_cast<RenderUpdateFlag>(pFlag | renderFlag); renderFlag = RenderUpdateFlag::None; opacity = MULTIPLY(opacity, this->opacity); - if (rTransform && pTransform) { - RenderTransform outTransform(pTransform, rTransform); - rd = smethod->update(renderer, &outTransform, clips, opacity, newFlag, clipper); - } else { - auto outTransform = pTransform ? pTransform : rTransform; - rd = smethod->update(renderer, outTransform, clips, opacity, newFlag, clipper); - } + RenderData rd = nullptr; + RenderTransform outTransform(pTransform, rTransform); + PAINT_METHOD(rd, update(renderer, &outTransform, clips, opacity, newFlag, clipper)); /* 3. Composition Post Processing */ if (compFastTrack) renderer.viewport(viewport); @@ -263,9 +299,13 @@ RenderData Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pT bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking) { Matrix* m = nullptr; + bool ret; //Case: No transformed, quick return! - if (!transformed || !(m = this->transform())) return smethod->bounds(x, y, w, h, stroking); + if (!transformed || !(m = this->transform())) { + PAINT_METHOD(ret, bounds(x, y, w, h, stroking)); + return ret; + } //Case: Transformed auto tx = 0.0f; @@ -273,7 +313,7 @@ bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transforme auto tw = 0.0f; auto th = 0.0f; - auto ret = smethod->bounds(&tx, &ty, &tw, &th, stroking); + PAINT_METHOD(ret, bounds(&tx, &ty, &tw, &th, stroking)); //Get vertices Point pt[4] = {{tx, ty}, {tx + tw, ty}, {tx + tw, ty + th}, {tx, ty + th}}; @@ -307,7 +347,7 @@ bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transforme /* External Class Implementation */ /************************************************************************/ -Paint :: Paint() : pImpl(new Impl()) +Paint :: Paint() : pImpl(new Impl(this)) { } @@ -419,7 +459,10 @@ uint32_t Paint::identifier() const noexcept Result Paint::blend(BlendMethod method) const noexcept { - pImpl->blendMethod = method; + if (pImpl->blendMethod != method) { + pImpl->blendMethod = method; + pImpl->renderFlag |= RenderUpdateFlag::Blend; + } return Result::Success; } diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.h b/thirdparty/thorvg/src/renderer/tvgPaint.h index 0ee07fedff..4ec9fa7f7e 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.h +++ b/thirdparty/thorvg/src/renderer/tvgPaint.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -38,19 +38,6 @@ namespace tvg virtual void begin() = 0; }; - struct StrategyMethod - { - virtual ~StrategyMethod() {} - - virtual bool dispose(RenderMethod& renderer) = 0; //return true if the deletion is allowed. - virtual void* update(RenderMethod& renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) = 0; //Return engine data if it has. - virtual bool render(RenderMethod& renderer) = 0; - virtual bool bounds(float* x, float* y, float* w, float* h, bool stroking) = 0; - virtual RenderRegion bounds(RenderMethod& renderer) const = 0; - virtual Paint* duplicate() = 0; - virtual Iterator* iterator() = 0; - }; - struct Composite { Paint* target; @@ -60,7 +47,7 @@ namespace tvg struct Paint::Impl { - StrategyMethod* smethod = nullptr; + Paint* paint = nullptr; RenderTransform* rTransform = nullptr; Composite* compData = nullptr; BlendMethod blendMethod = BlendMethod::Normal; //uint8_t @@ -70,13 +57,16 @@ namespace tvg uint8_t opacity = 255; uint8_t refCnt = 0; + Impl(Paint* pnt) : paint(pnt) + { + } + ~Impl() { if (compData) { - delete(compData->target); + if (P(compData->target)->unref() == 0) delete(compData->target); free(compData); } - delete(smethod); delete(rTransform); } @@ -92,11 +82,6 @@ namespace tvg return (--refCnt); } - void method(StrategyMethod* method) - { - smethod = method; - } - bool transform(const Matrix& m) { if (!rTransform) { @@ -119,29 +104,16 @@ namespace tvg return nullptr; } - RenderRegion bounds(RenderMethod& renderer) const - { - return smethod->bounds(renderer); - } - - bool dispose(RenderMethod& renderer) - { - if (compData) compData->target->pImpl->dispose(renderer); - return smethod->dispose(renderer); - } - - Iterator* iterator() - { - return smethod->iterator(); - } - bool composite(Paint* source, Paint* target, CompositeMethod method) { //Invalid case if ((!target && method != CompositeMethod::None) || (target && method == CompositeMethod::None)) return false; if (compData) { - delete(compData->target); + P(compData->target)->unref(); + if ((compData->target != target) && P(compData->target)->refCnt == 0) { + delete(compData->target); + } //Reset scenario if (!target && method == CompositeMethod::None) { free(compData); @@ -152,12 +124,16 @@ namespace tvg if (!target && method == CompositeMethod::None) return true; compData = static_cast<Composite*>(calloc(1, sizeof(Composite))); } + P(target)->ref(); compData->target = target; compData->source = source; compData->method = method; return true; } + RenderRegion bounds(RenderMethod& renderer) const; + bool dispose(RenderMethod& renderer); + Iterator* iterator(); bool rotate(float degree); bool scale(float factor); bool translate(float x, float y); @@ -166,51 +142,6 @@ namespace tvg bool render(RenderMethod& renderer); Paint* duplicate(); }; - - - template<class T> - struct PaintMethod : StrategyMethod - { - T* inst = nullptr; - - PaintMethod(T* _inst) : inst(_inst) {} - ~PaintMethod() {} - - bool bounds(float* x, float* y, float* w, float* h, bool stroking) override - { - return inst->bounds(x, y, w, h, stroking); - } - - RenderRegion bounds(RenderMethod& renderer) const override - { - return inst->bounds(renderer); - } - - bool dispose(RenderMethod& renderer) override - { - return inst->dispose(renderer); - } - - RenderData update(RenderMethod& renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag renderFlag, bool clipper) override - { - return inst->update(renderer, transform, clips, opacity, renderFlag, clipper); - } - - bool render(RenderMethod& renderer) override - { - return inst->render(renderer); - } - - Paint* duplicate() override - { - return inst->duplicate(); - } - - Iterator* iterator() override - { - return inst->iterator(); - } - }; } #endif //_TVG_PAINT_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.cpp b/thirdparty/thorvg/src/renderer/tvgPicture.cpp index 07877b92de..7f120593f4 100644 --- a/thirdparty/thorvg/src/renderer/tvgPicture.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPicture.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,9 +30,8 @@ RenderUpdateFlag Picture::Impl::load() { if (loader) { if (!paint) { - if (auto p = loader->paint()) { - paint = p.release(); - loader->close(); + paint = loader->paint(); + if (paint) { if (w != loader->w || h != loader->h) { if (!resizing) { w = loader->w; @@ -41,13 +40,12 @@ RenderUpdateFlag Picture::Impl::load() loader->resize(paint, w, h); resizing = false; } - if (paint) return RenderUpdateFlag::None; + return RenderUpdateFlag::None; } } else loader->sync(); if (!surface) { - if ((surface = loader->bitmap().release())) { - loader->close(); + if ((surface = loader->bitmap())) { return RenderUpdateFlag::Image; } } @@ -55,6 +53,93 @@ RenderUpdateFlag Picture::Impl::load() return RenderUpdateFlag::None; } + +bool Picture::Impl::needComposition(uint8_t opacity) +{ + //In this case, paint(scene) would try composition itself. + if (opacity < 255) return false; + + //Composition test + const Paint* target; + auto method = picture->composite(&target); + if (!target || method == tvg::CompositeMethod::ClipPath) return false; + if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return false; + + return true; +} + + +bool Picture::Impl::render(RenderMethod &renderer) +{ + bool ret = false; + if (surface) return renderer.renderImage(rd); + else if (paint) { + Compositor* cmp = nullptr; + if (needComp) { + cmp = renderer.target(bounds(renderer), renderer.colorSpace()); + renderer.beginComposite(cmp, CompositeMethod::None, 255); + } + ret = paint->pImpl->render(renderer); + if (cmp) renderer.endComposite(cmp); + } + return ret; +} + + +bool Picture::Impl::size(float w, float h) +{ + this->w = w; + this->h = h; + resizing = true; + return true; +} + + +RenderRegion Picture::Impl::bounds(RenderMethod& renderer) +{ + if (rd) return renderer.region(rd); + if (paint) return paint->pImpl->bounds(renderer); + return {0, 0, 0, 0}; +} + + +RenderTransform Picture::Impl::resizeTransform(const RenderTransform* pTransform) +{ + //Overriding Transformation by the desired image size + auto sx = w / loader->w; + auto sy = h / loader->h; + auto scale = sx < sy ? sx : sy; + + RenderTransform tmp; + tmp.m = {scale, 0, 0, 0, scale, 0, 0, 0, 1}; + + if (!pTransform) return tmp; + else return RenderTransform(pTransform, &tmp); +} + + +Result Picture::Impl::load(ImageLoader* loader) +{ + //Same resource has been loaded. + if (this->loader == loader) { + this->loader->sharing--; //make it sure the reference counting. + return Result::Success; + } else if (this->loader) { + LoaderMgr::retrieve(this->loader); + } + + this->loader = loader; + + if (!loader->read()) return Result::Unknown; + + this->w = loader->w; + this->h = loader->h; + + return Result::Success; +} + + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -62,7 +147,6 @@ RenderUpdateFlag Picture::Impl::load() Picture::Picture() : pImpl(new Impl(this)) { Paint::pImpl->id = TVG_CLASS_ID_PICTURE; - Paint::pImpl->method(new PaintMethod<Picture::Impl>(pImpl)); } diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.h b/thirdparty/thorvg/src/renderer/tvgPicture.h index 447f56ecb7..26a171ba66 100644 --- a/thirdparty/thorvg/src/renderer/tvgPicture.h +++ b/thirdparty/thorvg/src/renderer/tvgPicture.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,16 +20,13 @@ * SOFTWARE. */ -#ifndef _TVG_PICTURE_IMPL_H_ -#define _TVG_PICTURE_IMPL_H_ +#ifndef _TVG_PICTURE_H_ +#define _TVG_PICTURE_H_ #include <string> #include "tvgPaint.h" #include "tvgLoader.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ struct PictureIterator : Iterator { @@ -60,7 +57,7 @@ struct PictureIterator : Iterator struct Picture::Impl { - shared_ptr<LoadModule> loader = nullptr; + ImageLoader* loader = nullptr; Paint* paint = nullptr; //vector picture uses Surface* surface = nullptr; //bitmap picture uses @@ -71,14 +68,21 @@ struct Picture::Impl bool resizing = false; bool needComp = false; //need composition + RenderTransform resizeTransform(const RenderTransform* pTransform); + bool needComposition(uint8_t opacity); + bool render(RenderMethod &renderer); + bool size(float w, float h); + RenderRegion bounds(RenderMethod& renderer); + Result load(ImageLoader* ploader); + Impl(Picture* p) : picture(p) { } ~Impl() { + LoaderMgr::retrieve(loader); delete(paint); - delete(surface); } bool dispose(RenderMethod& renderer) @@ -89,34 +93,6 @@ struct Picture::Impl return true; } - RenderTransform resizeTransform(const RenderTransform* pTransform) - { - //Overriding Transformation by the desired image size - auto sx = w / loader->w; - auto sy = h / loader->h; - auto scale = sx < sy ? sx : sy; - - RenderTransform tmp; - tmp.m = {scale, 0, 0, 0, scale, 0, 0, 0, 1}; - - if (!pTransform) return tmp; - else return RenderTransform(pTransform, &tmp); - } - - bool needComposition(uint8_t opacity) - { - //In this case, paint(scene) would try composition itself. - if (opacity < 255) return false; - - //Composition test - const Paint* target; - auto method = picture->composite(&target); - if (!target || method == tvg::CompositeMethod::ClipPath) return false; - if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return false; - - return true; - } - RenderData update(RenderMethod &renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) { auto flag = load(); @@ -135,30 +111,6 @@ struct Picture::Impl return rd; } - bool render(RenderMethod &renderer) - { - bool ret = false; - if (surface) return renderer.renderImage(rd); - else if (paint) { - Compositor* cmp = nullptr; - if (needComp) { - cmp = renderer.target(bounds(renderer), renderer.colorSpace()); - renderer.beginComposite(cmp, CompositeMethod::None, 255); - } - ret = paint->pImpl->render(renderer); - if (cmp) renderer.endComposite(cmp); - } - return ret; - } - - bool size(float w, float h) - { - this->w = w; - this->h = h; - resizing = true; - return true; - } - bool bounds(float* x, float* y, float* w, float* h, bool stroking) { if (rm.triangleCnt > 0) { @@ -195,50 +147,35 @@ struct Picture::Impl return true; } - RenderRegion bounds(RenderMethod& renderer) - { - if (rd) return renderer.region(rd); - if (paint) return paint->pImpl->bounds(renderer); - return {0, 0, 0, 0}; - } - Result load(const string& path) { if (paint || surface) return Result::InsufficientCondition; - if (loader) loader->close(); + bool invalid; //Invalid Path - loader = LoaderMgr::loader(path, &invalid); + auto loader = static_cast<ImageLoader*>(LoaderMgr::loader(path, &invalid)); if (!loader) { if (invalid) return Result::InvalidArguments; return Result::NonSupport; } - if (!loader->read()) return Result::Unknown; - w = loader->w; - h = loader->h; - return Result::Success; + return load(loader); } Result load(const char* data, uint32_t size, const string& mimeType, bool copy) { if (paint || surface) return Result::InsufficientCondition; - if (loader) loader->close(); - loader = LoaderMgr::loader(data, size, mimeType, copy); + auto loader = static_cast<ImageLoader*>(LoaderMgr::loader(data, size, mimeType, copy)); if (!loader) return Result::NonSupport; - if (!loader->read()) return Result::Unknown; - w = loader->w; - h = loader->h; - return Result::Success; + return load(loader); } Result load(uint32_t* data, uint32_t w, uint32_t h, bool copy) { if (paint || surface) return Result::InsufficientCondition; - if (loader) loader->close(); - loader = LoaderMgr::loader(data, w, h, copy); + + auto loader = static_cast<ImageLoader*>(LoaderMgr::loader(data, w, h, copy)); if (!loader) return Result::FailedAllocation; - this->w = loader->w; - this->h = loader->h; - return Result::Success; + + return load(loader); } void mesh(const Polygon* triangles, const uint32_t triangleCnt) @@ -258,18 +195,17 @@ struct Picture::Impl { load(); - auto ret = Picture::gen(); + auto ret = Picture::gen().release(); + auto dup = ret->pImpl; - auto dup = ret.get()->pImpl; if (paint) dup->paint = paint->duplicate(); - dup->loader = loader; - if (surface) { - dup->surface = new Surface; - *dup->surface = *surface; - //TODO: A dupilcation is not a proxy... it needs copy of the pixel data? - dup->surface->owner = false; + if (loader) { + dup->loader = loader; + ++dup->loader->sharing; } + + dup->surface = surface; dup->w = w; dup->h = h; dup->resizing = resizing; @@ -280,7 +216,7 @@ struct Picture::Impl memcpy(dup->rm.triangles, rm.triangles, sizeof(Polygon) * rm.triangleCnt); } - return ret.release(); + return ret; } Iterator* iterator() @@ -308,4 +244,4 @@ struct Picture::Impl RenderUpdateFlag load(); }; -#endif //_TVG_PICTURE_IMPL_H_ +#endif //_TVG_PICTURE_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgRender.cpp b/thirdparty/thorvg/src/renderer/tvgRender.cpp index 9768b5ede0..bdfb9f322e 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.cpp +++ b/thirdparty/thorvg/src/renderer/tvgRender.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -39,12 +39,9 @@ void RenderTransform::override(const Matrix& m) } -bool RenderTransform::update() +void RenderTransform::update() { - if (overriding) return true; - - //Init Status - if (mathZero(x) && mathZero(y) && mathZero(degree) && mathEqual(scale, 1)) return false; + if (overriding) return; mathIdentity(&m); @@ -53,17 +50,13 @@ bool RenderTransform::update() if (!mathZero(degree)) mathRotate(&m, degree); mathTranslate(&m, x, y); - - return true; -} - - -RenderTransform::RenderTransform() -{ } RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs) { - m = mathMultiply(&lhs->m, &rhs->m); + if (lhs && rhs) m = mathMultiply(&lhs->m, &rhs->m); + else if (lhs) m = lhs->m; + else if (rhs) m = rhs->m; + else mathIdentity(&m); } diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h index 1231089ff5..1e70b53494 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.h +++ b/thirdparty/thorvg/src/renderer/tvgRender.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,6 +23,7 @@ #ifndef _TVG_RENDER_H_ #define _TVG_RENDER_H_ +#include <mutex> #include "tvgCommon.h" #include "tvgArray.h" @@ -32,7 +33,7 @@ namespace tvg using RenderData = void*; using pixel_t = uint32_t; -enum RenderUpdateFlag : uint8_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, All = 255}; +enum RenderUpdateFlag : uint8_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, Blend = 128, All = 255}; struct Surface; @@ -49,17 +50,33 @@ enum ColorSpace struct Surface { union { - pixel_t* data; //system based data pointer - uint32_t* buf32; //for explicit 32bits channels - uint8_t* buf8; //for explicit 8bits grayscale + pixel_t* data = nullptr; //system based data pointer + uint32_t* buf32; //for explicit 32bits channels + uint8_t* buf8; //for explicit 8bits grayscale }; - uint32_t stride; - uint32_t w, h; - ColorSpace cs; - uint8_t channelSize; + mutex mtx; //used for thread safety + uint32_t stride = 0; + uint32_t w = 0, h = 0; + ColorSpace cs = ColorSpace::Unsupported; + uint8_t channelSize = 0; + bool premultiplied = 0; //Alpha-premultiplied + + Surface() + { + } + + Surface(const Surface* rhs) + { + data = rhs->data; + stride = rhs->stride; + w = rhs->w; + h = rhs->h; + cs = rhs->cs; + channelSize = rhs->channelSize; + premultiplied = rhs->premultiplied; + } + - bool premultiplied; //Alpha-premultiplied - bool owner; //Only owner could modify the buffer }; struct Compositor @@ -123,10 +140,10 @@ struct RenderTransform float scale = 1.0f; //scale factor bool overriding = false; //user transform? - bool update(); + void update(); void override(const Matrix& m); - RenderTransform(); + RenderTransform() {} RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs); }; diff --git a/thirdparty/thorvg/src/renderer/tvgSaveModule.h b/thirdparty/thorvg/src/renderer/tvgSaveModule.h index a997b644a7..fed05c52df 100644 --- a/thirdparty/thorvg/src/renderer/tvgSaveModule.h +++ b/thirdparty/thorvg/src/renderer/tvgSaveModule.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,6 +34,7 @@ public: virtual ~SaveModule() {} virtual bool save(Paint* paint, const string& path, bool compress) = 0; + virtual bool save(Animation* animation, Paint* bg, const string& path, uint32_t quality, uint32_t fps) = 0; virtual bool close() = 0; }; diff --git a/thirdparty/thorvg/src/renderer/tvgSaver.cpp b/thirdparty/thorvg/src/renderer/tvgSaver.cpp index 3b4dfddcc2..11eb24d437 100644 --- a/thirdparty/thorvg/src/renderer/tvgSaver.cpp +++ b/thirdparty/thorvg/src/renderer/tvgSaver.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,9 @@ #ifdef THORVG_TVG_SAVER_SUPPORT #include "tvgTvgSaver.h" #endif +#ifdef THORVG_GIF_SAVER_SUPPORT + #include "tvgGifSaver.h" +#endif /************************************************************************/ /* Internal Class Implementation */ @@ -34,9 +37,12 @@ struct Saver::Impl { SaveModule* saveModule = nullptr; + Paint* bg = nullptr; + ~Impl() { delete(saveModule); + delete(bg); } }; @@ -50,6 +56,12 @@ static SaveModule* _find(FileType type) #endif break; } + case FileType::Gif: { +#ifdef THORVG_GIF_SAVER_SUPPORT + return new GifSaver; +#endif + break; + } default: { break; } @@ -62,12 +74,16 @@ static SaveModule* _find(FileType type) format = "TVG"; break; } + case FileType::Gif: { + format = "GIF"; + break; + } default: { format = "???"; break; } } - TVGLOG("SAVER", "%s format is not supported", format); + TVGLOG("RENDERER", "%s format is not supported", format); #endif return nullptr; } @@ -78,6 +94,8 @@ static SaveModule* _find(const string& path) auto ext = path.substr(path.find_last_of(".") + 1); if (!ext.compare("tvg")) { return _find(FileType::Tvg); + } else if (!ext.compare("gif")) { + return _find(FileType::Gif); } return nullptr; } @@ -124,6 +142,46 @@ Result Saver::save(std::unique_ptr<Paint> paint, const string& path, bool compre } +Result Saver::background(unique_ptr<Paint> paint) noexcept +{ + delete(pImpl->bg); + pImpl->bg = paint.release(); + + return Result::Success; +} + + +Result Saver::save(unique_ptr<Animation> animation, const string& path, uint32_t quality, uint32_t fps) noexcept +{ + auto a = animation.release(); + if (!a) return Result::MemoryCorruption; + + if (mathZero(a->totalFrame())) { + delete(a); + return Result::InsufficientCondition; + } + + //Already on saving an other resource. + if (pImpl->saveModule) { + delete(a); + return Result::InsufficientCondition; + } + + if (auto saveModule = _find(path)) { + if (saveModule->save(a, pImpl->bg, path, quality, fps)) { + pImpl->saveModule = saveModule; + return Result::Success; + } else { + delete(a); + delete(saveModule); + return Result::Unknown; + } + } + delete(a); + return Result::NonSupport; +} + + Result Saver::sync() noexcept { if (!pImpl->saveModule) return Result::InsufficientCondition; diff --git a/thirdparty/thorvg/src/renderer/tvgScene.cpp b/thirdparty/thorvg/src/renderer/tvgScene.cpp index 52e7ea2bf6..f5809cf93b 100644 --- a/thirdparty/thorvg/src/renderer/tvgScene.cpp +++ b/thirdparty/thorvg/src/renderer/tvgScene.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,7 +29,6 @@ Scene::Scene() : pImpl(new Impl(this)) { Paint::pImpl->id = TVG_CLASS_ID_SCENE; - Paint::pImpl->method(new PaintMethod<Scene::Impl>(pImpl)); } diff --git a/thirdparty/thorvg/src/renderer/tvgScene.h b/thirdparty/thorvg/src/renderer/tvgScene.h index 10daa49a99..1a5600c231 100644 --- a/thirdparty/thorvg/src/renderer/tvgScene.h +++ b/thirdparty/thorvg/src/renderer/tvgScene.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,15 +20,12 @@ * SOFTWARE. */ -#ifndef _TVG_SCENE_IMPL_H_ -#define _TVG_SCENE_IMPL_H_ +#ifndef _TVG_SCENE_H_ +#define _TVG_SCENE_H_ #include <float.h> #include "tvgPaint.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ struct SceneIterator : Iterator { @@ -66,7 +63,7 @@ struct Scene::Impl RenderData rd = nullptr; Scene* scene = nullptr; uint8_t opacity; //for composition - bool needComp; //composite or not + bool needComp = false; //composite or not Impl(Scene* s) : scene(s) { @@ -75,7 +72,7 @@ struct Scene::Impl ~Impl() { for (auto paint : paints) { - if (paint->pImpl->unref() == 0) delete(paint); + if (P(paint)->unref() == 0) delete(paint); } } @@ -126,8 +123,7 @@ struct Scene::Impl this->renderer = &renderer; if (clipper) { - Array<RenderData> rds; - rds.reserve(paints.size()); + Array<RenderData> rds(paints.size()); for (auto paint : paints) { rds.push(paint->pImpl->update(renderer, transform, clips, opacity, flag, true)); } @@ -148,6 +144,7 @@ struct Scene::Impl if (needComp) { cmp = renderer.target(bounds(renderer), renderer.colorSpace()); renderer.beginComposite(cmp, CompositeMethod::None, opacity); + needComp = false; } for (auto paint : paints) { @@ -215,9 +212,8 @@ struct Scene::Impl Paint* duplicate() { - auto ret = Scene::gen(); - - auto dup = ret.get()->pImpl; + auto ret = Scene::gen().release(); + auto dup = ret->pImpl; for (auto paint : paints) { auto cdup = paint->duplicate(); @@ -225,7 +221,7 @@ struct Scene::Impl dup->paints.push_back(cdup); } - return ret.release(); + return ret; } void clear(bool free) @@ -246,4 +242,4 @@ struct Scene::Impl } }; -#endif //_TVG_SCENE_IMPL_H_ +#endif //_TVG_SCENE_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgShape.cpp b/thirdparty/thorvg/src/renderer/tvgShape.cpp index efb7666b29..23b8006dd9 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.cpp +++ b/thirdparty/thorvg/src/renderer/tvgShape.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,7 +35,6 @@ constexpr auto PATH_KAPPA = 0.552284f; Shape :: Shape() : pImpl(new Impl(this)) { Paint::pImpl->id = TVG_CLASS_ID_SHAPE; - Paint::pImpl->method(new PaintMethod<Shape::Impl>(pImpl)); } @@ -62,7 +61,7 @@ Result Shape::reset() noexcept pImpl->rs.path.cmds.clear(); pImpl->rs.path.pts.clear(); - pImpl->flag = RenderUpdateFlag::Path; + pImpl->flag |= RenderUpdateFlag::Path; return Result::Success; } @@ -70,18 +69,14 @@ Result Shape::reset() noexcept uint32_t Shape::pathCommands(const PathCommand** cmds) const noexcept { - if (!cmds) return 0; - - *cmds = pImpl->rs.path.cmds.data; + if (cmds) *cmds = pImpl->rs.path.cmds.data; return pImpl->rs.path.cmds.count; } uint32_t Shape::pathCoords(const Point** pts) const noexcept { - if (!pts) return 0; - - *pts = pImpl->rs.path.pts.data; + if (pts) *pts = pImpl->rs.path.pts.data; return pImpl->rs.path.pts.count; } @@ -224,8 +219,8 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry) } else if (mathEqual(rx, halfW) && mathEqual(ry, halfH)) { return appendCircle(x + (w * 0.5f), y + (h * 0.5f), rx, ry); } else { - auto hrx = rx * 0.5f; - auto hry = ry * 0.5f; + auto hrx = rx * PATH_KAPPA; + auto hry = ry * PATH_KAPPA; pImpl->grow(10, 17); pImpl->moveTo(x + rx, y); pImpl->lineTo(x + w - rx, y); diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h index bb266866d0..a7f1226690 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.h +++ b/thirdparty/thorvg/src/renderer/tvgShape.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,16 +20,13 @@ * SOFTWARE. */ -#ifndef _TVG_SHAPE_IMPL_H_ -#define _TVG_SHAPE_IMPL_H_ +#ifndef _TVG_SHAPE_H_ +#define _TVG_SHAPE_H_ #include <memory.h> #include "tvgMath.h" #include "tvgPaint.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ struct Shape::Impl { @@ -38,7 +35,7 @@ struct Shape::Impl Shape* shape; uint8_t flag = RenderUpdateFlag::None; uint8_t opacity; //for composition - bool needComp; //composite or not + bool needComp = false; //composite or not Impl(Shape* s) : shape(s) { @@ -59,6 +56,7 @@ struct Shape::Impl if (needComp) { cmp = renderer.target(bounds(renderer), renderer.colorSpace()); renderer.beginComposite(cmp, CompositeMethod::None, opacity); + needComp = false; } ret = renderer.renderShape(rd); if (cmp) renderer.endComposite(cmp); @@ -340,9 +338,9 @@ struct Shape::Impl Paint* duplicate() { - auto ret = Shape::gen(); + auto ret = Shape::gen().release(); + auto dup = ret->pImpl; - auto dup = ret.get()->pImpl; dup->rs.rule = rs.rule; //Color @@ -378,7 +376,7 @@ struct Shape::Impl dup->flag |= RenderUpdateFlag::Gradient; } - return ret.release(); + return ret; } Iterator* iterator() @@ -387,4 +385,4 @@ struct Shape::Impl } }; -#endif //_TVG_SHAPE_IMPL_H_ +#endif //_TVG_SHAPE_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp index 95df6b486d..4404057049 100644 --- a/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp +++ b/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp index e3887c60fc..36d1ce1f8b 100644 --- a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp +++ b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,11 +20,11 @@ * SOFTWARE. */ -#include <deque> #include <thread> -#include <vector> #include <atomic> #include <condition_variable> +#include "tvgArray.h" +#include "tvgInlist.h" #include "tvgTaskScheduler.h" /************************************************************************/ @@ -34,7 +34,7 @@ namespace tvg { struct TaskQueue { - deque<Task*> taskDeque; + Inlist<Task> taskDeque; mutex mtx; condition_variable ready; bool done = false; @@ -44,8 +44,6 @@ struct TaskQueue { unique_lock<mutex> lock{mtx, try_to_lock}; if (!lock || taskDeque.empty()) return false; *task = taskDeque.front(); - taskDeque.pop_front(); - return true; } @@ -54,11 +52,9 @@ struct TaskQueue { { unique_lock<mutex> lock{mtx, try_to_lock}; if (!lock) return false; - taskDeque.push_back(task); + taskDeque.back(task); } - ready.notify_one(); - return true; } @@ -82,8 +78,6 @@ struct TaskQueue { if (taskDeque.empty()) return false; *task = taskDeque.front(); - taskDeque.pop_front(); - return true; } @@ -91,12 +85,10 @@ struct TaskQueue { { { unique_lock<mutex> lock{mtx}; - taskDeque.push_back(task); + taskDeque.back(task); } - ready.notify_one(); } - }; @@ -105,24 +97,36 @@ static thread_local bool _async = true; //toggle async tasking for each thread struct TaskSchedulerImpl { - uint32_t threadCnt; - vector<thread> threads; - vector<TaskQueue> taskQueues; + Array<thread*> threads; + Array<TaskQueue*> taskQueues; atomic<uint32_t> idx{0}; - TaskSchedulerImpl(unsigned threadCnt) : threadCnt(threadCnt), taskQueues(threadCnt) + TaskSchedulerImpl(unsigned threadCnt) { threads.reserve(threadCnt); + taskQueues.reserve(threadCnt); for (unsigned i = 0; i < threadCnt; ++i) { - threads.emplace_back([&, i] { run(i); }); + taskQueues.push(new TaskQueue); + threads.push(new thread); + } + for (unsigned i = 0; i < threadCnt; ++i) { + *threads.data[i] = thread([&, i] { run(i); }); } } ~TaskSchedulerImpl() { - for (auto& queue : taskQueues) queue.complete(); - for (auto& thread : threads) thread.join(); + for (auto tq = taskQueues.data; tq < taskQueues.end(); ++tq) { + (*tq)->complete(); + } + for (auto thread = threads.data; thread < threads.end(); ++thread) { + (*thread)->join(); + delete(*thread); + } + for (auto tq = taskQueues.data; tq < taskQueues.end(); ++tq) { + delete(*tq); + } } void run(unsigned i) @@ -132,14 +136,14 @@ struct TaskSchedulerImpl //Thread Loop while (true) { auto success = false; - for (unsigned x = 0; x < threadCnt * 2; ++x) { - if (taskQueues[(i + x) % threadCnt].tryPop(&task)) { + for (unsigned x = 0; x < threads.count * 2; ++x) { + if (taskQueues[(i + x) % threads.count]->tryPop(&task)) { success = true; break; } } - if (!success && !taskQueues[i].pop(&task)) break; + if (!success && !taskQueues[i]->pop(&task)) break; (*task)(i + 1); } } @@ -147,13 +151,13 @@ struct TaskSchedulerImpl void request(Task* task) { //Async - if (threadCnt > 0 && _async) { + if (threads.count > 0 && _async) { task->prepare(); auto i = idx++; - for (unsigned n = 0; n < threadCnt; ++n) { - if (taskQueues[(i + n) % threadCnt].tryPush(task)) return; + for (unsigned n = 0; n < threads.count; ++n) { + if (taskQueues[(i + n) % threads.count]->tryPush(task)) return; } - taskQueues[i % threadCnt].push(task); + taskQueues[i % threads.count]->push(task); //Sync } else { task->run(0); @@ -192,7 +196,7 @@ void TaskScheduler::request(Task* task) unsigned TaskScheduler::threads() { - if (inst) return inst->threadCnt; + if (inst) return inst->threads.count; return 0; } diff --git a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h index 2dad80f5d0..483e084880 100644 --- a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h +++ b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ #include <mutex> #include <condition_variable> #include "tvgCommon.h" +#include "tvgInlist.h" namespace tvg { @@ -50,6 +51,8 @@ private: bool pending = false; public: + INLIST_ITEM(Task); + virtual ~Task() = default; void done() diff --git a/thirdparty/thorvg/src/renderer/tvgText.cpp b/thirdparty/thorvg/src/renderer/tvgText.cpp new file mode 100644 index 0000000000..1fe244c11d --- /dev/null +++ b/thirdparty/thorvg/src/renderer/tvgText.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. + + * 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 "tvgText.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + + +Text::Text() : pImpl(new Impl) +{ + Paint::pImpl->id = TVG_CLASS_ID_TEXT; +} + + +Text::~Text() +{ + delete(pImpl); +} + + +Result Text::text(const char* text) noexcept +{ + return pImpl->text(text); +} + + +Result Text::font(const char* name, float size, const char* style) noexcept +{ + return pImpl->font(name, size, style); +} + + +Result Text::load(const std::string& path) noexcept +{ + bool invalid; //invalid path + if (!LoaderMgr::loader(path, &invalid)) { + if (invalid) return Result::InvalidArguments; + else return Result::NonSupport; + } + + return Result::Success; +} + + +Result Text::unload(const std::string& path) noexcept +{ + if (LoaderMgr::retrieve(path)) return Result::Success; + return Result::InsufficientCondition; +} + + +Result Text::fill(uint8_t r, uint8_t g, uint8_t b) noexcept +{ + if (!pImpl->paint) return Result::InsufficientCondition; + + return pImpl->fill(r, g, b); +} + + +Result Text::fill(unique_ptr<Fill> f) noexcept +{ + if (!pImpl->paint) return Result::InsufficientCondition; + + auto p = f.release(); + if (!p) return Result::MemoryCorruption; + + return pImpl->fill(p); +} + + +unique_ptr<Text> Text::gen() noexcept +{ + return unique_ptr<Text>(new Text); +} + + +uint32_t Text::identifier() noexcept +{ + return TVG_CLASS_ID_TEXT; +} diff --git a/thirdparty/thorvg/src/renderer/tvgText.h b/thirdparty/thorvg/src/renderer/tvgText.h new file mode 100644 index 0000000000..b9f7ef6079 --- /dev/null +++ b/thirdparty/thorvg/src/renderer/tvgText.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. + + * 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 _TVG_TEXT_H +#define _TVG_TEXT_H + +#include <cstring> +#include "tvgShape.h" +#include "tvgFill.h" + +#ifdef THORVG_TTF_LOADER_SUPPORT + #include "tvgTtfLoader.h" +#else + #include "tvgLoader.h" +#endif + +struct Text::Impl +{ + RenderData rd = nullptr; + FontLoader* loader = nullptr; + Shape* paint = nullptr; + char* utf8 = nullptr; + float fontSize; + bool italic = false; + bool changed = false; + + ~Impl() + { + free(utf8); + LoaderMgr::retrieve(loader); + delete(paint); + } + + Result fill(uint8_t r, uint8_t g, uint8_t b) + { + return paint->fill(r, g, b); + } + + Result fill(Fill* f) + { + return paint->fill(cast<Fill>(f)); + } + + Result text(const char* utf8) + { + free(this->utf8); + if (utf8) this->utf8 = strdup(utf8); + else this->utf8 = nullptr; + changed = true; + + return Result::Success; + } + + Result font(const char* name, float size, const char* style) + { + auto loader = LoaderMgr::loader(name); + if (!loader) return Result::InsufficientCondition; + + //Same resource has been loaded. + if (this->loader == loader) { + this->loader->sharing--; //make it sure the reference counting. + return Result::Success; + } else if (this->loader) { + LoaderMgr::retrieve(this->loader); + } + this->loader = static_cast<FontLoader*>(loader); + + if (!paint) paint = Shape::gen().release(); + + fontSize = size; + if (style && strstr(style, "italic")) italic = true; + changed = true; + return Result::Success; + } + + RenderRegion bounds(RenderMethod& renderer) + { + return renderer.region(rd); + } + + bool render(RenderMethod& renderer) + { + if (paint) return PP(paint)->render(renderer); + return false; + } + + bool load() + { + if (!loader) return false; + + //reload + if (changed) { + loader->request(paint, utf8, italic); + loader->read(); + changed = false; + } + if (paint) { + loader->resize(paint, fontSize, fontSize); + return true; + } + return false; + } + + RenderData update(RenderMethod& renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) + { + if (!load()) return nullptr; + + //transform the gradient coordinates based on the final scaled font. + if (P(paint)->flag & RenderUpdateFlag::Gradient) { + auto fill = P(paint)->rs.fill; + auto scale = 1.0f / loader->scale; + if (fill->identifier() == TVG_CLASS_ID_LINEAR) { + P(static_cast<LinearGradient*>(fill))->x1 *= scale; + P(static_cast<LinearGradient*>(fill))->y1 *= scale; + P(static_cast<LinearGradient*>(fill))->x2 *= scale; + P(static_cast<LinearGradient*>(fill))->y2 *= scale; + } else { + P(static_cast<RadialGradient*>(fill))->cx *= scale; + P(static_cast<RadialGradient*>(fill))->cy *= scale; + P(static_cast<RadialGradient*>(fill))->r *= scale; + P(static_cast<RadialGradient*>(fill))->fx *= scale; + P(static_cast<RadialGradient*>(fill))->fy *= scale; + P(static_cast<RadialGradient*>(fill))->fr *= scale; + } + } + rd = PP(paint)->update(renderer, transform, clips, opacity, pFlag, clipper); + return rd; + } + + bool bounds(float* x, float* y, float* w, float* h, TVG_UNUSED bool stroking) + { + if (!load() || !paint) return false; + paint->bounds(x, y, w, h, true); + return true; + } + + bool dispose(RenderMethod& renderer) + { + renderer.dispose(rd); + this->rd = nullptr; + return true; + } + + Paint* duplicate() + { + load(); + + auto ret = Text::gen().release(); + auto dup = ret->pImpl; + if (paint) dup->paint = static_cast<Shape*>(paint->duplicate()); + + if (loader) { + dup->loader = loader; + ++dup->loader->sharing; + } + + dup->utf8 = strdup(utf8); + dup->italic = italic; + dup->fontSize = fontSize; + + return ret; + } + + Iterator* iterator() + { + return nullptr; + } +}; + + + +#endif //_TVG_TEXT_H diff --git a/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp new file mode 100644 index 0000000000..5205df1737 --- /dev/null +++ b/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. + + * 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 "tvgCanvas.h" + +#ifdef THORVG_WG_RASTER_SUPPORT + #include "tvgWgRenderer.h" +#endif + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct WgCanvas::Impl +{ +}; + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +#ifdef THORVG_WG_RASTER_SUPPORT +WgCanvas::WgCanvas() : Canvas(WgRenderer::gen()), pImpl(new Impl) +#else +WgCanvas::WgCanvas() : Canvas(nullptr), pImpl(nullptr) +#endif +{ +} + +WgCanvas::~WgCanvas() +{ + delete pImpl; +} + +Result WgCanvas::target(void* window, uint32_t w, uint32_t h) noexcept +{ +#ifdef THORVG_WG_RASTER_SUPPORT + if (!window) return Result::InvalidArguments; + if ((w == 0) || (h == 0)) return Result::InvalidArguments; + + //We know renderer type, avoid dynamic_cast for performance. + auto renderer = static_cast<WgRenderer*>(Canvas::pImpl->renderer); + if (!renderer) return Result::MemoryCorruption; + + if (!renderer->target(window, w, h)) return Result::Unknown; + + //Paints must be updated again with this new target. + Canvas::pImpl->needRefresh(); + + return Result::Success; +#endif + return Result::NonSupport; +} + +unique_ptr<WgCanvas> WgCanvas::gen() noexcept +{ +#ifdef THORVG_WG_RASTER_SUPPORT + return unique_ptr<WgCanvas>(new WgCanvas); +#endif + return nullptr; +} diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh index 04d1dd0b9a..a1732d5157 100755 --- a/thirdparty/thorvg/update-thorvg.sh +++ b/thirdparty/thorvg/update-thorvg.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -VERSION=0.11.2 +VERSION=0.12.0 cd thirdparty/thorvg/ || true rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/ @@ -52,13 +52,13 @@ cp -rv src/renderer ../src/ # Only sw_engine is enabled. rm -rfv ../src/renderer/gl_engine +rm -rfv ../src/renderer/wg_engine # Enabled embedded loaders: raw, JPEG, PNG. mkdir ../src/loaders cp -rv src/loaders/svg src/loaders/raw ../src/loaders/ -cp -rv src/loaders/svg src/loaders/jpg ../src/loaders/ -cp -rv src/loaders/svg src/loaders/png ../src/loaders/ -cp -rv src/loaders/svg src/loaders/external_png ../src/loaders/ +cp -rv src/loaders/jpg ../src/loaders/ +cp -rv src/loaders/png src/loaders/external_png ../src/loaders/ popd rm -rf tmp |