summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--.mailmap8
-rw-r--r--AUTHORS.md11
-rw-r--r--DONORS.md155
-rw-r--r--core/config/project_settings.cpp11
-rw-r--r--core/config/project_settings.h2
-rw-r--r--core/core_constants.cpp1
-rw-r--r--core/extension/extension_api_dump.cpp210
-rw-r--r--core/input/input.cpp6
-rw-r--r--core/input/input_event.cpp41
-rw-r--r--core/input/input_event.h12
-rw-r--r--core/io/image.cpp58
-rw-r--r--core/io/image.h17
-rw-r--r--core/io/marshalls.cpp21
-rw-r--r--core/io/marshalls.h2
-rw-r--r--core/math/a_star_grid_2d.cpp60
-rw-r--r--core/math/a_star_grid_2d.h15
-rw-r--r--core/math/convex_hull.cpp3
-rw-r--r--core/math/math_defs.h1
-rw-r--r--core/math/math_funcs.h10
-rw-r--r--core/math/projection.cpp2
-rw-r--r--core/os/os.cpp4
-rw-r--r--core/os/os.h2
-rw-r--r--core/string/string_name.cpp4
-rw-r--r--core/string/string_name.h1
-rw-r--r--core/string/ustring.cpp31
-rw-r--r--core/string/ustring.h1
-rw-r--r--core/variant/type_info.h1
-rw-r--r--core/variant/variant_call.cpp2
-rw-r--r--core/variant/variant_internal.h28
-rw-r--r--doc/classes/@GlobalScope.xml3
-rw-r--r--doc/classes/AStarGrid2D.xml40
-rw-r--r--doc/classes/Animation.xml13
-rw-r--r--doc/classes/AnimationNodeStateMachineTransition.xml18
-rw-r--r--doc/classes/AnimationTree.xml14
-rw-r--r--doc/classes/Area2D.xml60
-rw-r--r--doc/classes/Area3D.xml60
-rw-r--r--doc/classes/ArrayMesh.xml4
-rw-r--r--doc/classes/AudioStreamRandomizer.xml4
-rw-r--r--doc/classes/Button.xml1
-rw-r--r--doc/classes/ButtonGroup.xml4
-rw-r--r--doc/classes/CanvasItem.xml7
-rw-r--r--doc/classes/CanvasLayer.xml6
-rw-r--r--doc/classes/CharacterBody3D.xml8
-rw-r--r--doc/classes/CheckBox.xml1
-rw-r--r--doc/classes/CheckButton.xml1
-rw-r--r--doc/classes/CodeEdit.xml1
-rw-r--r--doc/classes/Color.xml30
-rw-r--r--doc/classes/ColorPicker.xml3
-rw-r--r--doc/classes/ColorPickerButton.xml1
-rw-r--r--doc/classes/Control.xml3
-rw-r--r--doc/classes/Curve3D.xml2
-rw-r--r--doc/classes/Dictionary.xml2
-rw-r--r--doc/classes/EditorSpinSlider.xml22
-rw-r--r--doc/classes/EditorVCSInterface.xml4
-rw-r--r--doc/classes/FontFile.xml14
-rw-r--r--doc/classes/GeometryInstance3D.xml10
-rw-r--r--doc/classes/Image.xml31
-rw-r--r--doc/classes/Input.xml14
-rw-r--r--doc/classes/InputEventScreenDrag.xml9
-rw-r--r--doc/classes/ItemList.xml1
-rw-r--r--doc/classes/Label.xml1
-rw-r--r--doc/classes/LineEdit.xml1
-rw-r--r--doc/classes/LinkButton.xml19
-rw-r--r--doc/classes/MenuBar.xml1
-rw-r--r--doc/classes/MenuButton.xml1
-rw-r--r--doc/classes/MeshLibrary.xml27
-rw-r--r--doc/classes/NavigationAgent2D.xml49
-rw-r--r--doc/classes/NavigationAgent3D.xml49
-rw-r--r--doc/classes/NavigationLink2D.xml4
-rw-r--r--doc/classes/NavigationLink3D.xml4
-rw-r--r--doc/classes/NavigationMesh.xml14
-rw-r--r--doc/classes/NavigationMeshGenerator.xml10
-rw-r--r--doc/classes/NavigationObstacle2D.xml2
-rw-r--r--doc/classes/NavigationObstacle3D.xml2
-rw-r--r--doc/classes/NavigationPathQueryParameters2D.xml24
-rw-r--r--doc/classes/NavigationPathQueryParameters3D.xml24
-rw-r--r--doc/classes/NavigationPathQueryResult2D.xml19
-rw-r--r--doc/classes/NavigationPathQueryResult3D.xml19
-rw-r--r--doc/classes/NavigationPolygon.xml14
-rw-r--r--doc/classes/NavigationRegion2D.xml10
-rw-r--r--doc/classes/NavigationRegion3D.xml10
-rw-r--r--doc/classes/NavigationServer2D.xml8
-rw-r--r--doc/classes/NavigationServer3D.xml14
-rw-r--r--doc/classes/Node2D.xml6
-rw-r--r--doc/classes/Node3D.xml6
-rw-r--r--doc/classes/Object.xml2
-rw-r--r--doc/classes/OptionButton.xml5
-rw-r--r--doc/classes/PathFollow3D.xml2
-rw-r--r--doc/classes/PhysicsServer2D.xml32
-rw-r--r--doc/classes/PhysicsServer3D.xml15
-rw-r--r--doc/classes/PhysicsServer3DExtension.xml13
-rw-r--r--doc/classes/PopupMenu.xml1
-rw-r--r--doc/classes/ProgressBar.xml1
-rw-r--r--doc/classes/ProjectSettings.xml17
-rw-r--r--doc/classes/RenderingDevice.xml4
-rw-r--r--doc/classes/RenderingServer.xml12
-rw-r--r--doc/classes/RichTextLabel.xml10
-rw-r--r--doc/classes/String.xml8
-rw-r--r--doc/classes/StringName.xml8
-rw-r--r--doc/classes/TabBar.xml1
-rw-r--r--doc/classes/TabContainer.xml1
-rw-r--r--doc/classes/TextEdit.xml1
-rw-r--r--doc/classes/TextLine.xml2
-rw-r--r--doc/classes/TextParagraph.xml2
-rw-r--r--doc/classes/TextServer.xml14
-rw-r--r--doc/classes/TextServerExtension.xml3
-rw-r--r--doc/classes/TileMap.xml3
-rw-r--r--doc/classes/Tree.xml1
-rw-r--r--doc/classes/TubeTrailMesh.xml6
-rw-r--r--doc/classes/VisualInstance3D.xml7
-rw-r--r--drivers/SCsub1
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp200
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h5
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp28
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp15
-rw-r--r--drivers/gles3/shaders/canvas.glsl219
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl36
-rw-r--r--drivers/gles3/storage/config.cpp2
-rw-r--r--drivers/gles3/storage/config.h2
-rw-r--r--drivers/gles3/storage/light_storage.cpp4
-rw-r--r--drivers/gles3/storage/light_storage.h1
-rw-r--r--drivers/gles3/storage/material_storage.cpp477
-rw-r--r--drivers/gles3/storage/material_storage.h57
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp23
-rw-r--r--drivers/gles3/storage/mesh_storage.h3
-rw-r--r--drivers/gles3/storage/particles_storage.cpp11
-rw-r--r--drivers/gles3/storage/texture_storage.cpp11
-rw-r--r--drivers/unix/os_unix.cpp6
-rw-r--r--drivers/unix/os_unix.h2
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp661
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h14
-rw-r--r--editor/action_map_editor.cpp13
-rw-r--r--editor/action_map_editor.h3
-rw-r--r--editor/animation_bezier_editor.cpp18
-rw-r--r--editor/animation_track_editor.cpp2154
-rw-r--r--editor/animation_track_editor.h102
-rw-r--r--editor/animation_track_editor_plugins.cpp12
-rw-r--r--editor/debugger/editor_debugger_tree.cpp3
-rw-r--r--editor/debugger/editor_profiler.cpp13
-rw-r--r--editor/debugger/editor_profiler.h3
-rw-r--r--editor/debugger/editor_visual_profiler.cpp20
-rw-r--r--editor/debugger/editor_visual_profiler.h3
-rw-r--r--editor/debugger/script_editor_debugger.cpp23
-rw-r--r--editor/editor_data.cpp5
-rw-r--r--editor/editor_file_dialog.cpp2
-rw-r--r--editor/editor_inspector.cpp121
-rw-r--r--editor/editor_inspector.h4
-rw-r--r--editor/editor_layouts_dialog.cpp12
-rw-r--r--editor/editor_log.cpp2
-rw-r--r--editor/editor_node.cpp20
-rw-r--r--editor/editor_node.h4
-rw-r--r--editor/editor_properties.cpp29
-rw-r--r--editor/editor_properties.h10
-rw-r--r--editor/editor_properties_array_dict.cpp10
-rw-r--r--editor/editor_property_name_processor.cpp1
-rw-r--r--editor/editor_spin_slider.cpp143
-rw-r--r--editor/editor_vcs_interface.cpp4
-rw-r--r--editor/editor_vcs_interface.h4
-rw-r--r--editor/fbx_importer_manager.cpp158
-rw-r--r--editor/fbx_importer_manager.h66
-rw-r--r--editor/find_in_files.cpp19
-rw-r--r--editor/import/audio_stream_import_settings.cpp40
-rw-r--r--editor/import/scene_import_settings.cpp7
-rw-r--r--editor/plugin_config_dialog.cpp8
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp35
-rw-r--r--editor/plugins/animation_player_editor_plugin.h28
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp66
-rw-r--r--editor/plugins/animation_state_machine_editor.h11
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp22
-rw-r--r--editor/plugins/audio_stream_editor_plugin.cpp280
-rw-r--r--editor/plugins/audio_stream_editor_plugin.h93
-rw-r--r--editor/plugins/audio_stream_randomizer_editor_plugin.cpp4
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp6
-rw-r--r--editor/plugins/editor_preview_plugins.cpp3
-rw-r--r--editor/plugins/editor_preview_plugins.h20
-rw-r--r--editor/plugins/font_config_plugin.cpp4
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp16
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp12
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp4
-rw-r--r--editor/plugins/script_editor_plugin.cpp4
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp3
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp17
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp5
-rw-r--r--editor/plugins/tiles/tile_proxies_manager_dialog.cpp8
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp107
-rw-r--r--editor/plugins/version_control_editor_plugin.h8
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp6
-rw-r--r--editor/project_manager.cpp2
-rw-r--r--editor/project_settings_editor.cpp10
-rw-r--r--editor/project_settings_editor.h3
-rw-r--r--editor/register_editor_types.cpp2
-rw-r--r--editor/rename_dialog.cpp4
-rw-r--r--editor/scene_tree_dock.cpp41
-rw-r--r--editor/scene_tree_editor.cpp12
-rw-r--r--main/main.cpp2
-rw-r--r--modules/basis_universal/register_types.cpp1
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml1
-rw-r--r--modules/gdscript/gdscript.cpp47
-rw-r--r--modules/gdscript/gdscript.h5
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp792
-rw-r--r--modules/gdscript/gdscript_analyzer.h19
-rw-r--r--modules/gdscript/gdscript_cache.cpp14
-rw-r--r--modules/gdscript/gdscript_cache.h1
-rw-r--r--modules/gdscript/gdscript_codegen.h2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp91
-rw-r--r--modules/gdscript/gdscript_editor.cpp10
-rw-r--r--modules/gdscript/gdscript_parser.cpp52
-rw-r--r--modules/gdscript/gdscript_parser.h83
-rw-r--r--modules/gdscript/gdscript_vm.cpp20
-rw-r--r--modules/gdscript/gdscript_warning.cpp5
-rw-r--r--modules/gdscript/gdscript_warning.h1
-rw-r--r--modules/gdscript/language_server/godot_lsp.h2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.gd8
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external_a.notest.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.gd12
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.gd12
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/cast_non_null.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/cast_non_null.out3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/enum_as_const.gd29
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/enum_as_const.out17
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.out3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.gd7
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant_external.notest.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/out_of_order.gd51
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/out_of_order.out15
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.gd39
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.out15
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/out_of_order_external_a.notest.gd12
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/void_assignment.out5
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.gd4
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.gd4
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.gd4
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd8
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/typed_assignment.gd9
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/typed_assignment.out12
-rw-r--r--modules/gltf/editor/editor_scene_importer_fbx.cpp27
-rw-r--r--modules/gltf/editor/editor_scene_importer_fbx.h11
-rw-r--r--modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp1
-rw-r--r--modules/gltf/gltf_document.cpp316
-rw-r--r--modules/gltf/register_types.cpp17
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml23
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp1
-rw-r--r--modules/gridmap/grid_map.cpp141
-rw-r--r--modules/gridmap/grid_map.h19
-rw-r--r--modules/mono/csharp_script.cpp4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs31
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs9
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs6
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs4
-rw-r--r--modules/mono/editor/bindings_generator.cpp6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs167
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs91
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs20
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs2
-rw-r--r--modules/mono/glue/runtime_interop.cpp8
-rw-r--r--modules/navigation/godot_navigation_server.cpp46
-rw-r--r--modules/navigation/godot_navigation_server.h4
-rw-r--r--modules/navigation/nav_base.h4
-rw-r--r--modules/navigation/nav_link.h4
-rw-r--r--modules/navigation/nav_map.cpp85
-rw-r--r--modules/navigation/nav_map.h4
-rw-r--r--modules/navigation/nav_region.h4
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp102
-rw-r--r--modules/navigation/navigation_mesh_generator.h8
-rw-r--r--modules/noise/noise_texture_2d.cpp1
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.cpp13
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.h2
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.cpp2
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.cpp6
-rw-r--r--modules/openxr/editor/openxr_select_action_dialog.cpp4
-rw-r--r--modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp4
-rw-r--r--modules/openxr/extensions/openxr_android_extension.cpp2
-rw-r--r--modules/raycast/SCsub12
-rw-r--r--modules/svg/image_loader_svg.cpp23
-rw-r--r--modules/svg/image_loader_svg.h1
-rw-r--r--modules/text_server_adv/text_server_adv.cpp120
-rw-r--r--modules/text_server_adv/text_server_adv.h7
-rw-r--r--modules/text_server_fb/text_server_fb.cpp97
-rw-r--r--modules/text_server_fb/text_server_fb.h7
-rw-r--r--platform/android/api/jni_singleton.h23
-rw-r--r--platform/android/export/export_plugin.cpp138
-rw-r--r--platform/android/export/export_plugin.h2
-rw-r--r--platform/android/export/gradle_export_util.cpp58
-rw-r--r--platform/android/export/gradle_export_util.h16
-rw-r--r--platform/android/java/app/AndroidManifest.xml1
-rw-r--r--platform/android/java/editor/src/main/AndroidManifest.xml8
-rw-r--r--platform/android/java/editor/src/main/res/values/themes.xml5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java2
-rw-r--r--platform/android/jni_utils.cpp35
-rw-r--r--platform/ios/display_server_ios.h4
-rw-r--r--platform/ios/display_server_ios.mm38
-rw-r--r--platform/ios/godot_view.mm6
-rw-r--r--platform/ios/os_ios.h2
-rw-r--r--platform/ios/os_ios.mm45
-rw-r--r--platform/linuxbsd/detect.py3
-rw-r--r--platform/linuxbsd/tts_linux.cpp11
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp101
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h4
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c2
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h2
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c4
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h4
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c2
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h2
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c2
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h2
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c2
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h2
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c2
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h2
-rw-r--r--platform/macos/display_server_macos.h6
-rw-r--r--platform/macos/display_server_macos.mm41
-rw-r--r--platform/macos/export/plist.cpp290
-rw-r--r--platform/macos/export/plist.h25
-rw-r--r--platform/macos/godot_content_view.mm32
-rw-r--r--platform/macos/godot_window_delegate.h2
-rw-r--r--platform/macos/godot_window_delegate.mm65
-rw-r--r--platform/macos/os_macos.mm32
-rw-r--r--platform/windows/display_server_windows.cpp58
-rw-r--r--platform/windows/display_server_windows.h6
-rw-r--r--platform/windows/export/export_plugin.cpp2
-rw-r--r--platform/windows/os_windows.cpp7
-rw-r--r--platform/windows/platform_windows_builders.py13
-rw-r--r--scene/2d/collision_object_2d.cpp1
-rw-r--r--scene/2d/cpu_particles_2d.cpp1
-rw-r--r--scene/2d/gpu_particles_2d.cpp1
-rw-r--r--scene/2d/joint_2d.cpp5
-rw-r--r--scene/2d/light_2d.cpp1
-rw-r--r--scene/2d/light_occluder_2d.cpp3
-rw-r--r--scene/2d/line_builder.cpp4
-rw-r--r--scene/2d/multimesh_instance_2d.cpp10
-rw-r--r--scene/2d/navigation_agent_2d.cpp94
-rw-r--r--scene/2d/navigation_agent_2d.h25
-rw-r--r--scene/2d/navigation_link_2d.cpp1
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp1
-rw-r--r--scene/2d/navigation_region_2d.cpp389
-rw-r--r--scene/2d/navigation_region_2d.h71
-rw-r--r--scene/2d/node_2d.cpp22
-rw-r--r--scene/2d/node_2d.h4
-rw-r--r--scene/2d/polygon_2d.cpp1
-rw-r--r--scene/2d/skeleton_2d.cpp2
-rw-r--r--scene/2d/tile_map.cpp59
-rw-r--r--scene/3d/camera_3d.cpp2
-rw-r--r--scene/3d/collision_object_3d.cpp6
-rw-r--r--scene/3d/collision_shape_3d.cpp11
-rw-r--r--scene/3d/cpu_particles_3d.cpp1
-rw-r--r--scene/3d/decal.cpp1
-rw-r--r--scene/3d/fog_volume.cpp1
-rw-r--r--scene/3d/gpu_particles_3d.cpp1
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp2
-rw-r--r--scene/3d/joint_3d.cpp1
-rw-r--r--scene/3d/label_3d.cpp1
-rw-r--r--scene/3d/light_3d.cpp1
-rw-r--r--scene/3d/lightmap_gi.cpp1
-rw-r--r--scene/3d/mesh_instance_3d.cpp18
-rw-r--r--scene/3d/mesh_instance_3d.h2
-rw-r--r--scene/3d/navigation_agent_3d.cpp94
-rw-r--r--scene/3d/navigation_agent_3d.h25
-rw-r--r--scene/3d/navigation_link_3d.cpp2
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp1
-rw-r--r--scene/3d/navigation_region_3d.cpp66
-rw-r--r--scene/3d/navigation_region_3d.h11
-rw-r--r--scene/3d/node_3d.cpp30
-rw-r--r--scene/3d/node_3d.h4
-rw-r--r--scene/3d/occluder_instance_3d.cpp15
-rw-r--r--scene/3d/path_3d.cpp1
-rw-r--r--scene/3d/physics_body_3d.cpp10
-rw-r--r--scene/3d/physics_body_3d.h2
-rw-r--r--scene/3d/reflection_probe.cpp1
-rw-r--r--scene/3d/skeleton_3d.cpp2
-rw-r--r--scene/3d/soft_body_3d.cpp1
-rw-r--r--scene/3d/sprite_3d.cpp5
-rw-r--r--scene/3d/visible_on_screen_notifier_3d.cpp1
-rw-r--r--scene/3d/visual_instance_3d.cpp48
-rw-r--r--scene/3d/visual_instance_3d.h12
-rw-r--r--scene/3d/voxel_gi.cpp2
-rw-r--r--scene/animation/animation_blend_tree.cpp24
-rw-r--r--scene/animation/animation_node_state_machine.cpp85
-rw-r--r--scene/animation/animation_node_state_machine.h21
-rw-r--r--scene/animation/animation_player.cpp37
-rw-r--r--scene/animation/animation_tree.cpp13
-rw-r--r--scene/gui/base_button.cpp12
-rw-r--r--scene/gui/base_button.h2
-rw-r--r--scene/gui/code_edit.cpp24
-rw-r--r--scene/gui/color_picker.cpp3
-rw-r--r--scene/gui/color_picker.h4
-rw-r--r--scene/gui/control.cpp11
-rw-r--r--scene/gui/control.h2
-rw-r--r--scene/gui/file_dialog.cpp2
-rw-r--r--scene/gui/line_edit.cpp4
-rw-r--r--scene/gui/link_button.cpp19
-rw-r--r--scene/gui/link_button.h4
-rw-r--r--scene/gui/menu_bar.cpp1
-rw-r--r--scene/gui/rich_text_label.cpp79
-rw-r--r--scene/gui/rich_text_label.h6
-rw-r--r--scene/gui/tab_bar.cpp31
-rw-r--r--scene/gui/tree.cpp70
-rw-r--r--scene/main/canvas_item.cpp26
-rw-r--r--scene/main/canvas_item.h2
-rw-r--r--scene/main/canvas_layer.cpp14
-rw-r--r--scene/main/canvas_layer.h1
-rw-r--r--scene/main/scene_tree.cpp11
-rw-r--r--scene/main/viewport.cpp8
-rw-r--r--scene/main/window.cpp3
-rw-r--r--scene/register_scene_types.cpp2
-rw-r--r--scene/resources/animation.cpp50
-rw-r--r--scene/resources/animation.h9
-rw-r--r--scene/resources/bit_map.cpp2
-rw-r--r--scene/resources/camera_attributes.cpp1
-rw-r--r--scene/resources/canvas_item_material.cpp2
-rw-r--r--scene/resources/curve.cpp6
-rw-r--r--scene/resources/default_theme/default_theme.cpp12
-rw-r--r--scene/resources/environment.cpp1
-rw-r--r--scene/resources/fog_material.cpp1
-rw-r--r--scene/resources/font.cpp90
-rw-r--r--scene/resources/font.h39
-rw-r--r--scene/resources/gradient.cpp4
-rw-r--r--scene/resources/gradient.h2
-rw-r--r--scene/resources/immediate_mesh.cpp1
-rw-r--r--scene/resources/importer_mesh.cpp22
-rw-r--r--scene/resources/material.cpp2
-rw-r--r--scene/resources/mesh.cpp24
-rw-r--r--scene/resources/mesh.h1
-rw-r--r--scene/resources/mesh_library.cpp77
-rw-r--r--scene/resources/mesh_library.h17
-rw-r--r--scene/resources/multimesh.cpp2
-rw-r--r--scene/resources/navigation_mesh.cpp51
-rw-r--r--scene/resources/navigation_mesh.h12
-rw-r--r--scene/resources/navigation_polygon.cpp354
-rw-r--r--scene/resources/navigation_polygon.h94
-rw-r--r--scene/resources/particle_process_material.cpp1
-rw-r--r--scene/resources/primitive_meshes.cpp198
-rw-r--r--scene/resources/primitive_meshes.h8
-rw-r--r--scene/resources/shader.cpp1
-rw-r--r--scene/resources/sky.cpp1
-rw-r--r--scene/resources/surface_tool.cpp2
-rw-r--r--scene/resources/text_line.cpp12
-rw-r--r--scene/resources/text_line.h4
-rw-r--r--scene/resources/text_paragraph.cpp12
-rw-r--r--scene/resources/text_paragraph.h4
-rw-r--r--scene/resources/texture.cpp49
-rw-r--r--scene/resources/tile_set.cpp56
-rw-r--r--scene/resources/tile_set.h2
-rw-r--r--scene/resources/visual_shader.cpp4
-rw-r--r--scene/resources/world_2d.cpp3
-rw-r--r--scene/resources/world_3d.cpp3
-rw-r--r--scene/theme/theme_db.cpp7
-rw-r--r--scene/theme/theme_owner.cpp69
-rw-r--r--scene/theme/theme_owner.h1
-rw-r--r--servers/audio/audio_stream.cpp6
-rw-r--r--servers/audio/audio_stream.h2
-rw-r--r--servers/audio_server.cpp8
-rw-r--r--servers/camera/camera_feed.cpp1
-rw-r--r--servers/display_server.cpp2
-rw-r--r--servers/display_server.h2
-rw-r--r--servers/display_server_headless.h2
-rw-r--r--servers/extensions/physics_server_3d_extension.cpp3
-rw-r--r--servers/navigation/navigation_path_query_parameters_2d.cpp22
-rw-r--r--servers/navigation/navigation_path_query_parameters_2d.h12
-rw-r--r--servers/navigation/navigation_path_query_parameters_3d.cpp18
-rw-r--r--servers/navigation/navigation_path_query_parameters_3d.h12
-rw-r--r--servers/navigation/navigation_path_query_result_2d.cpp42
-rw-r--r--servers/navigation/navigation_path_query_result_2d.h19
-rw-r--r--servers/navigation/navigation_path_query_result_3d.cpp42
-rw-r--r--servers/navigation/navigation_path_query_result_3d.h20
-rw-r--r--servers/navigation/navigation_utilities.h18
-rw-r--r--servers/navigation_server_2d.cpp11
-rw-r--r--servers/navigation_server_2d.h4
-rw-r--r--servers/navigation_server_3d.cpp9
-rw-r--r--servers/navigation_server_3d.h4
-rw-r--r--servers/physics_2d/godot_body_pair_2d.cpp8
-rw-r--r--servers/physics_3d/godot_body_pair_3d.cpp10
-rw-r--r--servers/physics_3d/godot_collision_solver_3d.cpp4
-rw-r--r--servers/physics_3d/godot_space_3d.cpp1
-rw-r--r--servers/physics_server_2d.cpp6
-rw-r--r--servers/physics_server_3d.cpp3
-rw-r--r--servers/physics_server_3d.h1
-rw-r--r--servers/rendering/dummy/rasterizer_scene_dummy.h1
-rw-r--r--servers/rendering/dummy/storage/light_storage.h1
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp4
-rw-r--r--servers/rendering/renderer_canvas_cull.h2
-rw-r--r--servers/rendering/renderer_geometry_instance.cpp5
-rw-r--r--servers/rendering/renderer_geometry_instance.h8
-rw-r--r--servers/rendering/renderer_rd/SCsub1
-rw-r--r--servers/rendering/renderer_rd/environment/fog.cpp91
-rw-r--r--servers/rendering/renderer_rd/environment/fog.h9
-rw-r--r--servers/rendering/renderer_rd/environment/gi.cpp6
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp462
-rw-r--r--servers/rendering/renderer_rd/environment/sky.h76
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp239
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h11
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp105
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h10
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp139
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h10
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp93
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h12
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp96
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h10
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp9
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp109
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h8
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl16
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/gi.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sky.glsl61
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl13
-rw-r--r--servers/rendering/renderer_rd/spirv-reflect/SCsub (renamed from drivers/spirv-reflect/SCsub)2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.cpp25
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.h4
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp109
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.h22
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp21
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.h2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp108
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.h18
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp24
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h1
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp66
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h3
-rw-r--r--servers/rendering/renderer_scene_cull.cpp25
-rw-r--r--servers/rendering/renderer_scene_cull.h9
-rw-r--r--servers/rendering/renderer_scene_occlusion_cull.cpp2
-rw-r--r--servers/rendering/rendering_device.cpp329
-rw-r--r--servers/rendering/rendering_device.h43
-rw-r--r--servers/rendering/rendering_method.h1
-rw-r--r--servers/rendering/rendering_server_default.h3
-rw-r--r--servers/rendering/shader_compiler.cpp5
-rw-r--r--servers/rendering/shader_language.cpp37
-rw-r--r--servers/rendering/shader_language.h8
-rw-r--r--servers/rendering/storage/environment_storage.cpp2
-rw-r--r--servers/rendering/storage/light_storage.h2
-rw-r--r--servers/rendering_server.cpp3
-rw-r--r--servers/rendering_server.h3
-rw-r--r--servers/text/text_server_extension.cpp18
-rw-r--r--servers/text/text_server_extension.h12
-rw-r--r--servers/text_server.cpp6
-rw-r--r--servers/text_server.h6
-rw-r--r--servers/xr/xr_interface.cpp1
-rw-r--r--tests/core/config/test_project_settings.h102
-rw-r--r--tests/core/object/test_object.h78
-rw-r--r--tests/scene/test_code_edit.h86
-rw-r--r--tests/scene/test_gradient.h10
-rw-r--r--tests/scene/test_node.h415
-rw-r--r--tests/scene/test_visual_shader.h151
-rw-r--r--tests/servers/test_text_server.h48
-rw-r--r--tests/test_main.cpp3
-rw-r--r--thirdparty/README.md8
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh42
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh9
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh35
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh4
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh4
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh4
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh4
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh26
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh27
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh20
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh4
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh4
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh4
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh8
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh20
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh67
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/Glyph.hh139
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh49
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh10
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh353
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/composite-iter.hh68
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/coord-setter.hh34
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/glyf.hh66
-rw-r--r--thirdparty/harfbuzz/src/graph/classdef-graph.hh2
-rw-r--r--thirdparty/harfbuzz/src/graph/coverage-graph.hh2
-rw-r--r--thirdparty/harfbuzz/src/graph/graph.hh149
-rw-r--r--thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh6
-rw-r--r--thirdparty/harfbuzz/src/graph/markbasepos-graph.hh10
-rw-r--r--thirdparty/harfbuzz/src/graph/pairpos-graph.hh6
-rw-r--r--thirdparty/harfbuzz/src/graph/serialize.hh23
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-map.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-algs.hh137
-rw-r--r--thirdparty/harfbuzz/src/hb-array.hh94
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-page.hh90
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-set-invertible.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-set.hh72
-rw-r--r--thirdparty/harfbuzz/src/hb-blob.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh12
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh490
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer-serialize.cc8
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer-verify.cc5
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.cc99
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.hh11
-rw-r--r--thirdparty/harfbuzz/src/hb-cache.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-cff-interp-common.hh95
-rw-r--r--thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh16
-rw-r--r--thirdparty/harfbuzz/src/hb-common.cc14
-rw-r--r--thirdparty/harfbuzz/src/hb-config.hh14
-rw-r--r--thirdparty/harfbuzz/src/hb-coretext.cc13
-rw-r--r--thirdparty/harfbuzz/src/hb-draw.cc91
-rw-r--r--thirdparty/harfbuzz/src/hb-face.cc17
-rw-r--r--thirdparty/harfbuzz/src/hb-face.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-fallback-shape.cc10
-rw-r--r--thirdparty/harfbuzz/src/hb-font.cc154
-rw-r--r--thirdparty/harfbuzz/src/hb-font.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-ft.cc32
-rw-r--r--thirdparty/harfbuzz/src/hb-glib.cc77
-rw-r--r--thirdparty/harfbuzz/src/hb-graphite2.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-iter.hh16
-rw-r--r--thirdparty/harfbuzz/src/hb-machinery.hh14
-rw-r--r--thirdparty/harfbuzz/src/hb-map.hh219
-rw-r--r--thirdparty/harfbuzz/src/hb-meta.hh3
-rw-r--r--thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-multimap.hh92
-rw-r--r--thirdparty/harfbuzz/src/hb-mutex.hh7
-rw-r--r--thirdparty/harfbuzz/src/hb-number-parser.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-object.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-open-file.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-open-type.hh67
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff-common.hh156
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff1-table.hh10
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff2-table.hh11
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cmap-table.hh224
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh113
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-face-table-list.hh28
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-font.cc5
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-common.hh350
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh258
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.cc112
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.hh7
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-map.cc79
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-map.hh16
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-math-table.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-meta-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-name-table.hh211
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-name.cc51
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-os2-table.hh23
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-post-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc19
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-default.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh610
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc21
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc73
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh16
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-khmer.cc21
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh16
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-myanmar.cc48
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc12
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-thai.cc6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh16
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh270
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-use.cc33
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-stat-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-tag.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-common.hh21
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh12
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh229
-rw-r--r--thirdparty/harfbuzz/src/hb-pool.hh12
-rw-r--r--thirdparty/harfbuzz/src/hb-priority-queue.hh14
-rw-r--r--thirdparty/harfbuzz/src/hb-repacker.hh27
-rw-r--r--thirdparty/harfbuzz/src/hb-sanitize.hh15
-rw-r--r--thirdparty/harfbuzz/src/hb-serialize.hh64
-rw-r--r--thirdparty/harfbuzz/src/hb-set-digest.hh35
-rw-r--r--thirdparty/harfbuzz/src/hb-set.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-shape-plan.cc7
-rw-r--r--thirdparty/harfbuzz/src/hb-shape.cc5
-rw-r--r--thirdparty/harfbuzz/src/hb-shaper.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-static.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-accelerator.hh61
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff-common.cc11
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff-common.hh491
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff1.cc38
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff2.cc23
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-input.cc141
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-input.hh55
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.cc108
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.hh39
-rw-r--r--thirdparty/harfbuzz/src/hb-subset.cc95
-rw-r--r--thirdparty/harfbuzz/src/hb-subset.h17
-rw-r--r--thirdparty/harfbuzz/src/hb-ucd-table.hh2564
-rw-r--r--thirdparty/harfbuzz/src/hb-ucd.cc16
-rw-r--r--thirdparty/harfbuzz/src/hb-unicode.cc26
-rw-r--r--thirdparty/harfbuzz/src/hb-uniscribe.cc6
-rw-r--r--thirdparty/harfbuzz/src/hb-vector.hh100
-rw-r--r--thirdparty/harfbuzz/src/hb-version.h8
-rw-r--r--thirdparty/harfbuzz/src/hb.hh1
-rw-r--r--thirdparty/libpng/arm/arm_init.c5
-rw-r--r--thirdparty/libpng/png.c6
-rw-r--r--thirdparty/libpng/png.h16
-rw-r--r--thirdparty/libpng/pngconf.h2
-rw-r--r--thirdparty/libpng/pnglibconf.h2
-rw-r--r--thirdparty/libpng/pngpriv.h2
-rw-r--r--thirdparty/libpng/pngread.c4
-rw-r--r--thirdparty/libpng/pngrutil.c2
-rw-r--r--thirdparty/libpng/pngwrite.c8
-rw-r--r--thirdparty/libpng/pngwutil.c6
-rw-r--r--thirdparty/mbedtls/include/mbedtls/asn1write.h2
-rw-r--r--thirdparty/mbedtls/include/mbedtls/bignum.h69
-rw-r--r--thirdparty/mbedtls/include/mbedtls/bn_mul.h32
-rw-r--r--thirdparty/mbedtls/include/mbedtls/check_config.h30
-rw-r--r--thirdparty/mbedtls/include/mbedtls/config.h15
-rw-r--r--thirdparty/mbedtls/include/mbedtls/ecdsa.h4
-rw-r--r--thirdparty/mbedtls/include/mbedtls/md.h2
-rw-r--r--thirdparty/mbedtls/include/mbedtls/platform.h7
-rw-r--r--thirdparty/mbedtls/include/mbedtls/ripemd160.h2
-rw-r--r--thirdparty/mbedtls/include/mbedtls/rsa.h2
-rw-r--r--thirdparty/mbedtls/include/mbedtls/ssl.h6
-rw-r--r--thirdparty/mbedtls/include/mbedtls/ssl_internal.h2
-rw-r--r--thirdparty/mbedtls/include/mbedtls/version.h8
-rw-r--r--thirdparty/mbedtls/library/aes.c12
-rw-r--r--thirdparty/mbedtls/library/arc4.c7
-rw-r--r--thirdparty/mbedtls/library/aria.c61
-rw-r--r--thirdparty/mbedtls/library/asn1parse.c6
-rw-r--r--thirdparty/mbedtls/library/asn1write.c12
-rw-r--r--thirdparty/mbedtls/library/base64.c5
-rw-r--r--thirdparty/mbedtls/library/bignum.c230
-rw-r--r--thirdparty/mbedtls/library/camellia.c7
-rw-r--r--thirdparty/mbedtls/library/ccm.c7
-rw-r--r--thirdparty/mbedtls/library/chacha20.c12
-rw-r--r--thirdparty/mbedtls/library/chachapoly.c7
-rw-r--r--thirdparty/mbedtls/library/cipher.c5
-rw-r--r--thirdparty/mbedtls/library/cipher_wrap.c6
-rw-r--r--thirdparty/mbedtls/library/common.h45
-rw-r--r--thirdparty/mbedtls/library/constant_time.c11
-rw-r--r--thirdparty/mbedtls/library/constant_time_internal.h9
-rw-r--r--thirdparty/mbedtls/library/ctr_drbg.c7
-rw-r--r--thirdparty/mbedtls/library/debug.c14
-rw-r--r--thirdparty/mbedtls/library/des.c7
-rw-r--r--thirdparty/mbedtls/library/dhm.c8
-rw-r--r--thirdparty/mbedtls/library/ecdh.c6
-rw-r--r--thirdparty/mbedtls/library/ecdsa.c6
-rw-r--r--thirdparty/mbedtls/library/ecjpake.c5
-rw-r--r--thirdparty/mbedtls/library/ecp.c55
-rw-r--r--thirdparty/mbedtls/library/ecp_curves.c5
-rw-r--r--thirdparty/mbedtls/library/entropy.c9
-rw-r--r--thirdparty/mbedtls/library/entropy_poll.c2
-rw-r--r--thirdparty/mbedtls/library/error.c6
-rw-r--r--thirdparty/mbedtls/library/gcm.c10
-rw-r--r--thirdparty/mbedtls/library/hmac_drbg.c7
-rw-r--r--thirdparty/mbedtls/library/md.c6
-rw-r--r--thirdparty/mbedtls/library/md2.c7
-rw-r--r--thirdparty/mbedtls/library/md4.c7
-rw-r--r--thirdparty/mbedtls/library/md5.c7
-rw-r--r--thirdparty/mbedtls/library/mps_reader.c7
-rw-r--r--thirdparty/mbedtls/library/mps_trace.h6
-rw-r--r--thirdparty/mbedtls/library/net_sockets.c4
-rw-r--r--thirdparty/mbedtls/library/nist_kw.c7
-rw-r--r--thirdparty/mbedtls/library/oid.c4
-rw-r--r--thirdparty/mbedtls/library/pem.c6
-rw-r--r--thirdparty/mbedtls/library/pk_wrap.c8
-rw-r--r--thirdparty/mbedtls/library/pkcs11.c6
-rw-r--r--thirdparty/mbedtls/library/pkcs5.c5
-rw-r--r--thirdparty/mbedtls/library/pkparse.c6
-rw-r--r--thirdparty/mbedtls/library/pkwrite.c6
-rw-r--r--thirdparty/mbedtls/library/poly1305.c12
-rw-r--r--thirdparty/mbedtls/library/ripemd160.c7
-rw-r--r--thirdparty/mbedtls/library/rsa.c7
-rw-r--r--thirdparty/mbedtls/library/sha1.c7
-rw-r--r--thirdparty/mbedtls/library/sha256.c10
-rw-r--r--thirdparty/mbedtls/library/sha512.c14
-rw-r--r--thirdparty/mbedtls/library/ssl_cache.c6
-rw-r--r--thirdparty/mbedtls/library/ssl_ciphersuites.c4
-rw-r--r--thirdparty/mbedtls/library/ssl_cli.c94
-rw-r--r--thirdparty/mbedtls/library/ssl_cookie.c5
-rw-r--r--thirdparty/mbedtls/library/ssl_msg.c25
-rw-r--r--thirdparty/mbedtls/library/ssl_srv.c24
-rw-r--r--thirdparty/mbedtls/library/ssl_ticket.c42
-rw-r--r--thirdparty/mbedtls/library/ssl_tls.c79
-rw-r--r--thirdparty/mbedtls/library/ssl_tls13_keys.c8
-rw-r--r--thirdparty/mbedtls/library/timing.c7
-rw-r--r--thirdparty/mbedtls/library/x509.c52
-rw-r--r--thirdparty/mbedtls/library/x509_crl.c10
-rw-r--r--thirdparty/mbedtls/library/x509_crt.c46
-rw-r--r--thirdparty/mbedtls/library/x509_csr.c8
-rw-r--r--thirdparty/mbedtls/library/x509write_csr.c6
-rw-r--r--thirdparty/mbedtls/library/xtea.c9
-rw-r--r--thirdparty/mbedtls/patches/1453.diff28
-rw-r--r--thirdparty/mbedtls/patches/windows-arm64-hardclock.diff16
846 files changed, 18314 insertions, 11598 deletions
diff --git a/.gitignore b/.gitignore
index 1292be06fd..ca96220570 100644
--- a/.gitignore
+++ b/.gitignore
@@ -242,8 +242,10 @@ xcuserdata/
[Rr]eleases/
x64/
x86/
-# Not build results, this is Theora source code.
-!thirdparty/libtheora/x86/
+
+# Do not ignore x86 folders anywhere under thirdparty libraries
+!thirdparty/**/x86/
+
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
diff --git a/.mailmap b/.mailmap
index 4976c96ba9..aa57299278 100644
--- a/.mailmap
+++ b/.mailmap
@@ -2,6 +2,7 @@ Aaron Record <aaronjrecord@gmail.com>
Alexander Holland <alexander.holland@live.de>
Alexander Holland <alexander.holland@live.de> <alexander.holland@haw-hamburg.de>
Alexander Holland <alexander.holland@live.de> <AlexHolly>
+Alfred Reinold Baudisch <alfred@alfredbaudisch.com>
Andrea Catania <info@andreacatania.com>
Anish Bhobe <anishbhobe@hotmail.com>
Anutrix <numaanzaheerahmed@yahoo.com>
@@ -26,6 +27,7 @@ dankan1890 <mewuidev2@gmail.com>
Daniel J. Ramirez <djrmuv@gmail.com>
David Cambré <david.cambre@gmail.com> <David.Cambre@gmail.com>
Dominik 'dreamsComeTrue' Jasiński <dominikjasinski@o2.pl>
+DeeJayLSP <djlsplays@gmail.com> <60024671+DeeJayLSP@users.noreply.github.com>
Emmanuel Barroga <emmanuelbarroga@gmail.com>
Eric M <itsjusteza@gmail.com>
Eric Rybicki <info@ericrybicki.com> <stratos695@googlemail.com>
@@ -41,6 +43,7 @@ foxydevloper <12120644+foxydevloper@users.noreply.github.com>
Fredia Huya-Kouadio <fhuyakou@gmail.com>
Fredia Huya-Kouadio <fhuyakou@gmail.com> <fhuya@google.com>
Fredia Huya-Kouadio <fhuyakou@gmail.com> <fhuya@fb.com>
+Fredia Huya-Kouadio <fhuyakou@gmail.com> <fhuya@meta.com>
Geequlim <geequlim@gmail.com>
Gilles Roudiere <gilles.roudiere@gmail.com>
Gilles Roudiere <gilles.roudiere@gmail.com> <gilles.roudiere@laas.fr>
@@ -112,6 +115,7 @@ Nils ANDRÉ-CHANG <nils@nilsand.re> <nils.andre.chang@gmail.com>
Nuno Donato <nunodonato@gmail.com> <n.donato@estrelasustentavel.pt>
Pawel Kowal <pkowal1982@gmail.com>
Pedro J. Estébanez <pedrojrulez@gmail.com> <RandomShaper@users.noreply.github.com>
+Patrick <firefly2442@gmail.com>
Paul Batty <p_batty@hotmail.co.uk>
Paul Batty <p_batty@hotmail.co.uk> <Paulb23@users.noreply.github.com>
Pawel Kowal <pkowal1982@gmail.com> <pawel.kowal@javart.eu>
@@ -131,14 +135,18 @@ Rémi Verschelde <rverschelde@gmail.com> <remi@verschelde.fr>
Rhody Lugo <rhodylugo@gmail.com> <rhodylugo@me.com>
Ricardo Subtil <ricasubtil@gmail.com>
Rindbee <idleman@yeah.net>
+Riteo Siuga <riteo@posteo.net>
Robin Hübner <profan@prfn.se> <robinhubner@gmail.com>
romulox_x <romulox_x@yahoo.com>
+rune-scape <allie.smith.epic@gmail.com>
+rune-scape <allie.smith.epic@gmail.com> <spartacrafter@gmail.com>
Ruslan Mustakov <r.mustakov@gmail.com> <ruslan.mustakov@xored.com>
Saracen <SaracenOne@gmail.com>
sheepandshepherd <sheepandshepherd@hotmail.com> <sheepandshepherd@users.noreply.github.com>
Silc 'Tokage' Renew <tokage.it.lab@gmail.com>
Silc 'Tokage' Renew <tokage.it.lab@gmail.com> <61938263+TokageItLab@users.noreply.github.com>
Swarnim Arun <swarnimarun11@gmail.com>
+TechnoPorg <jonah.janzen@gmail.com> <69441745+TechnoPorg@users.noreply.github.com>
Theo Hallenius <redsymbzone@hotmail.com>
Tomasz Chabora <kobewi4e@gmail.com>
Twarit <wtwarit@gmail.com>
diff --git a/AUTHORS.md b/AUTHORS.md
index 6f6ac48db2..7079180274 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -29,8 +29,10 @@ name is available.
Aaron Franke (aaronfranke)
Aaron Record (LightningAA)
+ Adam Scott (adamscott)
Alexander Holland (AlexHolly)
Alexey Khoroshavin (allkhor)
+ Alfred Reinold Baudisch (alfredbaudisch)
Alket Rexhepi (alketii)
Andrea Catania (AndreaCatania)
Andrii Doroshenko (Xrayez)
@@ -64,6 +66,7 @@ name is available.
Dana Olson (adolson)
Daniel J. Ramirez (djrm)
Daniel Rakos (aqnuep)
+ Daniel Zilberleyb (dzil123)
Danil Alexeev (dalexeev)
dankan1890
David Cambré (Gallilus)
@@ -72,6 +75,7 @@ name is available.
Dharkael (lupoDharkael)
Dmitry Koteroff (Krakean)
Dominik Jasiński (dreamsComeTrue)
+ Douglas Leão (DeeJayLSP)
DualMatrix
Ellen Poe (ellenhp)
Emmanuel Barroga (codecustard)
@@ -118,13 +122,16 @@ name is available.
Jake Young (Duroxxigar)
Jakub Grzesik (kubecz3k)
James Buck (jbuck3)
+ Jason Knight (jasonwinterpixel)
Jean-Michel Bernard (jmb462)
Jérôme Gully (Nutriz)
Jia Jun Chai (SkyLucilfer)
Joan Fons Sanchez (JFonS)
Johan Manuel (29jm)
Johannes Witt (HaSa1002)
+ Jonathan Nicholl (jtnicholl)
Jordan Schidlowsky (winterpixelgames)
+ Josh Jones (DarkKilauea)
Joshua Grams (JoshuaGrams)
Juan Linietsky (reduz)
Julian Murgia (StraToN)
@@ -180,6 +187,7 @@ name is available.
Nathan Lovato (NathanLovato)
Nathan Warden (NathanWarden)
Nicholas Huelin (SirQuartz)
+ Nikita Lita (nikitalita)
Nils André-Chang (NilsIrl)
Noah Beard (TwistedTwigleg)
Nuno Donato (nunodonato)
@@ -210,9 +218,11 @@ name is available.
Rhody Lugo (rraallvv)
Ricardo Buring (rburing)
Ricardo Subtil (Ev1lbl0w)
+ Riteo Siuga (Riteo)
Roberto F. Arroyo (robfram)
Robin Hübner (profan)
romulox-x
+ Rune Smith (rune-scape)
Ruslan Mustakov (endragor)
Ryan Roden-Corrent (rrcore)
Saniko (sanikoyes)
@@ -227,6 +237,7 @@ name is available.
Stijn Hinlopen (hinlopen)
Swarnim Arun (minraws)
TC (floppyhammer)
+ TechnoPorg
Thakee Nathees (ThakeeNathees)
thebestnom
Theo Hallenius (TheoXD)
diff --git a/DONORS.md b/DONORS.md
index 04b4352b0e..5ce096b778 100644
--- a/DONORS.md
+++ b/DONORS.md
@@ -13,6 +13,7 @@ generous deed immortalized in the next stable release of Godot Engine.
## Platinum sponsors
Gamblify <https://www.gamblify.com>
+ Heroic Labs <https://heroiclabs.com>
Spiffcode <http://spiffcode.com>
## Gold sponsors
@@ -25,20 +26,24 @@ generous deed immortalized in the next stable release of Godot Engine.
ASIFA-Hollywood <https://www.asifa-hollywood.org>
Playful Studios <https://playfulstudios.com>
Robot Gentleman <http://robotgentleman.com>
+ Striked <https://developers.join-striked.com>
## Bronze sponsors
Basically Games
+ Bippinbits <https://bippinbits.com>
Brandon Lamb
Bri
Garry Newman
Gordon MacPherson
Hunter Dickson
Isaiah smith
+ Jb Evain
Keepsake Games <https://keepsake.games>
Kenney <https://kenney.nl>
Kitcat490
Kyle Szklenski
+ Matthew Campbell
Maxim Karsten
Moonwards <https://www.moonwards.com>
Nik Rudenko
@@ -49,12 +54,12 @@ generous deed immortalized in the next stable release of Godot Engine.
AD Ford
Albin Lundahl
Andres Hernandez
- Andrew Bowen
Andrew Dunai
anti666
Christian Baune
Christopher Montesano
Christopher Shifflett
+ Christoph Woinke
Daniel Edwards
Darrin Massena
David Mydlarz
@@ -68,6 +73,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Justin Arnold
Justo Delgado Baudí
Kossi Selom Banybah
+ Lloyd Bond
Marcel Kräml
Marek Belski
Markus Ort
@@ -75,13 +81,13 @@ generous deed immortalized in the next stable release of Godot Engine.
Michael
Mike King
Nassor Paulino da Silva
+ nate-wilkins
Nathan Warden
Neal Gompa (Conan Kudo)
Ninja_5tyl3
Patrick Horn
Patrick Schmidt
Rami
- René Habermann
Ronnie Cheng
Ryan Heath
Samantha
@@ -106,13 +112,14 @@ generous deed immortalized in the next stable release of Godot Engine.
Benito
Carlo Cabanilla
Daniel James
+ David Fedorchak
David Gehrig
David Hubber
David Snopek
Ed Morley
First Last
Frank Kurka
- Hunter Jones
+ Guy Kay Jay
Jacobus Dens
Javier Roman
Joan Fons
@@ -124,19 +131,17 @@ generous deed immortalized in the next stable release of Godot Engine.
Manuele Finocchiaro
Markus Wiesner
Mateo Navarrete
- Mathieu
Matthew Hillier
- Mert Kasar
Officine Pixel S.n.c.
Pedro Silva
Retro Village
Rob Messick
Roland Fredenhagen
Ronan Zeegers
+ Rudi
Sarksus
Sean
Sergey
- Sergio Airaldi
Sofox
Stephan Kessler
Stephen Molyneaux
@@ -148,11 +153,9 @@ generous deed immortalized in the next stable release of Godot Engine.
Victor
Xeno Coliseum
+ ␣
23BLUENINJA
- Adam Mill
- Adam Nakonieczny
- Adam Nelson
- Adam Stankiewicz
+ AdamRatai
Alexander Erlemann
Alexandre VALIN
Alexej Kowalew
@@ -164,6 +167,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Andriy
Antanas Paskauskas
Antoni Batchelli
+ Ari
Arthur S. Muszynski
BasicIncomePlz
Brandon Hawkinson
@@ -178,14 +182,14 @@ generous deed immortalized in the next stable release of Godot Engine.
Craig Smith
Cristopher
CT
- CzechBlueBear
+ CzechBlueBea
+ CzłowiekImadło
Daniel Reed
Daniel Tebbutt
Darrian Little
- David Thomason
+ DATSAGE
Daylon J Williams
Dennis Belfrage
- Dimitri Nüscheler
Donn Eddy
Duncan
Eric Brand
@@ -194,9 +198,7 @@ generous deed immortalized in the next stable release of Godot Engine.
flesk
foxydevloper
Fransiska
- FroggEater
Gabrielius Vaiškūnas
- Garpur
Gary Hulst
Geoffroy Warin
George Venizelos
@@ -209,8 +211,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Heath Hayes
Horváth-Lázár Péter
Hu Hund
- Hunter Barabas
- ihereou
illuxxium
Jaap Marsman
Jamal Bencharki
@@ -225,22 +225,17 @@ generous deed immortalized in the next stable release of Godot Engine.
Johnathan Kupferer
John Stinson
Josef Stumpfegger
- Jose Manuel Muñoz Perez
Joshie Sparks
Joshua Flores
Joshua Lesperance
Juan Velandia
Judd
Julian Todd
- Juraj Móza
JUSTIN CARROLL
- Justin Palmer
Kelteseth
- Kevan
Khora
kickmaniac
kinfox
- Lakshaya Goel
Laszlo Kiss
leetNightshade
Leo Fidel R Liban
@@ -264,26 +259,24 @@ generous deed immortalized in the next stable release of Godot Engine.
Michael Policastro
MikadoSC
nate etan
+ Nicola Cocchiaro
Nikita Blizniuk
Oliver Dick
- Oscar Campos
Otis Clark
+ Patrick Wuttke
Paul Hocker
Paul Von Zimmerman
- Pedro
Pete Goodwin
Petr Malac
Petrus Prinsloo
Philip Woods
- R
- RaiRu
RAMupgrade
+ red1939
Reilt
Rene Tailleur
Rhodochrone
Rickard Hermanson
Rob
- Robert McDermott
Rob McInroy
RodZilla
Romeo Disca
@@ -297,11 +290,8 @@ generous deed immortalized in the next stable release of Godot Engine.
Samuel Hummerstone
Samuel Judd
schroedinger's possum
- Serban Serafimescu
- Sergey Fonaryov
Shishir Tandale
Sing Chun Lee
- Skides
SKison
Song Junwoo
spacechase0
@@ -309,6 +299,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Steven Landow
Stoned Xander
Sven Carstensen
+ Talii
Teslatech
Thomas Bjarnelöf
Thomas Kurz
@@ -321,17 +312,17 @@ generous deed immortalized in the next stable release of Godot Engine.
Turntsnaco
UltyX
Valryia
- Vincent Cloutier
VoidPointer
+ whatever
Winston
- Wojciech Chojnacki
Yifan Lai
Yuancheng Zhang
+ zkip lan
## Silver donors
+ Aaron Mayfield
Aaron Oldenburg
- A. B.
Adam Brunnmeier
Adam Carr
Adam Long
@@ -353,18 +344,17 @@ generous deed immortalized in the next stable release of Godot Engine.
Alejandro Saucedo
AleMax
Alessandro Senese
- Alex Chan
Alex Clavelle
+ Alex de la Mare
alex raeside
Allan Davis
- Allen Schade
Amar Šahinović
Andre Altmueller
Andrei Pufu
Andre Stackhouse
+ Andrew
Andrew Groot
andrew james morris
- Andrew Thomas
angrykoala
Ano Nim
Anthony Avina
@@ -373,28 +363,23 @@ generous deed immortalized in the next stable release of Godot Engine.
Arda Erol
Arthur Brainville
Arturo Rosales
- Ashley Claymore
Aubrey Falconer
Auré Franky
aurelien condomines
- Austin Finlinson
Austin Miller
Azar Gurbanov
AzulCrescent
Balázs Batári
Beau Seymour
- Behzad Ghaffari
Benedikt
Ben Vercammen
Ben Visness
- Bernd Jänichen
Bernhard Werner
Bill Thibault
bitbrain
Bjarne Voigtländer
Black Block
Blunderjack
- BoiLudens
Bram
Brian
Brian Ford
@@ -402,15 +387,16 @@ generous deed immortalized in the next stable release of Godot Engine.
Bronson Zgeb
bugcaptor
Burney Waring
- Caleb Gartner
Caleb Makela
Caliburn
Cameron Meyer
Carlos Rios
Carl van der Geest
Casey
+ Cesar Ruiz
Chad Steadman
Checkpoint Charlie
+ Chris Cavalluzzi
Chris Jagusch
Chris Langford
Chris Ridenour
@@ -420,8 +406,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Christian Winter
Christoffer Dahlblom
Christophe Gagnier
- Christoph Woinke
- codedius
Codex404
Cody Parker
Conall O
@@ -429,26 +413,23 @@ generous deed immortalized in the next stable release of Godot Engine.
Corchari
Corey W
Craig Post
+ CrimsonZA
CrispyPin
- Cullen Canejo
cynwav
Dakota Watkins
Daniel H. Bahr
- Danielle Cheney
+ Danielle
Dare Looks
Daren Scot Wilson
- Dave Walker
+ Davesnothere
David Baker
David Bôle
David May
David Maziarka
- David Rapisarda
Devin Carraway
Devin R
Dimitri Roche
- Dmytro Korchynskyi
Dominik Wetzel
- Don B
Donovan Hutcheon
Douglas Plumley
Dragontrapper
@@ -460,7 +441,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Edward Herbert
Edward Swartz
Egon Elbre
- Elgenzay
Elias Nykrem
Elijah Anderson
Emerson MX
@@ -469,20 +449,15 @@ generous deed immortalized in the next stable release of Godot Engine.
Eric Stokes
Eric Walkingshaw
Eric Williams
- Erika Sanders
Erkki Seppälä
Ewan Holmes
- EZL games
Faisal Alkubaisi
Fault Boy
fby
- Fekinox
Felix Adam
- Felix Bohmann
Fer DC
Filip Lundby
Frank
- FrostMarble
fumangy
Game Endeavor
Gary Thomas
@@ -497,18 +472,14 @@ generous deed immortalized in the next stable release of Godot Engine.
Guo Hongci
Hans Jorgensen
Haplo
- Hayden Foley
Heribert Hirth
Hylian Ensemble
Ian Richard Kunert
Ian Williams
- IndustrialRobot
- Inki Crow
Interstice
iveks
Jacob D
Jaguar
- JAJAJA JA
Jake D
Jako Danar
James
@@ -518,40 +489,33 @@ generous deed immortalized in the next stable release of Godot Engine.
James Thomas
Jamie Massey
Janis Skuja
- JanPaul Bergeson
Jan Vetulani
JARKKO PARVIAINEN
- Jason Bolton
Jason Evans
Jason Uechi
Jeff Hungerford
Jeffrey Berube
Jennifer Graves
- Jeramie
Jesse Dubay
João Pedro Braz
Joe Hurdle
Joe Klemmer
- John Anders Stav
John Barlex
John Bruce
+ John Palgut
Jonas
Jonas Arndt
Jonas Bernemann
+ Jonas LHOSTE
Jonas Rudlang
Jonas Yamazaki
- Jonatan R
Jonathan Bieber
Jonathan Ellis
Jonathan G
- Jon Oakes
Jon Sully
- Jordan West
Jordy Goodridge
- Jorge Antunes
Jose Francisco 'Yiro' Vera Girona
Joseph Catrambone
- Josh P
Josh Segall
Josh Taylor
Joshua Heidrich
@@ -563,12 +527,11 @@ generous deed immortalized in the next stable release of Godot Engine.
Julian Murgia
Justin Hamilton
Justin Spedding
- KaDokta
+ Justin Zander
Kalydi Balázs
Katsuomi Kobayashi
Keedong Park
Keegan Scott
- Keinan Powers
Keith Bradner
Kenji Kawabata
Ken Minardo
@@ -576,22 +539,19 @@ generous deed immortalized in the next stable release of Godot Engine.
Kerotasma
Ketafuki
killaQueen
+ kimbring2
Kodera Software
Kolandrious
- Kristian Nygaard Jensen
KsyTek Games
kycho
Kyle Burnett
Kyle Jacobs
- Kyle Szklenski
Lasse le Dous
Laurent CHEA
Laurent Dethoor
Laxman Pradhan
Lech Rozanski
Leland Vakarian
- Lemin
- LEMMiNO
Leonardo Baumle
Levi Lindsey
LF
@@ -605,7 +565,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Luke Kasz
Major Haul
Malcolm
- Marco Lardelli
+ Mara Huldra
Marcos Heitor Carvalho
Markie Music
Mark Jad
@@ -614,7 +574,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Markus Michael Egger
Markus Strompen
Martin Holas
- Martin Linklater
Martin Liška
Martin Trbola
Martin Zabinski
@@ -623,14 +582,11 @@ generous deed immortalized in the next stable release of Godot Engine.
Matthew Booe
Maverick
Maxime Blade
- Maxime Santerre
Maxwell
McStuffings
- Melchor Morales
+ Melchor
Melissa Mears
- Merlyn Morgan-Graham
Metal Demon 2000
- mhilbrunner
Michael
Michael Haney
Michael Morrison
@@ -640,6 +596,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Mikayla
Mike Birkhead
Mike Copley
+ Mike McRoberts
Miss
Mitchell J. Wagner
MJacred
@@ -652,23 +609,17 @@ generous deed immortalized in the next stable release of Godot Engine.
MrAZIE
Mrjemandem
Nathaniel
- neighty
+ neguse
Neil Blakey-Milner
Neil Wang
Nerdforge
Nerdyninja
Nicholas La Roux
- Nicholas Orlowski
Nick Eldrenkamp
Nick Macholl
Nico Greve
- Nicolas Goll-Perrier
Nicolas Rosset
- Nicolò Brigadoi Calamari
Nils Nordmark
- Nima Farid
- Noah Shomette
- Noel Billig
Noesis
obscuresteel
Okatima
@@ -676,13 +627,10 @@ generous deed immortalized in the next stable release of Godot Engine.
Oliver Ambrose
oscar1000108
Oscar Domingo
- Panagiotis Xynos
Parth Patel
- Pascal
Patrick Indermühle
Patrickm
Patrick Nafarrete
- Patrick Wuttke
Paul Gieske
Paul Mozet
Paweł Kowal
@@ -690,6 +638,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Pedro Henrique Martins Garcia
Peter Höglund
Philip Ludington (MrPhil)
+ Phoenix Jauregui
Pierre Caye
Pille
Pixel Archipel
@@ -697,23 +646,20 @@ generous deed immortalized in the next stable release of Godot Engine.
Point08
Portponky
Preethi Vaidyanathan
+ Price Comstock
PsycHead
Puntigames
pwab
Quincy Quincy
Quinn Morrison
- RackBar Dingum
Rafa Laguna
+ RagingRoosevelt
Ragnar Pettersson
Rainer Amler
Rammeow
- red1939
Relintai
Remi Rampin
- Remtaine
Reneator
- Riccardo Marini
- Richard Hayes
Richard Ivánek
Riley
Robin Ward
@@ -725,7 +671,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Roka
Roland Rząsa
Roman Papush
- Ronald Ho Hip (CrimsonZA)
Roy Scayged
Russ
Ryan Groom
@@ -733,6 +678,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Rykk
Sammy Fischer
Sangeeth Pavithran
+ Sasha Schwartz
Sean Dee
Sebastian Michailidis
SeongWan Kim
@@ -742,7 +688,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Shane
Shane Lillie
Shane Spoor
- Silver1063
simdee
Simon Jonas Larsen
Simon Schoenenberger
@@ -757,22 +702,19 @@ generous deed immortalized in the next stable release of Godot Engine.
Soheib El-Harrache
Solene Waked
Sophie Winter
- Sparky
Squidgy
Squirrel
- Stéphane Roussel
+ SSebigo
Stephen Rice
Stephen Schlie
Steven Drovie
summerblind
Sung soo Choi
- Svenne Krap
SxP
tadashi endo
Tarch
Techwizz
Terry
- Theodore Lindsey
TheVoiceInMyHead
TheWint
Thibaut DECROMBECQUE
@@ -789,10 +731,8 @@ generous deed immortalized in the next stable release of Godot Engine.
Timothy B. MacDonald
Tim Riley
Toadile
- Tobias Bradtke
Tom Coxon
Tom Webster
- Torgeir Lilleskog
Torsten Crass
travis f w
Travis O'Brien
@@ -808,13 +748,15 @@ generous deed immortalized in the next stable release of Godot Engine.
v01tech
Vaida
Vaughan Ling
+ Vavin.X
VikFro
Vincent Barkmann
+ Vincent Cloutier
Vincent Foulon
Vitaliy Sapronenko
- Vi Watch
Vladimir Savin
- Vuli Nux
+ volklobo@live.com
+ Vulinux
Wapiti .
Wiley Thompson
William Bodin
@@ -826,6 +768,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Yan Shi
Zekim
Zher Huei Lee
+ Zoee Silcock
ケルベロス
貴宏 小松
郝晨煜
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index d0de39a79d..385cd2b2fd 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1124,8 +1124,12 @@ void ProjectSettings::set_setting(const String &p_setting, const Variant &p_valu
set(p_setting, p_value);
}
-Variant ProjectSettings::get_setting(const String &p_setting) const {
- return get(p_setting);
+Variant ProjectSettings::get_setting(const String &p_setting, const Variant &p_default_value) const {
+ if (has_setting(p_setting)) {
+ return get(p_setting);
+ } else {
+ return p_default_value;
+ }
}
bool ProjectSettings::has_custom_feature(const String &p_feature) const {
@@ -1158,7 +1162,7 @@ ProjectSettings::AutoloadInfo ProjectSettings::get_autoload(const StringName &p_
void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_setting", "name"), &ProjectSettings::has_setting);
ClassDB::bind_method(D_METHOD("set_setting", "name", "value"), &ProjectSettings::set_setting);
- ClassDB::bind_method(D_METHOD("get_setting", "name"), &ProjectSettings::get_setting);
+ ClassDB::bind_method(D_METHOD("get_setting", "name", "default_value"), &ProjectSettings::get_setting, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("set_order", "name", "position"), &ProjectSettings::set_order);
ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order);
ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value);
@@ -1277,7 +1281,6 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("physics/2d/run_on_separate_thread", false);
GLOBAL_DEF("physics/3d/run_on_separate_thread", false);
- GLOBAL_DEF("debug/disable_touch", false);
GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1");
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index 960dfe0395..2ffbda9cea 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -141,7 +141,7 @@ public:
static const int CONFIG_VERSION = 5;
void set_setting(const String &p_setting, const Variant &p_value);
- Variant get_setting(const String &p_setting) const;
+ Variant get_setting(const String &p_setting, const Variant &p_default_value = Variant()) const;
bool has_setting(String p_var) const;
String localize_path(const String &p_path) const;
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index e0772cd43d..c72b6212d7 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -153,6 +153,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TOP_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_CENTER_TO);
+ BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BASELINE_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BOTTOM_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_TOP);
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 5812a24c4f..a0e3778dcc 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -252,63 +252,140 @@ Dictionary GDExtensionAPIDump::generate_extension_api() {
}
{
- // Member offsets sizes.
+ // Member offsets, meta types and sizes.
+
+#define REAL_MEMBER_OFFSET(type, member) \
+ { \
+ type, \
+ member, \
+ "float", \
+ sizeof(float), \
+ "float", \
+ sizeof(float), \
+ "double", \
+ sizeof(double), \
+ "double", \
+ sizeof(double), \
+ }
+
+#define INT32_MEMBER_OFFSET(type, member) \
+ { \
+ type, \
+ member, \
+ "int32", \
+ sizeof(int32_t), \
+ "int32", \
+ sizeof(int32_t), \
+ "int32", \
+ sizeof(int32_t), \
+ "int32", \
+ sizeof(int32_t), \
+ }
+
+#define INT32_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \
+ { \
+ type, \
+ member, \
+ member_type, \
+ sizeof(int32_t) * member_elems, \
+ member_type, \
+ sizeof(int32_t) * member_elems, \
+ member_type, \
+ sizeof(int32_t) * member_elems, \
+ member_type, \
+ sizeof(int32_t) * member_elems, \
+ }
+
+#define REAL_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \
+ { \
+ type, \
+ member, \
+ member_type, \
+ sizeof(float) * member_elems, \
+ member_type, \
+ sizeof(float) * member_elems, \
+ member_type, \
+ sizeof(double) * member_elems, \
+ member_type, \
+ sizeof(double) * member_elems, \
+ }
+
struct {
Variant::Type type;
const char *member;
- uint32_t offset_32_bits_real_float;
- uint32_t offset_64_bits_real_float;
- uint32_t offset_32_bits_real_double;
- uint32_t offset_64_bits_real_double;
+ const char *member_meta_32_bits_real_float;
+ const uint32_t member_size_32_bits_real_float;
+ const char *member_meta_64_bits_real_float;
+ const uint32_t member_size_64_bits_real_float;
+ const char *member_meta_32_bits_real_double;
+ const uint32_t member_size_32_bits_real_double;
+ const char *member_meta_64_bits_real_double;
+ const uint32_t member_size_64_bits_real_double;
} member_offset_array[] = {
- { Variant::VECTOR2, "x", 0, 0, 0, 0 },
- { Variant::VECTOR2, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) },
- { Variant::VECTOR2I, "x", 0, 0, 0, 0 },
- { Variant::VECTOR2I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) },
- { Variant::RECT2, "position", 0, 0, 0, 0 },
- { Variant::RECT2, "size", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
- { Variant::RECT2I, "position", 0, 0, 0, 0 },
- { Variant::RECT2I, "size", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) },
- { Variant::VECTOR3, "x", 0, 0, 0, 0 },
- { Variant::VECTOR3, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) },
- { Variant::VECTOR3, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
- { Variant::VECTOR3I, "x", 0, 0, 0, 0 },
- { Variant::VECTOR3I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) },
- { Variant::VECTOR3I, "z", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) },
- { Variant::TRANSFORM2D, "x", 0, 0, 0, 0 },
- { Variant::TRANSFORM2D, "y", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
- { Variant::TRANSFORM2D, "origin", 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(double), 4 * sizeof(double) },
- { Variant::VECTOR4, "x", 0, 0, 0, 0 },
- { Variant::VECTOR4, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) },
- { Variant::VECTOR4, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
- { Variant::VECTOR4, "w", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(double), 3 * sizeof(double) },
- { Variant::VECTOR4I, "x", 0, 0, 0, 0 },
- { Variant::VECTOR4I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) },
- { Variant::VECTOR4I, "z", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) },
- { Variant::VECTOR4I, "w", 3 * sizeof(int32_t), 3 * sizeof(int32_t), 3 * sizeof(int32_t), 3 * sizeof(int32_t) },
- { Variant::PLANE, "normal", 0, 0, 0, 0 },
- { Variant::PLANE, "d", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) },
- { Variant::QUATERNION, "x", 0, 0, 0, 0 },
- { Variant::QUATERNION, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) },
- { Variant::QUATERNION, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
- { Variant::QUATERNION, "w", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(double), 3 * sizeof(double) },
- { Variant::AABB, "position", 0, 0, 0, 0 },
- { Variant::AABB, "size", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) },
- // Remember that basis vectors are flipped!
- { Variant::BASIS, "x", 0, 0, 0, 0 },
- { Variant::BASIS, "y", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) },
- { Variant::BASIS, "z", vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(double), vec3_elems * 2 * sizeof(double) },
- { Variant::TRANSFORM3D, "basis", 0, 0, 0, 0 },
- { Variant::TRANSFORM3D, "origin", (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) },
- { Variant::PROJECTION, "x", 0, 0, 0, 0 },
- { Variant::PROJECTION, "y", vec4_elems * sizeof(float), vec4_elems * sizeof(float), vec4_elems * sizeof(double), vec4_elems * sizeof(double) },
- { Variant::PROJECTION, "z", vec4_elems * 2 * sizeof(float), vec4_elems * 2 * sizeof(float), vec4_elems * 2 * sizeof(double), vec4_elems * 2 * sizeof(double) },
- { Variant::PROJECTION, "w", vec4_elems * 3 * sizeof(float), vec4_elems * 3 * sizeof(float), vec4_elems * 3 * sizeof(double), vec4_elems * 3 * sizeof(double) },
- { Variant::COLOR, "r", 0, 0, 0, 0 },
- { Variant::COLOR, "g", sizeof(float), sizeof(float), sizeof(float), sizeof(float) },
- { Variant::COLOR, "b", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float) },
- { Variant::COLOR, "a", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(float) },
- { Variant::NIL, nullptr, 0, 0, 0, 0 },
+ // Vector2
+ REAL_MEMBER_OFFSET(Variant::VECTOR2, "x"),
+ REAL_MEMBER_OFFSET(Variant::VECTOR2, "y"),
+ // Vector2i
+ INT32_MEMBER_OFFSET(Variant::VECTOR2I, "x"),
+ INT32_MEMBER_OFFSET(Variant::VECTOR2I, "y"),
+ // Rect2
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::RECT2, "position", "Vector2", 2),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::RECT2, "size", "Vector2", 2),
+ // Rect2i
+ INT32_BASED_BUILTIN_MEMBER_OFFSET(Variant::RECT2I, "position", "Vector2i", 2),
+ INT32_BASED_BUILTIN_MEMBER_OFFSET(Variant::RECT2I, "size", "Vector2i", 2),
+ // Vector3
+ REAL_MEMBER_OFFSET(Variant::VECTOR3, "x"),
+ REAL_MEMBER_OFFSET(Variant::VECTOR3, "y"),
+ REAL_MEMBER_OFFSET(Variant::VECTOR3, "z"),
+ // Vector3i
+ INT32_MEMBER_OFFSET(Variant::VECTOR3I, "x"),
+ INT32_MEMBER_OFFSET(Variant::VECTOR3I, "y"),
+ INT32_MEMBER_OFFSET(Variant::VECTOR3I, "z"),
+ // Transform2D
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM2D, "x", "Vector2", 2),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM2D, "y", "Vector2", 2),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM2D, "origin", "Vector2", 2),
+ // Vector4
+ REAL_MEMBER_OFFSET(Variant::VECTOR4, "x"),
+ REAL_MEMBER_OFFSET(Variant::VECTOR4, "y"),
+ REAL_MEMBER_OFFSET(Variant::VECTOR4, "z"),
+ REAL_MEMBER_OFFSET(Variant::VECTOR4, "w"),
+ // Vector4i
+ INT32_MEMBER_OFFSET(Variant::VECTOR4I, "x"),
+ INT32_MEMBER_OFFSET(Variant::VECTOR4I, "y"),
+ INT32_MEMBER_OFFSET(Variant::VECTOR4I, "z"),
+ INT32_MEMBER_OFFSET(Variant::VECTOR4I, "w"),
+ // Plane
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PLANE, "normal", "Vector3", vec3_elems),
+ REAL_MEMBER_OFFSET(Variant::PLANE, "d"),
+ // Quaternion
+ REAL_MEMBER_OFFSET(Variant::QUATERNION, "x"),
+ REAL_MEMBER_OFFSET(Variant::QUATERNION, "y"),
+ REAL_MEMBER_OFFSET(Variant::QUATERNION, "z"),
+ REAL_MEMBER_OFFSET(Variant::QUATERNION, "w"),
+ // AABB
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::AABB, "position", "Vector3", vec3_elems),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::AABB, "size", "Vector3", vec3_elems),
+ // Basis (remember that basis vectors are flipped!)
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::BASIS, "x", "Vector3", vec3_elems),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::BASIS, "y", "Vector3", vec3_elems),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::BASIS, "z", "Vector3", vec3_elems),
+ // Transform3D
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM3D, "basis", "Basis", vec3_elems * 3),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM3D, "origin", "Vector3", vec3_elems),
+ // Projection
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PROJECTION, "x", "Vector4", vec4_elems),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PROJECTION, "y", "Vector4", vec4_elems),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PROJECTION, "z", "Vector4", vec4_elems),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PROJECTION, "w", "Vector4", vec4_elems),
+ // Color (always composed of 4bytes floats)
+ { Variant::COLOR, "r", "float", sizeof(float), "float", sizeof(float), "float", sizeof(float), "float", sizeof(float) },
+ { Variant::COLOR, "g", "float", sizeof(float), "float", sizeof(float), "float", sizeof(float), "float", sizeof(float) },
+ { Variant::COLOR, "b", "float", sizeof(float), "float", sizeof(float), "float", sizeof(float), "float", sizeof(float) },
+ { Variant::COLOR, "a", "float", sizeof(float), "float", sizeof(float), "float", sizeof(float), "float", sizeof(float) },
+ // End marker, must stay last
+ { Variant::NIL, nullptr, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0 },
};
Array core_type_member_offsets;
@@ -319,15 +396,16 @@ Dictionary GDExtensionAPIDump::generate_extension_api() {
Array type_offsets;
uint32_t idx = 0;
- Variant::Type last_type = Variant::NIL;
+ Variant::Type previous_type = Variant::NIL;
Dictionary d2;
Array members;
+ uint32_t offset = 0;
while (true) {
Variant::Type t = member_offset_array[idx].type;
- if (t != last_type) {
- if (last_type != Variant::NIL) {
+ if (t != previous_type) {
+ if (previous_type != Variant::NIL) {
d2["members"] = members;
type_offsets.push_back(d2);
}
@@ -338,27 +416,35 @@ Dictionary GDExtensionAPIDump::generate_extension_api() {
String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t);
d2 = Dictionary();
members = Array();
+ offset = 0;
d2["name"] = name;
- last_type = t;
+ previous_type = t;
}
Dictionary d3;
- uint32_t offset = 0;
+ const char *member_meta = nullptr;
+ uint32_t member_size = 0;
switch (i) {
case 0:
- offset = member_offset_array[idx].offset_32_bits_real_float;
+ member_meta = member_offset_array[idx].member_meta_32_bits_real_float;
+ member_size = member_offset_array[idx].member_size_32_bits_real_float;
break;
case 1:
- offset = member_offset_array[idx].offset_64_bits_real_float;
+ member_meta = member_offset_array[idx].member_meta_64_bits_real_float;
+ member_size = member_offset_array[idx].member_size_64_bits_real_float;
break;
case 2:
- offset = member_offset_array[idx].offset_32_bits_real_double;
+ member_meta = member_offset_array[idx].member_meta_32_bits_real_double;
+ member_size = member_offset_array[idx].member_size_32_bits_real_double;
break;
case 3:
- offset = member_offset_array[idx].offset_64_bits_real_double;
+ member_meta = member_offset_array[idx].member_meta_64_bits_real_double;
+ member_size = member_offset_array[idx].member_size_64_bits_real_double;
break;
}
d3["member"] = member_offset_array[idx].member;
d3["offset"] = offset;
+ d3["meta"] = member_meta;
+ offset += member_size;
members.push_back(d3);
idx++;
}
diff --git a/core/input/input.cpp b/core/input/input.cpp
index cb65d2569c..554f8fad00 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -540,6 +540,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
drag_event->set_position(position);
drag_event->set_relative(relative);
+ drag_event->set_tilt(mm->get_tilt());
+ drag_event->set_pen_inverted(mm->get_pen_inverted());
+ drag_event->set_pressure(mm->get_pressure());
drag_event->set_velocity(get_last_mouse_velocity());
event_dispatch_function(drag_event);
@@ -605,6 +608,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
motion_event.instantiate();
motion_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE);
+ motion_event->set_tilt(sd->get_tilt());
+ motion_event->set_pen_inverted(sd->get_pen_inverted());
+ motion_event->set_pressure(sd->get_pressure());
motion_event->set_position(sd->get_position());
motion_event->set_global_position(sd->get_position());
motion_event->set_relative(sd->get_relative());
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 0a32b4bf68..4859490230 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -1223,6 +1223,30 @@ int InputEventScreenDrag::get_index() const {
return index;
}
+void InputEventScreenDrag::set_tilt(const Vector2 &p_tilt) {
+ tilt = p_tilt;
+}
+
+Vector2 InputEventScreenDrag::get_tilt() const {
+ return tilt;
+}
+
+void InputEventScreenDrag::set_pressure(float p_pressure) {
+ pressure = p_pressure;
+}
+
+float InputEventScreenDrag::get_pressure() const {
+ return pressure;
+}
+
+void InputEventScreenDrag::set_pen_inverted(bool p_inverted) {
+ pen_inverted = p_inverted;
+}
+
+bool InputEventScreenDrag::get_pen_inverted() const {
+ return pen_inverted;
+}
+
void InputEventScreenDrag::set_position(const Vector2 &p_pos) {
pos = p_pos;
}
@@ -1256,6 +1280,9 @@ Ref<InputEvent> InputEventScreenDrag::xformed_by(const Transform2D &p_xform, con
sd->set_window_id(get_window_id());
sd->set_index(index);
+ sd->set_pressure(get_pressure());
+ sd->set_pen_inverted(get_pen_inverted());
+ sd->set_tilt(get_tilt());
sd->set_position(p_xform.xform(pos + p_local_ofs));
sd->set_relative(p_xform.basis_xform(relative));
sd->set_velocity(p_xform.basis_xform(velocity));
@@ -1268,7 +1295,7 @@ String InputEventScreenDrag::as_text() const {
}
String InputEventScreenDrag::to_string() {
- return vformat("InputEventScreenDrag: index=%d, position=(%s), relative=(%s), velocity=(%s)", index, String(get_position()), String(get_relative()), String(get_velocity()));
+ return vformat("InputEventScreenDrag: index=%d, position=(%s), relative=(%s), velocity=(%s), pressure=%.2f, tilt=(%s), pen_inverted=(%s)", index, String(get_position()), String(get_relative()), String(get_velocity()), get_pressure(), String(get_tilt()), get_pen_inverted());
}
bool InputEventScreenDrag::accumulate(const Ref<InputEvent> &p_event) {
@@ -1292,6 +1319,15 @@ void InputEventScreenDrag::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_index", "index"), &InputEventScreenDrag::set_index);
ClassDB::bind_method(D_METHOD("get_index"), &InputEventScreenDrag::get_index);
+ ClassDB::bind_method(D_METHOD("set_tilt", "tilt"), &InputEventScreenDrag::set_tilt);
+ ClassDB::bind_method(D_METHOD("get_tilt"), &InputEventScreenDrag::get_tilt);
+
+ ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventScreenDrag::set_pressure);
+ ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventScreenDrag::get_pressure);
+
+ ClassDB::bind_method(D_METHOD("set_pen_inverted", "pen_inverted"), &InputEventScreenDrag::set_pen_inverted);
+ ClassDB::bind_method(D_METHOD("get_pen_inverted"), &InputEventScreenDrag::get_pen_inverted);
+
ClassDB::bind_method(D_METHOD("set_position", "position"), &InputEventScreenDrag::set_position);
ClassDB::bind_method(D_METHOD("get_position"), &InputEventScreenDrag::get_position);
@@ -1302,6 +1338,9 @@ void InputEventScreenDrag::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_velocity"), &InputEventScreenDrag::get_velocity);
ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "tilt"), "set_tilt", "get_tilt");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pressure"), "set_pressure", "get_pressure");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pen_inverted"), "set_pen_inverted", "get_pen_inverted");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "relative", PROPERTY_HINT_NONE, "suffix:px"), "set_relative", "get_relative");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "suffix:px/s"), "set_velocity", "get_velocity");
diff --git a/core/input/input_event.h b/core/input/input_event.h
index adbcb7cf68..06c3118abc 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -384,6 +384,9 @@ class InputEventScreenDrag : public InputEventFromWindow {
Vector2 pos;
Vector2 relative;
Vector2 velocity;
+ Vector2 tilt;
+ float pressure = 0;
+ bool pen_inverted = false;
protected:
static void _bind_methods();
@@ -392,6 +395,15 @@ public:
void set_index(int p_index);
int get_index() const;
+ void set_tilt(const Vector2 &p_tilt);
+ Vector2 get_tilt() const;
+
+ void set_pressure(float p_pressure);
+ float get_pressure() const;
+
+ void set_pen_inverted(bool p_inverted);
+ bool get_pen_inverted() const;
+
void set_position(const Vector2 &p_pos);
Vector2 get_position() const;
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 1b9538794a..a2e1bc22be 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -173,6 +173,14 @@ int Image::get_format_pixel_size(Format p_format) {
return 1;
case FORMAT_DXT5_RA_AS_RG:
return 1;
+ case FORMAT_ASTC_4x4:
+ return 1;
+ case FORMAT_ASTC_4x4_HDR:
+ return 1;
+ case FORMAT_ASTC_8x8:
+ return 1;
+ case FORMAT_ASTC_8x8_HDR:
+ return 1;
case FORMAT_MAX: {
}
}
@@ -213,7 +221,18 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
r_h = 4;
} break;
+ case FORMAT_ASTC_4x4:
+ case FORMAT_ASTC_4x4_HDR: {
+ r_w = 4;
+ r_h = 4;
+
+ } break;
+ case FORMAT_ASTC_8x8:
+ case FORMAT_ASTC_8x8_HDR: {
+ r_w = 8;
+ r_h = 8;
+ } break;
default: {
r_w = 1;
r_h = 1;
@@ -222,7 +241,9 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
}
int Image::get_format_pixel_rshift(Format p_format) {
- if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) {
+ if (p_format == FORMAT_ASTC_8x8) {
+ return 2;
+ } else if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) {
return 1;
} else {
return 0;
@@ -260,6 +281,14 @@ int Image::get_format_block_size(Format p_format) {
{
return 4;
}
+ case FORMAT_ASTC_4x4:
+ case FORMAT_ASTC_4x4_HDR: {
+ return 4;
+ }
+ case FORMAT_ASTC_8x8:
+ case FORMAT_ASTC_8x8_HDR: {
+ return 8;
+ }
default: {
}
}
@@ -2581,19 +2610,23 @@ Error Image::decompress() {
_image_decompress_etc1(this);
} else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RA_AS_RG && _image_decompress_etc2) {
_image_decompress_etc2(this);
+ } else if (format >= FORMAT_ASTC_4x4 && format <= FORMAT_ASTC_8x8_HDR && _image_decompress_astc) {
+ _image_decompress_astc(this);
} else {
return ERR_UNAVAILABLE;
}
return OK;
}
-Error Image::compress(CompressMode p_mode, CompressSource p_source, float p_lossy_quality) {
+Error Image::compress(CompressMode p_mode, CompressSource p_source, float p_lossy_quality, ASTCFormat p_astc_format) {
ERR_FAIL_INDEX_V_MSG(p_mode, COMPRESS_MAX, ERR_INVALID_PARAMETER, "Invalid compress mode.");
ERR_FAIL_INDEX_V_MSG(p_source, COMPRESS_SOURCE_MAX, ERR_INVALID_PARAMETER, "Invalid compress source.");
- return compress_from_channels(p_mode, detect_used_channels(p_source), p_lossy_quality);
+ return compress_from_channels(p_mode, detect_used_channels(p_source), p_lossy_quality, p_astc_format);
}
-Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality) {
+Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality, ASTCFormat p_astc_format) {
+ ERR_FAIL_COND_V(data.is_empty(), ERR_INVALID_DATA);
+
switch (p_mode) {
case COMPRESS_S3TC: {
ERR_FAIL_COND_V(!_image_compress_bc_func, ERR_UNAVAILABLE);
@@ -2611,6 +2644,10 @@ Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels
ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE);
_image_compress_bptc_func(this, p_lossy_quality, p_channels);
} break;
+ case COMPRESS_ASTC: {
+ ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE);
+ _image_compress_astc_func(this, p_lossy_quality, p_astc_format);
+ } break;
case COMPRESS_MAX: {
ERR_FAIL_V(ERR_INVALID_PARAMETER);
} break;
@@ -2967,10 +3004,12 @@ void (*Image::_image_compress_bc_func)(Image *, float, Image::UsedChannels) = nu
void (*Image::_image_compress_bptc_func)(Image *, float, Image::UsedChannels) = nullptr;
void (*Image::_image_compress_etc1_func)(Image *, float) = nullptr;
void (*Image::_image_compress_etc2_func)(Image *, float, Image::UsedChannels) = nullptr;
+void (*Image::_image_compress_astc_func)(Image *, float, Image::ASTCFormat) = nullptr;
void (*Image::_image_decompress_bc)(Image *) = nullptr;
void (*Image::_image_decompress_bptc)(Image *) = nullptr;
void (*Image::_image_decompress_etc1)(Image *) = nullptr;
void (*Image::_image_decompress_etc2)(Image *) = nullptr;
+void (*Image::_image_decompress_astc)(Image *) = nullptr;
Vector<uint8_t> (*Image::webp_lossy_packer)(const Ref<Image> &, float) = nullptr;
Vector<uint8_t> (*Image::webp_lossless_packer)(const Ref<Image> &) = nullptr;
@@ -3387,8 +3426,8 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_invisible"), &Image::is_invisible);
ClassDB::bind_method(D_METHOD("detect_used_channels", "source"), &Image::detect_used_channels, DEFVAL(COMPRESS_SOURCE_GENERIC));
- ClassDB::bind_method(D_METHOD("compress", "mode", "source", "lossy_quality"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(0.7));
- ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "lossy_quality"), &Image::compress_from_channels, DEFVAL(0.7));
+ ClassDB::bind_method(D_METHOD("compress", "mode", "source", "lossy_quality", "astc_format"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(0.7), DEFVAL(ASTC_FORMAT_4x4));
+ ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "lossy_quality", "astc_format"), &Image::compress_from_channels, DEFVAL(0.7), DEFVAL(ASTC_FORMAT_4x4));
ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress);
ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed);
@@ -3472,6 +3511,10 @@ void Image::_bind_methods() {
BIND_ENUM_CONSTANT(FORMAT_ETC2_RGB8A1);
BIND_ENUM_CONSTANT(FORMAT_ETC2_RA_AS_RG);
BIND_ENUM_CONSTANT(FORMAT_DXT5_RA_AS_RG);
+ BIND_ENUM_CONSTANT(FORMAT_ASTC_4x4);
+ BIND_ENUM_CONSTANT(FORMAT_ASTC_4x4_HDR);
+ BIND_ENUM_CONSTANT(FORMAT_ASTC_8x8);
+ BIND_ENUM_CONSTANT(FORMAT_ASTC_8x8_HDR);
BIND_ENUM_CONSTANT(FORMAT_MAX);
BIND_ENUM_CONSTANT(INTERPOLATE_NEAREST);
@@ -3499,6 +3542,9 @@ void Image::_bind_methods() {
BIND_ENUM_CONSTANT(COMPRESS_SOURCE_GENERIC);
BIND_ENUM_CONSTANT(COMPRESS_SOURCE_SRGB);
BIND_ENUM_CONSTANT(COMPRESS_SOURCE_NORMAL);
+
+ BIND_ENUM_CONSTANT(ASTC_FORMAT_4x4);
+ BIND_ENUM_CONSTANT(ASTC_FORMAT_8x8);
}
void Image::set_compress_bc_func(void (*p_compress_func)(Image *, float, UsedChannels)) {
diff --git a/core/io/image.h b/core/io/image.h
index ad5c0b4a04..8bcee4404b 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -109,6 +109,10 @@ public:
FORMAT_ETC2_RGB8A1,
FORMAT_ETC2_RA_AS_RG, //used to make basis universal happy
FORMAT_DXT5_RA_AS_RG, //used to make basis universal happy
+ FORMAT_ASTC_4x4,
+ FORMAT_ASTC_4x4_HDR,
+ FORMAT_ASTC_8x8,
+ FORMAT_ASTC_8x8_HDR,
FORMAT_MAX
};
@@ -134,6 +138,11 @@ public:
};
//some functions provided by something else
+ enum ASTCFormat {
+ ASTC_FORMAT_4x4,
+ ASTC_FORMAT_8x8,
+ };
+
static ImageMemLoadFunc _png_mem_loader_func;
static ImageMemLoadFunc _jpg_mem_loader_func;
static ImageMemLoadFunc _webp_mem_loader_func;
@@ -144,11 +153,13 @@ public:
static void (*_image_compress_bptc_func)(Image *, float p_lossy_quality, UsedChannels p_channels);
static void (*_image_compress_etc1_func)(Image *, float);
static void (*_image_compress_etc2_func)(Image *, float, UsedChannels p_channels);
+ static void (*_image_compress_astc_func)(Image *, float, ASTCFormat p_format);
static void (*_image_decompress_bc)(Image *);
static void (*_image_decompress_bptc)(Image *);
static void (*_image_decompress_etc1)(Image *);
static void (*_image_decompress_etc2)(Image *);
+ static void (*_image_decompress_astc)(Image *);
static Vector<uint8_t> (*webp_lossy_packer)(const Ref<Image> &p_image, float p_quality);
static Vector<uint8_t> (*webp_lossless_packer)(const Ref<Image> &p_image);
@@ -347,6 +358,7 @@ public:
COMPRESS_ETC,
COMPRESS_ETC2,
COMPRESS_BPTC,
+ COMPRESS_ASTC,
COMPRESS_MAX,
};
enum CompressSource {
@@ -356,8 +368,8 @@ public:
COMPRESS_SOURCE_MAX,
};
- Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, float p_lossy_quality = 0.7);
- Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality = 0.7);
+ Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, float p_lossy_quality = 0.7, ASTCFormat p_astc_format = ASTC_FORMAT_4x4);
+ Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality = 0.7, ASTCFormat p_astc_format = ASTC_FORMAT_4x4);
Error decompress();
bool is_compressed() const;
@@ -429,5 +441,6 @@ VARIANT_ENUM_CAST(Image::CompressSource)
VARIANT_ENUM_CAST(Image::UsedChannels)
VARIANT_ENUM_CAST(Image::AlphaMode)
VARIANT_ENUM_CAST(Image::RoughnessChannel)
+VARIANT_ENUM_CAST(Image::ASTCFormat)
#endif // IMAGE_H
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index 9ba653e1a9..9f89f5d8c9 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -1813,3 +1813,24 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
return OK;
}
+
+Vector<float> vector3_to_float32_array(const Vector3 *vecs, size_t count) {
+ // We always allocate a new array, and we don't memcpy.
+ // We also don't consider returning a pointer to the passed vectors when sizeof(real_t) == 4.
+ // One reason is that we could decide to put a 4th component in Vector3 for SIMD/mobile performance,
+ // which would cause trouble with these optimizations.
+ Vector<float> floats;
+ if (count == 0) {
+ return floats;
+ }
+ floats.resize(count * 3);
+ float *floats_w = floats.ptrw();
+ for (size_t i = 0; i < count; ++i) {
+ const Vector3 v = vecs[i];
+ floats_w[0] = v.x;
+ floats_w[1] = v.y;
+ floats_w[2] = v.z;
+ floats_w += 3;
+ }
+ return floats;
+}
diff --git a/core/io/marshalls.h b/core/io/marshalls.h
index fef3a1c2c1..66e2571066 100644
--- a/core/io/marshalls.h
+++ b/core/io/marshalls.h
@@ -215,4 +215,6 @@ public:
Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = nullptr, bool p_allow_objects = false, int p_depth = 0);
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false, int p_depth = 0);
+Vector<float> vector3_to_float32_array(const Vector3 *vecs, size_t count);
+
#endif // MARSHALLS_H
diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp
index c30acf32bb..cdcd0ed747 100644
--- a/core/math/a_star_grid_2d.cpp
+++ b/core/math/a_star_grid_2d.cpp
@@ -134,13 +134,22 @@ AStarGrid2D::DiagonalMode AStarGrid2D::get_diagonal_mode() const {
return diagonal_mode;
}
-void AStarGrid2D::set_default_heuristic(Heuristic p_heuristic) {
+void AStarGrid2D::set_default_compute_heuristic(Heuristic p_heuristic) {
ERR_FAIL_INDEX((int)p_heuristic, (int)HEURISTIC_MAX);
- default_heuristic = p_heuristic;
+ default_compute_heuristic = p_heuristic;
}
-AStarGrid2D::Heuristic AStarGrid2D::get_default_heuristic() const {
- return default_heuristic;
+AStarGrid2D::Heuristic AStarGrid2D::get_default_compute_heuristic() const {
+ return default_compute_heuristic;
+}
+
+void AStarGrid2D::set_default_estimate_heuristic(Heuristic p_heuristic) {
+ ERR_FAIL_INDEX((int)p_heuristic, (int)HEURISTIC_MAX);
+ default_estimate_heuristic = p_heuristic;
+}
+
+AStarGrid2D::Heuristic AStarGrid2D::get_default_estimate_heuristic() const {
+ return default_estimate_heuristic;
}
void AStarGrid2D::set_point_solid(const Vector2i &p_id, bool p_solid) {
@@ -155,6 +164,19 @@ bool AStarGrid2D::is_point_solid(const Vector2i &p_id) const {
return points[p_id.y][p_id.x].solid;
}
+void AStarGrid2D::set_point_weight_scale(const Vector2i &p_id, real_t p_weight_scale) {
+ ERR_FAIL_COND_MSG(dirty, "Grid is not initialized. Call the update method.");
+ ERR_FAIL_COND_MSG(!is_in_boundsv(p_id), vformat("Can't set point's weight scale. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height));
+ 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));
+ points[p_id.y][p_id.x].weight_scale = p_weight_scale;
+}
+
+real_t AStarGrid2D::get_point_weight_scale(const Vector2i &p_id) const {
+ ERR_FAIL_COND_V_MSG(dirty, 0, "Grid is not initialized. Call the update method.");
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), 0, vformat("Can't get point's weight scale. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height));
+ return points[p_id.y][p_id.x].weight_scale;
+}
+
AStarGrid2D::Point *AStarGrid2D::_jump(Point *p_from, Point *p_to) {
if (!p_to || p_to->solid) {
return nullptr;
@@ -388,7 +410,10 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) {
_get_nbors(p, nbors);
for (List<Point *>::Element *E = nbors.front(); E; E = E->next()) {
Point *e = E->get(); // The neighbour point.
+ real_t weight_scale = 1.0;
+
if (jumping_enabled) {
+ // TODO: Make it works with weight_scale.
e = _jump(p, e);
if (!e || e->closed_pass == pass) {
continue;
@@ -397,9 +422,10 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) {
if (e->solid || e->closed_pass == pass) {
continue;
}
+ weight_scale = e->weight_scale;
}
- real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id);
+ real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id) * weight_scale;
bool new_point = false;
if (e->open_pass != pass) { // The point wasn't inside the open list.
@@ -430,7 +456,7 @@ real_t AStarGrid2D::_estimate_cost(const Vector2i &p_from_id, const Vector2i &p_
if (GDVIRTUAL_CALL(_estimate_cost, p_from_id, p_to_id, scost)) {
return scost;
}
- return heuristics[default_heuristic](p_from_id, p_to_id);
+ return heuristics[default_estimate_heuristic](p_from_id, p_to_id);
}
real_t AStarGrid2D::_compute_cost(const Vector2i &p_from_id, const Vector2i &p_to_id) {
@@ -438,7 +464,7 @@ real_t AStarGrid2D::_compute_cost(const Vector2i &p_from_id, const Vector2i &p_t
if (GDVIRTUAL_CALL(_compute_cost, p_from_id, p_to_id, scost)) {
return scost;
}
- return heuristics[default_heuristic](p_from_id, p_to_id);
+ return heuristics[default_compute_heuristic](p_from_id, p_to_id);
}
void AStarGrid2D::clear() {
@@ -446,6 +472,12 @@ void AStarGrid2D::clear() {
size = Vector2i();
}
+Vector2 AStarGrid2D::get_point_position(const Vector2i &p_id) const {
+ ERR_FAIL_COND_V_MSG(dirty, Vector2(), "Grid is not initialized. Call the update method.");
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), Vector2(), vformat("Can't get point's position. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height));
+ return points[p_id.y][p_id.x].pos;
+}
+
Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
ERR_FAIL_COND_V_MSG(dirty, Vector<Vector2>(), "Grid is not initialized. Call the update method.");
ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_from_id), Vector<Vector2>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_from_id.x, size.width, p_from_id.y, size.height));
@@ -555,12 +587,17 @@ void AStarGrid2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_jumping_enabled"), &AStarGrid2D::is_jumping_enabled);
ClassDB::bind_method(D_METHOD("set_diagonal_mode", "mode"), &AStarGrid2D::set_diagonal_mode);
ClassDB::bind_method(D_METHOD("get_diagonal_mode"), &AStarGrid2D::get_diagonal_mode);
- ClassDB::bind_method(D_METHOD("set_default_heuristic", "heuristic"), &AStarGrid2D::set_default_heuristic);
- ClassDB::bind_method(D_METHOD("get_default_heuristic"), &AStarGrid2D::get_default_heuristic);
+ ClassDB::bind_method(D_METHOD("set_default_compute_heuristic", "heuristic"), &AStarGrid2D::set_default_compute_heuristic);
+ ClassDB::bind_method(D_METHOD("get_default_compute_heuristic"), &AStarGrid2D::get_default_compute_heuristic);
+ ClassDB::bind_method(D_METHOD("set_default_estimate_heuristic", "heuristic"), &AStarGrid2D::set_default_estimate_heuristic);
+ ClassDB::bind_method(D_METHOD("get_default_estimate_heuristic"), &AStarGrid2D::get_default_estimate_heuristic);
ClassDB::bind_method(D_METHOD("set_point_solid", "id", "solid"), &AStarGrid2D::set_point_solid, DEFVAL(true));
ClassDB::bind_method(D_METHOD("is_point_solid", "id"), &AStarGrid2D::is_point_solid);
+ ClassDB::bind_method(D_METHOD("set_point_weight_scale", "id", "weight_scale"), &AStarGrid2D::set_point_weight_scale);
+ ClassDB::bind_method(D_METHOD("get_point_weight_scale", "id"), &AStarGrid2D::get_point_weight_scale);
ClassDB::bind_method(D_METHOD("clear"), &AStarGrid2D::clear);
+ ClassDB::bind_method(D_METHOD("get_point_position", "id"), &AStarGrid2D::get_point_position);
ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStarGrid2D::get_point_path);
ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStarGrid2D::get_id_path);
@@ -572,8 +609,9 @@ void AStarGrid2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cell_size"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "jumping_enabled"), "set_jumping_enabled", "is_jumping_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "default_heuristic", PROPERTY_HINT_ENUM, "Euclidean,Manhattan,Octile,Chebyshev,Max"), "set_default_heuristic", "get_default_heuristic");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "diagonal_mode", PROPERTY_HINT_ENUM, "Never,Always,At Least One Walkable,Only If No Obstacles,Max"), "set_diagonal_mode", "get_diagonal_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "default_compute_heuristic", PROPERTY_HINT_ENUM, "Euclidean,Manhattan,Octile,Chebyshev"), "set_default_compute_heuristic", "get_default_compute_heuristic");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "default_estimate_heuristic", PROPERTY_HINT_ENUM, "Euclidean,Manhattan,Octile,Chebyshev"), "set_default_estimate_heuristic", "get_default_estimate_heuristic");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "diagonal_mode", PROPERTY_HINT_ENUM, "Never,Always,At Least One Walkable,Only If No Obstacles"), "set_diagonal_mode", "get_diagonal_mode");
BIND_ENUM_CONSTANT(HEURISTIC_EUCLIDEAN);
BIND_ENUM_CONSTANT(HEURISTIC_MANHATTAN);
diff --git a/core/math/a_star_grid_2d.h b/core/math/a_star_grid_2d.h
index 1002f18738..ca36013b61 100644
--- a/core/math/a_star_grid_2d.h
+++ b/core/math/a_star_grid_2d.h
@@ -65,13 +65,15 @@ private:
bool jumping_enabled = false;
DiagonalMode diagonal_mode = DIAGONAL_MODE_ALWAYS;
- Heuristic default_heuristic = HEURISTIC_EUCLIDEAN;
+ Heuristic default_compute_heuristic = HEURISTIC_EUCLIDEAN;
+ Heuristic default_estimate_heuristic = HEURISTIC_EUCLIDEAN;
struct Point {
Vector2i id;
bool solid = false;
Vector2 pos;
+ real_t weight_scale = 1.0;
// Used for pathfinding.
Point *prev_point = nullptr;
@@ -160,14 +162,21 @@ public:
void set_diagonal_mode(DiagonalMode p_diagonal_mode);
DiagonalMode get_diagonal_mode() const;
- void set_default_heuristic(Heuristic p_heuristic);
- Heuristic get_default_heuristic() const;
+ void set_default_compute_heuristic(Heuristic p_heuristic);
+ Heuristic get_default_compute_heuristic() const;
+
+ void set_default_estimate_heuristic(Heuristic p_heuristic);
+ Heuristic get_default_estimate_heuristic() const;
void set_point_solid(const Vector2i &p_id, bool p_solid = true);
bool is_point_solid(const Vector2i &p_id) const;
+ void set_point_weight_scale(const Vector2i &p_id, real_t p_weight_scale);
+ real_t get_point_weight_scale(const Vector2i &p_id) const;
+
void clear();
+ Vector2 get_point_position(const Vector2i &p_id) const;
Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to);
TypedArray<Vector2i> get_id_path(const Vector2i &p_from, const Vector2i &p_to);
};
diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp
index 561970d2ee..51d88d8ea0 100644
--- a/core/math/convex_hull.cpp
+++ b/core/math/convex_hull.cpp
@@ -2274,8 +2274,7 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
// Copy the edges over. There's two "half-edges" for every edge, so we pick only one of them.
r_mesh.edges.resize(ch.edges.size() / 2);
- OAHashMap<uint64_t, int32_t> edge_map;
- edge_map.reserve(ch.edges.size() * 4); // The higher the capacity, the faster the insert
+ OAHashMap<uint64_t, int32_t> edge_map(ch.edges.size() * 4); // The higher the capacity, the faster the insert
uint32_t edges_copied = 0;
for (uint32_t i = 0; i < ch.edges.size(); i++) {
diff --git a/core/math/math_defs.h b/core/math/math_defs.h
index 759667e2d5..1058a47c1a 100644
--- a/core/math/math_defs.h
+++ b/core/math/math_defs.h
@@ -86,6 +86,7 @@ enum InlineAlignment {
// Image alignment points.
INLINE_ALIGNMENT_TOP_TO = 0b0000,
INLINE_ALIGNMENT_CENTER_TO = 0b0001,
+ INLINE_ALIGNMENT_BASELINE_TO = 0b0011,
INLINE_ALIGNMENT_BOTTOM_TO = 0b0010,
INLINE_ALIGNMENT_IMAGE_MASK = 0b0011,
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 8dff8e6e7e..a998dece2a 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -453,7 +453,10 @@ public:
}
static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) {
double range = max - min;
- double result = is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range));
+ if (is_zero_approx(range)) {
+ return min;
+ }
+ double result = value - (range * Math::floor((value - min) / range));
if (is_equal_approx(result, max)) {
return min;
}
@@ -461,7 +464,10 @@ public:
}
static _ALWAYS_INLINE_ float wrapf(float value, float min, float max) {
float range = max - min;
- float result = is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range));
+ if (is_zero_approx(range)) {
+ return min;
+ }
+ float result = value - (range * Math::floor((value - min) / range));
if (is_equal_approx(result, max)) {
return min;
}
diff --git a/core/math/projection.cpp b/core/math/projection.cpp
index 9af388b081..c135e1946a 100644
--- a/core/math/projection.cpp
+++ b/core/math/projection.cpp
@@ -134,7 +134,7 @@ Projection Projection::create_for_hmd(int p_eye, real_t p_aspect, real_t p_intra
Projection Projection::create_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) {
Projection proj;
- proj.set_orthogonal(p_left, p_right, p_bottom, p_top, p_zfar, p_zfar);
+ proj.set_orthogonal(p_left, p_right, p_bottom, p_top, p_znear, p_zfar);
return proj;
}
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 6d567ffd43..6b199e883f 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -155,10 +155,6 @@ int OS::get_process_id() const {
return -1;
}
-void OS::vibrate_handheld(int p_duration_ms) {
- WARN_PRINT("vibrate_handheld() only works with Android, iOS and Web");
-}
-
bool OS::is_stdout_verbose() const {
return _verbose_stdout;
}
diff --git a/core/os/os.h b/core/os/os.h
index 72a91f318a..07e9020a51 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -159,7 +159,7 @@ public:
virtual Error kill(const ProcessID &p_pid) = 0;
virtual int get_process_id() const;
virtual bool is_process_running(const ProcessID &p_pid) const = 0;
- virtual void vibrate_handheld(int p_duration_ms = 500);
+ virtual void vibrate_handheld(int p_duration_ms = 500) {}
virtual Error shell_open(String p_uri);
virtual Error set_cwd(const String &p_cwd);
diff --git a/core/string/string_name.cpp b/core/string/string_name.cpp
index 9c4fc4e1b7..64d49b8b93 100644
--- a/core/string/string_name.cpp
+++ b/core/string/string_name.cpp
@@ -169,6 +169,10 @@ bool StringName::operator!=(const String &p_name) const {
return !(operator==(p_name));
}
+bool StringName::operator!=(const char *p_name) const {
+ return !(operator==(p_name));
+}
+
bool StringName::operator!=(const StringName &p_name) const {
// the real magic of all this mess happens here.
// this is why path comparisons are very fast
diff --git a/core/string/string_name.h b/core/string/string_name.h
index ff4c41af94..6a2420e02a 100644
--- a/core/string/string_name.h
+++ b/core/string/string_name.h
@@ -102,6 +102,7 @@ public:
bool operator==(const String &p_name) const;
bool operator==(const char *p_name) const;
bool operator!=(const String &p_name) const;
+ bool operator!=(const char *p_name) const;
_FORCE_INLINE_ bool is_node_unique_name() const {
if (!_data) {
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 4e26b61334..adab6d07c7 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -220,37 +220,6 @@ void CharString::copy_from(const char *p_cstr) {
/* String */
/*************************************************************************/
-//kind of poor should be rewritten properly
-String String::word_wrap(int p_chars_per_line) const {
- int from = 0;
- int last_space = 0;
- String ret;
- for (int i = 0; i < length(); i++) {
- if (i - from >= p_chars_per_line) {
- if (last_space == -1) {
- ret += substr(from, i - from + 1) + "\n";
- } else {
- ret += substr(from, last_space - from) + "\n";
- i = last_space; //rewind
- }
- from = i + 1;
- last_space = -1;
- } else if (operator[](i) == ' ' || operator[](i) == '\t') {
- last_space = i;
- } else if (operator[](i) == '\n') {
- ret += substr(from, i - from) + "\n";
- from = i + 1;
- last_space = -1;
- }
- }
-
- if (from < length()) {
- ret += substr(from, length());
- }
-
- return ret;
-}
-
Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path) const {
// Splits the URL into scheme, host, port, path. Strip credentials when present.
String base = *this;
diff --git a/core/string/ustring.h b/core/string/ustring.h
index ed3848fb8a..559f679f0f 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -425,7 +425,6 @@ public:
String c_escape_multiline() const;
String c_unescape() const;
String json_escape() const;
- String word_wrap(int p_chars_per_line) const;
Error parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path) const;
String property_name_encode() const;
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
index e355053296..8e2d150430 100644
--- a/core/variant/type_info.h
+++ b/core/variant/type_info.h
@@ -290,6 +290,7 @@ public:
_FORCE_INLINE_ void set_flag(T p_flag) { value |= p_flag; }
_FORCE_INLINE_ bool has_flag(T p_flag) const { return value & p_flag; }
_FORCE_INLINE_ void clear_flag(T p_flag) { return value &= ~p_flag; }
+ _FORCE_INLINE_ BitField() = default;
_FORCE_INLINE_ BitField(int64_t p_value) { value = p_value; }
_FORCE_INLINE_ operator int64_t() const { return value; }
_FORCE_INLINE_ operator Variant() const { return value; }
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index ac569941bf..57d62dac91 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -65,11 +65,13 @@ static _FORCE_INLINE_ void vc_method_call(R (T::*method)(P...) const, Variant *b
template <class T, class... P>
static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ VariantInternal::clear(&r_ret);
call_with_variant_args_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, p_defvals);
}
template <class T, class... P>
static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ VariantInternal::clear(&r_ret);
call_with_variant_argsc_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, p_defvals);
}
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 684baff348..f3b9bd235c 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -1314,7 +1314,7 @@ struct VariantZeroAssigner<float> {
template <>
struct VariantZeroAssigner<String> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_string(v) = String(); }
};
template <>
@@ -1399,12 +1399,12 @@ struct VariantZeroAssigner<Color> {
template <>
struct VariantZeroAssigner<StringName> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_string_name(v) = StringName(); }
};
template <>
struct VariantZeroAssigner<NodePath> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_node_path(v) = NodePath(); }
};
template <>
@@ -1414,12 +1414,12 @@ struct VariantZeroAssigner<::RID> {
template <>
struct VariantZeroAssigner<Callable> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_callable(v) = Callable(); }
};
template <>
struct VariantZeroAssigner<Signal> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_signal(v) = Signal(); }
};
template <>
@@ -1434,47 +1434,47 @@ struct VariantZeroAssigner<Array> {
template <>
struct VariantZeroAssigner<PackedByteArray> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_byte_array(v) = PackedByteArray(); }
};
template <>
struct VariantZeroAssigner<PackedInt32Array> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_int32_array(v) = PackedInt32Array(); }
};
template <>
struct VariantZeroAssigner<PackedInt64Array> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_int64_array(v) = PackedInt64Array(); }
};
template <>
struct VariantZeroAssigner<PackedFloat32Array> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_float32_array(v) = PackedFloat32Array(); }
};
template <>
struct VariantZeroAssigner<PackedFloat64Array> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_float64_array(v) = PackedFloat64Array(); }
};
template <>
struct VariantZeroAssigner<PackedStringArray> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_string_array(v) = PackedStringArray(); }
};
template <>
struct VariantZeroAssigner<PackedVector2Array> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector2_array(v) = PackedVector2Array(); }
};
template <>
struct VariantZeroAssigner<PackedVector3Array> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector3_array(v) = PackedVector3Array(); }
};
template <>
struct VariantZeroAssigner<PackedColorArray> {
- static _FORCE_INLINE_ void zero(Variant *v) {}
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_color_array(v) = PackedColorArray(); }
};
template <class T>
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 50c1ed847a..6b0dccd7fc 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1479,6 +1479,9 @@
<constant name="INLINE_ALIGNMENT_CENTER_TO" value="1" enum="InlineAlignment">
Aligns the center of the inline object (e.g. image, table) to the position of the text specified by [code]INLINE_ALIGNMENT_TO_*[/code] constant.
</constant>
+ <constant name="INLINE_ALIGNMENT_BASELINE_TO" value="3" enum="InlineAlignment">
+ Aligns the baseline (user defined) of the inline object (e.g. image, table) to the position of the text specified by [code]INLINE_ALIGNMENT_TO_*[/code] constant.
+ </constant>
<constant name="INLINE_ALIGNMENT_BOTTOM_TO" value="2" enum="InlineAlignment">
Aligns the bottom of the inline object (e.g. image, table) to the position of the text specified by [code]INLINE_ALIGNMENT_TO_*[/code] constant.
</constant>
diff --git a/doc/classes/AStarGrid2D.xml b/doc/classes/AStarGrid2D.xml
index 8dde3748d7..32599d7f7d 100644
--- a/doc/classes/AStarGrid2D.xml
+++ b/doc/classes/AStarGrid2D.xml
@@ -69,6 +69,20 @@
[b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector3Array] and will print an error message.
</description>
</method>
+ <method name="get_point_position" qualifiers="const">
+ <return type="Vector2" />
+ <param index="0" name="id" type="Vector2i" />
+ <description>
+ Returns the position of the point associated with the given [param id].
+ </description>
+ </method>
+ <method name="get_point_weight_scale" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="id" type="Vector2i" />
+ <description>
+ Returns the weight scale of the point associated with the given [param id].
+ </description>
+ </method>
<method name="is_dirty" qualifiers="const">
<return type="bool" />
<description>
@@ -103,6 +117,16 @@
<param index="1" name="solid" type="bool" default="true" />
<description>
Disables or enables the specified point for pathfinding. Useful for making an obstacle. By default, all points are enabled.
+ [b]Note:[/b] Calling [method update] is not needed after the call of this function.
+ </description>
+ </method>
+ <method name="set_point_weight_scale">
+ <return type="void" />
+ <param index="0" name="id" type="Vector2i" />
+ <param index="1" name="weight_scale" type="float" />
+ <description>
+ Sets the [param weight_scale] for the point with the given [param id]. The [param weight_scale] is multiplied by the result of [method _compute_cost] when determining the overall cost of traveling across a segment from a neighboring point to this point.
+ [b]Note:[/b] Calling [method update] is not needed after the call of this function.
</description>
</method>
<method name="update">
@@ -116,14 +140,18 @@
<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>
- <member name="default_heuristic" type="int" setter="set_default_heuristic" getter="get_default_heuristic" enum="AStarGrid2D.Heuristic" default="0">
- The default [enum Heuristic] which will be used to calculate the path if [method _compute_cost] and/or [method _estimate_cost] were not overridden.
+ <member name="default_compute_heuristic" type="int" setter="set_default_compute_heuristic" getter="get_default_compute_heuristic" enum="AStarGrid2D.Heuristic" default="0">
+ The default [enum Heuristic] which will be used to calculate the cost between two points if [method _compute_cost] was not overridden.
+ </member>
+ <member name="default_estimate_heuristic" type="int" setter="set_default_estimate_heuristic" getter="get_default_estimate_heuristic" enum="AStarGrid2D.Heuristic" default="0">
+ The default [enum Heuristic] which will be used to calculate the cost between the point and the end point if [method _estimate_cost] was not overridden.
</member>
<member name="diagonal_mode" type="int" setter="set_diagonal_mode" getter="get_diagonal_mode" enum="AStarGrid2D.DiagonalMode" default="0">
A specific [enum DiagonalMode] mode which will force the path to avoid or accept the specified diagonals.
</member>
<member name="jumping_enabled" type="bool" setter="set_jumping_enabled" getter="is_jumping_enabled" default="false">
Enables or disables jumping to skip up the intermediate points and speeds up the searching algorithm.
+ [b]Note:[/b] Currently, toggling it on disables the consideration of weight scaling in pathfinding.
</member>
<member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)">
The offset of the grid 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.
@@ -134,20 +162,22 @@
</members>
<constants>
<constant name="HEURISTIC_EUCLIDEAN" value="0" enum="Heuristic">
- The Euclidean heuristic to be used for the pathfinding using the following formula:
+ The [url=https://en.wikipedia.org/wiki/Euclidean_distance]Euclidean heuristic[/url] to be used for the pathfinding using the following formula:
[codeblock]
dx = abs(to_id.x - from_id.x)
dy = abs(to_id.y - from_id.y)
result = sqrt(dx * dx + dy * dy)
[/codeblock]
+ [b]Note:[/b] This is also the internal heuristic used in [AStar3D] and [AStar2D] by default (with the inclusion of possible z-axis coordinate).
</constant>
<constant name="HEURISTIC_MANHATTAN" value="1" enum="Heuristic">
- The Manhattan heuristic to be used for the pathfinding using the following formula:
+ The [url=https://en.wikipedia.org/wiki/Taxicab_geometry]Manhattan heuristic[/url] to be used for the pathfinding using the following formula:
[codeblock]
dx = abs(to_id.x - from_id.x)
dy = abs(to_id.y - from_id.y)
result = dx + dy
[/codeblock]
+ [b]Note:[/b] This heuristic is intended to be used with 4-side orthogonal movements, provided by setting the [member diagonal_mode] to [constant DIAGONAL_MODE_NEVER].
</constant>
<constant name="HEURISTIC_OCTILE" value="2" enum="Heuristic">
The Octile heuristic to be used for the pathfinding using the following formula:
@@ -159,7 +189,7 @@
[/codeblock]
</constant>
<constant name="HEURISTIC_CHEBYSHEV" value="3" enum="Heuristic">
- The Chebyshev heuristic to be used for the pathfinding using the following formula:
+ The [url=https://en.wikipedia.org/wiki/Chebyshev_distance]Chebyshev heuristic[/url] to be used for the pathfinding using the following formula:
[codeblock]
dx = abs(to_id.x - from_id.x)
dy = abs(to_id.y - from_id.y)
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index d9a1f896f1..c0626dcfe4 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -305,9 +305,9 @@
<return type="int" />
<param index="0" name="track_idx" type="int" />
<param index="1" name="time" type="float" />
- <param index="2" name="exact" type="bool" default="false" />
+ <param index="2" name="find_mode" type="int" enum="Animation.FindMode" default="0" />
<description>
- Finds the key index by time in a given track. Optionally, only find it if the exact time is given.
+ Finds the key index by time in a given track. Optionally, only find it if the approx/exact time is given.
</description>
</method>
<method name="track_get_interpolation_loop_wrap" qualifiers="const">
@@ -622,5 +622,14 @@
<constant name="LOOPED_FLAG_START" value="2" enum="LoopedFlag">
This flag indicates that the animation has reached the start of the animation and just after loop processed.
</constant>
+ <constant name="FIND_MODE_NEAREST" value="0" enum="FindMode">
+ Finds the nearest time key.
+ </constant>
+ <constant name="FIND_MODE_APPROX" value="1" enum="FindMode">
+ Finds only the key with approximating the time.
+ </constant>
+ <constant name="FIND_MODE_EXACT" value="2" enum="FindMode">
+ Finds only the key with matching the time.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml
index 4c2a30030b..814b2d0052 100644
--- a/doc/classes/AnimationNodeStateMachineTransition.xml
+++ b/doc/classes/AnimationNodeStateMachineTransition.xml
@@ -22,14 +22,11 @@
<member name="advance_expression" type="String" setter="set_advance_expression" getter="get_advance_expression" default="&quot;&quot;">
Use an expression as a condition for state machine transitions. It is possible to create complex animation advance conditions for switching between states and gives much greater flexibility for creating complex state machines by directly interfacing with the script code.
</member>
- <member name="auto_advance" type="bool" setter="set_auto_advance" getter="has_auto_advance" default="false">
- Turn on the transition automatically when this state is reached. This works best with [constant SWITCH_MODE_AT_END].
- </member>
- <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false">
- Don't use this transition during [method AnimationNodeStateMachinePlayback.travel] or [member auto_advance].
+ <member name="advance_mode" type="int" setter="set_advance_mode" getter="get_advance_mode" enum="AnimationNodeStateMachineTransition.AdvanceMode" default="1">
+ Determines whether the transition should disabled, enabled when using [method AnimationNodeStateMachinePlayback.travel], or traversed automatically if the [member advance_condition] and [member advance_expression] checks are true (if assigned).
</member>
<member name="priority" type="int" setter="set_priority" getter="get_priority" default="1">
- Lower priority transitions are preferred when travelling through the tree via [method AnimationNodeStateMachinePlayback.travel] or [member auto_advance].
+ Lower priority transitions are preferred when travelling through the tree via [method AnimationNodeStateMachinePlayback.travel] or [member advance_mode] is set to [constant ADVANCE_MODE_AUTO].
</member>
<member name="switch_mode" type="int" setter="set_switch_mode" getter="get_switch_mode" enum="AnimationNodeStateMachineTransition.SwitchMode" default="0">
The transition type.
@@ -58,5 +55,14 @@
<constant name="SWITCH_MODE_AT_END" value="2" enum="SwitchMode">
Wait for the current state playback to end, then switch to the beginning of the next state animation.
</constant>
+ <constant name="ADVANCE_MODE_DISABLED" value="0" enum="AdvanceMode">
+ Don't use this transition.
+ </constant>
+ <constant name="ADVANCE_MODE_ENABLED" value="1" enum="AdvanceMode">
+ Only use this transition during [method AnimationNodeStateMachinePlayback.travel].
+ </constant>
+ <constant name="ADVANCE_MODE_AUTO" value="2" enum="AdvanceMode">
+ Automatically use this transition if the [member advance_condition] and [member advance_expression] checks are true (if assigned).
+ </constant>
</constants>
</class>
diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml
index 21f4b37741..a17a727d7e 100644
--- a/doc/classes/AnimationTree.xml
+++ b/doc/classes/AnimationTree.xml
@@ -111,11 +111,25 @@
</member>
</members>
<signals>
+ <signal name="animation_finished">
+ <param index="0" name="anim_name" type="StringName" />
+ <description>
+ Notifies when an animation finished playing.
+ [b]Note:[/b] This signal is not emitted if an animation is looping or aborted. Also be aware of the possibility of unseen playback by sync and xfade.
+ </description>
+ </signal>
<signal name="animation_player_changed">
<description>
Emitted when the [member anim_player] is changed.
</description>
</signal>
+ <signal name="animation_started">
+ <param index="0" name="anim_name" type="StringName" />
+ <description>
+ Notifies when an animation starts playing.
+ [b]Note:[/b] This signal is not emitted if an animation is looping or playbacked from the middle. Also be aware of the possibility of unseen playback by sync and xfade.
+ </description>
+ </signal>
</signals>
<constants>
<constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessCallback">
diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml
index 29592f133d..3f76cc16ec 100644
--- a/doc/classes/Area2D.xml
+++ b/doc/classes/Area2D.xml
@@ -114,15 +114,13 @@
<signal name="area_entered">
<param index="0" name="area" type="Area2D" />
<description>
- Emitted when another Area2D enters this Area2D. Requires [member monitoring] to be set to [code]true[/code].
- [param area] the other Area2D.
+ Emitted when the received [param area] enters this area. Requires [member monitoring] to be set to [code]true[/code].
</description>
</signal>
<signal name="area_exited">
<param index="0" name="area" type="Area2D" />
<description>
- Emitted when another Area2D exits this Area2D. Requires [member monitoring] to be set to [code]true[/code].
- [param area] the other Area2D.
+ Emitted when the received [param area] exits this area. Requires [member monitoring] to be set to [code]true[/code].
</description>
</signal>
<signal name="area_shape_entered">
@@ -131,11 +129,18 @@
<param index="2" name="area_shape_index" type="int" />
<param index="3" name="local_shape_index" type="int" />
<description>
- Emitted when one of another Area2D's [Shape2D]s enters one of this Area2D's [Shape2D]s. Requires [member monitoring] to be set to [code]true[/code].
- [param area_rid] the [RID] of the other Area2D's [CollisionObject2D] used by the [PhysicsServer2D].
- [param area] the other Area2D.
- [param area_shape_index] the index of the [Shape2D] of the other Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code].
- [param local_shape_index] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ Emitted when a [Shape2D] of the received [param area] enters a shape of this area. Requires [member monitoring] to be set to [code]true[/code].
+ [param local_shape_index] and [param area_shape_index] contain indices of the interacting shapes from this area and the other area, respectively. [param area_rid] contains the [RID] of the other area. These values can be used with the [PhysicsServer2D].
+ [b]Example of getting the[/b] [CollisionShape2D] [b]node from the shape index:[/b]
+ [codeblocks]
+ [gdscript]
+ var other_shape_owner = area.shape_find_owner(area_shape_index)
+ var other_shape_node = area.shape_owner_get_owner(other_shape_owner)
+
+ var local_shape_owner = shape_find_owner(local_shape_index)
+ var local_shape_node = shape_owner_get_owner(local_shape_owner)
+ [/gdscript]
+ [/codeblocks]
</description>
</signal>
<signal name="area_shape_exited">
@@ -144,25 +149,20 @@
<param index="2" name="area_shape_index" type="int" />
<param index="3" name="local_shape_index" type="int" />
<description>
- Emitted when one of another Area2D's [Shape2D]s exits one of this Area2D's [Shape2D]s. Requires [member monitoring] to be set to [code]true[/code].
- [param area_rid] the [RID] of the other Area2D's [CollisionObject2D] used by the [PhysicsServer2D].
- [param area] the other Area2D.
- [param area_shape_index] the index of the [Shape2D] of the other Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code].
- [param local_shape_index] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ Emitted when a [Shape2D] of the received [param area] exits a shape of this area. Requires [member monitoring] to be set to [code]true[/code].
+ See also [signal area_shape_entered].
</description>
</signal>
<signal name="body_entered">
<param index="0" name="body" type="Node2D" />
<description>
- Emitted when a [PhysicsBody2D] or [TileMap] enters this Area2D. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
- [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
+ Emitted when the received [param body] enters this area. [param body] can be a [PhysicsBody2D] or a [TileMap]. [TileMap]s are detected if their [TileSet] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code].
</description>
</signal>
<signal name="body_exited">
<param index="0" name="body" type="Node2D" />
<description>
- Emitted when a [PhysicsBody2D] or [TileMap] exits this Area2D. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
- [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
+ Emitted when the received [param body] exits this area. [param body] can be a [PhysicsBody2D] or a [TileMap]. [TileMap]s are detected if their [TileSet] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code].
</description>
</signal>
<signal name="body_shape_entered">
@@ -171,11 +171,18 @@
<param index="2" name="body_shape_index" type="int" />
<param index="3" name="local_shape_index" type="int" />
<description>
- Emitted when one of a [PhysicsBody2D] or [TileMap]'s [Shape2D]s enters one of this Area2D's [Shape2D]s. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
- [param body_rid] the [RID] of the [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D].
- [param body] the [Node], if it exists in the tree, of the [PhysicsBody2D] or [TileMap].
- [param body_shape_index] the index of the [Shape2D] of the [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
- [param local_shape_index] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ Emitted when a [Shape2D] of the received [param body] enters a shape of this area. [param body] can be a [PhysicsBody2D] or a [TileMap]. [TileMap]s are detected if their [TileSet] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code].
+ [param local_shape_index] and [param body_shape_index] contain indices of the interacting shapes from this area and the interacting body, respectively. [param body_rid] contains the [RID] of the body. These values can be used with the [PhysicsServer2D].
+ [b]Example of getting the[/b] [CollisionShape2D] [b]node from the shape index:[/b]
+ [codeblocks]
+ [gdscript]
+ var body_shape_owner = body.shape_find_owner(body_shape_index)
+ var body_shape_node = body.shape_owner_get_owner(body_shape_owner)
+
+ var local_shape_owner = shape_find_owner(local_shape_index)
+ var local_shape_node = shape_owner_get_owner(local_shape_owner)
+ [/gdscript]
+ [/codeblocks]
</description>
</signal>
<signal name="body_shape_exited">
@@ -184,11 +191,8 @@
<param index="2" name="body_shape_index" type="int" />
<param index="3" name="local_shape_index" type="int" />
<description>
- Emitted when one of a [PhysicsBody2D] or [TileMap]'s [Shape2D]s exits one of this Area2D's [Shape2D]s. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
- [param body_rid] the [RID] of the [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D].
- [param body] the [Node], if it exists in the tree, of the [PhysicsBody2D] or [TileMap].
- [param body_shape_index] the index of the [Shape2D] of the [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
- [param local_shape_index] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ Emitted when a [Shape2D] of the received [param body] exits a shape of this area. [param body] can be a [PhysicsBody2D] or a [TileMap]. [TileMap]s are detected if their [TileSet] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code].
+ See also [signal body_shape_entered].
</description>
</signal>
</signals>
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index ea8cab324d..8923ac8aae 100644
--- a/doc/classes/Area3D.xml
+++ b/doc/classes/Area3D.xml
@@ -133,15 +133,13 @@
<signal name="area_entered">
<param index="0" name="area" type="Area3D" />
<description>
- Emitted when another Area3D enters this Area3D. Requires [member monitoring] to be set to [code]true[/code].
- [param area] the other Area3D.
+ Emitted when the received [param area] enters this area. Requires [member monitoring] to be set to [code]true[/code].
</description>
</signal>
<signal name="area_exited">
<param index="0" name="area" type="Area3D" />
<description>
- Emitted when another Area3D exits this Area3D. Requires [member monitoring] to be set to [code]true[/code].
- [param area] the other Area3D.
+ Emitted when the received [param area] exits this area. Requires [member monitoring] to be set to [code]true[/code].
</description>
</signal>
<signal name="area_shape_entered">
@@ -150,11 +148,18 @@
<param index="2" name="area_shape_index" type="int" />
<param index="3" name="local_shape_index" type="int" />
<description>
- Emitted when one of another Area3D's [Shape3D]s enters one of this Area3D's [Shape3D]s. Requires [member monitoring] to be set to [code]true[/code].
- [param area_rid] the [RID] of the other Area3D's [CollisionObject3D] used by the [PhysicsServer3D].
- [param area] the other Area3D.
- [param area_shape_index] the index of the [Shape3D] of the other Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code].
- [param local_shape_index] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ Emitted when a [Shape3D] of the received [param area] enters a shape of this area. Requires [member monitoring] to be set to [code]true[/code].
+ [param local_shape_index] and [param area_shape_index] contain indices of the interacting shapes from this area and the other area, respectively. [param area_rid] contains the [RID] of the other area. These values can be used with the [PhysicsServer3D].
+ [b]Example of getting the[/b] [CollisionShape3D] [b]node from the shape index:[/b]
+ [codeblocks]
+ [gdscript]
+ var other_shape_owner = area.shape_find_owner(area_shape_index)
+ var other_shape_node = area.shape_owner_get_owner(other_shape_owner)
+
+ var local_shape_owner = shape_find_owner(local_shape_index)
+ var local_shape_node = shape_owner_get_owner(local_shape_owner)
+ [/gdscript]
+ [/codeblocks]
</description>
</signal>
<signal name="area_shape_exited">
@@ -163,25 +168,20 @@
<param index="2" name="area_shape_index" type="int" />
<param index="3" name="local_shape_index" type="int" />
<description>
- Emitted when one of another Area3D's [Shape3D]s exits one of this Area3D's [Shape3D]s. Requires [member monitoring] to be set to [code]true[/code].
- [param area_rid] the [RID] of the other Area3D's [CollisionObject3D] used by the [PhysicsServer3D].
- [param area] the other Area3D.
- [param area_shape_index] the index of the [Shape3D] of the other Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code].
- [param local_shape_index] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ Emitted when a [Shape3D] of the received [param area] exits a shape of this area. Requires [member monitoring] to be set to [code]true[/code].
+ See also [signal area_shape_entered].
</description>
</signal>
<signal name="body_entered">
<param index="0" name="body" type="Node3D" />
<description>
- Emitted when a [PhysicsBody3D] or [GridMap] enters this Area3D. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
- [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
+ Emitted when the received [param body] enters this area. [param body] can be a [PhysicsBody3D] or a [GridMap]. [GridMap]s are detected if their [MeshLibrary] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code].
</description>
</signal>
<signal name="body_exited">
<param index="0" name="body" type="Node3D" />
<description>
- Emitted when a [PhysicsBody3D] or [GridMap] exits this Area3D. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
- [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
+ Emitted when the received [param body] exits this area. [param body] can be a [PhysicsBody3D] or a [GridMap]. [GridMap]s are detected if their [MeshLibrary] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code].
</description>
</signal>
<signal name="body_shape_entered">
@@ -190,11 +190,18 @@
<param index="2" name="body_shape_index" type="int" />
<param index="3" name="local_shape_index" type="int" />
<description>
- Emitted when one of a [PhysicsBody3D] or [GridMap]'s [Shape3D]s enters one of this Area3D's [Shape3D]s. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
- [param body_rid] the [RID] of the [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D].
- [param body] the [Node], if it exists in the tree, of the [PhysicsBody3D] or [GridMap].
- [param body_shape_index] the index of the [Shape3D] of the [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
- [param local_shape_index] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ Emitted when a [Shape3D] of the received [param body] enters a shape of this area. [param body] can be a [PhysicsBody3D] or a [GridMap]. [GridMap]s are detected if their [MeshLibrary] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code].
+ [param local_shape_index] and [param body_shape_index] contain indices of the interacting shapes from this area and the interacting body, respectively. [param body_rid] contains the [RID] of the body. These values can be used with the [PhysicsServer3D].
+ [b]Example of getting the[/b] [CollisionShape3D] [b]node from the shape index:[/b]
+ [codeblocks]
+ [gdscript]
+ var body_shape_owner = body.shape_find_owner(body_shape_index)
+ var body_shape_node = body.shape_owner_get_owner(body_shape_owner)
+
+ var local_shape_owner = shape_find_owner(local_shape_index)
+ var local_shape_node = shape_owner_get_owner(local_shape_owner)
+ [/gdscript]
+ [/codeblocks]
</description>
</signal>
<signal name="body_shape_exited">
@@ -203,11 +210,8 @@
<param index="2" name="body_shape_index" type="int" />
<param index="3" name="local_shape_index" type="int" />
<description>
- Emitted when one of a [PhysicsBody3D] or [GridMap]'s [Shape3D]s enters one of this Area3D's [Shape3D]s. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
- [param body_rid] the [RID] of the [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D].
- [param body] the [Node], if it exists in the tree, of the [PhysicsBody3D] or [GridMap].
- [param body_shape_index] the index of the [Shape3D] of the [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
- [param local_shape_index] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ Emitted when a [Shape3D] of the received [param body] exits a shape of this area. [param body] can be a [PhysicsBody3D] or a [GridMap]. [GridMap]s are detected if their [MeshLibrary] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code].
+ See also [signal body_shape_entered].
</description>
</signal>
</signals>
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index b9c8ab0f6c..70ce4ad516 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -102,13 +102,13 @@
<param index="0" name="transform" type="Transform3D" />
<param index="1" name="texel_size" type="float" />
<description>
- Will perform a UV unwrap on the [ArrayMesh] to prepare the mesh for lightmapping.
+ Performs a UV unwrap on the [ArrayMesh] to prepare the mesh for lightmapping.
</description>
</method>
<method name="regen_normal_maps">
<return type="void" />
<description>
- Will regenerate normal maps for the [ArrayMesh].
+ Regenerates tangents for each of the [ArrayMesh]'s surfaces.
</description>
</method>
<method name="set_blend_shape_name">
diff --git a/doc/classes/AudioStreamRandomizer.xml b/doc/classes/AudioStreamRandomizer.xml
index 9b58d78af5..d93f853c89 100644
--- a/doc/classes/AudioStreamRandomizer.xml
+++ b/doc/classes/AudioStreamRandomizer.xml
@@ -12,8 +12,10 @@
<method name="add_stream">
<return type="void" />
<param index="0" name="index" type="int" />
+ <param index="1" name="stream" type="AudioStream" />
+ <param index="2" name="weight" type="float" default="1.0" />
<description>
- Insert a stream at the specified index.
+ Insert a stream at the specified index. If the index is less than zero, the insertion occurs at the end of the underlying pool.
</description>
</method>
<method name="get_stream" qualifiers="const">
diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml
index d2c9a77486..961f3c495a 100644
--- a/doc/classes/Button.xml
+++ b/doc/classes/Button.xml
@@ -118,6 +118,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
[Font] of the [Button]'s text.
diff --git a/doc/classes/ButtonGroup.xml b/doc/classes/ButtonGroup.xml
index 277bda2836..8195669b10 100644
--- a/doc/classes/ButtonGroup.xml
+++ b/doc/classes/ButtonGroup.xml
@@ -4,8 +4,8 @@
Group of Buttons.
</brief_description>
<description>
- Group of [Button]. All direct and indirect children buttons become radios. Only one allows being pressed.
- [member BaseButton.toggle_mode] should be [code]true[/code].
+ Group of [BaseButton]. The members of this group are treated like radio buttons in the sense that only one button can be pressed at the same time.
+ Every member of the ButtonGroup should have [member BaseButton.toggle_mode] set to [code]true[/code].
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 499d53e63c..5171e0acbe 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -153,6 +153,7 @@
<param index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<param index="4" name="outline" type="float" default="0.0" />
<param index="5" name="pixel_range" type="float" default="4.0" />
+ <param index="6" name="scale" type="float" default="1.0" />
<description>
Draws a textured rectangle region of the multi-channel signed distance field texture at a given position, optionally modulated by a color. See [member FontFile.multichannel_signed_distance_field] for more information and caveats about MSDF font rendering.
If [param outline] is positive, each alpha channel value of pixel in region is set to maximum value of true distance in the [param outline] radius.
@@ -404,7 +405,7 @@
<method name="get_canvas_transform" qualifiers="const">
<return type="Transform2D" />
<description>
- Returns the transform matrix of this item's canvas.
+ Returns the transform from the coordinate system of the canvas, this item is in, to the [Viewport]s coordinate system.
</description>
</method>
<method name="get_global_mouse_position" qualifiers="const">
@@ -422,7 +423,7 @@
<method name="get_global_transform_with_canvas" qualifiers="const">
<return type="Transform2D" />
<description>
- Returns the global transform matrix of this item in relation to the canvas.
+ Returns the transform from the local coordinate system of this [CanvasItem] to the [Viewport]s coordinate system.
</description>
</method>
<method name="get_local_mouse_position" qualifiers="const">
@@ -453,7 +454,7 @@
<method name="get_viewport_transform" qualifiers="const">
<return type="Transform2D" />
<description>
- Returns this item's transform in relation to the viewport.
+ Returns the transform from the coordinate system of the canvas, this item is in, to the [Viewport]s embedders coordinate system.
</description>
</method>
<method name="get_visibility_layer_bit" qualifiers="const">
diff --git a/doc/classes/CanvasLayer.xml b/doc/classes/CanvasLayer.xml
index 7c1b19b961..ce999c06d3 100644
--- a/doc/classes/CanvasLayer.xml
+++ b/doc/classes/CanvasLayer.xml
@@ -19,6 +19,12 @@
Returns the RID of the canvas used by this layer.
</description>
</method>
+ <method name="get_final_transform" qualifiers="const">
+ <return type="Transform2D" />
+ <description>
+ Returns the transform from the [CanvasLayer]s coordinate system to the [Viewport]s coordinate system.
+ </description>
+ </method>
<method name="hide">
<return type="void" />
<description>
diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml
index 309e2231a4..821117122c 100644
--- a/doc/classes/CharacterBody3D.xml
+++ b/doc/classes/CharacterBody3D.xml
@@ -41,10 +41,16 @@
Returns a [KinematicCollision3D], which contains information about the latest collision that occurred during the last call to [method move_and_slide].
</description>
</method>
+ <method name="get_platform_angular_velocity" qualifiers="const">
+ <return type="Vector3" />
+ <description>
+ Returns the angular velocity of the platform at the last collision point. Only valid after calling [method move_and_slide].
+ </description>
+ </method>
<method name="get_platform_velocity" qualifiers="const">
<return type="Vector3" />
<description>
- Returns the linear velocity of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
+ Returns the linear velocity of the platform at the last collision point. Only valid after calling [method move_and_slide].
</description>
</method>
<method name="get_position_delta" qualifiers="const">
diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml
index 699e872e99..3ee18cf351 100644
--- a/doc/classes/CheckBox.xml
+++ b/doc/classes/CheckBox.xml
@@ -43,6 +43,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
The [Font] to use for the [CheckBox] text.
diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml
index dfbaa7cbee..03578cafd0 100644
--- a/doc/classes/CheckButton.xml
+++ b/doc/classes/CheckButton.xml
@@ -43,6 +43,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
The [Font] to use for the [CheckButton] text.
diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml
index e7ef5fb289..c313e6c875 100644
--- a/doc/classes/CodeEdit.xml
+++ b/doc/classes/CodeEdit.xml
@@ -651,6 +651,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
Sets the default [Font].
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index 4d78433915..d1387d088d 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -205,11 +205,18 @@
<description>
Returns the [Color] associated with the provided [param hex] integer in 32-bit ARGB format (8 bits per channel, alpha channel first).
In GDScript and C#, the [int] is best visualized with hexadecimal notation ([code]"0x"[/code] prefix).
- [codeblock]
+ [codeblocks]
+ [gdscript]
var red = Color.hex(0xffff0000)
var dark_cyan = Color.hex(0xff008b8b)
var my_color = Color.hex(0xa4bbefd2)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ var red = new Color(0xffff0000);
+ var dark_cyan = new Color(0xff008b8b);
+ var my_color = new Color(0xa4bbefd2);
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="hex64" qualifiers="static">
@@ -234,9 +241,9 @@
var col = Color.html("663399cc") # col is Color(0.4, 0.2, 0.6, 0.8)
[/gdscript]
[csharp]
- var blue = new Color("#0000ff"); // blue is Color(0.0, 0.0, 1.0, 1.0)
- var green = new Color("#0F0"); // green is Color(0.0, 1.0, 0.0, 1.0)
- var col = new Color("663399cc"); // col is Color(0.4, 0.2, 0.6, 0.8)
+ var blue = Color.FromHtml("#0000ff"); // blue is Color(0.0, 0.0, 1.0, 1.0)
+ var green = Color.FromHtml("#0F0"); // green is Color(0.0, 1.0, 0.0, 1.0)
+ var col = Color.FromHtml("663399cc"); // col is Color(0.4, 0.2, 0.6, 0.8)
[/csharp]
[/codeblocks]
</description>
@@ -257,14 +264,13 @@
Color.html_is_valid("#55aaFF5") # Returns false
[/gdscript]
[csharp]
- // This method is not available in C#. Use `StringExtensions.IsValidHtmlColor()`, instead.
- "#55AAFF".IsValidHtmlColor(); // Returns true
- "#55AAFF20".IsValidHtmlColor(); // Returns true
- "55AAFF".IsValidHtmlColor(); // Returns true
- "#F2C".IsValidHtmlColor(); // Returns true
+ Color.IsHtmlValid("#55AAFF"); // Returns true
+ Color.IsHtmlValid("#55AAFF20"); // Returns true
+ Color.IsHtmlValid("55AAFF"); // Returns true
+ Color.IsHtmlValid("#F2C"); // Returns true
- "#AABBC".IsValidHtmlColor(); // Returns false
- "#55aaFF5".IsValidHtmlColor(); // Returns false
+ Color.IsHtmlValid("#AABBC"); // Returns false
+ Color.IsHtmlValid("#55aaFF5"); // Returns false
[/csharp]
[/codeblocks]
</description>
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index 2b287d7546..823433c2df 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ColorPicker" inherits="BoxContainer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ColorPicker" inherits="VBoxContainer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Color picker control.
</brief_description>
@@ -88,7 +88,6 @@
<member name="sliders_visible" type="bool" setter="set_sliders_visible" getter="are_sliders_visible" default="true">
If [code]true[/code], the color sliders are visible.
</member>
- <member name="vertical" type="bool" setter="set_vertical" getter="is_vertical" overrides="BoxContainer" default="true" />
</members>
<signals>
<signal name="color_changed">
diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml
index b7a0bdfb0c..2a37cc162a 100644
--- a/doc/classes/ColorPickerButton.xml
+++ b/doc/classes/ColorPickerButton.xml
@@ -79,6 +79,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
[Font] of the [ColorPickerButton]'s text.
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index fd6aab6a49..b0351559ee 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -1050,6 +1050,9 @@
<member name="rotation" type="float" setter="set_rotation" getter="get_rotation" default="0.0">
The node's rotation around its pivot, in radians. See [member pivot_offset] to change the pivot's position.
</member>
+ <member name="rotation_degrees" type="float" setter="set_rotation_degrees" getter="get_rotation_degrees">
+ Helper property to access [member rotation] in degrees instead of radians.
+ </member>
<member name="scale" type="Vector2" setter="set_scale" getter="get_scale" default="Vector2(1, 1)">
The node's scale, relative to its [member size]. Change this property to scale the node around its [member pivot_offset]. The Control's [member tooltip_text] will also scale according to this value.
[b]Note:[/b] This property is mainly intended to be used for animation purposes. Text inside the Control will look pixelated or blurry when the Control is scaled. To support multiple resolutions in your project, use an appropriate viewport stretch mode as described in the [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]documentation[/url] instead of scaling Controls individually.
diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml
index cfe2036499..362d792b39 100644
--- a/doc/classes/Curve3D.xml
+++ b/doc/classes/Curve3D.xml
@@ -138,7 +138,7 @@
<param index="1" name="cubic" type="bool" default="false" />
<param index="2" name="apply_tilt" type="bool" default="false" />
<description>
- Similar with [code]interpolate_baked()[/code]. The the return value is [code]Transform3D[/code], with [code]origin[/code] as point position, [code]basis.x[/code] as sideway vector, [code]basis.y[/code] as up vector, [code]basis.z[/code] as forward vector. When the curve length is 0, there is no reasonable way to caculate the rotation, all vectors aligned with global space axes.
+ Similar with [code]interpolate_baked()[/code]. The the return value is [code]Transform3D[/code], with [code]origin[/code] as point position, [code]basis.x[/code] as sideway vector, [code]basis.y[/code] as up vector, [code]basis.z[/code] as forward vector. When the curve length is 0, there is no reasonable way to calculate the rotation, all vectors aligned with global space axes.
</description>
</method>
<method name="samplef" qualifiers="const">
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index 92225b816f..5f99ba82b8 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -135,7 +135,7 @@
[/csharp]
[/codeblocks]
[b]Note:[/b] Erasing elements while iterating over dictionaries is [b]not[/b] supported and will result in unpredictable behavior.
- [b]Note:[/b] When declaring a dictionary with [code]const[/code], the dictionary becomes read-only. A read-only Dictionary's entries cannot be overriden at run-time. This does [i]not[/i] affect nested [Array] and [Dictionary] values.
+ [b]Note:[/b] When declaring a dictionary with [code]const[/code], the dictionary becomes read-only. A read-only Dictionary's entries cannot be overridden at run-time. This does [i]not[/i] affect nested [Array] and [Dictionary] values.
</description>
<tutorials>
<link title="GDScript basics: Dictionary">$DOCS_URL/tutorials/scripting/gdscript/gdscript_basics.html#dictionary</link>
diff --git a/doc/classes/EditorSpinSlider.xml b/doc/classes/EditorSpinSlider.xml
index de105b32e1..d270d32df7 100644
--- a/doc/classes/EditorSpinSlider.xml
+++ b/doc/classes/EditorSpinSlider.xml
@@ -28,4 +28,26 @@
The suffix to display after the value (in a faded color). This should generally be a plural word. You may have to use an abbreviation if the suffix is too long to be displayed.
</member>
</members>
+ <signals>
+ <signal name="grabbed">
+ <description>
+ Emitted when the spinner/slider is grabbed.
+ </description>
+ </signal>
+ <signal name="ungrabbed">
+ <description>
+ Emitted when the spinner/slider is ungrabbed.
+ </description>
+ </signal>
+ <signal name="value_focus_entered">
+ <description>
+ Emitted when the value form gains focus.
+ </description>
+ </signal>
+ <signal name="value_focus_exited">
+ <description>
+ Emitted when the value form loses focus.
+ </description>
+ </signal>
+ </signals>
</class>
diff --git a/doc/classes/EditorVCSInterface.xml b/doc/classes/EditorVCSInterface.xml
index b766978c04..85c10fefd9 100644
--- a/doc/classes/EditorVCSInterface.xml
+++ b/doc/classes/EditorVCSInterface.xml
@@ -53,7 +53,7 @@
</description>
</method>
<method name="_get_branch_list" qualifiers="virtual">
- <return type="Dictionary[]" />
+ <return type="String[]" />
<description>
Gets an instance of an [Array] of [String]s containing available branch names in the VCS.
</description>
@@ -94,7 +94,7 @@
</description>
</method>
<method name="_get_remotes" qualifiers="virtual">
- <return type="Dictionary[]" />
+ <return type="String[]" />
<description>
Returns an [Array] of [String]s, each containing the name of a remote configured in the VCS.
</description>
diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml
index 1019c271dc..69a7627774 100644
--- a/doc/classes/FontFile.xml
+++ b/doc/classes/FontFile.xml
@@ -570,7 +570,7 @@
Weight (boldness) of the font. A value in the [code]100...999[/code] range, normal font weight is [code]400[/code], bold font weight is [code]700[/code].
</member>
<member name="force_autohinter" type="bool" setter="set_force_autohinter" getter="is_force_autohinter" default="false">
- If set to [code]true[/code], auto-hinting is supported and preferred over font built-in hinting. Used by dynamic fonts only.
+ If set to [code]true[/code], auto-hinting is supported and preferred over font built-in hinting. Used by dynamic fonts only (MSDF fonts don't support hinting).
</member>
<member name="generate_mipmaps" type="bool" setter="set_generate_mipmaps" getter="get_generate_mipmaps" default="false">
If set to [code]true[/code], generate mipmaps for the font textures.
@@ -579,25 +579,27 @@
Font hinting mode. Used by dynamic fonts only.
</member>
<member name="msdf_pixel_range" type="int" setter="set_msdf_pixel_range" getter="get_msdf_pixel_range" default="16">
- The width of the range around the shape between the minimum and maximum representable signed distance.
+ The width of the range around the shape between the minimum and maximum representable signed distance. If using font outlines, [member msdf_pixel_range] must be set to at least [i]twice[/i] the size of the largest font outline. The default [member msdf_pixel_range] value of [code]16[/code] allows outline sizes up to [code]8[/code] to look correct.
</member>
<member name="msdf_size" type="int" setter="set_msdf_size" getter="get_msdf_size" default="48">
- Source font size used to generate MSDF textures.
+ Source font size used to generate MSDF textures. Higher values allow for more precision, but are slower to render and require more memory. Only increase this value if you notice a visible lack of precision in glyph rendering.
</member>
<member name="multichannel_signed_distance_field" type="bool" setter="set_multichannel_signed_distance_field" getter="is_multichannel_signed_distance_field" default="false">
- If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data.
+ If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field (MSDF) generated from the dynamic font vector data. Since this approach does not rely on rasterizing the font every time its size changes, this allows for resizing the font in real-time without any performance penalty. Text will also not look grainy for [Control]s that are scaled down (or for [Label3D]s viewed from a long distance). As a downside, font hinting is not available with MSDF. The lack of font hinting may result in less crisp and less readable fonts at small sizes.
+ [b]Note:[/b] If using font outlines, [member msdf_pixel_range] must be set to at least [i]twice[/i] the size of the largest font outline.
+ [b]Note:[/b] MSDF font rendering does not render glyphs with overlapping shapes correctly. Overlapping shapes are not valid per the OpenType standard, but are still commonly found in many font files, especially those converted by Google Fonts. To avoid issues with overlapping glyphs, consider downloading the font file directly from the type foundry instead of relying on Google Fonts.
</member>
<member name="opentype_feature_overrides" type="Dictionary" setter="set_opentype_feature_overrides" getter="get_opentype_feature_overrides" default="{}">
Font OpenType feature set override.
</member>
<member name="oversampling" type="float" setter="set_oversampling" getter="get_oversampling" default="0.0">
- Font oversampling factor, if set to [code]0.0[/code] global oversampling factor is used instead. Used by dynamic fonts only.
+ Font oversampling factor. If set to [code]0.0[/code], the global oversampling factor is used instead. Used by dynamic fonts only (MSDF fonts ignore oversampling).
</member>
<member name="style_name" type="String" setter="set_font_style_name" getter="get_font_style_name" default="&quot;&quot;">
Font style name.
</member>
<member name="subpixel_positioning" type="int" setter="set_subpixel_positioning" getter="get_subpixel_positioning" enum="TextServer.SubpixelPositioning" default="1">
- Font glyph subpixel positioning mode. Subpixel positioning provides shaper text and better kerning for smaller font sizes, at the cost of memory usage and font rasterization speed. Use [constant TextServer.SUBPIXEL_POSITIONING_AUTO] to automatically enable it based on the font size.
+ Font glyph subpixel positioning mode. Subpixel positioning provides shaper text and better kerning for smaller font sizes, at the cost of higher memory usage and lower font rasterization speed. Use [constant TextServer.SUBPIXEL_POSITIONING_AUTO] to automatically enable it based on the font size.
</member>
</members>
</class>
diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml
index 90a983d28b..1ae4718536 100644
--- a/doc/classes/GeometryInstance3D.xml
+++ b/doc/classes/GeometryInstance3D.xml
@@ -16,13 +16,6 @@
Get the value of a shader parameter as set on this instance.
</description>
</method>
- <method name="set_custom_aabb">
- <return type="void" />
- <param index="0" name="aabb" type="AABB" />
- <description>
- Overrides the bounding box of this node with a custom one. To remove it, set an [AABB] with all fields set to zero.
- </description>
- </method>
<method name="set_instance_shader_parameter">
<return type="void" />
<param index="0" name="name" type="StringName" />
@@ -36,6 +29,9 @@
<member name="cast_shadow" type="int" setter="set_cast_shadows_setting" getter="get_cast_shadows_setting" enum="GeometryInstance3D.ShadowCastingSetting" default="1">
The selected shadow casting flag. See [enum ShadowCastingSetting] for possible values.
</member>
+ <member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb" default="AABB(0, 0, 0, 0, 0, 0)">
+ Overrides the bounding box of this node with a custom one. This can be used to avoid the expensive [AABB] recalculation that happens when a skeleton is used with a [MeshInstance3D] or to have fine control over the [MeshInstance3D]'s bounding box. To remove this, set value to an [AABB] with all fields set to zero.
+ </member>
<member name="extra_cull_margin" type="float" setter="set_extra_cull_margin" getter="get_extra_cull_margin" default="0.0">
The extra distance added to the GeometryInstance3D's bounding box ([AABB]) to increase its cull box.
</member>
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index be66b8a7b9..ed1b40488e 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -76,8 +76,12 @@
<param index="0" name="mode" type="int" enum="Image.CompressMode" />
<param index="1" name="source" type="int" enum="Image.CompressSource" default="0" />
<param index="2" name="lossy_quality" type="float" default="0.7" />
+ <param index="3" name="astc_format" type="int" enum="Image.ASTCFormat" default="0" />
<description>
- Compresses the image to use less memory. Can not directly access pixel data while the image is compressed. Returns error if the chosen compression mode is not available. See [enum CompressMode] and [enum CompressSource] constants.
+ Compresses the image to use less memory. Can not directly access pixel data while the image is compressed. Returns error if the chosen compression mode is not available.
+ The [param mode] parameter helps to pick the best compression method for DXT and ETC2 formats. It is ignored for ASTC compression.
+ The [param lossy_quality] parameter is optional for compressors that support it.
+ For ASTC compression, the [param astc_format] parameter must be supplied.
</description>
</method>
<method name="compress_from_channels">
@@ -85,7 +89,12 @@
<param index="0" name="mode" type="int" enum="Image.CompressMode" />
<param index="1" name="channels" type="int" enum="Image.UsedChannels" />
<param index="2" name="lossy_quality" type="float" default="0.7" />
+ <param index="3" name="astc_format" type="int" enum="Image.ASTCFormat" default="0" />
<description>
+ Compresses the image to use less memory. Can not directly access pixel data while the image is compressed. Returns error if the chosen compression mode is not available.
+ This is an alternative to [method compress] that lets the user supply the channels used in order for the compressor to pick the best DXT and ETC2 formats. For other formats (non DXT or ETC2), this argument is ignored.
+ The [param lossy_quality] parameter is optional for compressors that support it.
+ For ASTC compression, the [param astc_format] parameter must be supplied.
</description>
</method>
<method name="compute_image_metrics">
@@ -658,7 +667,19 @@
</constant>
<constant name="FORMAT_DXT5_RA_AS_RG" value="34" enum="Format">
</constant>
- <constant name="FORMAT_MAX" value="35" enum="Format">
+ <constant name="FORMAT_ASTC_4x4" value="35" enum="Format">
+ [url=https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression]Adaptive Scalable Texutre Compression[/url]. This implements the 4x4 (high quality) mode.
+ </constant>
+ <constant name="FORMAT_ASTC_4x4_HDR" value="36" enum="Format">
+ Same format as [constant FORMAT_ASTC_4x4], but with the hint to let the GPU know it is used for HDR.
+ </constant>
+ <constant name="FORMAT_ASTC_8x8" value="37" enum="Format">
+ [url=https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression]Adaptive Scalable Texutre Compression[/url]. This implements the 8x8 (low quality) mode.
+ </constant>
+ <constant name="FORMAT_ASTC_8x8_HDR" value="38" enum="Format">
+ Same format as [constant FORMAT_ASTC_8x8], but with the hint to let the GPU know it is used for HDR.
+ </constant>
+ <constant name="FORMAT_MAX" value="39" enum="Format">
Represents the size of the [enum Format] enum.
</constant>
<constant name="INTERPOLATE_NEAREST" value="0" enum="Interpolation">
@@ -722,5 +743,11 @@
<constant name="COMPRESS_SOURCE_NORMAL" value="2" enum="CompressSource">
Source texture (before compression) is a normal texture (e.g. it can be compressed into two channels).
</constant>
+ <constant name="ASTC_FORMAT_4x4" value="0" enum="ASTCFormat">
+ Hint to indicate that the high quality 4x4 ASTC compression format should be used.
+ </constant>
+ <constant name="ASTC_FORMAT_8x8" value="1" enum="ASTCFormat">
+ Hint to indicate that the low quality 8x8 ASTC compression format should be used.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index d246e64251..be8c8ff83f 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -339,7 +339,7 @@
<param index="2" name="strong_magnitude" type="float" />
<param index="3" name="duration" type="float" default="0" />
<description>
- Starts to vibrate the joypad. Joypads usually come with two rumble motors, a strong and a weak one. [param weak_magnitude] is the strength of the weak motor (between 0 and 1) and [param strong_magnitude] is the strength of the strong motor (between 0 and 1). [param duration] is the duration of the effect in seconds (a duration of 0 will try to play the vibration indefinitely).
+ Starts to vibrate the joypad. Joypads usually come with two rumble motors, a strong and a weak one. [param weak_magnitude] is the strength of the weak motor (between 0 and 1) and [param strong_magnitude] is the strength of the strong motor (between 0 and 1). [param duration] is the duration of the effect in seconds (a duration of 0 will try to play the vibration indefinitely). The vibration can be stopped early by calling [method stop_joy_vibration].
[b]Note:[/b] Not every hardware is compatible with long effect durations; it is recommended to restart an effect if it has to be played for more than a few seconds.
</description>
</method>
@@ -347,18 +347,18 @@
<return type="void" />
<param index="0" name="device" type="int" />
<description>
- Stops the vibration of the joypad.
+ Stops the vibration of the joypad started with [method start_joy_vibration].
</description>
</method>
<method name="vibrate_handheld">
<return type="void" />
<param index="0" name="duration_ms" type="int" default="500" />
<description>
- Vibrate handheld devices.
- [b]Note:[/b] This method is implemented on Android, iOS, and Web.
- [b]Note:[/b] For Android, it requires enabling the [code]VIBRATE[/code] permission in the export preset.
- [b]Note:[/b] For iOS, specifying the duration is supported in iOS 13 and later.
- [b]Note:[/b] Some web browsers such as Safari and Firefox for Android do not support this method.
+ Vibrate the handheld device for the specified duration in milliseconds.
+ [b]Note:[/b] This method is implemented on Android, iOS, and Web. It has no effect on other platforms.
+ [b]Note:[/b] For Android, [method vibrate_handheld] requires enabling the [code]VIBRATE[/code] permission in the export preset. Otherwise, [method vibrate_handheld] will have no effect.
+ [b]Note:[/b] For iOS, specifying the duration is only supported in iOS 13 and later.
+ [b]Note:[/b] Some web browsers such as Safari and Firefox for Android do not support [method vibrate_handheld].
</description>
</method>
<method name="warp_mouse">
diff --git a/doc/classes/InputEventScreenDrag.xml b/doc/classes/InputEventScreenDrag.xml
index e5cc522b21..c1d126ca4a 100644
--- a/doc/classes/InputEventScreenDrag.xml
+++ b/doc/classes/InputEventScreenDrag.xml
@@ -13,12 +13,21 @@
<member name="index" type="int" setter="set_index" getter="get_index" default="0">
The drag event index in the case of a multi-drag event.
</member>
+ <member name="pen_inverted" type="bool" setter="set_pen_inverted" getter="get_pen_inverted" default="false">
+ Returns [code]true[/code] when using the eraser end of a stylus pen.
+ </member>
<member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2(0, 0)">
The drag position.
</member>
+ <member name="pressure" type="float" setter="set_pressure" getter="get_pressure" default="0.0">
+ Represents the pressure the user puts on the pen. Ranges from [code]0.0[/code] to [code]1.0[/code].
+ </member>
<member name="relative" type="Vector2" setter="set_relative" getter="get_relative" default="Vector2(0, 0)">
The drag position relative to the previous position (position at the last frame).
</member>
+ <member name="tilt" type="Vector2" setter="set_tilt" getter="get_tilt" default="Vector2(0, 0)">
+ Represents the angles of tilt of the pen. Positive X-coordinate value indicates a tilt to the right. Positive Y-coordinate value indicates a tilt toward the user. Ranges from [code]-1.0[/code] to [code]1.0[/code] for both axes.
+ </member>
<member name="velocity" type="Vector2" setter="set_velocity" getter="get_velocity" default="Vector2(0, 0)">
The drag velocity.
</member>
diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml
index 844f260971..c485d26e0c 100644
--- a/doc/classes/ItemList.xml
+++ b/doc/classes/ItemList.xml
@@ -459,6 +459,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the item text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="v_separation" data_type="constant" type="int" default="2">
The vertical spacing between items.
diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml
index cd87b4558f..1a8cbf0584 100644
--- a/doc/classes/Label.xml
+++ b/doc/classes/Label.xml
@@ -111,6 +111,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
Text outline size.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="shadow_offset_x" data_type="constant" type="int" default="1">
The horizontal offset of the text's shadow.
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml
index e57cc68b36..b8383aaed9 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -424,6 +424,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
Font used for the text.
diff --git a/doc/classes/LinkButton.xml b/doc/classes/LinkButton.xml
index d7701ea184..b3938999f3 100644
--- a/doc/classes/LinkButton.xml
+++ b/doc/classes/LinkButton.xml
@@ -28,7 +28,23 @@
Base text writing direction.
</member>
<member name="underline" type="int" setter="set_underline_mode" getter="get_underline_mode" enum="LinkButton.UnderlineMode" default="0">
- Determines when to show the underline. See [enum UnderlineMode] for options.
+ The underline mode to use for the text. See [enum LinkButton.UnderlineMode] for the available modes.
+ </member>
+ <member name="uri" type="String" setter="set_uri" getter="get_uri" default="&quot;&quot;">
+ The [url=https://en.wikipedia.org/wiki/Uniform_Resource_Identifier]URI[/url] for this [LinkButton]. If set to a valid URI, pressing the button opens the URI using the operating system's default program for the protocol (via [method OS.shell_open]). HTTP and HTTPS URLs open the default web browser.
+ [b]Examples:[/b]
+ [codeblocks]
+ [gdscript]
+ uri = "https://godotengine.org" # Opens the URL in the default web browser.
+ uri = "C:\SomeFolder" # Opens the file explorer at the given path.
+ uri = "C:\SomeImage.png" # Opens the given image in the default viewing app.
+ [/gdscript]
+ [csharp]
+ Uri = "https://godotengine.org"; // Opens the URL in the default web browser.
+ Uri = "C:\SomeFolder"; // Opens the file explorer at the given path.
+ Uri = "C:\SomeImage.png"; // Opens the given image in the default viewing app.
+ [/csharp]
+ [/codeblocks]
</member>
</members>
<constants>
@@ -60,6 +76,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="underline_spacing" data_type="constant" type="int" default="2">
The vertical space between the baseline of text and the underline.
diff --git a/doc/classes/MenuBar.xml b/doc/classes/MenuBar.xml
index e8505937ff..79876e56a3 100644
--- a/doc/classes/MenuBar.xml
+++ b/doc/classes/MenuBar.xml
@@ -143,6 +143,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
[Font] of the menu item's text.
diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml
index 4d5d5a011b..3061149570 100644
--- a/doc/classes/MenuButton.xml
+++ b/doc/classes/MenuButton.xml
@@ -75,6 +75,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
[Font] of the [MenuButton]'s text.
diff --git a/doc/classes/MeshLibrary.xml b/doc/classes/MeshLibrary.xml
index 85e57dd0f3..7c93ba5dce 100644
--- a/doc/classes/MeshLibrary.xml
+++ b/doc/classes/MeshLibrary.xml
@@ -59,14 +59,21 @@
Returns the item's name.
</description>
</method>
- <method name="get_item_navmesh" qualifiers="const">
+ <method name="get_item_navigation_layers" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="id" type="int" />
+ <description>
+ Returns the item's navigation layers bitmask.
+ </description>
+ </method>
+ <method name="get_item_navigation_mesh" qualifiers="const">
<return type="NavigationMesh" />
<param index="0" name="id" type="int" />
<description>
Returns the item's navigation mesh.
</description>
</method>
- <method name="get_item_navmesh_transform" qualifiers="const">
+ <method name="get_item_navigation_mesh_transform" qualifiers="const">
<return type="Transform3D" />
<param index="0" name="id" type="int" />
<description>
@@ -126,18 +133,26 @@
This name is shown in the editor. It can also be used to look up the item later using [method find_item_by_name].
</description>
</method>
- <method name="set_item_navmesh">
+ <method name="set_item_navigation_layers">
+ <return type="void" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="navigation_layers" type="int" />
+ <description>
+ Sets the item's navigation layers bitmask.
+ </description>
+ </method>
+ <method name="set_item_navigation_mesh">
<return type="void" />
<param index="0" name="id" type="int" />
- <param index="1" name="navmesh" type="NavigationMesh" />
+ <param index="1" name="navigation_mesh" type="NavigationMesh" />
<description>
Sets the item's navigation mesh.
</description>
</method>
- <method name="set_item_navmesh_transform">
+ <method name="set_item_navigation_mesh_transform">
<return type="void" />
<param index="0" name="id" type="int" />
- <param index="1" name="navmesh" type="Transform3D" />
+ <param index="1" name="navigation_mesh" type="Transform3D" />
<description>
Sets the transform to apply to the item's navigation mesh.
</description>
diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml
index 8cf7824ff7..31d347d76c 100644
--- a/doc/classes/NavigationAgent2D.xml
+++ b/doc/classes/NavigationAgent2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationAgent2D" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationAgent2D" inherits="Node" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
2D Agent used in navigation for collision avoidance.
</brief_description>
@@ -16,24 +16,30 @@
Returns the distance to the target location, using the agent's global position. The user must set [member target_location] in order for this to be accurate.
</description>
</method>
- <method name="get_final_location">
- <return type="Vector2" />
- <description>
- Returns the reachable final location in global coordinates. This can change if the navigation path is altered in any way. Because of this, it would be best to check this each frame.
- </description>
- </method>
- <method name="get_nav_path" qualifiers="const">
+ <method name="get_current_navigation_path" qualifiers="const">
<return type="PackedVector2Array" />
<description>
Returns this agent's current path from start to finish in global coordinates. The path only updates when the target location is changed or the agent requires a repath. The path array is not intended to be used in direct path movement as the agent has its own internal path logic that would get corrupted by changing the path array manually. Use the intended [method get_next_location] once every physics frame to receive the next path point for the agents movement as this function also updates the internal path logic.
</description>
</method>
- <method name="get_nav_path_index" qualifiers="const">
+ <method name="get_current_navigation_path_index" qualifiers="const">
<return type="int" />
<description>
Returns which index the agent is currently on in the navigation path's [PackedVector2Array].
</description>
</method>
+ <method name="get_current_navigation_result" qualifiers="const">
+ <return type="NavigationPathQueryResult2D" />
+ <description>
+ Returns the path query result for the path the agent is currently following.
+ </description>
+ </method>
+ <method name="get_final_location">
+ <return type="Vector2" />
+ <description>
+ Returns the reachable final location in global coordinates. This can change if the navigation path is altered in any way. Because of this, it would be best to check this each frame.
+ </description>
+ </method>
<method name="get_navigation_layer_value" qualifiers="const">
<return type="bool" />
<param index="0" name="layer_number" type="int" />
@@ -122,6 +128,9 @@
<member name="path_max_distance" type="float" setter="set_path_max_distance" getter="get_path_max_distance" default="3.0">
The maximum distance the agent is allowed away from the ideal path to the final location. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path.
</member>
+ <member name="path_metadata_flags" type="int" setter="set_path_metadata_flags" getter="get_path_metadata_flags" enum="NavigationPathQueryParameters2D.PathMetadataFlags" default="7">
+ Additional information to return with the navigation path.
+ </member>
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="10.0">
The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_distance]).
Does not affect normal pathfinding. To change an actor's pathfinding radius bake [NavigationMesh] resources with a different [member NavigationMesh.agent_radius] property and use different navigation maps for each actor size.
@@ -137,6 +146,17 @@
</member>
</members>
<signals>
+ <signal name="link_reached">
+ <param index="0" name="details" type="Dictionary" />
+ <description>
+ Notifies when a navigation link has been reached.
+ The details dictionary may contain the following keys depending on the value of [member path_metadata_flags]:
+ - [code]location[/code]: The start location of the link that was reached.
+ - [code]type[/code]: Always [constant NavigationPathQueryResult2D.PATH_SEGMENT_TYPE_LINK].
+ - [code]rid[/code]: The [RID] of the link.
+ - [code]owner[/code]: The object which manages the link (usually [NavigationLink2D]).
+ </description>
+ </signal>
<signal name="navigation_finished">
<description>
Notifies when the final location is reached.
@@ -158,5 +178,16 @@
Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity]. Only emitted when [member avoidance_enabled] is true.
</description>
</signal>
+ <signal name="waypoint_reached">
+ <param index="0" name="details" type="Dictionary" />
+ <description>
+ Notifies when a waypoint along the path has been reached.
+ The details dictionary may contain the following keys depending on the value of [member path_metadata_flags]:
+ - [code]location[/code]: The location of the waypoint that was reached.
+ - [code]type[/code]: The type of navigation primitive (region or link) that contains this waypoint.
+ - [code]rid[/code]: The [RID] of the containing navigation primitive (region or link).
+ - [code]owner[/code]: The object which manages the containing navigation primitive (region or link).
+ </description>
+ </signal>
</signals>
</class>
diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml
index 44c17647f7..c3f4809b5e 100644
--- a/doc/classes/NavigationAgent3D.xml
+++ b/doc/classes/NavigationAgent3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationAgent3D" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationAgent3D" inherits="Node" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
3D Agent used in navigation for collision avoidance.
</brief_description>
@@ -16,24 +16,30 @@
Returns the distance to the target location, using the agent's global position. The user must set [member target_location] in order for this to be accurate.
</description>
</method>
- <method name="get_final_location">
- <return type="Vector3" />
- <description>
- Returns the reachable final location in global coordinates. This can change if the navigation path is altered in any way. Because of this, it would be best to check this each frame.
- </description>
- </method>
- <method name="get_nav_path" qualifiers="const">
+ <method name="get_current_navigation_path" qualifiers="const">
<return type="PackedVector3Array" />
<description>
Returns this agent's current path from start to finish in global coordinates. The path only updates when the target location is changed or the agent requires a repath. The path array is not intended to be used in direct path movement as the agent has its own internal path logic that would get corrupted by changing the path array manually. Use the intended [method get_next_location] once every physics frame to receive the next path point for the agents movement as this function also updates the internal path logic.
</description>
</method>
- <method name="get_nav_path_index" qualifiers="const">
+ <method name="get_current_navigation_path_index" qualifiers="const">
<return type="int" />
<description>
Returns which index the agent is currently on in the navigation path's [PackedVector3Array].
</description>
</method>
+ <method name="get_current_navigation_result" qualifiers="const">
+ <return type="NavigationPathQueryResult3D" />
+ <description>
+ Returns the path query result for the path the agent is currently following.
+ </description>
+ </method>
+ <method name="get_final_location">
+ <return type="Vector3" />
+ <description>
+ Returns the reachable final location in global coordinates. This can change if the navigation path is altered in any way. Because of this, it would be best to check this each frame.
+ </description>
+ </method>
<method name="get_navigation_layer_value" qualifiers="const">
<return type="bool" />
<param index="0" name="layer_number" type="int" />
@@ -128,6 +134,9 @@
<member name="path_max_distance" type="float" setter="set_path_max_distance" getter="get_path_max_distance" default="3.0">
The maximum distance the agent is allowed away from the ideal path to the final location. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path.
</member>
+ <member name="path_metadata_flags" type="int" setter="set_path_metadata_flags" getter="get_path_metadata_flags" enum="NavigationPathQueryParameters3D.PathMetadataFlags" default="7">
+ Additional information to return with the navigation path.
+ </member>
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_distance]).
Does not affect normal pathfinding. To change an actor's pathfinding radius bake [NavigationMesh] resources with a different [member NavigationMesh.agent_radius] property and use different navigation maps for each actor size.
@@ -143,6 +152,17 @@
</member>
</members>
<signals>
+ <signal name="link_reached">
+ <param index="0" name="details" type="Dictionary" />
+ <description>
+ Notifies when a navigation link has been reached.
+ The details dictionary may contain the following keys depending on the value of [member path_metadata_flags]:
+ - [code]location[/code]: The start location of the link that was reached.
+ - [code]type[/code]: Always [constant NavigationPathQueryResult3D.PATH_SEGMENT_TYPE_LINK].
+ - [code]rid[/code]: The [RID] of the link.
+ - [code]owner[/code]: The object which manages the link (usually [NavigationLink3D]).
+ </description>
+ </signal>
<signal name="navigation_finished">
<description>
Notifies when the final location is reached.
@@ -164,5 +184,16 @@
Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity]. Only emitted when [member avoidance_enabled] is true.
</description>
</signal>
+ <signal name="waypoint_reached">
+ <param index="0" name="details" type="Dictionary" />
+ <description>
+ Notifies when a waypoint along the path has been reached.
+ The details dictionary may contain the following keys depending on the value of [member path_metadata_flags]:
+ - [code]location[/code]: The location of the waypoint that was reached.
+ - [code]type[/code]: The type of navigation primitive (region or link) that contains this waypoint.
+ - [code]rid[/code]: The [RID] of the containing navigation primitive (region or link).
+ - [code]owner[/code]: The object which manages the containing navigation primitive (region or link).
+ </description>
+ </signal>
</signals>
</class>
diff --git a/doc/classes/NavigationLink2D.xml b/doc/classes/NavigationLink2D.xml
index 1e086fb730..9d75694360 100644
--- a/doc/classes/NavigationLink2D.xml
+++ b/doc/classes/NavigationLink2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationLink2D" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationLink2D" inherits="Node2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Creates a link between two locations that [NavigationServer2D] can route agents through.
</brief_description>
@@ -38,7 +38,7 @@
The distance the link will search is controlled by [method NavigationServer2D.map_set_link_connection_radius].
</member>
<member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0">
- When pathfinding enters this link from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
+ When pathfinding enters this link from another regions navigation mesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
</member>
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
A bitfield determining all navigation layers the link belongs to. These navigation layers will be checked when requesting a path with [method NavigationServer2D.map_get_path].
diff --git a/doc/classes/NavigationLink3D.xml b/doc/classes/NavigationLink3D.xml
index 4d5d81bec5..730c43c5a8 100644
--- a/doc/classes/NavigationLink3D.xml
+++ b/doc/classes/NavigationLink3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationLink3D" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationLink3D" inherits="Node3D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Creates a link between two locations that [NavigationServer3D] can route agents through.
</brief_description>
@@ -38,7 +38,7 @@
The distance the link will search is controlled by [method NavigationServer3D.map_set_link_connection_radius].
</member>
<member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0">
- When pathfinding enters this link from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
+ When pathfinding enters this link from another regions navigation mesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
</member>
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
A bitfield determining all navigation layers the link belongs to. These navigation layers will be checked when requesting a path with [method NavigationServer3D.map_get_path].
diff --git a/doc/classes/NavigationMesh.xml b/doc/classes/NavigationMesh.xml
index c86bc47e04..ff898551d4 100644
--- a/doc/classes/NavigationMesh.xml
+++ b/doc/classes/NavigationMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationMesh" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationMesh" inherits="Resource" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A mesh to approximate the walkable areas and obstacles.
</brief_description>
@@ -133,13 +133,10 @@
<member name="geometry_source_geometry_mode" type="int" setter="set_source_geometry_mode" getter="get_source_geometry_mode" enum="NavigationMesh.SourceGeometryMode" default="0">
The source of the geometry used when baking. See [enum SourceGeometryMode] for possible values.
</member>
- <member name="geometry_source_group_name" type="StringName" setter="set_source_group_name" getter="get_source_group_name" default="&amp;&quot;navmesh&quot;">
+ <member name="geometry_source_group_name" type="StringName" setter="set_source_group_name" getter="get_source_group_name" default="&amp;&quot;navigation_mesh_source_group&quot;">
The name of the group to scan for geometry.
Only used when [member geometry_source_geometry_mode] is [constant SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN] or [constant SOURCE_GEOMETRY_GROUPS_EXPLICIT].
</member>
- <member name="polygon_verts_per_poly" type="float" setter="set_verts_per_poly" getter="get_verts_per_poly" default="6.0">
- The maximum number of vertices allowed for polygons generated during the contour to polygon conversion process.
- </member>
<member name="region_merge_size" type="float" setter="set_region_merge_size" getter="get_region_merge_size" default="20.0">
Any regions with a size smaller than this will be merged with larger regions if possible.
[b]Note:[/b] This value will be squared to calculate the number of cells. For example, a value of 20 will set the number of cells to 400.
@@ -151,6 +148,9 @@
<member name="sample_partition_type" type="int" setter="set_sample_partition_type" getter="get_sample_partition_type" enum="NavigationMesh.SamplePartitionType" default="0">
Partitioning algorithm for creating the navigation mesh polys. See [enum SamplePartitionType] for possible values.
</member>
+ <member name="vertices_per_polygon" type="float" setter="set_vertices_per_polygon" getter="get_vertices_per_polygon" default="6.0">
+ The maximum number of vertices allowed for polygons generated during the contour to polygon conversion process.
+ </member>
</members>
<constants>
<constant name="SAMPLE_PARTITION_WATERSHED" value="0" enum="SamplePartitionType">
@@ -177,8 +177,8 @@
<constant name="PARSED_GEOMETRY_MAX" value="3" enum="ParsedGeometryType">
Represents the size of the [enum ParsedGeometryType] enum.
</constant>
- <constant name="SOURCE_GEOMETRY_NAVMESH_CHILDREN" value="0" enum="SourceGeometryMode">
- Scans the child nodes of [NavigationRegion3D] recursively for geometry.
+ <constant name="SOURCE_GEOMETRY_ROOT_NODE_CHILDREN" value="0" enum="SourceGeometryMode">
+ Scans the child nodes of the root node recursively for geometry.
</constant>
<constant name="SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN" value="1" enum="SourceGeometryMode">
Scans nodes in a group and their child nodes recursively for geometry. The group is specified by [member geometry_source_group_name].
diff --git a/doc/classes/NavigationMeshGenerator.xml b/doc/classes/NavigationMeshGenerator.xml
index 4c337db90f..15d149a229 100644
--- a/doc/classes/NavigationMeshGenerator.xml
+++ b/doc/classes/NavigationMeshGenerator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationMeshGenerator" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationMeshGenerator" inherits="Object" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Helper class for creating and clearing navigation meshes.
</brief_description>
@@ -15,17 +15,17 @@
<methods>
<method name="bake">
<return type="void" />
- <param index="0" name="nav_mesh" type="NavigationMesh" />
+ <param index="0" name="navigation_mesh" type="NavigationMesh" />
<param index="1" name="root_node" type="Node" />
<description>
- Bakes navigation data to the provided [param nav_mesh] by parsing child nodes under the provided [param root_node] or a specific group of nodes for potential source geometry. The parse behavior can be controlled with the [member NavigationMesh.geometry_parsed_geometry_type] and [member NavigationMesh.geometry_source_geometry_mode] properties on the [NavigationMesh] resource.
+ Bakes navigation data to the provided [param navigation_mesh] by parsing child nodes under the provided [param root_node] or a specific group of nodes for potential source geometry. The parse behavior can be controlled with the [member NavigationMesh.geometry_parsed_geometry_type] and [member NavigationMesh.geometry_source_geometry_mode] properties on the [NavigationMesh] resource.
</description>
</method>
<method name="clear">
<return type="void" />
- <param index="0" name="nav_mesh" type="NavigationMesh" />
+ <param index="0" name="navigation_mesh" type="NavigationMesh" />
<description>
- Removes all polygons and vertices from the provided [param nav_mesh] resource.
+ Removes all polygons and vertices from the provided [param navigation_mesh] resource.
</description>
</method>
</methods>
diff --git a/doc/classes/NavigationObstacle2D.xml b/doc/classes/NavigationObstacle2D.xml
index 68d9691ccf..ce0f05ad28 100644
--- a/doc/classes/NavigationObstacle2D.xml
+++ b/doc/classes/NavigationObstacle2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationObstacle2D" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationObstacle2D" inherits="Node" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
2D Obstacle used in navigation for collision avoidance.
</brief_description>
diff --git a/doc/classes/NavigationObstacle3D.xml b/doc/classes/NavigationObstacle3D.xml
index 90eb55887f..78bbb788d9 100644
--- a/doc/classes/NavigationObstacle3D.xml
+++ b/doc/classes/NavigationObstacle3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationObstacle3D" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationObstacle3D" inherits="Node" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
3D Obstacle used in navigation for collision avoidance.
</brief_description>
diff --git a/doc/classes/NavigationPathQueryParameters2D.xml b/doc/classes/NavigationPathQueryParameters2D.xml
index 397ca8b713..511b2e7a8c 100644
--- a/doc/classes/NavigationPathQueryParameters2D.xml
+++ b/doc/classes/NavigationPathQueryParameters2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationPathQueryParameters2D" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationPathQueryParameters2D" inherits="RefCounted" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Parameters to be sent to a 2D navigation path query.
</brief_description>
@@ -12,6 +12,9 @@
<member name="map" type="RID" setter="set_map" getter="get_map">
The navigation [code]map[/code] [RID] used in the path query.
</member>
+ <member name="metadata_flags" type="int" setter="set_metadata_flags" getter="get_metadata_flags" enum="NavigationPathQueryParameters2D.PathMetadataFlags" default="7">
+ Additional information to include with the navigation path.
+ </member>
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
The navigation layers the query will use (as a bitmask).
</member>
@@ -33,10 +36,25 @@
The path query uses the default A* pathfinding algorithm.
</constant>
<constant name="PATH_POSTPROCESSING_CORRIDORFUNNEL" value="0" enum="PathPostProcessing">
- Applies a funnel algorithm to the raw path corridor found by the pathfinding algorithm. This will result in the shortest path possible inside the path corridor. This postprocessing very much depends on the navmesh polygon layout and the created corridor. Especially tile- or gridbased layouts can face artificial corners with diagonal movement due to a jagged path corridor imposed by the cell shapes.
+ Applies a funnel algorithm to the raw path corridor found by the pathfinding algorithm. This will result in the shortest path possible inside the path corridor. This postprocessing very much depends on the navigation mesh polygon layout and the created corridor. Especially tile- or gridbased layouts can face artificial corners with diagonal movement due to a jagged path corridor imposed by the cell shapes.
</constant>
<constant name="PATH_POSTPROCESSING_EDGECENTERED" value="1" enum="PathPostProcessing">
- Centers every path position in the middle of the traveled navmesh polygon edge. This creates better paths for tile- or gridbased layouts that restrict the movement to the cells center.
+ Centers every path position in the middle of the traveled navigation mesh polygon edge. This creates better paths for tile- or gridbased layouts that restrict the movement to the cells center.
+ </constant>
+ <constant name="PATH_METADATA_INCLUDE_NONE" value="0" enum="PathMetadataFlags" is_bitfield="true">
+ Don't include any additional metadata about the returned path.
+ </constant>
+ <constant name="PATH_METADATA_INCLUDE_TYPES" value="1" enum="PathMetadataFlags" is_bitfield="true">
+ Include the type of navigation primitive (region or link) that each point of the path goes through.
+ </constant>
+ <constant name="PATH_METADATA_INCLUDE_RIDS" value="2" enum="PathMetadataFlags" is_bitfield="true">
+ Include the [RID]s of the regions and links that each point of the path goes through.
+ </constant>
+ <constant name="PATH_METADATA_INCLUDE_OWNERS" value="4" enum="PathMetadataFlags" is_bitfield="true">
+ Include the [code]ObjectID[/code]s of the [Object]s which manage the regions and links each point of the path goes through.
+ </constant>
+ <constant name="PATH_METADATA_INCLUDE_ALL" value="7" enum="PathMetadataFlags" is_bitfield="true">
+ Include all available metadata about the returned path.
</constant>
</constants>
</class>
diff --git a/doc/classes/NavigationPathQueryParameters3D.xml b/doc/classes/NavigationPathQueryParameters3D.xml
index 29faa5561b..b5031f60f2 100644
--- a/doc/classes/NavigationPathQueryParameters3D.xml
+++ b/doc/classes/NavigationPathQueryParameters3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationPathQueryParameters3D" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationPathQueryParameters3D" inherits="RefCounted" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Parameters to be sent to a 3D navigation path query.
</brief_description>
@@ -12,6 +12,9 @@
<member name="map" type="RID" setter="set_map" getter="get_map">
The navigation [code]map[/code] [RID] used in the path query.
</member>
+ <member name="metadata_flags" type="int" setter="set_metadata_flags" getter="get_metadata_flags" enum="NavigationPathQueryParameters3D.PathMetadataFlags" default="7">
+ Additional information to include with the navigation path.
+ </member>
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
The navigation layers the query will use (as a bitmask).
</member>
@@ -33,10 +36,25 @@
The path query uses the default A* pathfinding algorithm.
</constant>
<constant name="PATH_POSTPROCESSING_CORRIDORFUNNEL" value="0" enum="PathPostProcessing">
- Applies a funnel algorithm to the raw path corridor found by the pathfinding algorithm. This will result in the shortest path possible inside the path corridor. This postprocessing very much depends on the navmesh polygon layout and the created corridor. Especially tile- or gridbased layouts can face artificial corners with diagonal movement due to a jagged path corridor imposed by the cell shapes.
+ Applies a funnel algorithm to the raw path corridor found by the pathfinding algorithm. This will result in the shortest path possible inside the path corridor. This postprocessing very much depends on the navigation mesh polygon layout and the created corridor. Especially tile- or gridbased layouts can face artificial corners with diagonal movement due to a jagged path corridor imposed by the cell shapes.
</constant>
<constant name="PATH_POSTPROCESSING_EDGECENTERED" value="1" enum="PathPostProcessing">
- Centers every path position in the middle of the traveled navmesh polygon edge. This creates better paths for tile- or gridbased layouts that restrict the movement to the cells center.
+ Centers every path position in the middle of the traveled navigation mesh polygon edge. This creates better paths for tile- or gridbased layouts that restrict the movement to the cells center.
+ </constant>
+ <constant name="PATH_METADATA_INCLUDE_NONE" value="0" enum="PathMetadataFlags" is_bitfield="true">
+ Don't include any additional metadata about the returned path.
+ </constant>
+ <constant name="PATH_METADATA_INCLUDE_TYPES" value="1" enum="PathMetadataFlags" is_bitfield="true">
+ Include the type of navigation primitive (region or link) that each point of the path goes through.
+ </constant>
+ <constant name="PATH_METADATA_INCLUDE_RIDS" value="2" enum="PathMetadataFlags" is_bitfield="true">
+ Include the [RID]s of the regions and links that each point of the path goes through.
+ </constant>
+ <constant name="PATH_METADATA_INCLUDE_OWNERS" value="4" enum="PathMetadataFlags" is_bitfield="true">
+ Include the [code]ObjectID[/code]s of the [Object]s which manage the regions and links each point of the path goes through.
+ </constant>
+ <constant name="PATH_METADATA_INCLUDE_ALL" value="7" enum="PathMetadataFlags" is_bitfield="true">
+ Include all available metadata about the returned path.
</constant>
</constants>
</class>
diff --git a/doc/classes/NavigationPathQueryResult2D.xml b/doc/classes/NavigationPathQueryResult2D.xml
index 95b90e9383..75f7cc47aa 100644
--- a/doc/classes/NavigationPathQueryResult2D.xml
+++ b/doc/classes/NavigationPathQueryResult2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationPathQueryResult2D" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationPathQueryResult2D" inherits="RefCounted" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Result from a [NavigationPathQueryParameters2D] navigation path query.
</brief_description>
@@ -20,5 +20,22 @@
<member name="path" type="PackedVector2Array" setter="set_path" getter="get_path" default="PackedVector2Array()">
The resulting path array from the navigation query. All path array positions are in global coordinates. Without customized query parameters this is the same path as returned by [method NavigationServer2D.map_get_path].
</member>
+ <member name="path_owner_ids" type="PackedInt64Array" setter="set_path_owner_ids" getter="get_path_owner_ids" default="PackedInt64Array()">
+ The [code]ObjectID[/code]s of the [Object]s which manage the regions and links each point of the path goes through.
+ </member>
+ <member name="path_rids" type="RID[]" setter="set_path_rids" getter="get_path_rids" default="[]">
+ The [RID]s of the regions and links that each point of the path goes through.
+ </member>
+ <member name="path_types" type="PackedInt32Array" setter="set_path_types" getter="get_path_types" default="PackedInt32Array()">
+ The type of navigation primitive (region or link) that each point of the path goes through.
+ </member>
</members>
+ <constants>
+ <constant name="PATH_SEGMENT_TYPE_REGION" value="0" enum="PathSegmentType">
+ This segment of the path goes through a region.
+ </constant>
+ <constant name="PATH_SEGMENT_TYPE_LINK" value="1" enum="PathSegmentType">
+ This segment of the path goes through a link.
+ </constant>
+ </constants>
</class>
diff --git a/doc/classes/NavigationPathQueryResult3D.xml b/doc/classes/NavigationPathQueryResult3D.xml
index b4ca8288db..03d41cb230 100644
--- a/doc/classes/NavigationPathQueryResult3D.xml
+++ b/doc/classes/NavigationPathQueryResult3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationPathQueryResult3D" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationPathQueryResult3D" inherits="RefCounted" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Result from a [NavigationPathQueryParameters3D] navigation path query.
</brief_description>
@@ -20,5 +20,22 @@
<member name="path" type="PackedVector3Array" setter="set_path" getter="get_path" default="PackedVector3Array()">
The resulting path array from the navigation query. All path array positions are in global coordinates. Without customized query parameters this is the same path as returned by [method NavigationServer3D.map_get_path].
</member>
+ <member name="path_owner_ids" type="PackedInt64Array" setter="set_path_owner_ids" getter="get_path_owner_ids" default="PackedInt64Array()">
+ The [code]ObjectID[/code]s of the [Object]s which manage the regions and links each point of the path goes through.
+ </member>
+ <member name="path_rids" type="RID[]" setter="set_path_rids" getter="get_path_rids" default="[]">
+ The [RID]s of the regions and links that each point of the path goes through.
+ </member>
+ <member name="path_types" type="PackedInt32Array" setter="set_path_types" getter="get_path_types" default="PackedInt32Array()">
+ The type of navigation primitive (region or link) that each point of the path goes through.
+ </member>
</members>
+ <constants>
+ <constant name="PATH_SEGMENT_TYPE_REGION" value="0" enum="PathSegmentType">
+ This segment of the path goes through a region.
+ </constant>
+ <constant name="PATH_SEGMENT_TYPE_LINK" value="1" enum="PathSegmentType">
+ This segment of the path goes through a link.
+ </constant>
+ </constants>
</class>
diff --git a/doc/classes/NavigationPolygon.xml b/doc/classes/NavigationPolygon.xml
index 19466c171f..b30dd2703a 100644
--- a/doc/classes/NavigationPolygon.xml
+++ b/doc/classes/NavigationPolygon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationPolygon" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationPolygon" inherits="Resource" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node that has methods to draw outlines or use indices of vertices to create navigation polygons.
</brief_description>
@@ -12,14 +12,14 @@
var outline = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
polygon.add_outline(outline)
polygon.make_polygons_from_outlines()
- $NavigationRegion2D.navpoly = polygon
+ $NavigationRegion2D.navigation_polygon = polygon
[/gdscript]
[csharp]
var polygon = new NavigationPolygon();
var outline = new Vector2[] { new Vector2(0, 0), new Vector2(0, 50), new Vector2(50, 50), new Vector2(50, 0) };
polygon.AddOutline(outline);
polygon.MakePolygonsFromOutlines();
- GetNode&lt;NavigationRegion2D&gt;("NavigationRegion2D").Navpoly = polygon;
+ GetNode&lt;NavigationRegion2D&gt;("NavigationRegion2D").NavigationPolygon = polygon;
[/csharp]
[/codeblocks]
Using [method add_polygon] and indices of the vertices array.
@@ -30,7 +30,7 @@
polygon.vertices = vertices
var indices = PackedInt32Array([0, 1, 2, 3])
polygon.add_polygon(indices)
- $NavigationRegion2D.navpoly = polygon
+ $NavigationRegion2D.navigation_polygon = polygon
[/gdscript]
[csharp]
var polygon = new NavigationPolygon();
@@ -38,7 +38,7 @@
polygon.Vertices = vertices;
var indices = new int[] { 0, 1, 2, 3 };
polygon.AddPolygon(indices);
- GetNode&lt;NavigationRegion2D&gt;("NavigationRegion2D").Navpoly = polygon;
+ GetNode&lt;NavigationRegion2D&gt;("NavigationRegion2D").NavigationPolygon = polygon;
[/csharp]
[/codeblocks]
</description>
@@ -80,10 +80,10 @@
Clears the array of polygons, but it doesn't clear the array of outlines and vertices.
</description>
</method>
- <method name="get_mesh">
+ <method name="get_navigation_mesh">
<return type="NavigationMesh" />
<description>
- Returns the [NavigationMesh] resulting from this navigation polygon. This navmesh can be used to update the navmesh of a region with the [method NavigationServer3D.region_set_navmesh] API directly (as 2D uses the 3D server behind the scene).
+ Returns the [NavigationMesh] resulting from this navigation polygon. This navigation mesh can be used to update the navigation mesh of a region with the [method NavigationServer3D.region_set_navigation_mesh] API directly (as 2D uses the 3D server behind the scene).
</description>
</method>
<method name="get_outline" qualifiers="const">
diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml
index 0f28081201..8b8793b3b4 100644
--- a/doc/classes/NavigationRegion2D.xml
+++ b/doc/classes/NavigationRegion2D.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationRegion2D" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationRegion2D" inherits="Node2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A region of the 2D navigation map.
</brief_description>
<description>
A region of the navigation map. It tells the [NavigationServer2D] what can be navigated and what cannot, based on its [NavigationPolygon] resource.
Two regions can be connected to each other if they share a similar edge. You can set the minimum distance between two vertices required to connect two edges by using [method NavigationServer2D.map_set_edge_connection_margin].
- [b]Note:[/b] Overlapping two regions' polygons is not enough for connecting two regions. They must share a similar edge.
+ [b]Note:[/b] Overlapping two regions' navigation polygons is not enough for connecting two regions. They must share a similar edge.
The pathfinding cost of entering this region from another region can be controlled with the [member enter_cost] value.
[b]Note:[/b] This value is not added to the path cost when the start position is already inside this region.
The pathfinding cost of traveling distances inside this region can be controlled with the [member travel_cost] multiplier.
@@ -42,16 +42,16 @@
Determines if the [NavigationRegion2D] is enabled or disabled.
</member>
<member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0">
- When pathfinding enters this region's navmesh from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
+ When pathfinding enters this region's navigation mesh from another regions navigation mesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
</member>
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
A bitfield determining all navigation layers the region belongs to. These navigation layers can be checked upon when requesting a path with [method NavigationServer2D.map_get_path].
</member>
- <member name="navpoly" type="NavigationPolygon" setter="set_navigation_polygon" getter="get_navigation_polygon">
+ <member name="navigation_polygon" type="NavigationPolygon" setter="set_navigation_polygon" getter="get_navigation_polygon">
The [NavigationPolygon] resource to use.
</member>
<member name="travel_cost" type="float" setter="set_travel_cost" getter="get_travel_cost" default="1.0">
- When pathfinding moves inside this region's navmesh the traveled distances are multiplied with [code]travel_cost[/code] for determining the shortest path.
+ When pathfinding moves inside this region's navigation mesh the traveled distances are multiplied with [code]travel_cost[/code] for determining the shortest path.
</member>
</members>
</class>
diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml
index 85f163b3c2..10662db869 100644
--- a/doc/classes/NavigationRegion3D.xml
+++ b/doc/classes/NavigationRegion3D.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationRegion3D" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationRegion3D" inherits="Node3D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A region of the navigation map.
</brief_description>
<description>
A region of the navigation map. It tells the [NavigationServer3D] what can be navigated and what cannot, based on its [NavigationMesh] resource.
Two regions can be connected to each other if they share a similar edge. You can set the minimum distance between two vertices required to connect two edges by using [method NavigationServer3D.map_set_edge_connection_margin].
- [b]Note:[/b] Overlapping two regions' navmeshes is not enough for connecting two regions. They must share a similar edge.
+ [b]Note:[/b] Overlapping two regions' navigation meshes is not enough for connecting two regions. They must share a similar edge.
The cost of entering this region from another region can be controlled with the [member enter_cost] value.
[b]Note:[/b] This value is not added to the path cost when the start position is already inside this region.
The cost of traveling distances inside this region can be controlled with the [member travel_cost] multiplier.
@@ -49,16 +49,16 @@
Determines if the [NavigationRegion3D] is enabled or disabled.
</member>
<member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0">
- When pathfinding enters this region's navmesh from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
+ When pathfinding enters this region's navigation mesh from another regions navigation mesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
</member>
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
A bitfield determining all navigation layers the region belongs to. These navigation layers can be checked upon when requesting a path with [method NavigationServer3D.map_get_path].
</member>
- <member name="navmesh" type="NavigationMesh" setter="set_navigation_mesh" getter="get_navigation_mesh">
+ <member name="navigation_mesh" type="NavigationMesh" setter="set_navigation_mesh" getter="get_navigation_mesh">
The [NavigationMesh] resource to use.
</member>
<member name="travel_cost" type="float" setter="set_travel_cost" getter="get_travel_cost" default="1.0">
- When pathfinding moves inside this region's navmesh the traveled distances are multiplied with [code]travel_cost[/code] for determining the shortest path.
+ When pathfinding moves inside this region's navigation mesh the traveled distances are multiplied with [code]travel_cost[/code] for determining the shortest path.
</member>
</members>
<signals>
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index 230e58a12a..32e48cde54 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationServer2D" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationServer2D" inherits="Object" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Server interface for low-level 2D navigation access
</brief_description>
@@ -489,12 +489,12 @@
Set the region's navigation layers. This allows selecting regions from a path request (when using [method NavigationServer2D.map_get_path]).
</description>
</method>
- <method name="region_set_navpoly" qualifiers="const">
+ <method name="region_set_navigation_polygon" qualifiers="const">
<return type="void" />
<param index="0" name="region" type="RID" />
- <param index="1" name="nav_poly" type="NavigationPolygon" />
+ <param index="1" name="navigation_polygon" type="NavigationPolygon" />
<description>
- Sets the navigation mesh for the region.
+ Sets the [param navigation_polygon] for the region.
</description>
</method>
<method name="region_set_owner_id" qualifiers="const">
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index c7da3b7b5b..c156dfac16 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationServer3D" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationServer3D" inherits="Object" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Server interface for low-level 3D navigation access
</brief_description>
@@ -433,12 +433,12 @@
Queries a path in a given navigation map. Start and target position and other parameters are defined through [NavigationPathQueryParameters3D]. Updates the provided [NavigationPathQueryResult3D] result object with the path among other results requested by the query.
</description>
</method>
- <method name="region_bake_navmesh" qualifiers="const">
+ <method name="region_bake_navigation_mesh" qualifiers="const">
<return type="void" />
- <param index="0" name="mesh" type="NavigationMesh" />
- <param index="1" name="node" type="Node" />
+ <param index="0" name="navigation_mesh" type="NavigationMesh" />
+ <param index="1" name="root_node" type="Node" />
<description>
- Bakes the navigation mesh.
+ Bakes the [param navigation_mesh] with bake source geometry collected starting from the [param root_node].
</description>
</method>
<method name="region_create" qualifiers="const">
@@ -539,10 +539,10 @@
Set the region's navigation layers. This allows selecting regions from a path request (when using [method NavigationServer3D.map_get_path]).
</description>
</method>
- <method name="region_set_navmesh" qualifiers="const">
+ <method name="region_set_navigation_mesh" qualifiers="const">
<return type="void" />
<param index="0" name="region" type="RID" />
- <param index="1" name="nav_mesh" type="NavigationMesh" />
+ <param index="1" name="navigation_mesh" type="NavigationMesh" />
<description>
Sets the navigation mesh for the region.
</description>
diff --git a/doc/classes/Node2D.xml b/doc/classes/Node2D.xml
index 26efe37dce..9d224f09b1 100644
--- a/doc/classes/Node2D.xml
+++ b/doc/classes/Node2D.xml
@@ -99,6 +99,9 @@
<member name="global_rotation" type="float" setter="set_global_rotation" getter="get_global_rotation">
Global rotation in radians.
</member>
+ <member name="global_rotation_degrees" type="float" setter="set_global_rotation_degrees" getter="get_global_rotation_degrees">
+ Helper property to access [member global_rotation] in degrees instead of radians.
+ </member>
<member name="global_scale" type="Vector2" setter="set_global_scale" getter="get_global_scale">
Global scale.
</member>
@@ -114,6 +117,9 @@
<member name="rotation" type="float" setter="set_rotation" getter="get_rotation" default="0.0">
Rotation in radians, relative to the node's parent.
</member>
+ <member name="rotation_degrees" type="float" setter="set_rotation_degrees" getter="get_rotation_degrees">
+ Helper property to access [member rotation] in degrees instead of radians.
+ </member>
<member name="scale" type="Vector2" setter="set_scale" getter="get_scale" default="Vector2(1, 1)">
The node's scale. Unscaled value: [code](1, 1)[/code].
[b]Note:[/b] Negative X scales in 2D are not decomposable from the transformation matrix. Due to the way scale is represented with transformation matrices in Godot, negative scales on the X axis will be changed to negative scales on the Y axis and a rotation of 180 degrees when decomposed.
diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml
index b6024b1887..1aa71113e9 100644
--- a/doc/classes/Node3D.xml
+++ b/doc/classes/Node3D.xml
@@ -274,6 +274,9 @@
Rotation part of the global transformation in radians, specified in terms of YXZ-Euler angles in the format (X angle, Y angle, Z angle).
[b]Note:[/b] In the mathematical sense, rotation is a matrix and not a vector. The three Euler angles, which are the three independent parameters of the Euler-angle parametrization of the rotation matrix, are stored in a [Vector3] data structure not because the rotation is a vector, but only because [Vector3] exists as a convenient data-structure to store 3 floating-point numbers. Therefore, applying affine operations on the rotation "vector" is not meaningful.
</member>
+ <member name="global_rotation_degrees" type="Vector3" setter="set_global_rotation_degrees" getter="get_global_rotation_degrees">
+ Helper property to access [member global_rotation] in degrees instead of radians.
+ </member>
<member name="global_transform" type="Transform3D" setter="set_global_transform" getter="get_global_transform">
World3D space (global) [Transform3D] of this node.
</member>
@@ -287,6 +290,9 @@
Rotation part of the local transformation in radians, specified in terms of Euler angles. The angles construct a rotaton in the order specified by the [member rotation_order] property.
[b]Note:[/b] In the mathematical sense, rotation is a matrix and not a vector. The three Euler angles, which are the three independent parameters of the Euler-angle parametrization of the rotation matrix, are stored in a [Vector3] data structure not because the rotation is a vector, but only because [Vector3] exists as a convenient data-structure to store 3 floating-point numbers. Therefore, applying affine operations on the rotation "vector" is not meaningful.
</member>
+ <member name="rotation_degrees" type="Vector3" setter="set_rotation_degrees" getter="get_rotation_degrees">
+ Helper property to access [member rotation] in degrees instead of radians.
+ </member>
<member name="rotation_edit_mode" type="int" setter="set_rotation_edit_mode" getter="get_rotation_edit_mode" enum="Node3D.RotationEditMode" default="0">
Specify how rotation (and scale) will be presented in the editor.
</member>
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 5e834b3d91..e015bec134 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -8,7 +8,7 @@
You can create new instances, using [code]Object.new()[/code] in GDScript, or [code]new Object[/code] in C#.
To delete an Object instance, call [method free]. This is necessary for most classes inheriting Object, because they do not manage memory on their own, and will otherwise cause memory leaks when no longer in use. There are a few classes that perform memory management. For example, [RefCounted] (and by extension [Resource]) deletes itself when no longer referenced, and [Node] deletes its children when freed.
Objects can have a [Script] attached to them. Once the [Script] is instantiated, it effectively acts as an extension to the base class, allowing it to define and inherit new properties, methods and signals.
- Inside a [Script], [method _get_property_list] may be overriden to customize properties in several ways. This allows them to be available to the editor, display as lists of options, sub-divide into groups, save on disk, etc. Scripting languages offer easier ways to customize properties, such as with the [annotation @GDScript.@export] annotation.
+ Inside a [Script], [method _get_property_list] may be overridden to customize properties in several ways. This allows them to be available to the editor, display as lists of options, sub-divide into groups, save on disk, etc. Scripting languages offer easier ways to customize properties, such as with the [annotation @GDScript.@export] annotation.
Godot is very dynamic. An object's script, and therefore its properties, methods and signals, can be changed at run-time. Because of this, there can be occasions where, for example, a property required by a method may not exist. To prevent run-time errors, see methods such as [method set], [method get], [method call], [method has_method], [method has_signal], etc. Note that these methods are [b]much[/b] slower than direct references.
In GDScript, you can also check if a given property, method, or signal name exists in an object with the [code]in[/code] operator:
[codeblock]
diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml
index e63e822648..fdf0fff0fb 100644
--- a/doc/classes/OptionButton.xml
+++ b/doc/classes/OptionButton.xml
@@ -94,6 +94,8 @@
<return type="int" />
<param index="0" name="from_last" type="bool" default="false" />
<description>
+ Returns the index of the first item which is not disabled, or marked as a separator. If [param from_last] is [code]true[/code], the items will be searched in reverse order.
+ Returns [code]-1[/code] if no item is found.
</description>
</method>
<method name="get_selected_id" qualifiers="const">
@@ -111,6 +113,7 @@
<method name="has_selectable_items" qualifiers="const">
<return type="bool" />
<description>
+ Returns [code]true[/code] if this button contains at least one item which is not disabled, or marked as a separator.
</description>
</method>
<method name="is_item_disabled" qualifiers="const">
@@ -124,6 +127,7 @@
<return type="bool" />
<param index="0" name="idx" type="int" />
<description>
+ Returns [code]true[/code] if the item at index [param idx] is marked as a separator.
</description>
</method>
<method name="remove_item">
@@ -259,6 +263,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
[Font] of the [OptionButton]'s text.
diff --git a/doc/classes/PathFollow3D.xml b/doc/classes/PathFollow3D.xml
index fa7580b7b6..01275471d0 100644
--- a/doc/classes/PathFollow3D.xml
+++ b/doc/classes/PathFollow3D.xml
@@ -15,7 +15,7 @@
<param index="0" name="transform" type="Transform3D" />
<param index="1" name="rotation_mode" type="int" enum="PathFollow3D.RotationMode" />
<description>
- Correct the [code]transform[/code]. [code]rotation_mode[/code] implicitly specifies how posture (forward, up and sideway direction) is caculated.
+ Correct the [code]transform[/code]. [code]rotation_mode[/code] implicitly specifies how posture (forward, up and sideway direction) is calculated.
</description>
</method>
</methods>
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index 18ac8a11df..f1316fa991 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -736,6 +736,14 @@
<description>
</description>
</method>
+ <method name="joint_disable_collisions_between_bodies">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="disable" type="bool" />
+ <description>
+ Sets whether the bodies attached to the [Joint2D] will collide with each other.
+ </description>
+ </method>
<method name="joint_get_param" qualifiers="const">
<return type="float" />
<param index="0" name="joint" type="RID" />
@@ -751,6 +759,13 @@
Returns a joint's type (see [enum JointType]).
</description>
</method>
+ <method name="joint_is_disabled_collisions_between_bodies" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="joint" type="RID" />
+ <description>
+ Returns whether the bodies attached to the [Joint2D] will collide with each other.
+ </description>
+ </method>
<method name="joint_make_damped_spring">
<return type="void" />
<param index="0" name="joint" type="RID" />
@@ -790,6 +805,23 @@
Sets a joint parameter. See [enum JointParam] for a list of available parameters.
</description>
</method>
+ <method name="pin_joint_get_param" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.PinJointParam" />
+ <description>
+ Returns the value of a pin joint parameter. See [enum PinJointParam] for a list of available parameters.
+ </description>
+ </method>
+ <method name="pin_joint_set_param">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.PinJointParam" />
+ <param index="2" name="value" type="float" />
+ <description>
+ Sets a pin joint parameter. See [enum PinJointParam] for a list of available parameters.
+ </description>
+ </method>
<method name="rectangle_shape_create">
<return type="RID" />
<description>
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index 95f7fb69a2..e62bda0dd3 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -815,6 +815,14 @@
<description>
</description>
</method>
+ <method name="joint_disable_collisions_between_bodies">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="disable" type="bool" />
+ <description>
+ Sets whether the bodies attached to the [Joint3D] will collide with each other.
+ </description>
+ </method>
<method name="joint_get_solver_priority" qualifiers="const">
<return type="int" />
<param index="0" name="joint" type="RID" />
@@ -829,6 +837,13 @@
Returns the type of the Joint3D.
</description>
</method>
+ <method name="joint_is_disabled_collisions_between_bodies" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="joint" type="RID" />
+ <description>
+ Returns whether the bodies attached to the [Joint3D] will collide with each other.
+ </description>
+ </method>
<method name="joint_make_cone_twist">
<return type="void" />
<param index="0" name="joint" type="RID" />
diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml
index 1e9df54de5..d45cb17510 100644
--- a/doc/classes/PhysicsServer3DExtension.xml
+++ b/doc/classes/PhysicsServer3DExtension.xml
@@ -772,6 +772,13 @@
<description>
</description>
</method>
+ <method name="_joint_disable_collisions_between_bodies" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="disable" type="bool" />
+ <description>
+ </description>
+ </method>
<method name="_joint_get_solver_priority" qualifiers="virtual const">
<return type="int" />
<param index="0" name="joint" type="RID" />
@@ -784,6 +791,12 @@
<description>
</description>
</method>
+ <method name="_joint_is_disabled_collisions_between_bodies" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="joint" type="RID" />
+ <description>
+ </description>
+ </method>
<method name="_joint_make_cone_twist" qualifiers="virtual">
<return type="void" />
<param index="0" name="joint" type="RID" />
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 6810b0e8e4..8dec4eaf86 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -584,6 +584,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the item text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="separator_outline_size" data_type="constant" type="int" default="0">
The size of the labeled separator text outline.
diff --git a/doc/classes/ProgressBar.xml b/doc/classes/ProgressBar.xml
index 510b8d5bd1..9f89a4e4c3 100644
--- a/doc/classes/ProgressBar.xml
+++ b/doc/classes/ProgressBar.xml
@@ -42,6 +42,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
Font used to draw the fill percentage if [member show_percentage] is [code]true[/code].
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 72f9a0e32f..d4c42e36eb 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -70,15 +70,18 @@
<method name="get_setting" qualifiers="const">
<return type="Variant" />
<param index="0" name="name" type="String" />
+ <param index="1" name="default_value" type="Variant" default="null" />
<description>
- Returns the value of a setting.
+ Returns the value of the setting identified by [param name]. If the setting doesn't exist and [param default_value] is specified, the value of [param default_value] is returned. Otherwise, [code]null[/code] is returned.
[b]Example:[/b]
[codeblocks]
[gdscript]
print(ProjectSettings.get_setting("application/config/name"))
+ print(ProjectSettings.get_setting("application/config/custom_description", "No description specified."))
[/gdscript]
[csharp]
GD.Print(ProjectSettings.GetSetting("application/config/name"));
+ GD.Print(ProjectSettings.GetSetting("application/config/custom_description", "No description specified."));
[/csharp]
[/codeblocks]
</description>
@@ -344,9 +347,6 @@
<member name="compression/formats/zstd/window_log_size" type="int" setter="" getter="" default="27">
Largest size limit (in power of 2) allowed when compressing using long-distance matching with Zstandard. Higher values can result in better compression, but will require more memory when compressing and decompressing.
</member>
- <member name="debug/disable_touch" type="bool" setter="" getter="" default="false">
- Disable touch input. Only has effect on iOS.
- </member>
<member name="debug/file_logging/enable_file_logging" type="bool" setter="" getter="" default="false">
If [code]true[/code], logs all output to files.
</member>
@@ -464,9 +464,6 @@
<member name="debug/gdscript/warnings/unused_variable" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable is unused.
</member>
- <member name="debug/gdscript/warnings/void_assignment" type="int" setter="" getter="" default="1">
- When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when assigning the result of a function that returns [code]void[/code] to a variable.
- </member>
<member name="debug/settings/crash_handler/message" type="String" setter="" getter="" default="&quot;Please include this when reporting the bug to the project developer.&quot;">
Message to be displayed before the backtrace when the engine crashes. By default, this message is only used in exported projects due to the editor-only override applied to this setting.
</member>
@@ -585,7 +582,7 @@
[b]Note:[/b] This setting has no effect on the home indicator if [code]hide_home_indicator[/code] is [code]true[/code].
</member>
<member name="display/window/per_pixel_transparency/allowed" type="bool" setter="" getter="" default="false">
- If [code]true[/code], allows per-pixel transparency for the window background. This affects performance, so leave it on [code]false[/code] unless you need it. See also [member display/window/size/transparent] and [member rendering/transparent_background].
+ If [code]true[/code], allows per-pixel transparency for the window background. This affects performance, so leave it on [code]false[/code] unless you need it. See also [member display/window/size/transparent] and [member rendering/viewport/transparent_background].
</member>
<member name="display/window/size/always_on_top" type="bool" setter="" getter="" default="false">
Forces the main window to be always on top.
@@ -610,7 +607,7 @@
[b]Note:[/b] This setting is ignored on iOS.
</member>
<member name="display/window/size/transparent" type="bool" setter="" getter="" default="false">
- If [code]true[/code], enables a window manager hint that the main window background [i]can[/i] be transparent. This does not make the background actually transparent. For the background to be transparent, the root viewport must also be made transparent by enabling [member rendering/transparent_background].
+ If [code]true[/code], enables a window manager hint that the main window background [i]can[/i] be transparent. This does not make the background actually transparent. For the background to be transparent, the root viewport must also be made transparent by enabling [member rendering/viewport/transparent_background].
[b]Note:[/b] To use a transparent splash screen, set [member application/boot_splash/bg_color] to [code]Color(0, 0, 0, 0)[/code].
[b]Note:[/b] This setting has no effect if [member display/window/per_pixel_transparency/allowed] is set to [code]false[/code].
</member>
@@ -2256,7 +2253,7 @@
<member name="rendering/textures/webp_compression/lossless_compression_factor" type="float" setter="" getter="" default="25">
The default compression factor for lossless WebP. Decompression speed is mostly unaffected by the compression factor. Supported values are 0 to 100.
</member>
- <member name="rendering/transparent_background" type="bool" setter="" getter="" default="false">
+ <member name="rendering/viewport/transparent_background" type="bool" setter="" getter="" default="false">
If [code]true[/code], enables [member Viewport.transparent_bg] on the root viewport. This allows per-pixel transparency to be effective after also enabling [member display/window/size/transparent] and [member display/window/per_pixel_transparency/allowed].
</member>
<member name="rendering/vrs/mode" type="int" setter="" getter="" default="0">
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index 797231ac5e..f318430611 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -504,7 +504,7 @@
<return type="RID" />
<param index="0" name="size_bytes" type="int" />
<param index="1" name="data" type="PackedByteArray" default="PackedByteArray()" />
- <param index="2" name="usage" type="int" default="0" />
+ <param index="2" name="usage" type="int" enum="RenderingDevice.StorageBufferUsage" default="0" />
<description>
</description>
</method>
@@ -1273,7 +1273,7 @@
</constant>
<constant name="INDEX_BUFFER_FORMAT_UINT32" value="1" enum="IndexBufferFormat">
</constant>
- <constant name="STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT" value="1" enum="StorageBufferUsage">
+ <constant name="STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT" value="1" enum="StorageBufferUsage" is_bitfield="true">
</constant>
<constant name="UNIFORM_TYPE_SAMPLER" value="0" enum="UniformType">
</constant>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 7a9a380032..87e569ba20 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -241,6 +241,7 @@
<param index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<param index="5" name="outline_size" type="int" default="0" />
<param index="6" name="px_range" type="float" default="1.0" />
+ <param index="7" name="scale" type="float" default="1.0" />
<description>
</description>
</method>
@@ -1559,7 +1560,7 @@
<param index="0" name="instance" type="RID" />
<param index="1" name="aabb" type="AABB" />
<description>
- Sets a custom AABB to use when culling objects from the view frustum. Equivalent to [method GeometryInstance3D.set_custom_aabb].
+ Sets a custom AABB to use when culling objects from the view frustum. Equivalent to setting [member GeometryInstance3D.custom_aabb].
</description>
</method>
<method name="instance_set_extra_visibility_margin">
@@ -1585,6 +1586,15 @@
Sets the render layers that this instance will be drawn to. Equivalent to [member VisualInstance3D.layers].
</description>
</method>
+ <method name="instance_set_pivot_data">
+ <return type="void" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="sorting_offset" type="float" />
+ <param index="2" name="use_aabb_center" type="bool" />
+ <description>
+ Sets the sorting offset and switches between using the bounding box or instance origin for depth sorting.
+ </description>
+ </method>
<method name="instance_set_scenario">
<return type="void" />
<param index="0" name="instance" type="RID" />
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index e222894647..dd291a425d 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -367,6 +367,7 @@
<return type="void" />
<param index="0" name="columns" type="int" />
<param index="1" name="inline_align" type="int" enum="InlineAlignment" default="0" />
+ <param index="2" name="align_to_row" type="int" default="-1" />
<description>
Adds a [code][table=columns,inline_align][/code] tag to the tag stack.
</description>
@@ -377,12 +378,12 @@
Adds a [code][u][/code] tag to the tag stack.
</description>
</method>
- <method name="remove_line">
+ <method name="remove_paragraph">
<return type="bool" />
- <param index="0" name="line" type="int" />
+ <param index="0" name="paragraph" type="int" />
<description>
- Removes a line of content from the label. Returns [code]true[/code] if the line exists.
- The [param line] argument is the index of the line to remove, it can take values in the interval [code][0, get_line_count() - 1][/code].
+ Removes a paragraph of content from the label. Returns [code]true[/code] if the paragraph exists.
+ The [param paragraph] argument is the index of the paragraph to remove, it can take values in the interval [code][0, get_paragraph_count() - 1][/code].
</description>
</method>
<method name="scroll_to_line">
@@ -655,6 +656,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="shadow_offset_x" data_type="constant" type="int" default="1">
The horizontal offset of the font's shadow.
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 653d53607e..97466e7860 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -973,11 +973,11 @@
[codeblocks]
[gdscript]
var url = "$DOCS_URL/?highlight=Godot%20Engine%3%docs"
- print(url.uri_decode()) # Prints "$DOCS_URL/?hightlight=Godot Engine:docs"
+ print(url.uri_decode()) # Prints "$DOCS_URL/?highlight=Godot Engine:docs"
[/gdscript]
[csharp]
var url = "$DOCS_URL/?highlight=Godot%20Engine%3%docs"
- GD.Print(url.URIDecode()) // Prints "$DOCS_URL/?hightlight=Godot Engine:docs"
+ GD.Print(url.URIDecode()) // Prints "$DOCS_URL/?highlight=Godot Engine:docs"
[/csharp]
[/codeblocks]
</description>
@@ -988,13 +988,13 @@
Encodes the string to URL-friendly format. This method is meant to properly encode the parameters in a URL when sending an HTTP request.
[codeblocks]
[gdscript]
- var prefix = "$DOCS_URL/?hightlight="
+ var prefix = "$DOCS_URL/?highlight="
var url = prefix + "Godot Engine:docs".uri_encode()
print(url) # Prints "$DOCS_URL/?highlight=Godot%20Engine%3%docs"
[/gdscript]
[csharp]
- var prefix = "$DOCS_URL/?hightlight=";
+ var prefix = "$DOCS_URL/?highlight=";
var url = prefix + "Godot Engine:docs".URIEncode();
GD.Print(url); // Prints "$DOCS_URL/?highlight=Godot%20Engine%3%docs"
diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml
index 44d78a46fb..b46e39b8d7 100644
--- a/doc/classes/StringName.xml
+++ b/doc/classes/StringName.xml
@@ -880,11 +880,11 @@
[codeblocks]
[gdscript]
var url = "$DOCS_URL/?highlight=Godot%20Engine%3%docs"
- print(url.uri_decode()) # Prints "$DOCS_URL/?hightlight=Godot Engine:docs"
+ print(url.uri_decode()) # Prints "$DOCS_URL/?highlight=Godot Engine:docs"
[/gdscript]
[csharp]
var url = "$DOCS_URL/?highlight=Godot%20Engine%3%docs"
- GD.Print(url.URIDecode()) // Prints "$DOCS_URL/?hightlight=Godot Engine:docs"
+ GD.Print(url.URIDecode()) // Prints "$DOCS_URL/?highlight=Godot Engine:docs"
[/csharp]
[/codeblocks]
</description>
@@ -895,13 +895,13 @@
Encodes the string to URL-friendly format. This method is meant to properly encode the parameters in a URL when sending an HTTP request.
[codeblocks]
[gdscript]
- var prefix = "$DOCS_URL/?hightlight="
+ var prefix = "$DOCS_URL/?highlight="
var url = prefix + "Godot Engine:docs".uri_encode()
print(url) # Prints "$DOCS_URL/?highlight=Godot%20Engine%3%docs"
[/gdscript]
[csharp]
- var prefix = "$DOCS_URL/?hightlight=";
+ var prefix = "$DOCS_URL/?highlight=";
var url = prefix + "Godot Engine:docs".URIEncode();
GD.Print(url); // Prints "$DOCS_URL/?highlight=Godot%20Engine%3%docs"
diff --git a/doc/classes/TabBar.xml b/doc/classes/TabBar.xml
index 713c016651..8d56cbda13 100644
--- a/doc/classes/TabBar.xml
+++ b/doc/classes/TabBar.xml
@@ -319,6 +319,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the tab text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
The font used to draw tab names.
diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml
index e2e7a0c37e..c744c9b439 100644
--- a/doc/classes/TabContainer.xml
+++ b/doc/classes/TabContainer.xml
@@ -214,6 +214,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the tab text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="side_margin" data_type="constant" type="int" default="8">
The space at the left or right edges of the tab bar, accordingly with the current [member tab_alignment].
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index d4f5233438..1efd0f9326 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -1396,6 +1396,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
Sets the default [Font].
diff --git a/doc/classes/TextLine.xml b/doc/classes/TextLine.xml
index d1dfdecbd2..1ebae9889d 100644
--- a/doc/classes/TextLine.xml
+++ b/doc/classes/TextLine.xml
@@ -15,6 +15,7 @@
<param index="1" name="size" type="Vector2" />
<param index="2" name="inline_align" type="int" enum="InlineAlignment" default="5" />
<param index="3" name="length" type="int" default="1" />
+ <param index="4" name="baseline" type="float" default="0.0" />
<description>
Adds inline object to the text buffer, [param key] must be unique. In the text, object is represented as [param length] object replacement characters.
</description>
@@ -122,6 +123,7 @@
<param index="0" name="key" type="Variant" />
<param index="1" name="size" type="Vector2" />
<param index="2" name="inline_align" type="int" enum="InlineAlignment" default="5" />
+ <param index="3" name="baseline" type="float" default="0.0" />
<description>
Sets new size and alignment of embedded object.
</description>
diff --git a/doc/classes/TextParagraph.xml b/doc/classes/TextParagraph.xml
index e0729ba844..38afd9b5f8 100644
--- a/doc/classes/TextParagraph.xml
+++ b/doc/classes/TextParagraph.xml
@@ -15,6 +15,7 @@
<param index="1" name="size" type="Vector2" />
<param index="2" name="inline_align" type="int" enum="InlineAlignment" default="5" />
<param index="3" name="length" type="int" default="1" />
+ <param index="4" name="baseline" type="float" default="0.0" />
<description>
Adds inline object to the text buffer, [param key] must be unique. In the text, object is represented as [param length] object replacement characters.
</description>
@@ -228,6 +229,7 @@
<param index="0" name="key" type="Variant" />
<param index="1" name="size" type="Vector2" />
<param index="2" name="inline_align" type="int" enum="InlineAlignment" default="5" />
+ <param index="3" name="baseline" type="float" default="0.0" />
<description>
Sets new size and alignment of embedded object.
</description>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 4fc6ee3312..d2c6dee373 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -930,6 +930,7 @@
<param index="1" name="language" type="String" default="&quot;&quot;" />
<description>
Converts a number from the Western Arabic (0..9) to the numeral systems used in [param language].
+ If [param language] is omitted, the active locale will be used.
</description>
</method>
<method name="free_rid">
@@ -1097,6 +1098,7 @@
<param index="2" name="size" type="Vector2" />
<param index="3" name="inline_align" type="int" enum="InlineAlignment" default="5" />
<param index="4" name="length" type="int" default="1" />
+ <param index="5" name="baseline" type="float" default="0.0" />
<description>
Adds inline object to the text buffer, [param key] must be unique. In the text, object is represented as [param length] object replacement characters.
</description>
@@ -1438,6 +1440,7 @@
<param index="1" name="key" type="Variant" />
<param index="2" name="size" type="Vector2" />
<param index="3" name="inline_align" type="int" enum="InlineAlignment" default="5" />
+ <param index="4" name="baseline" type="float" default="0.0" />
<description>
Sets new size and alignment of embedded object.
</description>
@@ -1546,8 +1549,15 @@
<return type="PackedInt32Array" />
<param index="0" name="string" type="String" />
<param index="1" name="language" type="String" default="&quot;&quot;" />
- <description>
- Returns array of the word break character offsets.
+ <param index="2" name="chars_per_line" type="int" default="0" />
+ <description>
+ Returns an array of the word break boundaries. Elements in the returned array are the offsets of the start and end of words. Therefore the length of the array is always even.
+ When [param chars_per_line] is greater than zero, line break boundaries are returned instead.
+ [codeblock]
+ var ts = TextServerManager.get_primary_interface()
+ print(ts.string_get_word_breaks("Godot Engine")) # Prints [0, 5, 6, 12]
+ print(ts.string_get_word_breaks("Godot Engine", "en", 5)) # Prints [0, 5, 6, 11, 11, 12]
+ [/codeblock]
</description>
</method>
<method name="string_to_lower" qualifiers="const">
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index 4c9817fcd4..e144b09eb6 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -945,6 +945,7 @@
<param index="2" name="size" type="Vector2" />
<param index="3" name="inline_align" type="int" enum="InlineAlignment" />
<param index="4" name="length" type="int" />
+ <param index="5" name="baseline" type="float" />
<description>
</description>
</method>
@@ -1242,6 +1243,7 @@
<param index="1" name="key" type="Variant" />
<param index="2" name="size" type="Vector2" />
<param index="3" name="inline_align" type="int" enum="InlineAlignment" />
+ <param index="4" name="baseline" type="float" />
<description>
</description>
</method>
@@ -1344,6 +1346,7 @@
<return type="PackedInt32Array" />
<param index="0" name="string" type="String" />
<param index="1" name="language" type="String" />
+ <param index="2" name="chars_per_line" type="int" />
<description>
</description>
</method>
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index e9e2a738d3..8b537545bc 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -257,8 +257,9 @@
<description>
Sets the tile indentifiers for the cell on layer [param layer] at coordinates [param coords]. Each tile of the [TileSet] is identified using three parts:
- The source identifier [param source_id] identifies a [TileSetSource] identifier. See [method TileSet.set_source_id],
- - The atlas coordinates identifier [param atlas_coords] identifies a tile coordinates in the atlas (if the source is a [TileSetAtlasSource]. For [TileSetScenesCollectionSource] it should be 0),
+ - The atlas coordinates identifier [param atlas_coords] identifies a tile coordinates in the atlas (if the source is a [TileSetAtlasSource]. For [TileSetScenesCollectionSource] it should always be [code]Vector2i(0, 0)[/code]),
- The alternative tile identifier [param alternative_tile] identifies a tile alternative the source is a [TileSetAtlasSource], and the scene for a [TileSetScenesCollectionSource].
+ If [param source_id] is set to [code]-1[/code], [param atlas_coords] to [code]Vector2i(-1, -1)[/code] or [param alternative_tile] to [code]-1[/code], the cell will be erased. An erased cell gets [b]all[/b] its identifiers automatically set to their respective invalid values, namely [code]-1[/code], [code]Vector2i(-1, -1)[/code] and [code]-1[/code].
</description>
</method>
<method name="set_cells_terrain_connect">
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index 629c271417..584a2a2a7b 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -522,6 +522,7 @@
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
+ [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
</theme_item>
<theme_item name="parent_hl_line_margin" data_type="constant" type="int" default="0">
The space between the parent relationship lines for the selected [TreeItem] and the relationship lines to its siblings that are not selected.
diff --git a/doc/classes/TubeTrailMesh.xml b/doc/classes/TubeTrailMesh.xml
index ddc544dc97..7457aa4050 100644
--- a/doc/classes/TubeTrailMesh.xml
+++ b/doc/classes/TubeTrailMesh.xml
@@ -7,6 +7,12 @@
<tutorials>
</tutorials>
<members>
+ <member name="cap_bottom" type="bool" setter="set_cap_bottom" getter="is_cap_bottom" default="true">
+ If [code]true[/code], generates a cap at the bottom of the tube. This can be set to [code]false[/code] to speed up generation and rendering when the cap is never seen by the camera.
+ </member>
+ <member name="cap_top" type="bool" setter="set_cap_top" getter="is_cap_top" default="true">
+ If [code]true[/code], generates a cap at the top of the tube. This can be set to [code]false[/code] to speed up generation and rendering when the cap is never seen by the camera.
+ </member>
<member name="curve" type="Curve" setter="set_curve" getter="get_curve">
</member>
<member name="radial_steps" type="int" setter="set_radial_steps" getter="get_radial_steps" default="8">
diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml
index 31811f817b..e069642e50 100644
--- a/doc/classes/VisualInstance3D.xml
+++ b/doc/classes/VisualInstance3D.xml
@@ -61,5 +61,12 @@
This object will only be visible for [Camera3D]s whose cull mask includes the render object this [VisualInstance3D] is set to.
For [Light3D]s, this can be used to control which [VisualInstance3D]s are affected by a specific light. For [GPUParticles3D], this can be used to control which particles are effected by a specific attractor. For [Decal]s, this can be used to control which [VisualInstance3D]s are affected by a specific decal.
</member>
+ <member name="sorting_offset" type="float" setter="set_sorting_offset" getter="get_sorting_offset" default="0.0">
+ The sorting offset used by this [VisualInstance3D]. Adjusting it to a higher value will make the [VisualInstance3D] reliably draw on top of other [VisualInstance3D]s that are otherwise positioned at the same spot.
+ </member>
+ <member name="sorting_use_aabb_center" type="bool" setter="set_sorting_use_aabb_center" getter="is_sorting_use_aabb_center" default="true">
+ If [code]true[/code], the object is sorted based on the [AABB] center. The object will be sorted based on the global position otherwise.
+ The [AABB] center based sorting is generally more accurate for 3D models. The position based sorting instead allows to better control the drawing order when working with [GPUParticles3D] and [CPUParticles3D].
+ </member>
</members>
</class>
diff --git a/drivers/SCsub b/drivers/SCsub
index 6cfcb1d18c..276b99e10b 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -24,7 +24,6 @@ SConscript("winmidi/SCsub")
# Graphics drivers
if env["vulkan"]:
- SConscript("spirv-reflect/SCsub")
SConscript("vulkan/SCsub")
if env["opengl3"]:
SConscript("gl_context/SCsub")
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 7b39641029..ecad4b66a5 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -568,9 +568,8 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
_new_batch(batch_broken, index);
// Override the start position and index as we want to start from where we finished off last time.
- state.canvas_instance_batches[state.current_batch_index].start = r_last_index * sizeof(InstanceData);
+ state.canvas_instance_batches[state.current_batch_index].start = r_last_index;
index = 0;
- _align_instance_data_buffer(index);
for (int i = 0; i < p_item_count; i++) {
Item *ci = items[i];
@@ -630,14 +629,14 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
}
// Copy over all data needed for rendering.
- glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].ubo);
+ glBindBuffer(GL_ARRAY_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].buffer);
#ifdef WEB_ENABLED
- glBufferSubData(GL_UNIFORM_BUFFER, r_last_index * sizeof(InstanceData), sizeof(InstanceData) * index, state.instance_data_array);
+ glBufferSubData(GL_ARRAY_BUFFER, r_last_index * sizeof(InstanceData), sizeof(InstanceData) * index, state.instance_data_array);
#else
// On Desktop and mobile we map the memory without synchronizing for maximum speed.
- void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, r_last_index * sizeof(InstanceData), index * sizeof(InstanceData), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
- memcpy(ubo, state.instance_data_array, index * sizeof(InstanceData));
- glUnmapBuffer(GL_UNIFORM_BUFFER);
+ void *buffer = glMapBufferRange(GL_ARRAY_BUFFER, r_last_index * sizeof(InstanceData), index * sizeof(InstanceData), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
+ memcpy(buffer, state.instance_data_array, index * sizeof(InstanceData));
+ glUnmapBuffer(GL_ARRAY_BUFFER);
#endif
glDisable(GL_SCISSOR_TEST);
@@ -664,7 +663,17 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
uint64_t specialization = 0;
specialization |= uint64_t(state.canvas_instance_batches[i].lights_disabled);
specialization |= uint64_t(!GLES3::Config::get_singleton()->float_texture_supported) << 1;
- bool success = _bind_material(material_data, variant, specialization);
+ RID shader_version = data.canvas_shader_default_version;
+
+ if (material_data) {
+ if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {
+ // Bind uniform buffer and textures
+ material_data->bind_uniforms();
+ shader_version = material_data->shader_data->version;
+ }
+ }
+
+ bool success = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(shader_version, variant, specialization);
if (!success) {
continue;
}
@@ -1122,16 +1131,10 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
RID particles = pt->particles;
state.canvas_instance_batches[state.current_batch_index].tex = pt->texture;
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
- bool local_coords = particles_storage->particles_is_using_local_coords(particles);
if (particles_storage->particles_has_collision(particles) && texture_storage->render_target_is_sdf_enabled(p_render_target)) {
// Pass collision information.
- Transform2D xform;
- if (local_coords) {
- xform = p_item->final_transform;
- } else {
- xform = p_canvas_transform_inverse;
- }
+ Transform2D xform = p_item->final_transform;
GLuint sdf_texture = texture_storage->render_target_get_sdf_texture(p_render_target);
@@ -1217,26 +1220,15 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
_bind_canvas_texture(state.canvas_instance_batches[p_index].tex, state.canvas_instance_batches[p_index].filter, state.canvas_instance_batches[p_index].repeat);
- // Bind the region of the UBO used by this batch.
- // If region exceeds the boundary of the UBO, just ignore.
- uint32_t range_bytes = data.max_instances_per_batch * sizeof(InstanceData);
- if (state.canvas_instance_batches[p_index].start >= (data.max_instances_per_ubo - 1) * sizeof(InstanceData)) {
- return;
- } else if (state.canvas_instance_batches[p_index].start >= (data.max_instances_per_ubo - data.max_instances_per_batch) * sizeof(InstanceData)) {
- // If we have less than a full batch at the end, we can just draw it anyway.
- // OpenGL will complain about the UBO being smaller than expected, but it should render fine.
- range_bytes = (data.max_instances_per_ubo - 1) * sizeof(InstanceData) - state.canvas_instance_batches[p_index].start;
- }
-
- uint32_t range_start = state.canvas_instance_batches[p_index].start;
- glBindBufferRange(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer].ubo, range_start, range_bytes);
-
switch (state.canvas_instance_batches[p_index].command_type) {
case Item::Command::TYPE_RECT:
case Item::Command::TYPE_NINEPATCH: {
glBindVertexArray(data.indexed_quad_array);
- glDrawElements(GL_TRIANGLES, state.canvas_instance_batches[p_index].instance_count * 6, GL_UNSIGNED_INT, 0);
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].buffer);
+ uint32_t range_start = state.canvas_instance_batches[p_index].start * sizeof(InstanceData);
+ _enable_attributes(range_start, false);
+
+ glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0, state.canvas_instance_batches[p_index].instance_count);
glBindVertexArray(0);
} break;
@@ -1248,18 +1240,21 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
ERR_FAIL_COND(!pb);
glBindVertexArray(pb->vertex_array);
+ glBindBuffer(GL_ARRAY_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].buffer);
+
+ uint32_t range_start = state.canvas_instance_batches[p_index].start * sizeof(InstanceData);
+ _enable_attributes(range_start, false);
if (pb->color_disabled && pb->color != Color(1.0, 1.0, 1.0, 1.0)) {
glVertexAttrib4f(RS::ARRAY_COLOR, pb->color.r, pb->color.g, pb->color.b, pb->color.a);
}
if (pb->index_buffer != 0) {
- glDrawElements(prim[polygon->primitive], pb->count, GL_UNSIGNED_INT, nullptr);
+ glDrawElementsInstanced(prim[polygon->primitive], pb->count, GL_UNSIGNED_INT, nullptr, 1);
} else {
- glDrawArrays(prim[polygon->primitive], 0, pb->count);
+ glDrawArraysInstanced(prim[polygon->primitive], 0, pb->count, 1);
}
glBindVertexArray(0);
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
if (pb->color_disabled && pb->color != Color(1.0, 1.0, 1.0, 1.0)) {
// Reset so this doesn't pollute other draw calls.
@@ -1269,14 +1264,16 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
case Item::Command::TYPE_PRIMITIVE: {
glBindVertexArray(data.canvas_quad_array);
+ glBindBuffer(GL_ARRAY_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].buffer);
+ uint32_t range_start = state.canvas_instance_batches[p_index].start * sizeof(InstanceData);
+ _enable_attributes(range_start, true);
+
const GLenum primitive[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLES };
int instance_count = state.canvas_instance_batches[p_index].instance_count;
- if (instance_count > 1) {
+ ERR_FAIL_COND(instance_count <= 0);
+ if (instance_count >= 1) {
glDrawArraysInstanced(primitive[state.canvas_instance_batches[p_index].primitive_points], 0, state.canvas_instance_batches[p_index].primitive_points, instance_count);
- } else {
- glDrawArrays(primitive[state.canvas_instance_batches[p_index].primitive_points], 0, state.canvas_instance_batches[p_index].primitive_points);
}
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
} break;
@@ -1370,6 +1367,11 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
index_array_gl = mesh_storage->mesh_surface_get_index_buffer(surface, 0);
bool use_index_buffer = false;
glBindVertexArray(vertex_array_gl);
+ glBindBuffer(GL_ARRAY_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].buffer);
+
+ uint32_t range_start = state.canvas_instance_batches[p_index].start * sizeof(InstanceData);
+ _enable_attributes(range_start, false, instance_count);
+
if (index_array_gl != 0) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_gl);
use_index_buffer = true;
@@ -1396,20 +1398,13 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
}
GLenum primitive_gl = prim[int(primitive)];
- if (instance_count == 1) {
- if (use_index_buffer) {
- glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0);
- } else {
- glDrawArrays(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface));
- }
- } else if (instance_count > 1) {
- if (use_index_buffer) {
- glDrawElementsInstanced(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0, instance_count);
- } else {
- glDrawArraysInstanced(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), instance_count);
- }
- }
+ if (use_index_buffer) {
+ glDrawElementsInstanced(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0, instance_count);
+ } else {
+ glDrawArraysInstanced(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), instance_count);
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
if (instance_count > 1) {
glDisableVertexAttribArray(5);
@@ -1429,7 +1424,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
}
void RasterizerCanvasGLES3::_add_to_batch(uint32_t &r_index, bool &r_batch_broken) {
- if (r_index >= data.max_instances_per_ubo - 1) {
+ if (r_index >= data.max_instances_per_buffer - 1) {
ERR_PRINT_ONCE("Trying to draw too many items. Please increase maximum number of items in the project settings 'rendering/gl_compatibility/item_buffer_size'");
return;
}
@@ -1457,27 +1452,25 @@ void RasterizerCanvasGLES3::_new_batch(bool &r_batch_broken, uint32_t &r_index)
// Copy the properties of the current batch, we will manually update the things that changed.
Batch new_batch = state.canvas_instance_batches[state.current_batch_index];
new_batch.instance_count = 0;
- new_batch.start = state.canvas_instance_batches[state.current_batch_index].start + state.canvas_instance_batches[state.current_batch_index].instance_count * sizeof(InstanceData);
+ new_batch.start = state.canvas_instance_batches[state.current_batch_index].start + state.canvas_instance_batches[state.current_batch_index].instance_count;
state.current_batch_index++;
state.canvas_instance_batches.push_back(new_batch);
- _align_instance_data_buffer(r_index);
}
-bool RasterizerCanvasGLES3::_bind_material(GLES3::CanvasMaterialData *p_material_data, CanvasShaderGLES3::ShaderVariant p_variant, uint64_t p_specialization) {
- if (p_material_data) {
- if (p_material_data->shader_data->version.is_valid() && p_material_data->shader_data->valid) {
- // Bind uniform buffer and textures
- p_material_data->bind_uniforms();
- return GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(p_material_data->shader_data->version, p_variant, p_specialization);
- } else {
- return GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(data.canvas_shader_default_version, p_variant, p_specialization);
- }
- } else {
- return GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(data.canvas_shader_default_version, p_variant, p_specialization);
+void RasterizerCanvasGLES3::_enable_attributes(uint32_t p_start, bool p_primitive, uint32_t p_rate) {
+ uint32_t split = p_primitive ? 11 : 12;
+ for (uint32_t i = 6; i < split; i++) {
+ glEnableVertexAttribArray(i);
+ glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, sizeof(InstanceData), CAST_INT_TO_UCHAR_PTR(p_start + (i - 6) * 4 * sizeof(float)));
+ glVertexAttribDivisor(i, p_rate);
+ }
+ for (uint32_t i = split; i <= 13; i++) {
+ glEnableVertexAttribArray(i);
+ glVertexAttribIPointer(i, 4, GL_UNSIGNED_INT, sizeof(InstanceData), CAST_INT_TO_UCHAR_PTR(p_start + (i - 6) * 4 * sizeof(float)));
+ glVertexAttribDivisor(i, p_rate);
}
}
-
RID RasterizerCanvasGLES3::light_create() {
CanvasLight canvas_light;
return canvas_light_owner.make_rid(canvas_light);
@@ -2102,6 +2095,9 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
if (t) {
ERR_FAIL_COND(!t->canvas_texture);
ct = t->canvas_texture;
+ if (t->render_target) {
+ t->render_target->used_in_frame = true;
+ }
} else {
ct = texture_storage->get_canvas_texture(p_texture);
}
@@ -2129,6 +2125,9 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
glBindTexture(GL_TEXTURE_2D, texture->tex_id);
texture->gl_set_filter(filter);
texture->gl_set_repeat(repeat);
+ if (texture->render_target) {
+ texture->render_target->used_in_frame = true;
+ }
}
GLES3::Texture *normal_map = texture_storage->get_texture(ct->normal_map);
@@ -2142,6 +2141,9 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
glBindTexture(GL_TEXTURE_2D, normal_map->tex_id);
normal_map->gl_set_filter(filter);
normal_map->gl_set_repeat(repeat);
+ if (normal_map->render_target) {
+ normal_map->render_target->used_in_frame = true;
+ }
}
GLES3::Texture *specular_map = texture_storage->get_texture(ct->specular);
@@ -2155,6 +2157,9 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
glBindTexture(GL_TEXTURE_2D, specular_map->tex_id);
specular_map->gl_set_filter(filter);
specular_map->gl_set_repeat(repeat);
+ if (specular_map->render_target) {
+ specular_map->render_target->used_in_frame = true;
+ }
}
}
@@ -2416,8 +2421,8 @@ void RasterizerCanvasGLES3::_allocate_instance_data_buffer() {
GLuint new_buffers[3];
glGenBuffers(3, new_buffers);
// Batch UBO.
- glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[0]);
- glBufferData(GL_UNIFORM_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, new_buffers[0]);
+ glBufferData(GL_ARRAY_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
// Light uniform buffer.
glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[1]);
glBufferData(GL_UNIFORM_BUFFER, sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW);
@@ -2427,36 +2432,16 @@ void RasterizerCanvasGLES3::_allocate_instance_data_buffer() {
state.current_buffer = (state.current_buffer + 1);
DataBuffer db;
- db.ubo = new_buffers[0];
+ db.buffer = new_buffers[0];
db.light_ubo = new_buffers[1];
db.state_ubo = new_buffers[2];
db.last_frame_used = RSG::rasterizer->get_frame_number();
state.canvas_instance_data_buffers.insert(state.current_buffer, db);
state.current_buffer = state.current_buffer % state.canvas_instance_data_buffers.size();
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
-// Batch start positions need to be aligned to the device's GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT.
-// This needs to be called anytime a new batch is created.
-void RasterizerCanvasGLES3::_align_instance_data_buffer(uint32_t &r_index) {
- if (GLES3::Config::get_singleton()->uniform_buffer_offset_alignment > int(sizeof(InstanceData))) {
- uint32_t offset = state.canvas_instance_batches[state.current_batch_index].start % GLES3::Config::get_singleton()->uniform_buffer_offset_alignment;
- if (offset > 0) {
- // uniform_buffer_offset_alignment can be 4, 16, 32, or 256. Our instance batches are 128 bytes.
- // Accordingly, this branch is only triggered if we are 128 bytes off.
- uint32_t offset_bytes = GLES3::Config::get_singleton()->uniform_buffer_offset_alignment - offset;
- state.canvas_instance_batches[state.current_batch_index].start += offset_bytes;
- // Offset the instance array so it stays in sync with batch start points.
- // This creates gaps in the instance buffer with wasted space, but we can't help it.
- r_index += offset_bytes / sizeof(InstanceData);
- if (r_index > 0) {
- // In this case we need to copy over the basic data.
- state.instance_data_array[r_index] = state.instance_data_array[r_index - 1];
- }
- }
- }
-}
-
void RasterizerCanvasGLES3::set_time(double p_time) {
state.time = p_time;
}
@@ -2601,12 +2586,12 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
data.max_instances_per_batch = 128;
} else {
data.max_lights_per_render = 256;
- data.max_instances_per_batch = 512;
+ data.max_instances_per_batch = 2048;
}
// Reserve 3 Uniform Buffers for instance data Frame N, N+1 and N+2
- data.max_instances_per_ubo = MAX(data.max_instances_per_batch, uint32_t(GLOBAL_GET("rendering/gl_compatibility/item_buffer_size")));
- data.max_instance_buffer_size = data.max_instances_per_ubo * sizeof(InstanceData); // 16,384 instances * 128 bytes = 2,097,152 bytes = 2,048 kb
+ data.max_instances_per_buffer = MAX(data.max_instances_per_batch, uint32_t(GLOBAL_GET("rendering/gl_compatibility/item_buffer_size")));
+ data.max_instance_buffer_size = data.max_instances_per_buffer * sizeof(InstanceData); // 16,384 instances * 128 bytes = 2,097,152 bytes = 2,048 kb
state.canvas_instance_data_buffers.resize(3);
state.canvas_instance_batches.reserve(200);
@@ -2614,8 +2599,8 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
GLuint new_buffers[3];
glGenBuffers(3, new_buffers);
// Batch UBO.
- glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[0]);
- glBufferData(GL_UNIFORM_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, new_buffers[0]);
+ glBufferData(GL_ARRAY_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
// Light uniform buffer.
glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[1]);
glBufferData(GL_UNIFORM_BUFFER, sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW);
@@ -2623,41 +2608,28 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[2]);
glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), nullptr, GL_STREAM_DRAW);
DataBuffer db;
- db.ubo = new_buffers[0];
+ db.buffer = new_buffers[0];
db.light_ubo = new_buffers[1];
db.state_ubo = new_buffers[2];
db.last_frame_used = 0;
db.fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
state.canvas_instance_data_buffers[i] = db;
}
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
- state.instance_data_array = memnew_arr(InstanceData, data.max_instances_per_ubo);
+ state.instance_data_array = memnew_arr(InstanceData, data.max_instances_per_buffer);
state.light_uniforms = memnew_arr(LightUniform, data.max_lights_per_render);
{
- const uint32_t no_of_instances = data.max_instances_per_batch;
-
+ const uint32_t indices[6] = { 0, 2, 1, 3, 2, 0 };
glGenVertexArrays(1, &data.indexed_quad_array);
glBindVertexArray(data.indexed_quad_array);
glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices);
-
- const uint32_t num_indices = 6;
- const uint32_t quad_indices[num_indices] = { 0, 2, 1, 3, 2, 0 };
-
- const uint32_t total_indices = no_of_instances * num_indices;
- uint32_t *indices = new uint32_t[total_indices];
- for (uint32_t i = 0; i < total_indices; i++) {
- uint32_t quad = i / num_indices;
- uint32_t quad_local = i % num_indices;
- indices[i] = quad_indices[quad_local] + quad * num_indices;
- }
-
glGenBuffers(1, &data.indexed_quad_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.indexed_quad_buffer);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * total_indices, indices, GL_STATIC_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * 6, indices, GL_STATIC_DRAW);
glBindVertexArray(0);
- delete[] indices;
}
String global_defines;
@@ -2665,7 +2637,7 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
global_defines += "#define MAX_LIGHTS " + itos(data.max_lights_per_render) + "\n";
global_defines += "#define MAX_DRAW_DATA_INSTANCES " + itos(data.max_instances_per_batch) + "\n";
- GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.initialize(global_defines);
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.initialize(global_defines, 1);
data.canvas_shader_default_version = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_create();
shadow_render.shader.initialize();
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index bd87973404..d99a8414f7 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -245,7 +245,7 @@ public:
uint32_t max_lights_per_render = 256;
uint32_t max_lights_per_item = 16;
uint32_t max_instances_per_batch = 512;
- uint32_t max_instances_per_ubo = 16384;
+ uint32_t max_instances_per_buffer = 16384;
uint32_t max_instance_buffer_size = 16384 * 128;
} data;
@@ -278,7 +278,7 @@ public:
// We track them and ensure that they don't get reused until at least 2 frames have passed
// to avoid the GPU stalling to wait for a resource to become available.
struct DataBuffer {
- GLuint ubo = 0;
+ GLuint buffer = 0;
GLuint light_ubo = 0;
GLuint state_ubo = 0;
uint64_t last_frame_used = -3;
@@ -359,6 +359,7 @@ public:
void _add_to_batch(uint32_t &r_index, bool &r_batch_broken);
void _allocate_instance_data_buffer();
void _align_instance_data_buffer(uint32_t &r_index);
+ void _enable_attributes(uint32_t p_start, bool p_primitive, uint32_t p_rate = 1);
void set_time(double p_time);
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 7b4131b3a3..75fc0c8c35 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -333,18 +333,14 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
return;
}
- Size2i win_size = DisplayServer::get_singleton()->screen_get_size();
+ Size2i win_size = DisplayServer::get_singleton()->window_get_size();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, win_size.width, win_size.height);
- glDisable(GL_BLEND);
+ glEnable(GL_BLEND);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
glDepthMask(GL_FALSE);
- if (false) {
- // if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
- glClearColor(0.0, 0.0, 0.0, 0.0);
- } else {
- glClearColor(p_color.r, p_color.g, p_color.b, 1.0);
- }
+ glClearColor(p_color.r, p_color.g, p_color.b, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
RID texture = texture_storage->texture_allocate();
@@ -370,14 +366,24 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
screenrect.position += ((Size2(win_size.width, win_size.height) - screenrect.size) / 2.0).floor();
}
+ // Flip Y.
+ screenrect.position.y = win_size.y - screenrect.position.y;
+ screenrect.size.y = -screenrect.size.y;
+
+ // Normalize texture coordinates to window size.
+ screenrect.position /= win_size;
+ screenrect.size /= win_size;
+
GLES3::Texture *t = texture_storage->get_texture(texture);
- glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 1);
+ t->gl_set_filter(p_use_filter ? RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR : RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
+ glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, t->tex_id);
+ copy_effects->copy_to_rect(screenrect);
glBindTexture(GL_TEXTURE_2D, 0);
- texture_storage->texture_free(texture);
-
end_frame(true);
+
+ texture_storage->texture_free(texture);
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index ae5515e249..1faecfd4d0 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1170,12 +1170,17 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
for (int i = 0; i < (int)p_render_data->instances->size(); i++) {
GeometryInstanceGLES3 *inst = static_cast<GeometryInstanceGLES3 *>((*p_render_data->instances)[i]);
+ Vector3 center = inst->transform.origin;
if (p_render_data->cam_orthogonal) {
- Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal);
- inst->depth = near_plane.distance_to(support_min);
+ if (inst->use_aabb_center) {
+ center = inst->transformed_aabb.get_support(-near_plane.normal);
+ }
+ inst->depth = near_plane.distance_to(center) - inst->sorting_offset;
} else {
- Vector3 aabb_center = inst->transformed_aabb.position + (inst->transformed_aabb.size * 0.5);
- inst->depth = p_render_data->cam_transform.origin.distance_to(aabb_center);
+ if (inst->use_aabb_center) {
+ center = inst->transformed_aabb.position + (inst->transformed_aabb.size * 0.5);
+ }
+ inst->depth = p_render_data->cam_transform.origin.distance_to(center) - inst->sorting_offset;
}
uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15);
@@ -1739,7 +1744,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
render_data.reflection_probes = &empty;
}
- bool reverse_cull = false;
+ bool reverse_cull = render_data.cam_transform.basis.determinant() < 0;
///////////
// Fill Light lists here
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index c1c26ed963..9a90f33674 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -11,6 +11,7 @@ mode_instanced = #define USE_ATTRIBUTES \n#define USE_INSTANCING
DISABLE_LIGHTING = false
USE_RGBA_SHADOWS = false
+SINGLE_INSTANCE = false
#[vertex]
@@ -25,9 +26,74 @@ layout(location = 1) in highp vec4 instance_xform0;
layout(location = 2) in highp vec4 instance_xform1;
layout(location = 5) in highp uvec4 instance_color_custom_data; // Color packed into xy, custom_data packed into zw for compatibility with 3D
+#endif // USE_INSTANCING
+
+#endif // USE_ATTRIBUTES
+
+#include "stdlib_inc.glsl"
+
+layout(location = 6) in highp vec4 attrib_A;
+layout(location = 7) in highp vec4 attrib_B;
+layout(location = 8) in highp vec4 attrib_C;
+layout(location = 9) in highp vec4 attrib_D;
+layout(location = 10) in highp vec4 attrib_E;
+#ifdef USE_PRIMITIVE
+layout(location = 11) in highp uvec4 attrib_F;
+#else
+layout(location = 11) in highp vec4 attrib_F;
+#endif
+layout(location = 12) in highp uvec4 attrib_G;
+layout(location = 13) in highp uvec4 attrib_H;
+
+#define read_draw_data_world_x attrib_A.xy
+#define read_draw_data_world_y attrib_A.zw
+#define read_draw_data_world_ofs attrib_B.xy
+#define read_draw_data_color_texture_pixel_size attrib_B.zw
+
+#ifdef USE_PRIMITIVE
+
+#define read_draw_data_point_a attrib_C.xy
+#define read_draw_data_point_b attrib_C.zw
+#define read_draw_data_point_c attrib_D.xy
+#define read_draw_data_uv_a attrib_D.zw
+#define read_draw_data_uv_b attrib_E.xy
+#define read_draw_data_uv_c attrib_E.zw
+
+#define read_draw_data_color_a_rg attrib_F.x
+#define read_draw_data_color_a_ba attrib_F.y
+#define read_draw_data_color_b_rg attrib_F.z
+#define read_draw_data_color_b_ba attrib_F.w
+#define read_draw_data_color_c_rg attrib_G.x
+#define read_draw_data_color_c_ba attrib_G.y
+
+#else
+
+#define read_draw_data_modulation attrib_C
+#define read_draw_data_ninepatch_margins attrib_D
+#define read_draw_data_dst_rect attrib_E
+#define read_draw_data_src_rect attrib_F
+
#endif
+#define read_draw_data_flags attrib_G.z
+#define read_draw_data_specular_shininess attrib_G.w
+#define read_draw_data_lights attrib_H
+
+// Varyings so the per-instance info can be used in the fragment shader
+flat out vec4 varying_A;
+flat out vec2 varying_B;
+#ifndef USE_PRIMITIVE
+flat out vec4 varying_C;
+#ifndef USE_ATTRIBUTES
+#ifdef USE_NINEPATCH
+
+flat out vec2 varying_D;
+#endif
+flat out vec4 varying_E;
+#endif
#endif
+flat out uvec2 varying_F;
+flat out uvec4 varying_G;
// This needs to be outside clang-format so the ubo comment is in the right place
#ifdef MATERIAL_UNIFORMS_USED
@@ -39,12 +105,10 @@ layout(std140) uniform MaterialUniforms{ //ubo:4
#endif
/* clang-format on */
#include "canvas_uniforms_inc.glsl"
-#include "stdlib_inc.glsl"
out vec2 uv_interp;
out vec4 color_interp;
out vec2 vertex_interp;
-flat out int draw_data_instance;
#ifdef USE_NINEPATCH
@@ -55,35 +119,46 @@ out vec2 pixel_size_interp;
#GLOBALS
void main() {
+ varying_A = vec4(read_draw_data_world_x, read_draw_data_world_y);
+ varying_B = read_draw_data_color_texture_pixel_size;
+#ifndef USE_PRIMITIVE
+ varying_C = read_draw_data_ninepatch_margins;
+
+#ifndef USE_ATTRIBUTES
+#ifdef USE_NINEPATCH
+ varying_D = vec2(read_draw_data_dst_rect.z, read_draw_data_dst_rect.w);
+#endif // USE_NINEPATCH
+ varying_E = read_draw_data_src_rect;
+#endif // !USE_ATTRIBUTES
+#endif // USE_PRIMITIVE
+
+ varying_F = uvec2(read_draw_data_flags, read_draw_data_specular_shininess);
+ varying_G = read_draw_data_lights;
+
vec4 instance_custom = vec4(0.0);
#ifdef USE_PRIMITIVE
- draw_data_instance = gl_InstanceID;
vec2 vertex;
vec2 uv;
vec4 color;
if (gl_VertexID % 3 == 0) {
- vertex = draw_data[draw_data_instance].point_a;
- uv = draw_data[draw_data_instance].uv_a;
- color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_a_rg), unpackHalf2x16(draw_data[draw_data_instance].color_a_ba));
+ vertex = read_draw_data_point_a;
+ uv = read_draw_data_uv_a;
+ color = vec4(unpackHalf2x16(read_draw_data_color_a_rg), unpackHalf2x16(read_draw_data_color_a_ba));
} else if (gl_VertexID % 3 == 1) {
- vertex = draw_data[draw_data_instance].point_b;
- uv = draw_data[draw_data_instance].uv_b;
- color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_b_rg), unpackHalf2x16(draw_data[draw_data_instance].color_b_ba));
+ vertex = read_draw_data_point_b;
+ uv = read_draw_data_uv_b;
+ color = vec4(unpackHalf2x16(read_draw_data_color_b_rg), unpackHalf2x16(read_draw_data_color_b_ba));
} else {
- vertex = draw_data[draw_data_instance].point_c;
- uv = draw_data[draw_data_instance].uv_c;
- color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_c_rg), unpackHalf2x16(draw_data[draw_data_instance].color_c_ba));
+ vertex = read_draw_data_point_c;
+ uv = read_draw_data_uv_c;
+ color = vec4(unpackHalf2x16(read_draw_data_color_c_rg), unpackHalf2x16(read_draw_data_color_c_ba));
}
#elif defined(USE_ATTRIBUTES)
- draw_data_instance = gl_InstanceID;
-#ifdef USE_INSTANCING
- draw_data_instance = 0;
-#endif
vec2 vertex = vertex_attrib;
- vec4 color = color_attrib * draw_data[draw_data_instance].modulation;
+ vec4 color = color_attrib * read_draw_data_modulation;
vec2 uv = uv_attrib;
#ifdef USE_INSTANCING
@@ -93,30 +168,29 @@ void main() {
#endif
#else
- draw_data_instance = gl_VertexID / 6;
vec2 vertex_base_arr[6] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 vertex_base = vertex_base_arr[gl_VertexID % 6];
- vec2 uv = draw_data[draw_data_instance].src_rect.xy + abs(draw_data[draw_data_instance].src_rect.zw) * ((draw_data[draw_data_instance].flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy);
- vec4 color = draw_data[draw_data_instance].modulation;
- vec2 vertex = draw_data[draw_data_instance].dst_rect.xy + abs(draw_data[draw_data_instance].dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(draw_data[draw_data_instance].src_rect.zw, vec2(0.0, 0.0)));
+ vec2 uv = read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) * ((read_draw_data_flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy);
+ vec4 color = read_draw_data_modulation;
+ vec2 vertex = read_draw_data_dst_rect.xy + abs(read_draw_data_dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(read_draw_data_src_rect.zw, vec2(0.0, 0.0)));
#endif
- mat4 model_matrix = mat4(vec4(draw_data[draw_data_instance].world_x, 0.0, 0.0), vec4(draw_data[draw_data_instance].world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(draw_data[draw_data_instance].world_ofs, 0.0, 1.0));
+ mat4 model_matrix = mat4(vec4(read_draw_data_world_x, 0.0, 0.0), vec4(read_draw_data_world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(read_draw_data_world_ofs, 0.0, 1.0));
#ifdef USE_INSTANCING
model_matrix = model_matrix * transpose(mat4(instance_xform0, instance_xform1, vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)));
#endif // USE_INSTANCING
#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
- if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_PARTICLES)) {
+ if (bool(read_draw_data_flags & FLAGS_USING_PARTICLES)) {
//scale by texture size
- vertex /= draw_data[draw_data_instance].color_texture_pixel_size;
+ vertex /= read_draw_data_color_texture_pixel_size;
}
#endif
- vec2 color_texture_pixel_size = draw_data[draw_data_instance].color_texture_pixel_size.xy;
+ vec2 color_texture_pixel_size = read_draw_data_color_texture_pixel_size;
#ifdef USE_POINT_SIZE
float point_size = 1.0;
@@ -126,7 +200,7 @@ void main() {
}
#ifdef USE_NINEPATCH
- pixel_size_interp = abs(draw_data[draw_data_instance].dst_rect.zw) * vertex_base;
+ pixel_size_interp = abs(read_draw_data_dst_rect.zw) * vertex_base;
#endif
#if !defined(SKIP_TRANSFORM_USED)
@@ -159,6 +233,46 @@ void main() {
#include "canvas_uniforms_inc.glsl"
#include "stdlib_inc.glsl"
+in vec2 uv_interp;
+in vec2 vertex_interp;
+in vec4 color_interp;
+
+#ifdef USE_NINEPATCH
+
+in vec2 pixel_size_interp;
+
+#endif
+
+// Can all be flat as they are the same for the whole batched instance
+flat in vec4 varying_A;
+flat in vec2 varying_B;
+#define read_draw_data_world_x varying_A.xy
+#define read_draw_data_world_y varying_A.zw
+#define read_draw_data_color_texture_pixel_size varying_B
+
+#ifndef USE_PRIMITIVE
+flat in vec4 varying_C;
+#define read_draw_data_ninepatch_margins varying_C
+
+#ifndef USE_ATTRIBUTES
+#ifdef USE_NINEPATCH
+
+flat in vec2 varying_D;
+#define read_draw_data_dst_rect_z varying_D.x
+#define read_draw_data_dst_rect_w varying_D.y
+#endif
+
+flat in vec4 varying_E;
+#define read_draw_data_src_rect varying_E
+#endif // USE_ATTRIBUTES
+#endif // USE_PRIMITIVE
+
+flat in uvec2 varying_F;
+flat in uvec4 varying_G;
+#define read_draw_data_flags varying_F.x
+#define read_draw_data_specular_shininess varying_F.y
+#define read_draw_data_lights varying_G
+
#ifndef DISABLE_LIGHTING
uniform sampler2D atlas_texture; //texunit:-2
uniform sampler2D shadow_atlas_texture; //texunit:-3
@@ -170,17 +284,6 @@ uniform sampler2D specular_texture; //texunit:-7
uniform sampler2D color_texture; //texunit:0
-in vec2 uv_interp;
-in vec4 color_interp;
-in vec2 vertex_interp;
-flat in int draw_data_instance;
-
-#ifdef USE_NINEPATCH
-
-in vec2 pixel_size_interp;
-
-#endif
-
layout(location = 0) out vec4 frag_color;
#ifdef MATERIAL_UNIFORMS_USED
@@ -366,7 +469,7 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
} else if (pixel >= draw_size - margin_end) {
return (tex_size - (draw_size - pixel)) * tex_pixel_size;
} else {
- if (!bool(draw_data[draw_data_instance].flags & FLAGS_NINEPACH_DRAW_CENTER)) {
+ if (!bool(read_draw_data_flags & FLAGS_NINEPACH_DRAW_CENTER)) {
draw_center--;
}
@@ -414,28 +517,26 @@ void main() {
int draw_center = 2;
uv = vec2(
- map_ninepatch_axis(pixel_size_interp.x, abs(draw_data[draw_data_instance].dst_rect.z), draw_data[draw_data_instance].color_texture_pixel_size.x, draw_data[draw_data_instance].ninepatch_margins.x, draw_data[draw_data_instance].ninepatch_margins.z, int(draw_data[draw_data_instance].flags >> FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center),
- map_ninepatch_axis(pixel_size_interp.y, abs(draw_data[draw_data_instance].dst_rect.w), draw_data[draw_data_instance].color_texture_pixel_size.y, draw_data[draw_data_instance].ninepatch_margins.y, draw_data[draw_data_instance].ninepatch_margins.w, int(draw_data[draw_data_instance].flags >> FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center));
+ map_ninepatch_axis(pixel_size_interp.x, abs(read_draw_data_dst_rect_z), read_draw_data_color_texture_pixel_size.x, read_draw_data_ninepatch_margins.x, read_draw_data_ninepatch_margins.z, int(read_draw_data_flags >> FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center),
+ map_ninepatch_axis(pixel_size_interp.y, abs(read_draw_data_dst_rect_w), read_draw_data_color_texture_pixel_size.y, read_draw_data_ninepatch_margins.y, read_draw_data_ninepatch_margins.w, int(read_draw_data_flags >> FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center));
if (draw_center == 0) {
color.a = 0.0;
}
- uv = uv * draw_data[draw_data_instance].src_rect.zw + draw_data[draw_data_instance].src_rect.xy; //apply region if needed
+ uv = uv * read_draw_data_src_rect.zw + read_draw_data_src_rect.xy; //apply region if needed
#endif
- if (bool(draw_data[draw_data_instance].flags & FLAGS_CLIP_RECT_UV)) {
- uv = clamp(uv, draw_data[draw_data_instance].src_rect.xy, draw_data[draw_data_instance].src_rect.xy + abs(draw_data[draw_data_instance].src_rect.zw));
+ if (bool(read_draw_data_flags & FLAGS_CLIP_RECT_UV)) {
+ uv = clamp(uv, read_draw_data_src_rect.xy, read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw));
}
#endif
#ifndef USE_PRIMITIVE
- if (bool(draw_data[draw_data_instance].flags & FLAGS_USE_MSDF)) {
- float px_range = draw_data[draw_data_instance].ninepatch_margins.x;
- float outline_thickness = draw_data[draw_data_instance].ninepatch_margins.y;
- //float reserved1 = draw_data[draw_data_instance].ninepatch_margins.z;
- //float reserved2 = draw_data[draw_data_instance].ninepatch_margins.w;
+ if (bool(read_draw_data_flags & FLAGS_USE_MSDF)) {
+ float px_range = read_draw_data_ninepatch_margins.x;
+ float outline_thickness = read_draw_data_ninepatch_margins.y;
vec4 msdf_sample = texture(color_texture, uv);
vec2 msdf_size = vec2(textureSize(color_texture, 0));
@@ -451,7 +552,7 @@ void main() {
float a = clamp(d * px_size + 0.5, 0.0, 1.0);
color.a = a * color.a;
}
- } else if (bool(draw_data[draw_data_instance].flags & FLAGS_USE_LCD)) {
+ } else if (bool(read_draw_data_flags & FLAGS_USE_LCD)) {
vec4 lcd_sample = texture(color_texture, uv);
if (lcd_sample.a == 1.0) {
color.rgb = lcd_sample.rgb * color.a;
@@ -465,7 +566,7 @@ void main() {
color *= texture(color_texture, uv);
}
- uint light_count = (draw_data[draw_data_instance].flags >> uint(FLAGS_LIGHT_COUNT_SHIFT)) & uint(0xF); //max 16 lights
+ uint light_count = (read_draw_data_flags >> uint(FLAGS_LIGHT_COUNT_SHIFT)) & uint(0xF); //max 16 lights
bool using_light = light_count > 0u || directional_light_count > 0u;
vec3 normal;
@@ -476,7 +577,7 @@ void main() {
bool normal_used = false;
#endif
- if (normal_used || (using_light && bool(draw_data[draw_data_instance].flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
+ if (normal_used || (using_light && bool(read_draw_data_flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(normal_texture, uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
normal_used = true;
@@ -493,9 +594,9 @@ void main() {
bool specular_shininess_used = false;
#endif
- if (specular_shininess_used || (using_light && normal_used && bool(draw_data[draw_data_instance].flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
+ if (specular_shininess_used || (using_light && normal_used && bool(read_draw_data_flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
specular_shininess = texture(specular_texture, uv);
- specular_shininess *= godot_unpackUnorm4x8(draw_data[draw_data_instance].specular_shininess);
+ specular_shininess *= godot_unpackUnorm4x8(read_draw_data_specular_shininess);
specular_shininess_used = true;
} else {
specular_shininess = vec4(1.0);
@@ -507,7 +608,7 @@ void main() {
vec2 screen_uv = vec2(0.0);
#endif
- vec2 color_texture_pixel_size = draw_data[draw_data_instance].color_texture_pixel_size.xy;
+ vec2 color_texture_pixel_size = read_draw_data_color_texture_pixel_size.xy;
vec3 light_vertex = vec3(vertex, 0.0);
vec2 shadow_vertex = vertex;
@@ -529,7 +630,7 @@ void main() {
if (normal_used) {
//convert by item transform
- normal.xy = mat2(normalize(draw_data[draw_data_instance].world_x), normalize(draw_data[draw_data_instance].world_y)) * normal.xy;
+ normal.xy = mat2(normalize(read_draw_data_world_x), normalize(read_draw_data_world_y)) * normal.xy;
//convert by canvas transform
normal = normalize((canvas_normal_transform * vec4(normal, 0.0)).xyz);
}
@@ -591,15 +692,15 @@ void main() {
uint light_base;
if (i < 8u) {
if (i < 4u) {
- light_base = draw_data[draw_data_instance].lights[0];
+ light_base = read_draw_data_lights[0];
} else {
- light_base = draw_data[draw_data_instance].lights[1];
+ light_base = read_draw_data_lights[1];
}
} else {
if (i < 12u) {
- light_base = draw_data[draw_data_instance].lights[2];
+ light_base = read_draw_data_lights[2];
} else {
- light_base = draw_data[draw_data_instance].lights[3];
+ light_base = read_draw_data_lights[3];
}
}
light_base >>= (i & 3u) * 8u;
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
index dd5ebecb1a..f65558f042 100644
--- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl
+++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
@@ -27,38 +27,6 @@
#define FLAGS_USE_MSDF uint(1 << 28)
#define FLAGS_USE_LCD uint(1 << 29)
-// must be always 128 bytes long
-struct DrawData {
- vec2 world_x;
- vec2 world_y;
- vec2 world_ofs;
- vec2 color_texture_pixel_size;
-#ifdef USE_PRIMITIVE
- vec2 point_a;
- vec2 point_b;
- vec2 point_c;
- vec2 uv_a;
- vec2 uv_b;
- vec2 uv_c;
- uint color_a_rg;
- uint color_a_ba;
- uint color_b_rg;
- uint color_b_ba;
- uint color_c_rg;
- uint color_c_ba;
-#else
- vec4 modulation;
- vec4 ninepatch_margins;
- vec4 dst_rect; //for built-in rect and UV
- vec4 src_rect;
- uint pad;
- uint pad2;
-#endif
- uint flags;
- uint specular_shininess;
- uvec4 lights;
-};
-
layout(std140) uniform GlobalShaderUniformData { //ubo:1
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
};
@@ -116,7 +84,3 @@ layout(std140) uniform LightData { //ubo:2
Light light_array[MAX_LIGHTS];
};
#endif // DISABLE_LIGHTING
-layout(std140) uniform DrawDataInstances { //ubo:3
-
- DrawData draw_data[MAX_DRAW_DATA_INSTANCES];
-};
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
index 9b496c0999..46dc2b806e 100644
--- a/drivers/gles3/storage/config.cpp
+++ b/drivers/gles3/storage/config.cpp
@@ -90,8 +90,6 @@ Config::Config() {
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size);
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size);
- glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_offset_alignment);
-
support_anisotropic_filter = extensions.has("GL_EXT_texture_filter_anisotropic");
if (support_anisotropic_filter) {
glGetFloatv(_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic_level);
diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h
index 87202fde84..1a93b4b8ef 100644
--- a/drivers/gles3/storage/config.h
+++ b/drivers/gles3/storage/config.h
@@ -67,8 +67,6 @@ public:
int max_renderable_lights = 0;
int max_lights_per_object = 0;
- int uniform_buffer_offset_alignment = 0;
-
// TODO implement wireframe in OpenGL
// bool generate_wireframes;
diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp
index b6bd4a2760..710112bff4 100644
--- a/drivers/gles3/storage/light_storage.cpp
+++ b/drivers/gles3/storage/light_storage.cpp
@@ -502,6 +502,10 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_
return false;
}
+Ref<RenderSceneBuffers> LightStorage::reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) {
+ return Ref<RenderSceneBuffers>();
+}
+
bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) {
return true;
}
diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h
index 12cb2c4393..f41dafa5b0 100644
--- a/drivers/gles3/storage/light_storage.h
+++ b/drivers/gles3/storage/light_storage.h
@@ -366,6 +366,7 @@ public:
virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
+ virtual Ref<RenderSceneBuffers> reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) override;
virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
/* LIGHTMAP CAPTURE */
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index 19e841f466..ebafdc88d8 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -923,6 +923,104 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
}
///////////////////////////////////////////////////////////////////////////
+// ShaderData
+
+void ShaderData::set_path_hint(const String &p_hint) {
+ path = p_hint;
+}
+
+void ShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
+ if (!p_texture.is_valid()) {
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
+ }
+ }
+ } else {
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = HashMap<int, RID>();
+ }
+ default_texture_params[p_name][p_index] = p_texture;
+ }
+}
+
+Variant ShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
+ }
+ return Variant();
+}
+
+void ShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
+ SortArray<Pair<StringName, int>, ShaderLanguage::UniformOrderComparator> sorter;
+ LocalVector<Pair<StringName, int>> filtered_uniforms;
+
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ continue;
+ }
+ if (E.value.texture_order >= 0) {
+ filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.texture_order + 100000));
+ } else {
+ filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.order));
+ }
+ }
+ int uniform_count = filtered_uniforms.size();
+ sorter.sort(filtered_uniforms.ptr(), uniform_count);
+
+ String last_group;
+ for (int i = 0; i < uniform_count; i++) {
+ const StringName &uniform_name = filtered_uniforms[i].first;
+ const ShaderLanguage::ShaderNode::Uniform &uniform = uniforms[uniform_name];
+
+ String group = uniform.group;
+ if (!uniform.subgroup.is_empty()) {
+ group += "::" + uniform.subgroup;
+ }
+
+ if (group != last_group) {
+ PropertyInfo pi;
+ pi.usage = PROPERTY_USAGE_GROUP;
+ pi.name = group;
+ p_param_list->push_back(pi);
+
+ last_group = group;
+ }
+
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniform);
+ pi.name = uniform_name;
+ p_param_list->push_back(pi);
+ }
+}
+
+void ShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RendererMaterialStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E.value);
+ p.info.name = E.key; //supply name
+ p.index = E.value.instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool ShaderData::is_parameter_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+///////////////////////////////////////////////////////////////////////////
// MaterialData
// Look up table to translate ShaderLanguage::DataType to GL_TEXTURE_*
@@ -2806,10 +2904,6 @@ void MaterialStorage::material_update_dependency(RID p_material, DependencyTrack
/* Canvas Shader Data */
-void CanvasShaderData::set_path_hint(const String &p_path) {
- path = p_path;
-}
-
void CanvasShaderData::set_code(const String &p_code) {
// compile the shader
@@ -2890,85 +2984,6 @@ void CanvasShaderData::set_code(const String &p_code) {
valid = true;
}
-void CanvasShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
- if (!p_texture.is_valid()) {
- if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
- default_texture_params[p_name].erase(p_index);
-
- if (default_texture_params[p_name].is_empty()) {
- default_texture_params.erase(p_name);
- }
- }
- } else {
- if (!default_texture_params.has(p_name)) {
- default_texture_params[p_name] = HashMap<int, RID>();
- }
- default_texture_params[p_name][p_index] = p_texture;
- }
-}
-
-void CanvasShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
- HashMap<int, StringName> order;
-
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
- continue;
- }
- if (E.value.texture_order >= 0) {
- order[E.value.texture_order + 100000] = E.key;
- } else {
- order[E.value.order] = E.key;
- }
- }
-
- String last_group;
- for (const KeyValue<int, StringName> &E : order) {
- String group = uniforms[E.value].group;
- if (!uniforms[E.value].subgroup.is_empty()) {
- group += "::" + uniforms[E.value].subgroup;
- }
-
- if (group != last_group) {
- PropertyInfo pi;
- pi.usage = PROPERTY_USAGE_GROUP;
- pi.name = group;
- p_param_list->push_back(pi);
-
- last_group = group;
- }
-
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
- pi.name = E.value;
- p_param_list->push_back(pi);
- }
-}
-
-void CanvasShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererMaterialStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E.value);
- p.info.name = E.key; //supply name
- p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
- p_param_list->push_back(p);
- }
-}
-
-bool CanvasShaderData::is_parameter_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
bool CanvasShaderData::is_animated() const {
return false;
}
@@ -2977,15 +2992,6 @@ bool CanvasShaderData::casts_shadows() const {
return false;
}
-Variant CanvasShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
- }
- return Variant();
-}
-
RS::ShaderNativeSourceCode CanvasShaderData::get_native_source_code() const {
return MaterialStorage::get_singleton()->shaders.canvas_shader.version_get_native_source_code(version);
}
@@ -3021,6 +3027,9 @@ void CanvasMaterialData::bind_uniforms() {
Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
glActiveTexture(GL_TEXTURE1 + ti); // Start at GL_TEXTURE1 because texture slot 0 is used by the base texture
glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+ if (texture->render_target) {
+ texture->render_target->used_in_frame = true;
+ }
// Set sampler state here as the same texture can be used in multiple places with different flags
// Need to convert sampler state from ShaderLanguage::Texture* to RS::CanvasItemTexture*
@@ -3044,10 +3053,6 @@ GLES3::MaterialData *GLES3::_create_canvas_material_func(ShaderData *p_shader) {
////////////////////////////////////////////////////////////////////////////////
// SKY SHADER
-void SkyShaderData::set_path_hint(const String &p_path) {
- path = p_path;
-}
-
void SkyShaderData::set_code(const String &p_code) {
//compile
@@ -3138,83 +3143,6 @@ void SkyShaderData::set_code(const String &p_code) {
valid = true;
}
-void SkyShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
- if (!p_texture.is_valid()) {
- if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
- default_texture_params[p_name].erase(p_index);
-
- if (default_texture_params[p_name].is_empty()) {
- default_texture_params.erase(p_name);
- }
- }
- } else {
- if (!default_texture_params.has(p_name)) {
- default_texture_params[p_name] = HashMap<int, RID>();
- }
- default_texture_params[p_name][p_index] = p_texture;
- }
-}
-
-void SkyShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
- RBMap<int, StringName> order;
-
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- if (E.value.texture_order >= 0) {
- order[E.value.texture_order + 100000] = E.key;
- } else {
- order[E.value.order] = E.key;
- }
- }
-
- String last_group;
- for (const KeyValue<int, StringName> &E : order) {
- String group = uniforms[E.value].group;
- if (!uniforms[E.value].subgroup.is_empty()) {
- group += "::" + uniforms[E.value].subgroup;
- }
-
- if (group != last_group) {
- PropertyInfo pi;
- pi.usage = PROPERTY_USAGE_GROUP;
- pi.name = group;
- p_param_list->push_back(pi);
-
- last_group = group;
- }
-
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
- pi.name = E.value;
- p_param_list->push_back(pi);
- }
-}
-
-void SkyShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererMaterialStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E.value);
- p.info.name = E.key; //supply name
- p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
- p_param_list->push_back(p);
- }
-}
-
-bool SkyShaderData::is_parameter_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
bool SkyShaderData::is_animated() const {
return false;
}
@@ -3223,15 +3151,6 @@ bool SkyShaderData::casts_shadows() const {
return false;
}
-Variant SkyShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
- }
- return Variant();
-}
-
RS::ShaderNativeSourceCode SkyShaderData::get_native_source_code() const {
return MaterialStorage::get_singleton()->shaders.sky_shader.version_get_native_source_code(version);
}
@@ -3278,6 +3197,9 @@ void SkyMaterialData::bind_uniforms() {
Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
glActiveTexture(GL_TEXTURE0 + ti);
glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+ if (texture->render_target) {
+ texture->render_target->used_in_frame = true;
+ }
// Set sampler state here as the same texture can be used in multiple places with different flags
// Need to convert sampler state from ShaderLanguage::Texture* to RS::CanvasItemTexture*
@@ -3291,10 +3213,6 @@ void SkyMaterialData::bind_uniforms() {
////////////////////////////////////////////////////////////////////////////////
// Scene SHADER
-void SceneShaderData::set_path_hint(const String &p_path) {
- path = p_path;
-}
-
void SceneShaderData::set_code(const String &p_code) {
//compile
@@ -3471,86 +3389,6 @@ void SceneShaderData::set_code(const String &p_code) {
valid = true;
}
-void SceneShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
- if (!p_texture.is_valid()) {
- if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
- default_texture_params[p_name].erase(p_index);
-
- if (default_texture_params[p_name].is_empty()) {
- default_texture_params.erase(p_name);
- }
- }
- } else {
- if (!default_texture_params.has(p_name)) {
- default_texture_params[p_name] = HashMap<int, RID>();
- }
- default_texture_params[p_name][p_index] = p_texture;
- }
-}
-
-void SceneShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
- RBMap<int, StringName> order;
-
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
- continue;
- }
-
- if (E.value.texture_order >= 0) {
- order[E.value.texture_order + 100000] = E.key;
- } else {
- order[E.value.order] = E.key;
- }
- }
-
- String last_group;
- for (const KeyValue<int, StringName> &E : order) {
- String group = uniforms[E.value].group;
- if (!uniforms[E.value].subgroup.is_empty()) {
- group += "::" + uniforms[E.value].subgroup;
- }
-
- if (group != last_group) {
- PropertyInfo pi;
- pi.usage = PROPERTY_USAGE_GROUP;
- pi.name = group;
- p_param_list->push_back(pi);
-
- last_group = group;
- }
-
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
- pi.name = E.value;
- p_param_list->push_back(pi);
- }
-}
-
-void SceneShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererMaterialStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E.value);
- p.info.name = E.key; //supply name
- p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
- p_param_list->push_back(p);
- }
-}
-
-bool SceneShaderData::is_parameter_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
bool SceneShaderData::is_animated() const {
return (uses_fragment_time && uses_discard) || (uses_vertex_time && uses_vertex);
}
@@ -3563,15 +3401,6 @@ bool SceneShaderData::casts_shadows() const {
return !has_alpha || (uses_depth_pre_pass && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
}
-Variant SceneShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
- }
- return Variant();
-}
-
RS::ShaderNativeSourceCode SceneShaderData::get_native_source_code() const {
return MaterialStorage::get_singleton()->shaders.scene_shader.version_get_native_source_code(version);
}
@@ -3624,6 +3453,9 @@ void SceneMaterialData::bind_uniforms() {
Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
glActiveTexture(GL_TEXTURE0 + ti);
glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+ if (texture->render_target) {
+ texture->render_target->used_in_frame = true;
+ }
// Set sampler state here as the same texture can be used in multiple places with different flags
// Need to convert sampler state from ShaderLanguage::Texture* to RS::CanvasItemTexture*
@@ -3636,10 +3468,6 @@ void SceneMaterialData::bind_uniforms() {
/* Particles SHADER */
-void ParticlesShaderData::set_path_hint(const String &p_path) {
- path = p_path;
-}
-
void ParticlesShaderData::set_code(const String &p_code) {
//compile
@@ -3696,83 +3524,6 @@ void ParticlesShaderData::set_code(const String &p_code) {
valid = true;
}
-void ParticlesShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
- if (!p_texture.is_valid()) {
- if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
- default_texture_params[p_name].erase(p_index);
-
- if (default_texture_params[p_name].is_empty()) {
- default_texture_params.erase(p_name);
- }
- }
- } else {
- if (!default_texture_params.has(p_name)) {
- default_texture_params[p_name] = HashMap<int, RID>();
- }
- default_texture_params[p_name][p_index] = p_texture;
- }
-}
-
-void ParticlesShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
- HashMap<int, StringName> order;
-
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- if (E.value.texture_order >= 0) {
- order[E.value.texture_order + 100000] = E.key;
- } else {
- order[E.value.order] = E.key;
- }
- }
-
- String last_group;
- for (const KeyValue<int, StringName> &E : order) {
- String group = uniforms[E.value].group;
- if (!uniforms[E.value].subgroup.is_empty()) {
- group += "::" + uniforms[E.value].subgroup;
- }
-
- if (group != last_group) {
- PropertyInfo pi;
- pi.usage = PROPERTY_USAGE_GROUP;
- pi.name = group;
- p_param_list->push_back(pi);
-
- last_group = group;
- }
-
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
- pi.name = E.value;
- p_param_list->push_back(pi);
- }
-}
-
-void ParticlesShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererMaterialStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E.value);
- p.info.name = E.key; //supply name
- p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
- p_param_list->push_back(p);
- }
-}
-
-bool ParticlesShaderData::is_parameter_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
bool ParticlesShaderData::is_animated() const {
return false;
}
@@ -3781,15 +3532,6 @@ bool ParticlesShaderData::casts_shadows() const {
return false;
}
-Variant ParticlesShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
- }
- return Variant();
-}
-
RS::ShaderNativeSourceCode ParticlesShaderData::get_native_source_code() const {
return MaterialStorage::get_singleton()->shaders.particles_process_shader.version_get_native_source_code(version);
}
@@ -3827,8 +3569,11 @@ void ParticleProcessMaterialData::bind_uniforms() {
ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
for (int ti = 0; ti < texture_cache.size(); ti++) {
Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
- glActiveTexture(GL_TEXTURE1 + ti); // Start at GL_TEXTURE1 becuase texture slot 0 is reserved for the heightmap texture.
+ glActiveTexture(GL_TEXTURE1 + ti); // Start at GL_TEXTURE1 because texture slot 0 is reserved for the heightmap texture.
glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+ if (texture->render_target) {
+ texture->render_target->used_in_frame = true;
+ }
// Set sampler state here as the same texture can be used in multiple places with different flags
// Need to convert sampler state from ShaderLanguage::Texture* to RS::CanvasItemTexture*
diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h
index 8ae5e5eb9c..9965d23070 100644
--- a/drivers/gles3/storage/material_storage.h
+++ b/drivers/gles3/storage/material_storage.h
@@ -53,16 +53,20 @@ namespace GLES3 {
/* Shader Structs */
struct ShaderData {
- virtual void set_code(const String &p_Code) = 0;
- virtual void set_path_hint(const String &p_hint) = 0;
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) = 0;
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const = 0;
+ String path;
+ HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ HashMap<StringName, HashMap<int, RID>> default_texture_params;
- virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const = 0;
- virtual bool is_parameter_texture(const StringName &p_param) const = 0;
+ virtual void set_path_hint(const String &p_hint);
+ virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
+ virtual bool is_parameter_texture(const StringName &p_param) const;
+
+ virtual void set_code(const String &p_Code) = 0;
virtual bool is_animated() const = 0;
virtual bool casts_shadows() const = 0;
- virtual Variant get_default_parameter(const StringName &p_parameter) const = 0;
virtual RS::ShaderNativeSourceCode get_native_source_code() const { return RS::ShaderNativeSourceCode(); }
virtual ~ShaderData() {}
@@ -149,17 +153,14 @@ struct CanvasShaderData : public ShaderData {
bool valid;
RID version;
- String path;
BlendMode blend_mode = BLEND_MODE_MIX;
- HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size;
String code;
- HashMap<StringName, HashMap<int, RID>> default_texture_params;
bool uses_screen_texture = false;
bool uses_screen_texture_mipmaps = false;
@@ -167,15 +168,8 @@ struct CanvasShaderData : public ShaderData {
bool uses_time = false;
virtual void set_code(const String &p_Code);
- virtual void set_path_hint(const String &p_hint);
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
- virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
-
- virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
CanvasShaderData();
@@ -202,15 +196,12 @@ struct SkyShaderData : public ShaderData {
bool valid;
RID version;
- HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size;
- String path;
String code;
- HashMap<StringName, HashMap<int, RID>> default_texture_params;
bool uses_time;
bool uses_position;
@@ -219,14 +210,8 @@ struct SkyShaderData : public ShaderData {
bool uses_light;
virtual void set_code(const String &p_Code);
- virtual void set_path_hint(const String &p_hint);
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
- virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
- virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
SkyShaderData();
virtual ~SkyShaderData();
@@ -284,16 +269,12 @@ struct SceneShaderData : public ShaderData {
bool valid;
RID version;
- String path;
-
- HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size;
String code;
- HashMap<StringName, HashMap<int, RID>> default_texture_params;
BlendMode blend_mode;
AlphaAntiAliasing alpha_antialiasing_mode;
@@ -343,15 +324,8 @@ struct SceneShaderData : public ShaderData {
uint32_t index = 0;
virtual void set_code(const String &p_Code);
- virtual void set_path_hint(const String &p_hint);
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
- virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
-
- virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
SceneShaderData();
@@ -386,15 +360,12 @@ struct ParticlesShaderData : public ShaderData {
RID version;
bool uses_collision = false;
- HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
- String path;
String code;
- HashMap<StringName, HashMap<int, RID>> default_texture_params;
bool uses_time = false;
@@ -402,14 +373,8 @@ struct ParticlesShaderData : public ShaderData {
uint32_t userdata_count = 0;
virtual void set_code(const String &p_Code);
- virtual void set_path_hint(const String &p_hint);
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
- virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
- virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
ParticlesShaderData() {}
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index 5bbbc7b91b..d31ac4d413 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -323,27 +323,8 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
}
if (mesh->surface_count == 0) {
- mesh->bone_aabbs = p_surface.bone_aabbs;
mesh->aabb = p_surface.aabb;
} else {
- if (mesh->bone_aabbs.size() < p_surface.bone_aabbs.size()) {
- // ArrayMesh::_surface_set_data only allocates bone_aabbs up to max_bone
- // Each surface may affect different numbers of bones.
- mesh->bone_aabbs.resize(p_surface.bone_aabbs.size());
- }
- for (int i = 0; i < p_surface.bone_aabbs.size(); i++) {
- const AABB &bone = p_surface.bone_aabbs[i];
- if (bone.has_volume()) {
- AABB &mesh_bone = mesh->bone_aabbs.write[i];
- if (mesh_bone != AABB()) {
- // Already initialized, merge AABBs.
- mesh_bone.merge_with(bone);
- } else {
- // Not yet initialized, copy the bone AABB.
- mesh_bone = bone;
- }
- }
- }
mesh->aabb.merge_with(p_surface.aabb);
}
@@ -528,7 +509,7 @@ 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) {
+ if (!skeleton || skeleton->size == 0 || mesh->skeleton_aabb_version == skeleton->version) {
return mesh->aabb;
}
@@ -622,6 +603,8 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
}
}
+ mesh->aabb = aabb;
+ mesh->skeleton_aabb_version = skeleton->version;
return aabb;
}
diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h
index 0f30814928..cbbba0d03e 100644
--- a/drivers/gles3/storage/mesh_storage.h
+++ b/drivers/gles3/storage/mesh_storage.h
@@ -120,12 +120,11 @@ struct Mesh {
Surface **surfaces = nullptr;
uint32_t surface_count = 0;
- Vector<AABB> bone_aabbs;
-
bool has_bone_weights = false;
AABB aabb;
AABB custom_aabb;
+ uint64_t skeleton_aabb_version = 0;
Vector<RID> material_cache;
diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp
index 1a0d97df01..e158a3e90c 100644
--- a/drivers/gles3/storage/particles_storage.cpp
+++ b/drivers/gles3/storage/particles_storage.cpp
@@ -53,7 +53,7 @@ ParticlesStorage::ParticlesStorage() {
{
String global_defines;
global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now
- material_storage->shaders.particles_process_shader.initialize(global_defines);
+ material_storage->shaders.particles_process_shader.initialize(global_defines, 1);
}
{
// default material and shader for particles shader
@@ -528,6 +528,15 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
//2D collision
Transform2D xform = p_particles->sdf_collision_transform; //will use dotproduct manually so invert beforehand
+
+ if (!p_particles->use_local_coords) {
+ Transform2D emission;
+ emission.columns[0] = Vector2(p_particles->emission_transform.basis.get_column(0).x, p_particles->emission_transform.basis.get_column(0).y);
+ emission.columns[1] = Vector2(p_particles->emission_transform.basis.get_column(1).x, p_particles->emission_transform.basis.get_column(1).y);
+ emission.set_origin(Vector2(p_particles->emission_transform.origin.x, p_particles->emission_transform.origin.y));
+ xform = xform * emission.affine_inverse();
+ }
+
Transform2D revert = xform.affine_inverse();
frame_params.collider_count = 1;
frame_params.colliders[0].transform[0] = xform.columns[0][0];
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 99908d197a..e6aa6a39c1 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -1606,9 +1606,9 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
return;
}
- if (rt->overridden.color.is_valid()) {
- texture->is_render_target = true;
- } else {
+ texture->is_render_target = true;
+ texture->render_target = rt;
+ if (rt->overridden.color.is_null()) {
texture->format = rt->image_format;
texture->real_format = rt->image_format;
texture->target = texture_target;
@@ -1717,9 +1717,12 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
tex->width = 0;
tex->height = 0;
tex->active = false;
+ tex->render_target = nullptr;
+ tex->is_render_target = false;
}
} else {
Texture *tex = get_texture(rt->overridden.color);
+ tex->render_target = nullptr;
tex->is_render_target = false;
}
@@ -1751,7 +1754,7 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
RID TextureStorage::render_target_create() {
RenderTarget render_target;
- //render_target.was_used = false;
+ render_target.used_in_frame = false;
render_target.clear_requested = false;
Texture t;
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index b02a100784..711fd7b962 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -152,12 +152,10 @@ Vector<String> OS_Unix::get_video_adapter_driver_info() const {
String OS_Unix::get_stdin_string(bool p_block) {
if (p_block) {
char buff[1024];
- String ret = stdin_buf + fgets(buff, 1024, stdin);
- stdin_buf = "";
- return ret;
+ return String::utf8(fgets(buff, 1024, stdin));
}
- return "";
+ return String();
}
Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) {
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index ce06a52a95..68d2dd0042 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -46,8 +46,6 @@ protected:
virtual void finalize_core() override;
- String stdin_buf;
-
public:
OS_Unix();
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 45f544c02d..b982ab3e40 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -40,7 +40,6 @@
#include "drivers/vulkan/vulkan_context.h"
#include "thirdparty/misc/smolv.h"
-#include "thirdparty/spirv-reflect/spirv_reflect.h"
//#define FORCE_FULL_BARRIER
@@ -996,8 +995,11 @@ void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFor
case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: // Again, not sure about astc.
- case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK:
- case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK:
+ case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: {
+ r_w = 4;
+ r_h = 4;
+ } break;
+ case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: // Unsupported
case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK:
case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK:
@@ -1008,10 +1010,16 @@ void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFor
case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK:
case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK:
case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK:
- case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK:
+ case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: {
+ r_w = 4;
+ r_h = 4;
+ } break;
case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK:
- case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
- case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK:
+ case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: {
+ r_w = 8;
+ r_h = 8;
+ } break;
+ case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: // Unsupported
case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK:
case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK:
case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK:
@@ -1101,7 +1109,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(Data
case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK:
case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK:
case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK:
- return 8; // Wrong.
+ return 16;
default: {
}
}
@@ -1123,6 +1131,10 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFor
case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
return 1;
+ case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
+ case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: {
+ return 2;
+ }
default: {
}
}
@@ -4524,14 +4536,6 @@ RID RenderingDeviceVulkan::index_array_create(RID p_index_buffer, uint32_t p_ind
/**** SHADER ****/
/****************/
-static const char *shader_stage_names[RenderingDevice::SHADER_STAGE_MAX] = {
- "Vertex",
- "Fragment",
- "TesselationControl",
- "TesselationEvaluation",
- "Compute"
-};
-
static const char *shader_uniform_names[RenderingDevice::UNIFORM_TYPE_MAX] = {
"Sampler", "CombinedSampler", "Texture", "Image", "TextureBuffer", "SamplerTextureBuffer", "ImageBuffer", "UniformBuffer", "StorageBuffer", "InputAttachment"
};
@@ -4562,198 +4566,6 @@ String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) {
}
return ret;
}
-#if 0
-bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLayoutBinding> > &bindings, Vector<Vector<UniformInfo> > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error) {
- VkDescriptorSetLayoutBinding layout_binding;
- UniformInfo info;
-
- switch (reflection.getType()->getBasicType()) {
- case glslang::EbtSampler: {
- //print_line("DEBUG: IsSampler");
- if (reflection.getType()->getSampler().dim == glslang::EsdBuffer) {
- // Texture buffers.
- if (reflection.getType()->getSampler().isCombined()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
- info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER;
- //print_line("DEBUG: SAMPLER: texel combined");
- } else if (reflection.getType()->getSampler().isTexture()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
- info.type = UNIFORM_TYPE_TEXTURE_BUFFER;
- //print_line("DEBUG: SAMPLER: texel alone");
- } else if (reflection.getType()->getSampler().isImage()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
- info.type = UNIFORM_TYPE_IMAGE_BUFFER;
- //print_line("DEBUG: SAMPLER: texel buffer");
- } else {
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' is of unsupported buffer type.";
- }
- return false;
- }
- } else if (reflection.getType()->getSampler().isCombined()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
- //print_line("DEBUG: SAMPLER: combined");
- } else if (reflection.getType()->getSampler().isPureSampler()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
- info.type = UNIFORM_TYPE_SAMPLER;
- //print_line("DEBUG: SAMPLER: sampler");
- } else if (reflection.getType()->getSampler().isTexture()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
- info.type = UNIFORM_TYPE_TEXTURE;
- //print_line("DEBUG: SAMPLER: image");
- } else if (reflection.getType()->getSampler().isImage()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
- info.type = UNIFORM_TYPE_IMAGE;
- //print_line("DEBUG: SAMPLER: storage image");
- } else {
- //print_line("DEBUG: sampler unknown");
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' is of unsupported sampler type.";
- }
- return false;
- }
-
- if (reflection.getType()->isArray()) {
- layout_binding.descriptorCount = reflection.getType()->getArraySizes()->getCumulativeSize();
- //print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount));
- } else {
- layout_binding.descriptorCount = 1;
- }
-
- info.length = layout_binding.descriptorCount;
-
- } break;
- /*case glslang::EbtStruct: {
- print_line("DEBUG: Struct");
-
- } break;*/
- case glslang::EbtBlock: {
- //print_line("DEBUG: Block");
- if (reflection.getType()->getQualifier().storage == glslang::EvqUniform) {
- if (reflection.getType()->getQualifier().layoutPushConstant) {
- uint32_t len = reflection.size;
- if (push_constant.push_constant_size != 0 && push_constant.push_constant_size != len) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' push constants for different stages should all be the same size.";
- return false;
- }
- push_constant.push_constant_size = len;
- push_constant.push_constants_vk_stage |= shader_stage_masks[p_stage];
- return true;
- }
- //print_line("DEBUG: Uniform buffer");
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- info.type = UNIFORM_TYPE_UNIFORM_BUFFER;
- } else if (reflection.getType()->getQualifier().storage == glslang::EvqBuffer) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- info.type = UNIFORM_TYPE_STORAGE_BUFFER;
- //print_line("DEBUG: Storage buffer");
- } else {
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' is of unsupported block type: (" + itos(reflection.getType()->getQualifier().storage) + ").";
- }
- return false;
- }
-
- if (reflection.getType()->isArray()) {
- layout_binding.descriptorCount = reflection.getType()->getArraySizes()->getCumulativeSize();
- //print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount));
- } else {
- layout_binding.descriptorCount = 1;
- }
-
- info.length = reflection.size;
-
- } break;
- /*case glslang::EbtReference: {
- } break;*/
- /*case glslang::EbtAtomicUint: {
- } break;*/
- default: {
- if (reflection.getType()->getQualifier().hasOffset() || reflection.name.find(".") != std::string::npos) {
- // Member of uniform block?
- return true;
- }
-
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' unsupported uniform type.";
- }
- return false;
- }
- }
-
- if (!reflection.getType()->getQualifier().hasBinding()) {
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' lacks a binding number.";
- }
- return false;
- }
-
- uint32_t set = reflection.getType()->getQualifier().hasSet() ? reflection.getType()->getQualifier().layoutSet : 0;
-
- if (set >= MAX_UNIFORM_SETS) {
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ").";
- }
- return false;
- }
-
- if (set >= limits.maxBoundDescriptorSets) {
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").";
- }
- return false;
- }
-
- uint32_t binding = reflection.getType()->getQualifier().layoutBinding;
-
- if (set < (uint32_t)bindings.size()) {
- // Check if this already exists.
- for (int i = 0; i < bindings[set].size(); i++) {
- if (bindings[set][i].binding == binding) {
- // Already exists, verify that it's the same type.
- if (bindings[set][i].descriptorType != layout_binding.descriptorType) {
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform type.";
- }
- return false;
- }
-
- // Also, verify that it's the same size.
- if (bindings[set][i].descriptorCount != layout_binding.descriptorCount || uniform_infos[set][i].length != info.length) {
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform size.";
- }
- return false;
- }
-
- // Just append stage mask and return.
- bindings.write[set].write[i].stageFlags |= shader_stage_masks[p_stage];
- uniform_infos.write[set].write[i].stages |= 1 << p_stage;
- return true;
- }
- }
- }
- layout_binding.binding = binding;
- layout_binding.stageFlags = shader_stage_masks[p_stage];
- layout_binding.pImmutableSamplers = nullptr; // No support for this yet.
-
- info.stages = 1 << p_stage;
- info.binding = binding;
-
- if (set >= (uint32_t)bindings.size()) {
- bindings.resize(set + 1);
- uniform_infos.resize(set + 1);
- }
-#if 0
- print_line("stage: " + String(shader_stage_names[p_stage]) + " set: " + itos(set) + " binding: " + itos(info.binding) + " type:" + shader_uniform_names[info.type] + " length: " + itos(info.length));
-#endif
- bindings.write[set].push_back(layout_binding);
- uniform_infos.write[set].push_back(info);
-
- return true;
-}
-#endif
// Version 1: initial.
// Version 2: Added shader name.
@@ -4786,346 +4598,68 @@ struct RenderingDeviceVulkanShaderBinarySpecializationConstant {
struct RenderingDeviceVulkanShaderBinaryData {
uint32_t vertex_input_mask;
- uint32_t fragment_outputs;
- uint32_t specialization_constant_count;
+ uint32_t fragment_output_mask;
+ uint32_t specialization_constants_count;
uint32_t is_compute;
uint32_t compute_local_size[3];
uint32_t set_count;
uint32_t push_constant_size;
- uint32_t push_constants_vk_stage;
+ uint32_t push_constant_vk_stages_mask;
uint32_t stage_count;
uint32_t shader_name_len;
};
Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name) {
- RenderingDeviceVulkanShaderBinaryData binary_data;
- binary_data.vertex_input_mask = 0;
- binary_data.fragment_outputs = 0;
- binary_data.specialization_constant_count = 0;
- binary_data.is_compute = 0;
- binary_data.compute_local_size[0] = 0;
- binary_data.compute_local_size[1] = 0;
- binary_data.compute_local_size[2] = 0;
- binary_data.set_count = 0;
- binary_data.push_constant_size = 0;
- binary_data.push_constants_vk_stage = 0;
+ SpirvReflectionData spirv_data;
+ if (_reflect_spirv(p_spirv, spirv_data) != OK) {
+ return Vector<uint8_t>();
+ }
+ ERR_FAIL_COND_V_MSG((uint32_t)spirv_data.uniforms.size() > limits.maxBoundDescriptorSets, Vector<uint8_t>(),
+ "Number of uniform sets is larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").");
+
+ // Collect reflection data into binary data.
+ RenderingDeviceVulkanShaderBinaryData binary_data;
Vector<Vector<RenderingDeviceVulkanShaderBinaryDataBinding>> uniform_info; // Set bindings.
Vector<RenderingDeviceVulkanShaderBinarySpecializationConstant> specialization_constants;
-
- uint32_t stages_processed = 0;
-
- for (int i = 0; i < p_spirv.size(); i++) {
- if (p_spirv[i].shader_stage == SHADER_STAGE_COMPUTE) {
- binary_data.is_compute = true;
- ERR_FAIL_COND_V_MSG(p_spirv.size() != 1, Vector<uint8_t>(),
- "Compute shaders can only receive one stage, dedicated to compute.");
- }
- ERR_FAIL_COND_V_MSG(stages_processed & (1 << p_spirv[i].shader_stage), Vector<uint8_t>(),
- "Stage " + String(shader_stage_names[p_spirv[i].shader_stage]) + " submitted more than once.");
-
- {
- SpvReflectShaderModule module;
- const uint8_t *spirv = p_spirv[i].spir_v.ptr();
- SpvReflectResult result = spvReflectCreateShaderModule(p_spirv[i].spir_v.size(), spirv, &module);
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed parsing shader.");
-
- if (binary_data.is_compute) {
- binary_data.compute_local_size[0] = module.entry_points->local_size.x;
- binary_data.compute_local_size[1] = module.entry_points->local_size.y;
- binary_data.compute_local_size[2] = module.entry_points->local_size.z;
- }
- uint32_t binding_count = 0;
- result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, nullptr);
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating descriptor bindings.");
-
- uint32_t stage = p_spirv[i].shader_stage;
-
- if (binding_count > 0) {
- // Parse bindings.
-
- Vector<SpvReflectDescriptorBinding *> bindings;
- bindings.resize(binding_count);
- result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, bindings.ptrw());
-
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed getting descriptor bindings.");
-
- for (uint32_t j = 0; j < binding_count; j++) {
- const SpvReflectDescriptorBinding &binding = *bindings[j];
-
- RenderingDeviceVulkanShaderBinaryDataBinding info{};
-
- bool need_array_dimensions = false;
- bool need_block_size = false;
- bool may_be_writable = false;
-
- switch (binding.descriptor_type) {
- case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER: {
- info.type = UNIFORM_TYPE_SAMPLER;
- need_array_dimensions = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
- info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
- need_array_dimensions = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE: {
- info.type = UNIFORM_TYPE_TEXTURE;
- need_array_dimensions = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
- info.type = UNIFORM_TYPE_IMAGE;
- need_array_dimensions = true;
- may_be_writable = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: {
- info.type = UNIFORM_TYPE_TEXTURE_BUFFER;
- need_array_dimensions = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
- info.type = UNIFORM_TYPE_IMAGE_BUFFER;
- need_array_dimensions = true;
- may_be_writable = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
- info.type = UNIFORM_TYPE_UNIFORM_BUFFER;
- need_block_size = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
- info.type = UNIFORM_TYPE_STORAGE_BUFFER;
- need_block_size = true;
- may_be_writable = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: {
- ERR_PRINT("Dynamic uniform buffer not supported.");
- continue;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
- ERR_PRINT("Dynamic storage buffer not supported.");
- continue;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
- info.type = UNIFORM_TYPE_INPUT_ATTACHMENT;
- need_array_dimensions = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
- ERR_PRINT("Acceleration structure not supported.");
- continue;
- } break;
- }
-
- if (need_array_dimensions) {
- if (binding.array.dims_count == 0) {
- info.length = 1;
- } else {
- for (uint32_t k = 0; k < binding.array.dims_count; k++) {
- if (k == 0) {
- info.length = binding.array.dims[0];
- } else {
- info.length *= binding.array.dims[k];
- }
- }
- }
-
- } else if (need_block_size) {
- info.length = binding.block.size;
- } else {
- info.length = 0;
- }
-
- if (may_be_writable) {
- info.writable = !(binding.type_description->decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE) && !(binding.block.decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE);
- } else {
- info.writable = false;
- }
-
- info.binding = binding.binding;
- uint32_t set = binding.set;
-
- ERR_FAIL_COND_V_MSG(set >= MAX_UNIFORM_SETS, Vector<uint8_t>(),
- "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ").");
-
- ERR_FAIL_COND_V_MSG(set >= limits.maxBoundDescriptorSets, Vector<uint8_t>(),
- "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").");
-
- if (set < (uint32_t)uniform_info.size()) {
- // Check if this already exists.
- bool exists = false;
- for (int k = 0; k < uniform_info[set].size(); k++) {
- if (uniform_info[set][k].binding == (uint32_t)info.binding) {
- // Already exists, verify that it's the same type.
- ERR_FAIL_COND_V_MSG(uniform_info[set][k].type != info.type, Vector<uint8_t>(),
- "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform type.");
-
- // Also, verify that it's the same size.
- ERR_FAIL_COND_V_MSG(uniform_info[set][k].length != info.length, Vector<uint8_t>(),
- "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform size.");
-
- // Also, verify that it has the same writability.
- ERR_FAIL_COND_V_MSG(uniform_info[set][k].writable != info.writable, Vector<uint8_t>(),
- "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different writability.");
-
- // Just append stage mask and return.
- uniform_info.write[set].write[k].stages |= 1 << stage;
- exists = true;
- break;
- }
- }
-
- if (exists) {
- continue; // Merged.
- }
- }
-
- info.stages = 1 << stage;
-
- if (set >= (uint32_t)uniform_info.size()) {
- uniform_info.resize(set + 1);
- }
-
- uniform_info.write[set].push_back(info);
- }
- }
-
- {
- // Specialization constants.
-
- uint32_t sc_count = 0;
- result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, nullptr);
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating specialization constants.");
-
- if (sc_count) {
- Vector<SpvReflectSpecializationConstant *> spec_constants;
- spec_constants.resize(sc_count);
-
- result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, spec_constants.ptrw());
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining specialization constants.");
-
- for (uint32_t j = 0; j < sc_count; j++) {
- int32_t existing = -1;
- RenderingDeviceVulkanShaderBinarySpecializationConstant sconst{};
- SpvReflectSpecializationConstant *spc = spec_constants[j];
-
- sconst.constant_id = spc->constant_id;
- sconst.int_value = 0.0; // Clear previous value JIC.
- switch (spc->constant_type) {
- case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: {
- sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
- sconst.bool_value = spc->default_value.int_bool_value != 0;
- } break;
- case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: {
- sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
- sconst.int_value = spc->default_value.int_bool_value;
- } break;
- case SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT: {
- sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
- sconst.float_value = spc->default_value.float_value;
- } break;
- }
- sconst.stage_flags = 1 << p_spirv[i].shader_stage;
-
- for (int k = 0; k < specialization_constants.size(); k++) {
- if (specialization_constants[k].constant_id == sconst.constant_id) {
- ERR_FAIL_COND_V_MSG(specialization_constants[k].type != sconst.type, Vector<uint8_t>(), "More than one specialization constant used for id (" + itos(sconst.constant_id) + "), but their types differ.");
- ERR_FAIL_COND_V_MSG(specialization_constants[k].int_value != sconst.int_value, Vector<uint8_t>(), "More than one specialization constant used for id (" + itos(sconst.constant_id) + "), but their default values differ.");
- existing = k;
- break;
- }
- }
-
- if (existing > 0) {
- specialization_constants.write[existing].stage_flags |= sconst.stage_flags;
- } else {
- specialization_constants.push_back(sconst);
- }
- }
- }
- }
-
- if (stage == SHADER_STAGE_VERTEX) {
- uint32_t iv_count = 0;
- result = spvReflectEnumerateInputVariables(&module, &iv_count, nullptr);
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating input variables.");
-
- if (iv_count) {
- Vector<SpvReflectInterfaceVariable *> input_vars;
- input_vars.resize(iv_count);
-
- result = spvReflectEnumerateInputVariables(&module, &iv_count, input_vars.ptrw());
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining input variables.");
-
- for (uint32_t j = 0; j < iv_count; j++) {
- if (input_vars[j] && input_vars[j]->decoration_flags == 0) { // Regular input.
- binary_data.vertex_input_mask |= (1 << uint32_t(input_vars[j]->location));
- }
- }
- }
- }
-
- if (stage == SHADER_STAGE_FRAGMENT) {
- uint32_t ov_count = 0;
- result = spvReflectEnumerateOutputVariables(&module, &ov_count, nullptr);
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating output variables.");
-
- if (ov_count) {
- Vector<SpvReflectInterfaceVariable *> output_vars;
- output_vars.resize(ov_count);
-
- result = spvReflectEnumerateOutputVariables(&module, &ov_count, output_vars.ptrw());
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining output variables.");
-
- for (uint32_t j = 0; j < ov_count; j++) {
- const SpvReflectInterfaceVariable *refvar = output_vars[j];
- if (refvar != nullptr && refvar->built_in != SpvBuiltInFragDepth) {
- binary_data.fragment_outputs |= 1 << refvar->location;
- }
- }
- }
+ {
+ binary_data.vertex_input_mask = spirv_data.vertex_input_mask;
+ binary_data.fragment_output_mask = spirv_data.fragment_output_mask;
+ binary_data.specialization_constants_count = spirv_data.specialization_constants.size();
+ binary_data.is_compute = spirv_data.is_compute;
+ binary_data.compute_local_size[0] = spirv_data.compute_local_size[0];
+ binary_data.compute_local_size[1] = spirv_data.compute_local_size[1];
+ binary_data.compute_local_size[2] = spirv_data.compute_local_size[2];
+ binary_data.set_count = spirv_data.uniforms.size();
+ binary_data.push_constant_size = spirv_data.push_constant_size;
+ for (uint32_t i = 0; i < SHADER_STAGE_MAX; i++) {
+ if (spirv_data.push_constant_stages_mask.has_flag((ShaderStage)(1 << i))) {
+ binary_data.push_constant_vk_stages_mask |= shader_stage_masks[i];
}
+ }
- uint32_t pc_count = 0;
- result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, nullptr);
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating push constants.");
-
- if (pc_count) {
- ERR_FAIL_COND_V_MSG(pc_count > 1, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "': Only one push constant is supported, which should be the same across shader stages.");
-
- Vector<SpvReflectBlockVariable *> pconstants;
- pconstants.resize(pc_count);
- result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, pconstants.ptrw());
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining push constants.");
-#if 0
- if (pconstants[0] == nullptr) {
- Ref<FileAccess> f = FileAccess::open("res://popo.spv", FileAccess::WRITE);
- f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t));
- }
-#endif
-
- ERR_FAIL_COND_V_MSG(binary_data.push_constant_size && binary_data.push_constant_size != pconstants[0]->size, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "': Push constant block must be the same across shader stages.");
-
- binary_data.push_constant_size = pconstants[0]->size;
- binary_data.push_constants_vk_stage |= shader_stage_masks[stage];
-
- //print_line("Stage: " + String(shader_stage_names[stage]) + " push constant of size=" + itos(push_constant.push_constant_size));
+ for (const Vector<SpirvReflectionData::Uniform> &spirv_set : spirv_data.uniforms) {
+ Vector<RenderingDeviceVulkanShaderBinaryDataBinding> set_bindings;
+ for (const SpirvReflectionData::Uniform &spirv_uniform : spirv_set) {
+ RenderingDeviceVulkanShaderBinaryDataBinding binding{};
+ binding.type = (uint32_t)spirv_uniform.type;
+ binding.binding = spirv_uniform.binding;
+ binding.stages = (uint32_t)spirv_uniform.stages_mask;
+ binding.length = spirv_uniform.length;
+ binding.writable = (uint32_t)spirv_uniform.writable;
+ set_bindings.push_back(binding);
}
-
- // Destroy the reflection data when no longer required.
- spvReflectDestroyShaderModule(&module);
+ uniform_info.push_back(set_bindings);
}
- stages_processed |= (1 << p_spirv[i].shader_stage);
+ for (const SpirvReflectionData::SpecializationConstant &spirv_sc : spirv_data.specialization_constants) {
+ RenderingDeviceVulkanShaderBinarySpecializationConstant spec_constant{};
+ spec_constant.type = (uint32_t)spirv_sc.type;
+ spec_constant.constant_id = spirv_sc.constant_id;
+ spec_constant.int_value = spirv_sc.int_value;
+ spec_constant.stage_flags = (uint32_t)spirv_sc.stages_mask;
+ specialization_constants.push_back(spec_constant);
+ }
}
Vector<Vector<uint8_t>> compressed_stages;
@@ -5167,7 +4701,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
stages_binary_size += s;
}
- binary_data.specialization_constant_count = specialization_constants.size();
+ binary_data.specialization_constants_count = specialization_constants.size();
binary_data.set_count = uniform_info.size();
binary_data.stage_count = p_spirv.size();
@@ -5273,12 +4807,12 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
const RenderingDeviceVulkanShaderBinaryData &binary_data = *(reinterpret_cast<const RenderingDeviceVulkanShaderBinaryData *>(binptr + 12));
Shader::PushConstant push_constant;
- push_constant.push_constant_size = binary_data.push_constant_size;
- push_constant.push_constants_vk_stage = binary_data.push_constants_vk_stage;
+ push_constant.size = binary_data.push_constant_size;
+ push_constant.vk_stages_mask = binary_data.push_constant_vk_stages_mask;
uint32_t vertex_input_mask = binary_data.vertex_input_mask;
- uint32_t fragment_outputs = binary_data.fragment_outputs;
+ uint32_t fragment_output_mask = binary_data.fragment_output_mask;
bool is_compute = binary_data.is_compute;
@@ -5374,11 +4908,11 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
read_offset += set_size;
}
- ERR_FAIL_COND_V(read_offset + binary_data.specialization_constant_count * sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) >= binsize, RID());
+ ERR_FAIL_COND_V(read_offset + binary_data.specialization_constants_count * sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) >= binsize, RID());
Vector<Shader::SpecializationConstant> specialization_constants;
- for (uint32_t i = 0; i < binary_data.specialization_constant_count; i++) {
+ for (uint32_t i = 0; i < binary_data.specialization_constants_count; i++) {
const RenderingDeviceVulkanShaderBinarySpecializationConstant &src_sc = *(reinterpret_cast<const RenderingDeviceVulkanShaderBinarySpecializationConstant *>(binptr + read_offset));
Shader::SpecializationConstant sc;
sc.constant.int_value = src_sc.int_value;
@@ -5444,7 +4978,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
Shader shader;
shader.vertex_input_mask = vertex_input_mask;
- shader.fragment_output_mask = fragment_outputs;
+ shader.fragment_output_mask = fragment_output_mask;
shader.push_constant = push_constant;
shader.is_compute = is_compute;
shader.compute_local_size[0] = compute_local_size[0];
@@ -5474,19 +5008,11 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
break;
}
- const VkShaderStageFlagBits shader_stage_bits[SHADER_STAGE_MAX] = {
- VK_SHADER_STAGE_VERTEX_BIT,
- VK_SHADER_STAGE_FRAGMENT_BIT,
- VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
- VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
- VK_SHADER_STAGE_COMPUTE_BIT,
- };
-
VkPipelineShaderStageCreateInfo shader_stage;
shader_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shader_stage.pNext = nullptr;
shader_stage.flags = 0;
- shader_stage.stage = shader_stage_bits[stage_type[i]];
+ shader_stage.stage = shader_stage_masks[stage_type[i]];
shader_stage.module = module;
shader_stage.pName = "main";
shader_stage.pSpecializationInfo = nullptr;
@@ -5558,10 +5084,10 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
// Needs to be declared in this outer scope, otherwise it may not outlive its assignment
// to pipeline_layout_create_info.
VkPushConstantRange push_constant_range;
- if (push_constant.push_constant_size) {
- push_constant_range.stageFlags = push_constant.push_constants_vk_stage;
+ if (push_constant.size) {
+ push_constant_range.stageFlags = push_constant.vk_stages_mask;
push_constant_range.offset = 0;
- push_constant_range.size = push_constant.push_constant_size;
+ push_constant_range.size = push_constant.size;
pipeline_layout_create_info.pushConstantRangeCount = 1;
pipeline_layout_create_info.pPushConstantRanges = &push_constant_range;
@@ -5635,7 +5161,7 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Ve
return id;
}
-RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, uint32_t p_usage) {
+RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, BitField<StorageBufferUsage> p_usage) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG(draw_list != nullptr && p_data.size(), RID(),
"Creating buffers with data is forbidden during creation of a draw list");
@@ -5646,7 +5172,7 @@ RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Ve
Buffer buffer;
uint32_t flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
- if (p_usage & STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT) {
+ if (p_usage.has_flag(STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT)) {
flags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
}
Error err = _buffer_allocate(&buffer, p_size_bytes, flags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
@@ -5956,10 +5482,8 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
// Can also be used as storage, add to mutable sampled.
mutable_sampled_textures.push_back(texture);
}
- if (texture->owner.is_valid()) {
- texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
- }
+
+ DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -6010,10 +5534,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
mutable_sampled_textures.push_back(texture);
}
- if (texture->owner.is_valid()) {
- texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
- }
+ DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -6058,10 +5579,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
mutable_storage_textures.push_back(texture);
}
- if (texture->owner.is_valid()) {
- texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
- }
+ DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
img_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
@@ -6223,10 +5741,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
img_info.sampler = VK_NULL_HANDLE;
img_info.imageView = texture->view;
- if (texture->owner.is_valid()) {
- texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
- }
+ DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -6878,10 +6393,10 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateGraphicsPipelines failed with error " + itos(err) + " for shader '" + shader->name + "'.");
pipeline.set_formats = shader->set_formats;
- pipeline.push_constant_stages = shader->push_constant.push_constants_vk_stage;
+ pipeline.push_constant_stages_mask = shader->push_constant.vk_stages_mask;
pipeline.pipeline_layout = shader->pipeline_layout;
pipeline.shader = p_shader;
- pipeline.push_constant_size = shader->push_constant.push_constant_size;
+ pipeline.push_constant_size = shader->push_constant.size;
#ifdef DEBUG_ENABLED
pipeline.validation.dynamic_state = p_dynamic_state_flags;
@@ -6993,10 +6508,10 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<Pi
ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateComputePipelines failed with error " + itos(err) + ".");
pipeline.set_formats = shader->set_formats;
- pipeline.push_constant_stages = shader->push_constant.push_constants_vk_stage;
+ pipeline.push_constant_stages_mask = shader->push_constant.vk_stages_mask;
pipeline.pipeline_layout = shader->pipeline_layout;
pipeline.shader = p_shader;
- pipeline.push_constant_size = shader->push_constant.push_constant_size;
+ pipeline.push_constant_size = shader->push_constant.size;
pipeline.local_group_size[0] = shader->compute_local_size[0];
pipeline.local_group_size[1] = shader->compute_local_size[1];
pipeline.local_group_size[2] = shader->compute_local_size[2];
@@ -7638,7 +7153,7 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI
dl->state.set_count = pcount; // Update set count.
if (pipeline->push_constant_size) {
- dl->state.pipeline_push_constant_stages = pipeline->push_constant_stages;
+ dl->state.pipeline_push_constant_stages = pipeline->push_constant_stages_mask;
#ifdef DEBUG_ENABLED
dl->validation.pipeline_push_constant_supplied = false;
#endif
@@ -8254,7 +7769,7 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l
cl->state.set_count = pcount; // Update set count.
if (pipeline->push_constant_size) {
- cl->state.pipeline_push_constant_stages = pipeline->push_constant_stages;
+ cl->state.pipeline_push_constant_stages = pipeline->push_constant_stages_mask;
#ifdef DEBUG_ENABLED
cl->validation.pipeline_push_constant_supplied = false;
#endif
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index 2321b95f18..3ccd7bb1d9 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -543,10 +543,6 @@ class RenderingDeviceVulkan : public RenderingDevice {
// As a result, we need to figure out quickly when something is no longer "compatible".
// in order to avoid costly rebinds.
- enum {
- MAX_UNIFORM_SETS = 16
- };
-
struct UniformInfo {
UniformType type = UniformType::UNIFORM_TYPE_MAX;
bool writable = false;
@@ -628,8 +624,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t fragment_output_mask = 0;
struct PushConstant {
- uint32_t push_constant_size = 0;
- uint32_t push_constants_vk_stage = 0;
+ uint32_t size = 0;
+ uint32_t vk_stages_mask = 0;
};
PushConstant push_constant;
@@ -791,7 +787,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; // Not owned, needed for push constants.
VkPipeline pipeline = VK_NULL_HANDLE;
uint32_t push_constant_size = 0;
- uint32_t push_constant_stages = 0;
+ uint32_t push_constant_stages_mask = 0;
};
RID_Owner<RenderPipeline, true> render_pipeline_owner;
@@ -802,7 +798,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; // Not owned, needed for push constants.
VkPipeline pipeline = VK_NULL_HANDLE;
uint32_t push_constant_size = 0;
- uint32_t push_constant_stages = 0;
+ uint32_t push_constant_stages_mask = 0;
uint32_t local_group_size[3] = { 0, 0, 0 };
};
@@ -1117,7 +1113,7 @@ public:
/*****************/
virtual RID uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>());
- virtual RID storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), uint32_t p_usage = 0);
+ virtual RID storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), BitField<StorageBufferUsage> p_usage = 0);
virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>());
virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index c376d5434f..a1e4b5fde4 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -35,6 +35,7 @@
#include "editor/input_event_configuration_dialog.h"
#include "scene/gui/check_button.h"
#include "scene/gui/tree.h"
+#include "scene/scene_string_names.h"
static bool _is_action_name_valid(const String &p_name) {
const char32_t *cstr = p_name.get_data();
@@ -362,6 +363,8 @@ void ActionMapEditor::_bind_methods() {
ADD_SIGNAL(MethodInfo("action_removed", PropertyInfo(Variant::STRING, "name")));
ADD_SIGNAL(MethodInfo("action_renamed", PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name")));
ADD_SIGNAL(MethodInfo("action_reordered", PropertyInfo(Variant::STRING, "action_name"), PropertyInfo(Variant::STRING, "relative_to"), PropertyInfo(Variant::BOOL, "before")));
+ ADD_SIGNAL(MethodInfo(SNAME("filter_focused")));
+ ADD_SIGNAL(MethodInfo(SNAME("filter_unfocused")));
}
LineEdit *ActionMapEditor::get_search_box() const {
@@ -492,6 +495,14 @@ void ActionMapEditor::use_external_search_box(LineEdit *p_searchbox) {
action_list_search->connect("text_changed", callable_mp(this, &ActionMapEditor::_search_term_updated));
}
+void ActionMapEditor::_on_filter_focused() {
+ emit_signal(SNAME("filter_focused"));
+}
+
+void ActionMapEditor::_on_filter_unfocused() {
+ emit_signal(SNAME("filter_unfocused"));
+}
+
ActionMapEditor::ActionMapEditor() {
// Main Vbox Container
VBoxContainer *main_vbox = memnew(VBoxContainer);
@@ -512,6 +523,8 @@ ActionMapEditor::ActionMapEditor() {
action_list_search_by_event->set_h_size_flags(Control::SIZE_EXPAND_FILL);
action_list_search_by_event->set_stretch_ratio(0.75);
action_list_search_by_event->connect("event_changed", callable_mp(this, &ActionMapEditor::_search_by_event));
+ action_list_search_by_event->connect(SceneStringNames::get_singleton()->focus_entered, callable_mp(this, &ActionMapEditor::_on_filter_focused));
+ action_list_search_by_event->connect(SceneStringNames::get_singleton()->focus_exited, callable_mp(this, &ActionMapEditor::_on_filter_unfocused));
top_hbox->add_child(action_list_search_by_event);
Button *clear_all_search = memnew(Button);
diff --git a/editor/action_map_editor.h b/editor/action_map_editor.h
index ad9980c4ef..1908805b17 100644
--- a/editor/action_map_editor.h
+++ b/editor/action_map_editor.h
@@ -106,6 +106,9 @@ private:
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+ void _on_filter_focused();
+ void _on_filter_unfocused();
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index 530708f3e5..7b5a7b7046 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -575,7 +575,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
ep.point_rect.size = bezier_icon->get_size();
if (selection.has(IntPair(i, j))) {
draw_texture(selected_icon, ep.point_rect.position);
- draw_string(font, ep.point_rect.position + Vector2(8, -font->get_height(font_size) - 8), TTR("Time:") + " " + TS->format_number(rtos(Math::snapped(offset, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
+ draw_string(font, ep.point_rect.position + Vector2(8, -font->get_height(font_size) - 8), TTR("Time:") + " " + TS->format_number(rtos(Math::snapped(offset, 0.0001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
draw_string(font, ep.point_rect.position + Vector2(8, -8), TTR("Value:") + " " + TS->format_number(rtos(Math::snapped(value, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
} else {
Color track_color = Color(1, 1, 1, 1);
@@ -812,7 +812,7 @@ void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int
return;
}
- int idx = animation->track_find_key(p_track, p_pos, true);
+ int idx = animation->track_find_key(p_track, p_pos, Animation::FIND_MODE_APPROX);
ERR_FAIL_COND(idx < 0);
selection.insert(IntPair(p_track, idx));
@@ -1168,8 +1168,8 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
new_point[4] = 0;
real_t time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
- while (animation->track_find_key(selected_track, time, true) != -1) {
- time += 0.001;
+ while (animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX) != -1) {
+ time += 0.0001;
}
Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
@@ -1179,7 +1179,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
undo_redo->commit_action();
//then attempt to move
- int index = animation->track_find_key(selected_track, time, true);
+ int index = animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX);
ERR_FAIL_COND(index == -1);
_clear_selection();
selection.insert(IntPair(selected_track, index));
@@ -1283,7 +1283,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
real_t newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
- int idx = animation->track_find_key(E->get().first, newtime, true);
+ int idx = animation->track_find_key(E->get().first, newtime, Animation::FIND_MODE_APPROX);
if (idx == -1) {
continue;
}
@@ -1539,7 +1539,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
real_t time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
- while (animation->track_find_key(selected_track, time, true) != -1) {
+ while (animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX) != -1) {
time += 0.001;
}
@@ -1599,7 +1599,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
real_t t = animation->track_get_key_time(E->get().first, E->get().second);
real_t dst_time = t + (timeline->get_play_position() - top_time);
- int existing_idx = animation->track_find_key(E->get().first, dst_time, true);
+ int existing_idx = animation->track_find_key(E->get().first, dst_time, Animation::FIND_MODE_APPROX);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, dst_time, animation->track_get_key_value(E->get().first, E->get().second), animation->track_get_key_transition(E->get().first, E->get().second));
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, dst_time);
@@ -1623,7 +1623,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
int track = E.first;
real_t time = E.second;
- int existing_idx = animation->track_find_key(track, time, true);
+ int existing_idx = animation->track_find_key(track, time, Animation::FIND_MODE_APPROX);
if (existing_idx == -1) {
continue;
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 2ee06a0dbd..74e0db967d 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -48,1356 +48,1182 @@
#include "scene/scene_string_names.h"
#include "servers/audio/audio_stream.h"
-class AnimationTrackKeyEdit : public Object {
- GDCLASS(AnimationTrackKeyEdit, Object);
-
-public:
- bool setting = false;
- bool animation_read_only = false;
+void AnimationTrackKeyEdit::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj);
+ ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationTrackKeyEdit::_key_ofs_changed);
+ ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationTrackKeyEdit::_hide_script_from_inspector);
+ ClassDB::bind_method(D_METHOD("_hide_metadata_from_inspector"), &AnimationTrackKeyEdit::_hide_metadata_from_inspector);
+ ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationTrackKeyEdit::get_root_path);
+ ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationTrackKeyEdit::_dont_undo_redo);
+ ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationTrackKeyEdit::_is_read_only);
+}
- bool _hide_script_from_inspector() { return true; }
- bool _hide_metadata_from_inspector() { return true; }
- bool _dont_undo_redo() { return true; }
+void AnimationTrackKeyEdit::_fix_node_path(Variant &value) {
+ NodePath np = value;
- bool _is_read_only() {
- return animation_read_only;
+ if (np == NodePath()) {
+ return;
}
- static void _bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj);
- ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationTrackKeyEdit::_key_ofs_changed);
- ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationTrackKeyEdit::_hide_script_from_inspector);
- ClassDB::bind_method(D_METHOD("_hide_metadata_from_inspector"), &AnimationTrackKeyEdit::_hide_metadata_from_inspector);
- ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationTrackKeyEdit::get_root_path);
- ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationTrackKeyEdit::_dont_undo_redo);
- ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationTrackKeyEdit::_is_read_only);
- }
+ Node *root = EditorNode::get_singleton()->get_tree()->get_root();
- void _fix_node_path(Variant &value) {
- NodePath np = value;
+ Node *np_node = root->get_node(np);
+ ERR_FAIL_COND(!np_node);
- if (np == NodePath()) {
- return;
- }
+ Node *edited_node = root->get_node(base);
+ ERR_FAIL_COND(!edited_node);
- Node *root = EditorNode::get_singleton()->get_tree()->get_root();
+ value = edited_node->get_path_to(np_node);
+}
- Node *np_node = root->get_node(np);
- ERR_FAIL_COND(!np_node);
+void AnimationTrackKeyEdit::_update_obj(const Ref<Animation> &p_anim) {
+ if (setting || animation != p_anim) {
+ return;
+ }
- Node *edited_node = root->get_node(base);
- ERR_FAIL_COND(!edited_node);
+ notify_change();
+}
- value = edited_node->get_path_to(np_node);
+void AnimationTrackKeyEdit::_key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) {
+ if (animation != p_anim || from != key_ofs) {
+ return;
}
- void _update_obj(const Ref<Animation> &p_anim) {
- if (setting || animation != p_anim) {
- return;
- }
+ key_ofs = to;
- notify_change();
+ if (setting) {
+ return;
}
- void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) {
- if (animation != p_anim || from != key_ofs) {
- return;
- }
+ notify_change();
+}
- key_ofs = to;
+bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_value) {
+ int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
+ ERR_FAIL_COND_V(key == -1, false);
- if (setting) {
- return;
- }
+ String name = p_name;
+ if (name == "easing") {
+ float val = p_value;
+ float prev_val = animation->track_get_key_transition(track, key);
+ setting = true;
+ Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ undo_redo->create_action(TTR("Animation Change Transition"), UndoRedo::MERGE_ENDS);
+ undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val);
+ undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val);
+ undo_redo->add_do_method(this, "_update_obj", animation);
+ undo_redo->add_undo_method(this, "_update_obj", animation);
+ undo_redo->commit_action();
- notify_change();
+ setting = false;
+ return true;
}
- bool _set(const StringName &p_name, const Variant &p_value) {
- int key = animation->track_find_key(track, key_ofs, true);
- ERR_FAIL_COND_V(key == -1, false);
-
- String name = p_name;
- if (name == "time" || name == "frame") {
- float new_time = p_value;
-
- if (name == "frame") {
- float fps = animation->get_step();
- if (fps > 0) {
- fps = 1.0 / fps;
+ Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ switch (animation->track_get_type(track)) {
+ case Animation::TYPE_POSITION_3D:
+ case Animation::TYPE_ROTATION_3D:
+ case Animation::TYPE_SCALE_3D: {
+ if (name == "position" || name == "rotation" || name == "scale") {
+ Variant old = animation->track_get_key_value(track, key);
+ setting = true;
+ String chan;
+ switch (animation->track_get_type(track)) {
+ case Animation::TYPE_POSITION_3D:
+ chan = "Position3D";
+ break;
+ case Animation::TYPE_ROTATION_3D:
+ chan = "Rotation3D";
+ break;
+ case Animation::TYPE_SCALE_3D:
+ chan = "Scale3D";
+ break;
+ default: {
+ }
}
- new_time /= fps;
- }
- if (new_time == key_ofs) {
+ undo_redo->create_action(vformat(TTR("Animation Change %s"), chan));
+ undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value);
+ undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old);
+ undo_redo->add_do_method(this, "_update_obj", animation);
+ undo_redo->add_undo_method(this, "_update_obj", animation);
+ undo_redo->commit_action();
+
+ setting = false;
return true;
}
- int existing = animation->track_find_key(track, new_time, true);
+ } break;
+ case Animation::TYPE_BLEND_SHAPE:
+ case Animation::TYPE_VALUE: {
+ if (name == "value") {
+ Variant value = p_value;
- setting = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
- undo_redo->create_action(TTR("Animation Change Keyframe Time"), UndoRedo::MERGE_ENDS);
+ if (value.get_type() == Variant::NODE_PATH) {
+ _fix_node_path(value);
+ }
- Variant val = animation->track_get_key_value(track, key);
- float trans = animation->track_get_key_transition(track, key);
+ setting = true;
+ undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ Variant prev = animation->track_get_key_value(track, key);
+ undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value);
+ undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, prev);
+ undo_redo->add_do_method(this, "_update_obj", animation);
+ undo_redo->add_undo_method(this, "_update_obj", animation);
+ undo_redo->commit_action();
- undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, key);
- undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, val, trans);
- undo_redo->add_do_method(this, "_key_ofs_changed", animation, key_ofs, new_time);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time);
- undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_ofs, val, trans);
- undo_redo->add_undo_method(this, "_key_ofs_changed", animation, new_time, key_ofs);
+ setting = false;
+ return true;
+ }
+ } break;
+ case Animation::TYPE_METHOD: {
+ Dictionary d_old = animation->track_get_key_value(track, key);
+ Dictionary d_new = d_old.duplicate();
+
+ bool change_notify_deserved = false;
+ bool mergeable = false;
+
+ if (name == "name") {
+ d_new["method"] = p_value;
+ } else if (name == "arg_count") {
+ Vector<Variant> args = d_old["args"];
+ args.resize(p_value);
+ d_new["args"] = args;
+ change_notify_deserved = true;
+ } else if (name.begins_with("args/")) {
+ Vector<Variant> args = d_old["args"];
+ int idx = name.get_slice("/", 1).to_int();
+ ERR_FAIL_INDEX_V(idx, args.size(), false);
+
+ String what = name.get_slice("/", 2);
+ if (what == "type") {
+ Variant::Type t = Variant::Type(int(p_value));
+
+ if (t != args[idx].get_type()) {
+ Callable::CallError err;
+ if (Variant::can_convert(args[idx].get_type(), t)) {
+ Variant old = args[idx];
+ Variant *ptrs[1] = { &old };
+ Variant::construct(t, args.write[idx], (const Variant **)ptrs, 1, err);
+ } else {
+ Variant::construct(t, args.write[idx], nullptr, 0, err);
+ }
+ change_notify_deserved = true;
+ d_new["args"] = args;
+ }
+ } else if (what == "value") {
+ Variant value = p_value;
+ if (value.get_type() == Variant::NODE_PATH) {
+ _fix_node_path(value);
+ }
- if (existing != -1) {
- Variant v = animation->track_get_key_value(track, existing);
- trans = animation->track_get_key_transition(track, existing);
- undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, new_time, v, trans);
+ args.write[idx] = value;
+ d_new["args"] = args;
+ mergeable = true;
+ }
}
- undo_redo->commit_action();
- setting = false;
- return true;
- }
+ if (mergeable) {
+ undo_redo->create_action(TTR("Animation Change Call"), UndoRedo::MERGE_ENDS);
+ } else {
+ undo_redo->create_action(TTR("Animation Change Call"));
+ }
- if (name == "easing") {
- float val = p_value;
- float prev_val = animation->track_get_key_transition(track, key);
setting = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
- undo_redo->create_action(TTR("Animation Change Transition"), UndoRedo::MERGE_ENDS);
- undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val);
- undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val);
+ undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new);
+ undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old);
undo_redo->add_do_method(this, "_update_obj", animation);
undo_redo->add_undo_method(this, "_update_obj", animation);
undo_redo->commit_action();
setting = false;
+ if (change_notify_deserved) {
+ notify_change();
+ }
return true;
- }
-
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
- switch (animation->track_get_type(track)) {
- case Animation::TYPE_POSITION_3D:
- case Animation::TYPE_ROTATION_3D:
- case Animation::TYPE_SCALE_3D: {
- if (name == "position" || name == "rotation" || name == "scale") {
- Variant old = animation->track_get_key_value(track, key);
- setting = true;
- String chan;
- switch (animation->track_get_type(track)) {
- case Animation::TYPE_POSITION_3D:
- chan = "Position3D";
- break;
- case Animation::TYPE_ROTATION_3D:
- chan = "Rotation3D";
- break;
- case Animation::TYPE_SCALE_3D:
- chan = "Scale3D";
- break;
- default: {
- }
- }
-
- undo_redo->create_action(vformat(TTR("Anim Change %s"), chan));
- undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value);
- undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old);
- undo_redo->add_do_method(this, "_update_obj", animation);
- undo_redo->add_undo_method(this, "_update_obj", animation);
- undo_redo->commit_action();
+ } break;
+ case Animation::TYPE_BEZIER: {
+ if (name == "value") {
+ const Variant &value = p_value;
- setting = false;
- return true;
- }
+ setting = true;
+ undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ float prev = animation->bezier_track_get_key_value(track, key);
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_value", track, key, value);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_value", track, key, prev);
+ undo_redo->add_do_method(this, "_update_obj", animation);
+ undo_redo->add_undo_method(this, "_update_obj", animation);
+ undo_redo->commit_action();
- } break;
- case Animation::TYPE_BLEND_SHAPE:
- case Animation::TYPE_VALUE: {
- if (name == "value") {
- Variant value = p_value;
+ setting = false;
+ return true;
+ }
- if (value.get_type() == Variant::NODE_PATH) {
- _fix_node_path(value);
- }
+ if (name == "in_handle") {
+ const Variant &value = p_value;
- setting = true;
- undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- Variant prev = animation->track_get_key_value(track, key);
- undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, prev);
- undo_redo->add_do_method(this, "_update_obj", animation);
- undo_redo->add_undo_method(this, "_update_obj", animation);
- undo_redo->commit_action();
+ setting = true;
+ undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ Vector2 prev = animation->bezier_track_get_key_in_handle(track, key);
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, value);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev);
+ undo_redo->add_do_method(this, "_update_obj", animation);
+ undo_redo->add_undo_method(this, "_update_obj", animation);
+ undo_redo->commit_action();
- setting = false;
- return true;
- }
- } break;
- case Animation::TYPE_METHOD: {
- Dictionary d_old = animation->track_get_key_value(track, key);
- Dictionary d_new = d_old.duplicate();
+ setting = false;
+ return true;
+ }
- bool change_notify_deserved = false;
- bool mergeable = false;
+ if (name == "out_handle") {
+ const Variant &value = p_value;
- if (name == "name") {
- d_new["method"] = p_value;
- } else if (name == "arg_count") {
- Vector<Variant> args = d_old["args"];
- args.resize(p_value);
- d_new["args"] = args;
- change_notify_deserved = true;
- } else if (name.begins_with("args/")) {
- Vector<Variant> args = d_old["args"];
- int idx = name.get_slice("/", 1).to_int();
- ERR_FAIL_INDEX_V(idx, args.size(), false);
-
- String what = name.get_slice("/", 2);
- if (what == "type") {
- Variant::Type t = Variant::Type(int(p_value));
-
- if (t != args[idx].get_type()) {
- Callable::CallError err;
- if (Variant::can_convert(args[idx].get_type(), t)) {
- Variant old = args[idx];
- Variant *ptrs[1] = { &old };
- Variant::construct(t, args.write[idx], (const Variant **)ptrs, 1, err);
- } else {
- Variant::construct(t, args.write[idx], nullptr, 0, err);
- }
- change_notify_deserved = true;
- d_new["args"] = args;
- }
- } else if (what == "value") {
- Variant value = p_value;
- if (value.get_type() == Variant::NODE_PATH) {
- _fix_node_path(value);
- }
+ setting = true;
+ undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ Vector2 prev = animation->bezier_track_get_key_out_handle(track, key);
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, value);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev);
+ undo_redo->add_do_method(this, "_update_obj", animation);
+ undo_redo->add_undo_method(this, "_update_obj", animation);
+ undo_redo->commit_action();
- args.write[idx] = value;
- d_new["args"] = args;
- mergeable = true;
- }
- }
+ setting = false;
+ return true;
+ }
- if (mergeable) {
- undo_redo->create_action(TTR("Animation Change Call"), UndoRedo::MERGE_ENDS);
- } else {
- undo_redo->create_action(TTR("Animation Change Call"));
- }
+ if (name == "handle_mode") {
+ const Variant &value = p_value;
setting = true;
- undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new);
- undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old);
+ undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ int prev = animation->bezier_track_get_key_handle_mode(track, key);
+ undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value);
+ undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev);
undo_redo->add_do_method(this, "_update_obj", animation);
undo_redo->add_undo_method(this, "_update_obj", animation);
undo_redo->commit_action();
setting = false;
- if (change_notify_deserved) {
- notify_change();
- }
return true;
- } break;
- case Animation::TYPE_BEZIER: {
- if (name == "value") {
- const Variant &value = p_value;
-
- setting = true;
- undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- float prev = animation->bezier_track_get_key_value(track, key);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_value", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_value", track, key, prev);
- undo_redo->add_do_method(this, "_update_obj", animation);
- undo_redo->add_undo_method(this, "_update_obj", animation);
- undo_redo->commit_action();
-
- setting = false;
- return true;
- }
+ }
+ } break;
+ case Animation::TYPE_AUDIO: {
+ if (name == "stream") {
+ Ref<AudioStream> stream = p_value;
- if (name == "in_handle") {
- const Variant &value = p_value;
+ setting = true;
+ undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ Ref<Resource> prev = animation->audio_track_get_key_stream(track, key);
+ undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream);
+ undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_stream", track, key, prev);
+ undo_redo->add_do_method(this, "_update_obj", animation);
+ undo_redo->add_undo_method(this, "_update_obj", animation);
+ undo_redo->commit_action();
- setting = true;
- undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- Vector2 prev = animation->bezier_track_get_key_in_handle(track, key);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev);
- undo_redo->add_do_method(this, "_update_obj", animation);
- undo_redo->add_undo_method(this, "_update_obj", animation);
- undo_redo->commit_action();
-
- setting = false;
- return true;
- }
+ setting = false;
+ return true;
+ }
- if (name == "out_handle") {
- const Variant &value = p_value;
+ if (name == "start_offset") {
+ float value = p_value;
- setting = true;
- undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- Vector2 prev = animation->bezier_track_get_key_out_handle(track, key);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev);
- undo_redo->add_do_method(this, "_update_obj", animation);
- undo_redo->add_undo_method(this, "_update_obj", animation);
- undo_redo->commit_action();
-
- setting = false;
- return true;
- }
+ setting = true;
+ undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ float prev = animation->audio_track_get_key_start_offset(track, key);
+ undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, value);
+ undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, prev);
+ undo_redo->add_do_method(this, "_update_obj", animation);
+ undo_redo->add_undo_method(this, "_update_obj", animation);
+ undo_redo->commit_action();
- if (name == "handle_mode") {
- const Variant &value = p_value;
+ setting = false;
+ return true;
+ }
- setting = true;
- undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- int prev = animation->bezier_track_get_key_handle_mode(track, key);
- undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value);
- undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev);
- undo_redo->add_do_method(this, "_update_obj", animation);
- undo_redo->add_undo_method(this, "_update_obj", animation);
- undo_redo->commit_action();
-
- setting = false;
- return true;
- }
- } break;
- case Animation::TYPE_AUDIO: {
- if (name == "stream") {
- Ref<AudioStream> stream = p_value;
+ if (name == "end_offset") {
+ float value = p_value;
- setting = true;
- undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- Ref<Resource> prev = animation->audio_track_get_key_stream(track, key);
- undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream);
- undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_stream", track, key, prev);
- undo_redo->add_do_method(this, "_update_obj", animation);
- undo_redo->add_undo_method(this, "_update_obj", animation);
- undo_redo->commit_action();
-
- setting = false;
- return true;
- }
+ setting = true;
+ undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ float prev = animation->audio_track_get_key_end_offset(track, key);
+ undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, value);
+ undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, prev);
+ undo_redo->add_do_method(this, "_update_obj", animation);
+ undo_redo->add_undo_method(this, "_update_obj", animation);
+ undo_redo->commit_action();
- if (name == "start_offset") {
- float value = p_value;
+ setting = false;
+ return true;
+ }
+ } break;
+ case Animation::TYPE_ANIMATION: {
+ if (name == "animation") {
+ StringName anim_name = p_value;
- setting = true;
- undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- float prev = animation->audio_track_get_key_start_offset(track, key);
- undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, prev);
- undo_redo->add_do_method(this, "_update_obj", animation);
- undo_redo->add_undo_method(this, "_update_obj", animation);
- undo_redo->commit_action();
-
- setting = false;
- return true;
- }
+ setting = true;
+ undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ StringName prev = animation->animation_track_get_key_animation(track, key);
+ undo_redo->add_do_method(animation.ptr(), "animation_track_set_key_animation", track, key, anim_name);
+ undo_redo->add_undo_method(animation.ptr(), "animation_track_set_key_animation", track, key, prev);
+ undo_redo->add_do_method(this, "_update_obj", animation);
+ undo_redo->add_undo_method(this, "_update_obj", animation);
+ undo_redo->commit_action();
- if (name == "end_offset") {
- float value = p_value;
+ setting = false;
+ return true;
+ }
+ } break;
+ }
- setting = true;
- undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- float prev = animation->audio_track_get_key_end_offset(track, key);
- undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, prev);
- undo_redo->add_do_method(this, "_update_obj", animation);
- undo_redo->add_undo_method(this, "_update_obj", animation);
- undo_redo->commit_action();
-
- setting = false;
- return true;
- }
- } break;
- case Animation::TYPE_ANIMATION: {
- if (name == "animation") {
- StringName anim_name = p_value;
+ return false;
+}
- setting = true;
- undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- StringName prev = animation->animation_track_get_key_animation(track, key);
- undo_redo->add_do_method(animation.ptr(), "animation_track_set_key_animation", track, key, anim_name);
- undo_redo->add_undo_method(animation.ptr(), "animation_track_set_key_animation", track, key, prev);
- undo_redo->add_do_method(this, "_update_obj", animation);
- undo_redo->add_undo_method(this, "_update_obj", animation);
- undo_redo->commit_action();
-
- setting = false;
- return true;
- }
- } break;
- }
+bool AnimationTrackKeyEdit::_get(const StringName &p_name, Variant &r_ret) const {
+ int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
+ ERR_FAIL_COND_V(key == -1, false);
- return false;
+ String name = p_name;
+ if (name == "easing") {
+ r_ret = animation->track_get_key_transition(track, key);
+ return true;
}
- bool _get(const StringName &p_name, Variant &r_ret) const {
- int key = animation->track_find_key(track, key_ofs, true);
- ERR_FAIL_COND_V(key == -1, false);
-
- String name = p_name;
- if (name == "time") {
- r_ret = key_ofs;
- return true;
- }
-
- if (name == "frame") {
- float fps = animation->get_step();
- if (fps > 0) {
- fps = 1.0 / fps;
+ switch (animation->track_get_type(track)) {
+ case Animation::TYPE_POSITION_3D:
+ case Animation::TYPE_ROTATION_3D:
+ case Animation::TYPE_SCALE_3D: {
+ if (name == "position" || name == "rotation" || name == "scale") {
+ r_ret = animation->track_get_key_value(track, key);
+ return true;
+ }
+ } break;
+ case Animation::TYPE_BLEND_SHAPE:
+ case Animation::TYPE_VALUE: {
+ if (name == "value") {
+ r_ret = animation->track_get_key_value(track, key);
+ return true;
}
- r_ret = key_ofs * fps;
- return true;
- }
- if (name == "easing") {
- r_ret = animation->track_get_key_transition(track, key);
- return true;
- }
+ } break;
+ case Animation::TYPE_METHOD: {
+ Dictionary d = animation->track_get_key_value(track, key);
- switch (animation->track_get_type(track)) {
- case Animation::TYPE_POSITION_3D:
- case Animation::TYPE_ROTATION_3D:
- case Animation::TYPE_SCALE_3D: {
- if (name == "position" || name == "rotation" || name == "scale") {
- r_ret = animation->track_get_key_value(track, key);
- return true;
- }
- } break;
- case Animation::TYPE_BLEND_SHAPE:
- case Animation::TYPE_VALUE: {
- if (name == "value") {
- r_ret = animation->track_get_key_value(track, key);
- return true;
- }
+ if (name == "name") {
+ ERR_FAIL_COND_V(!d.has("method"), false);
+ r_ret = d["method"];
+ return true;
+ }
- } break;
- case Animation::TYPE_METHOD: {
- Dictionary d = animation->track_get_key_value(track, key);
+ ERR_FAIL_COND_V(!d.has("args"), false);
- if (name == "name") {
- ERR_FAIL_COND_V(!d.has("method"), false);
- r_ret = d["method"];
- return true;
- }
+ Vector<Variant> args = d["args"];
- ERR_FAIL_COND_V(!d.has("args"), false);
+ if (name == "arg_count") {
+ r_ret = args.size();
+ return true;
+ }
- Vector<Variant> args = d["args"];
+ if (name.begins_with("args/")) {
+ int idx = name.get_slice("/", 1).to_int();
+ ERR_FAIL_INDEX_V(idx, args.size(), false);
- if (name == "arg_count") {
- r_ret = args.size();
+ String what = name.get_slice("/", 2);
+ if (what == "type") {
+ r_ret = args[idx].get_type();
return true;
}
- if (name.begins_with("args/")) {
- int idx = name.get_slice("/", 1).to_int();
- ERR_FAIL_INDEX_V(idx, args.size(), false);
-
- String what = name.get_slice("/", 2);
- if (what == "type") {
- r_ret = args[idx].get_type();
- return true;
- }
-
- if (what == "value") {
- r_ret = args[idx];
- return true;
- }
- }
-
- } break;
- case Animation::TYPE_BEZIER: {
- if (name == "value") {
- r_ret = animation->bezier_track_get_key_value(track, key);
+ if (what == "value") {
+ r_ret = args[idx];
return true;
}
+ }
- if (name == "in_handle") {
- r_ret = animation->bezier_track_get_key_in_handle(track, key);
- return true;
- }
+ } break;
+ case Animation::TYPE_BEZIER: {
+ if (name == "value") {
+ r_ret = animation->bezier_track_get_key_value(track, key);
+ return true;
+ }
- if (name == "out_handle") {
- r_ret = animation->bezier_track_get_key_out_handle(track, key);
- return true;
- }
+ if (name == "in_handle") {
+ r_ret = animation->bezier_track_get_key_in_handle(track, key);
+ return true;
+ }
- if (name == "handle_mode") {
- r_ret = animation->bezier_track_get_key_handle_mode(track, key);
- return true;
- }
+ if (name == "out_handle") {
+ r_ret = animation->bezier_track_get_key_out_handle(track, key);
+ return true;
+ }
- } break;
- case Animation::TYPE_AUDIO: {
- if (name == "stream") {
- r_ret = animation->audio_track_get_key_stream(track, key);
- return true;
- }
+ if (name == "handle_mode") {
+ r_ret = animation->bezier_track_get_key_handle_mode(track, key);
+ return true;
+ }
- if (name == "start_offset") {
- r_ret = animation->audio_track_get_key_start_offset(track, key);
- return true;
- }
+ } break;
+ case Animation::TYPE_AUDIO: {
+ if (name == "stream") {
+ r_ret = animation->audio_track_get_key_stream(track, key);
+ return true;
+ }
- if (name == "end_offset") {
- r_ret = animation->audio_track_get_key_end_offset(track, key);
- return true;
- }
+ if (name == "start_offset") {
+ r_ret = animation->audio_track_get_key_start_offset(track, key);
+ return true;
+ }
- } break;
- case Animation::TYPE_ANIMATION: {
- if (name == "animation") {
- r_ret = animation->animation_track_get_key_animation(track, key);
- return true;
- }
+ if (name == "end_offset") {
+ r_ret = animation->audio_track_get_key_end_offset(track, key);
+ return true;
+ }
- } break;
- }
+ } break;
+ case Animation::TYPE_ANIMATION: {
+ if (name == "animation") {
+ r_ret = animation->animation_track_get_key_animation(track, key);
+ return true;
+ }
- return false;
+ } break;
}
- void _get_property_list(List<PropertyInfo> *p_list) const {
- if (animation.is_null()) {
- return;
- }
- ERR_FAIL_INDEX(track, animation->get_track_count());
- int key = animation->track_find_key(track, key_ofs, true);
- ERR_FAIL_COND(key == -1);
+ return false;
+}
- if (use_fps && animation->get_step() > 0) {
- float max_frame = animation->get_length() / animation->get_step();
- p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("frame"), PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",1"));
- } else {
- p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("time"), PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01"));
- }
+void AnimationTrackKeyEdit::_get_property_list(List<PropertyInfo> *p_list) const {
+ if (animation.is_null()) {
+ return;
+ }
- switch (animation->track_get_type(track)) {
- case Animation::TYPE_POSITION_3D: {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, PNAME("position")));
- } break;
- case Animation::TYPE_ROTATION_3D: {
- p_list->push_back(PropertyInfo(Variant::QUATERNION, PNAME("rotation")));
- } break;
- case Animation::TYPE_SCALE_3D: {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, PNAME("scale")));
- } break;
- case Animation::TYPE_BLEND_SHAPE: {
- p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value")));
- } break;
- case Animation::TYPE_VALUE: {
- Variant v = animation->track_get_key_value(track, key);
+ ERR_FAIL_INDEX(track, animation->get_track_count());
+ int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
+ ERR_FAIL_COND(key == -1);
- if (hint.type != Variant::NIL) {
- PropertyInfo pi = hint;
- pi.name = PNAME("value");
- p_list->push_back(pi);
- } else {
- PropertyHint val_hint = PROPERTY_HINT_NONE;
- String val_hint_string;
-
- if (v.get_type() == Variant::OBJECT) {
- // Could actually check the object property if exists..? Yes I will!
- Ref<Resource> res = v;
- if (res.is_valid()) {
- val_hint = PROPERTY_HINT_RESOURCE_TYPE;
- val_hint_string = res->get_class();
- }
- }
+ switch (animation->track_get_type(track)) {
+ case Animation::TYPE_POSITION_3D: {
+ p_list->push_back(PropertyInfo(Variant::VECTOR3, PNAME("position")));
+ } break;
+ case Animation::TYPE_ROTATION_3D: {
+ p_list->push_back(PropertyInfo(Variant::QUATERNION, PNAME("rotation")));
+ } break;
+ case Animation::TYPE_SCALE_3D: {
+ p_list->push_back(PropertyInfo(Variant::VECTOR3, PNAME("scale")));
+ } break;
+ case Animation::TYPE_BLEND_SHAPE: {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value")));
+ } break;
+ case Animation::TYPE_VALUE: {
+ Variant v = animation->track_get_key_value(track, key);
- if (v.get_type() != Variant::NIL) {
- p_list->push_back(PropertyInfo(v.get_type(), PNAME("value"), val_hint, val_hint_string));
+ if (hint.type != Variant::NIL) {
+ PropertyInfo pi = hint;
+ pi.name = PNAME("value");
+ p_list->push_back(pi);
+ } else {
+ PropertyHint val_hint = PROPERTY_HINT_NONE;
+ String val_hint_string;
+
+ if (v.get_type() == Variant::OBJECT) {
+ // Could actually check the object property if exists..? Yes I will!
+ Ref<Resource> res = v;
+ if (res.is_valid()) {
+ val_hint = PROPERTY_HINT_RESOURCE_TYPE;
+ val_hint_string = res->get_class();
}
}
- } break;
- case Animation::TYPE_METHOD: {
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("name")));
- p_list->push_back(PropertyInfo(Variant::INT, PNAME("arg_count"), PROPERTY_HINT_RANGE, "0,32,1,or_greater"));
-
- Dictionary d = animation->track_get_key_value(track, key);
- ERR_FAIL_COND(!d.has("args"));
- Vector<Variant> args = d["args"];
- String vtypes;
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (i > 0) {
- vtypes += ",";
- }
- vtypes += Variant::get_type_name(Variant::Type(i));
+ if (v.get_type() != Variant::NIL) {
+ p_list->push_back(PropertyInfo(v.get_type(), PNAME("value"), val_hint, val_hint_string));
}
+ }
- for (int i = 0; i < args.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::INT, vformat("%s/%d/%s", PNAME("args"), i, PNAME("type")), PROPERTY_HINT_ENUM, vtypes));
- if (args[i].get_type() != Variant::NIL) {
- p_list->push_back(PropertyInfo(args[i].get_type(), vformat("%s/%d/%s", PNAME("args"), i, PNAME("value"))));
- }
+ } break;
+ case Animation::TYPE_METHOD: {
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("name")));
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("arg_count"), PROPERTY_HINT_RANGE, "0,32,1,or_greater"));
+
+ Dictionary d = animation->track_get_key_value(track, key);
+ ERR_FAIL_COND(!d.has("args"));
+ Vector<Variant> args = d["args"];
+ String vtypes;
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ if (i > 0) {
+ vtypes += ",";
}
+ vtypes += Variant::get_type_name(Variant::Type(i));
+ }
- } break;
- case Animation::TYPE_BEZIER: {
- Animation::HandleMode hm = animation->bezier_track_get_key_handle_mode(track, key);
- p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value")));
- if (hm == Animation::HANDLE_MODE_LINEAR) {
- p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY));
- } else {
- p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle")));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle")));
+ for (int i = 0; i < args.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("%s/%d/%s", PNAME("args"), i, PNAME("type")), PROPERTY_HINT_ENUM, vtypes));
+ if (args[i].get_type() != Variant::NIL) {
+ p_list->push_back(PropertyInfo(args[i].get_type(), vformat("%s/%d/%s", PNAME("args"), i, PNAME("value"))));
}
- p_list->push_back(PropertyInfo(Variant::INT, PNAME("handle_mode"), PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored"));
-
- } break;
- case Animation::TYPE_AUDIO: {
- p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("stream"), PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("start_offset"), PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("end_offset"), PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater"));
+ }
- } break;
- case Animation::TYPE_ANIMATION: {
- String animations;
+ } break;
+ case Animation::TYPE_BEZIER: {
+ Animation::HandleMode hm = animation->bezier_track_get_key_handle_mode(track, key);
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value")));
+ if (hm == Animation::HANDLE_MODE_LINEAR) {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY));
+ } else {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle")));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle")));
+ }
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("handle_mode"), PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored"));
- if (root_path && root_path->has_node(animation->track_get_path(track))) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(root_path->get_node(animation->track_get_path(track)));
- if (ap) {
- List<StringName> anims;
- ap->get_animation_list(&anims);
- for (const StringName &E : anims) {
- if (!animations.is_empty()) {
- animations += ",";
- }
+ } break;
+ case Animation::TYPE_AUDIO: {
+ p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("stream"), PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("start_offset"), PROPERTY_HINT_RANGE, "0,3600,0.0001,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("end_offset"), PROPERTY_HINT_RANGE, "0,3600,0.0001,or_greater"));
- animations += String(E);
+ } break;
+ case Animation::TYPE_ANIMATION: {
+ String animations;
+
+ if (root_path && root_path->has_node(animation->track_get_path(track))) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(root_path->get_node(animation->track_get_path(track)));
+ if (ap) {
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ for (const StringName &E : anims) {
+ if (!animations.is_empty()) {
+ animations += ",";
}
+
+ animations += String(E);
}
}
+ }
- if (!animations.is_empty()) {
- animations += ",";
- }
- animations += "[stop]";
+ if (!animations.is_empty()) {
+ animations += ",";
+ }
+ animations += "[stop]";
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("animation"), PROPERTY_HINT_ENUM, animations));
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("animation"), PROPERTY_HINT_ENUM, animations));
- } break;
- }
+ } break;
+ }
- if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("easing"), PROPERTY_HINT_EXP_EASING));
- }
+ if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("easing"), PROPERTY_HINT_EXP_EASING));
}
+}
- Ref<Animation> animation;
- int track = -1;
- float key_ofs = 0;
- Node *root_path = nullptr;
+void AnimationTrackKeyEdit::notify_change() {
+ notify_property_list_changed();
+}
- PropertyInfo hint;
- NodePath base;
- bool use_fps = false;
+Node *AnimationTrackKeyEdit::get_root_path() {
+ return root_path;
+}
- void notify_change() {
- notify_property_list_changed();
- }
+void AnimationTrackKeyEdit::set_use_fps(bool p_enable) {
+ use_fps = p_enable;
+ notify_property_list_changed();
+}
- Node *get_root_path() {
- return root_path;
- }
+void AnimationMultiTrackKeyEdit::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationMultiTrackKeyEdit::_update_obj);
+ ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationMultiTrackKeyEdit::_key_ofs_changed);
+ ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_script_from_inspector);
+ ClassDB::bind_method(D_METHOD("_hide_metadata_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_metadata_from_inspector);
+ ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationMultiTrackKeyEdit::get_root_path);
+ ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationMultiTrackKeyEdit::_dont_undo_redo);
+ ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationMultiTrackKeyEdit::_is_read_only);
+}
- void set_use_fps(bool p_enable) {
- use_fps = p_enable;
- notify_property_list_changed();
+void AnimationMultiTrackKeyEdit::_fix_node_path(Variant &value, NodePath &base) {
+ NodePath np = value;
+
+ if (np == NodePath()) {
+ return;
}
-};
-class AnimationMultiTrackKeyEdit : public Object {
- GDCLASS(AnimationMultiTrackKeyEdit, Object);
+ Node *root = EditorNode::get_singleton()->get_tree()->get_root();
-public:
- bool setting = false;
- bool animation_read_only = false;
+ Node *np_node = root->get_node(np);
+ ERR_FAIL_COND(!np_node);
- bool _hide_script_from_inspector() { return true; }
- bool _hide_metadata_from_inspector() { return true; }
- bool _dont_undo_redo() { return true; }
+ Node *edited_node = root->get_node(base);
+ ERR_FAIL_COND(!edited_node);
- bool _is_read_only() {
- return animation_read_only;
- }
+ value = edited_node->get_path_to(np_node);
+}
- static void _bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationMultiTrackKeyEdit::_update_obj);
- ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationMultiTrackKeyEdit::_key_ofs_changed);
- ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_script_from_inspector);
- ClassDB::bind_method(D_METHOD("_hide_metadata_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_metadata_from_inspector);
- ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationMultiTrackKeyEdit::get_root_path);
- ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationMultiTrackKeyEdit::_dont_undo_redo);
- ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationMultiTrackKeyEdit::_is_read_only);
+void AnimationMultiTrackKeyEdit::_update_obj(const Ref<Animation> &p_anim) {
+ if (setting || animation != p_anim) {
+ return;
}
- void _fix_node_path(Variant &value, NodePath &base) {
- NodePath np = value;
+ notify_change();
+}
- if (np == NodePath()) {
- return;
- }
+void AnimationMultiTrackKeyEdit::_key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) {
+ if (animation != p_anim) {
+ return;
+ }
- Node *root = EditorNode::get_singleton()->get_tree()->get_root();
+ for (const KeyValue<int, List<float>> &E : key_ofs_map) {
+ int key = 0;
+ for (const float &key_ofs : E.value) {
+ if (from != key_ofs) {
+ key++;
+ continue;
+ }
- Node *np_node = root->get_node(np);
- ERR_FAIL_COND(!np_node);
+ int track = E.key;
+ key_ofs_map[track][key] = to;
- Node *edited_node = root->get_node(base);
- ERR_FAIL_COND(!edited_node);
+ if (setting) {
+ return;
+ }
- value = edited_node->get_path_to(np_node);
- }
+ notify_change();
- void _update_obj(const Ref<Animation> &p_anim) {
- if (setting || animation != p_anim) {
return;
}
-
- notify_change();
}
+}
- void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) {
- if (animation != p_anim) {
- return;
- }
-
- for (const KeyValue<int, List<float>> &E : key_ofs_map) {
- int key = 0;
- for (const float &key_ofs : E.value) {
- if (from != key_ofs) {
- key++;
- continue;
- }
+bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p_value) {
+ bool update_obj = false;
+ bool change_notify_deserved = false;
+ for (const KeyValue<int, List<float>> &E : key_ofs_map) {
+ int track = E.key;
+ for (const float &key_ofs : E.value) {
+ int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
+ ERR_FAIL_COND_V(key == -1, false);
- int track = E.key;
- key_ofs_map[track][key] = to;
+ String name = p_name;
+ if (name == "easing") {
+ float val = p_value;
+ float prev_val = animation->track_get_key_transition(track, key);
- if (setting) {
- return;
+ Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ if (!setting) {
+ setting = true;
+ undo_redo->create_action(TTR("Animation Multi Change Transition"), UndoRedo::MERGE_ENDS);
}
-
- notify_change();
-
- return;
+ undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val);
+ undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val);
+ update_obj = true;
}
- }
- }
- bool _set(const StringName &p_name, const Variant &p_value) {
- bool update_obj = false;
- bool change_notify_deserved = false;
- for (const KeyValue<int, List<float>> &E : key_ofs_map) {
- int track = E.key;
- for (const float &key_ofs : E.value) {
- int key = animation->track_find_key(track, key_ofs, true);
- ERR_FAIL_COND_V(key == -1, false);
-
- String name = p_name;
- if (name == "time" || name == "frame") {
- float new_time = p_value;
-
- if (name == "frame") {
- float fps = animation->get_step();
- if (fps > 0) {
- fps = 1.0 / fps;
+ Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ switch (animation->track_get_type(track)) {
+ case Animation::TYPE_POSITION_3D:
+ case Animation::TYPE_ROTATION_3D:
+ case Animation::TYPE_SCALE_3D: {
+ Variant old = animation->track_get_key_value(track, key);
+ if (!setting) {
+ String chan;
+ switch (animation->track_get_type(track)) {
+ case Animation::TYPE_POSITION_3D:
+ chan = "Position3D";
+ break;
+ case Animation::TYPE_ROTATION_3D:
+ chan = "Rotation3D";
+ break;
+ case Animation::TYPE_SCALE_3D:
+ chan = "Scale3D";
+ break;
+ default: {
+ }
}
- new_time /= fps;
- }
-
- int existing = animation->track_find_key(track, new_time, true);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
- if (!setting) {
setting = true;
- undo_redo->create_action(TTR("Animation Multi Change Keyframe Time"), UndoRedo::MERGE_ENDS);
+ undo_redo->create_action(vformat(TTR("Animation Multi Change %s"), chan));
}
+ undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value);
+ undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old);
+ update_obj = true;
+ } break;
+ case Animation::TYPE_BLEND_SHAPE:
+ case Animation::TYPE_VALUE: {
+ if (name == "value") {
+ Variant value = p_value;
- Variant val = animation->track_get_key_value(track, key);
- float trans = animation->track_get_key_transition(track, key);
-
- undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, key);
- undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, val, trans);
- undo_redo->add_do_method(this, "_key_ofs_changed", animation, key_ofs, new_time);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time);
- undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_ofs, val, trans);
- undo_redo->add_undo_method(this, "_key_ofs_changed", animation, new_time, key_ofs);
+ if (value.get_type() == Variant::NODE_PATH) {
+ _fix_node_path(value, base_map[track]);
+ }
- if (existing != -1) {
- Variant v = animation->track_get_key_value(track, existing);
- trans = animation->track_get_key_transition(track, existing);
- undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, new_time, v, trans);
+ if (!setting) {
+ setting = true;
+ undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ }
+ Variant prev = animation->track_get_key_value(track, key);
+ undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value);
+ undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, prev);
+ update_obj = true;
}
- } else if (name == "easing") {
- float val = p_value;
- float prev_val = animation->track_get_key_transition(track, key);
+ } break;
+ case Animation::TYPE_METHOD: {
+ Dictionary d_old = animation->track_get_key_value(track, key);
+ Dictionary d_new = d_old.duplicate();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
- if (!setting) {
- setting = true;
- undo_redo->create_action(TTR("Animation Multi Change Transition"), UndoRedo::MERGE_ENDS);
- }
- undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val);
- undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val);
- update_obj = true;
- }
+ bool mergeable = false;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
- switch (animation->track_get_type(track)) {
- case Animation::TYPE_POSITION_3D:
- case Animation::TYPE_ROTATION_3D:
- case Animation::TYPE_SCALE_3D: {
- Variant old = animation->track_get_key_value(track, key);
- if (!setting) {
- String chan;
- switch (animation->track_get_type(track)) {
- case Animation::TYPE_POSITION_3D:
- chan = "Position3D";
- break;
- case Animation::TYPE_ROTATION_3D:
- chan = "Rotation3D";
- break;
- case Animation::TYPE_SCALE_3D:
- chan = "Scale3D";
- break;
- default: {
+ if (name == "name") {
+ d_new["method"] = p_value;
+ } else if (name == "arg_count") {
+ Vector<Variant> args = d_old["args"];
+ args.resize(p_value);
+ d_new["args"] = args;
+ change_notify_deserved = true;
+ } else if (name.begins_with("args/")) {
+ Vector<Variant> args = d_old["args"];
+ int idx = name.get_slice("/", 1).to_int();
+ ERR_FAIL_INDEX_V(idx, args.size(), false);
+
+ String what = name.get_slice("/", 2);
+ if (what == "type") {
+ Variant::Type t = Variant::Type(int(p_value));
+
+ if (t != args[idx].get_type()) {
+ Callable::CallError err;
+ if (Variant::can_convert(args[idx].get_type(), t)) {
+ Variant old = args[idx];
+ Variant *ptrs[1] = { &old };
+ Variant::construct(t, args.write[idx], (const Variant **)ptrs, 1, err);
+ } else {
+ Variant::construct(t, args.write[idx], nullptr, 0, err);
}
+ change_notify_deserved = true;
+ d_new["args"] = args;
}
-
- setting = true;
- undo_redo->create_action(vformat(TTR("Animation Multi Change %s"), chan));
- }
- undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value);
- undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old);
- update_obj = true;
- } break;
- case Animation::TYPE_BLEND_SHAPE:
- case Animation::TYPE_VALUE: {
- if (name == "value") {
+ } else if (what == "value") {
Variant value = p_value;
-
if (value.get_type() == Variant::NODE_PATH) {
_fix_node_path(value, base_map[track]);
}
- if (!setting) {
- setting = true;
- undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- }
- Variant prev = animation->track_get_key_value(track, key);
- undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, prev);
- update_obj = true;
+ args.write[idx] = value;
+ d_new["args"] = args;
+ mergeable = true;
}
- } break;
- case Animation::TYPE_METHOD: {
- Dictionary d_old = animation->track_get_key_value(track, key);
- Dictionary d_new = d_old.duplicate();
+ }
- bool mergeable = false;
+ Variant prev = animation->track_get_key_value(track, key);
- if (name == "name") {
- d_new["method"] = p_value;
- } else if (name == "arg_count") {
- Vector<Variant> args = d_old["args"];
- args.resize(p_value);
- d_new["args"] = args;
- change_notify_deserved = true;
- } else if (name.begins_with("args/")) {
- Vector<Variant> args = d_old["args"];
- int idx = name.get_slice("/", 1).to_int();
- ERR_FAIL_INDEX_V(idx, args.size(), false);
-
- String what = name.get_slice("/", 2);
- if (what == "type") {
- Variant::Type t = Variant::Type(int(p_value));
-
- if (t != args[idx].get_type()) {
- Callable::CallError err;
- if (Variant::can_convert(args[idx].get_type(), t)) {
- Variant old = args[idx];
- Variant *ptrs[1] = { &old };
- Variant::construct(t, args.write[idx], (const Variant **)ptrs, 1, err);
- } else {
- Variant::construct(t, args.write[idx], nullptr, 0, err);
- }
- change_notify_deserved = true;
- d_new["args"] = args;
- }
- } else if (what == "value") {
- Variant value = p_value;
- if (value.get_type() == Variant::NODE_PATH) {
- _fix_node_path(value, base_map[track]);
- }
+ if (!setting) {
+ if (mergeable) {
+ undo_redo->create_action(TTR("Animation Multi Change Call"), UndoRedo::MERGE_ENDS);
+ } else {
+ undo_redo->create_action(TTR("Animation Multi Change Call"));
+ }
- args.write[idx] = value;
- d_new["args"] = args;
- mergeable = true;
- }
+ setting = true;
+ }
+
+ undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new);
+ undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old);
+ update_obj = true;
+ } break;
+ case Animation::TYPE_BEZIER: {
+ if (name == "value") {
+ const Variant &value = p_value;
+
+ if (!setting) {
+ setting = true;
+ undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
}
+ float prev = animation->bezier_track_get_key_value(track, key);
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_value", track, key, value);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_value", track, key, prev);
+ update_obj = true;
+ } else if (name == "in_handle") {
+ const Variant &value = p_value;
- Variant prev = animation->track_get_key_value(track, key);
+ if (!setting) {
+ setting = true;
+ undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ }
+ Vector2 prev = animation->bezier_track_get_key_in_handle(track, key);
+ undo_redo->add_do_method(this, "_bezier_track_set_key_in_handle", track, key, value);
+ undo_redo->add_undo_method(this, "_bezier_track_set_key_in_handle", track, key, prev);
+ update_obj = true;
+ } else if (name == "out_handle") {
+ const Variant &value = p_value;
if (!setting) {
- if (mergeable) {
- undo_redo->create_action(TTR("Animation Multi Change Call"), UndoRedo::MERGE_ENDS);
- } else {
- undo_redo->create_action(TTR("Animation Multi Change Call"));
- }
+ setting = true;
+ undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ }
+ Vector2 prev = animation->bezier_track_get_key_out_handle(track, key);
+ undo_redo->add_do_method(this, "_bezier_track_set_key_out_handle", track, key, value);
+ undo_redo->add_undo_method(this, "_bezier_track_set_key_out_handle", track, key, prev);
+ update_obj = true;
+ } else if (name == "handle_mode") {
+ const Variant &value = p_value;
+ if (!setting) {
setting = true;
+ undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
}
+ int prev = animation->bezier_track_get_key_handle_mode(track, key);
+ undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value);
+ undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev);
+ update_obj = true;
+ }
+ } break;
+ case Animation::TYPE_AUDIO: {
+ if (name == "stream") {
+ Ref<AudioStream> stream = p_value;
- undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new);
- undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old);
+ if (!setting) {
+ setting = true;
+ undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
+ }
+ Ref<Resource> prev = animation->audio_track_get_key_stream(track, key);
+ undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream);
+ undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_stream", track, key, prev);
update_obj = true;
- } break;
- case Animation::TYPE_BEZIER: {
- if (name == "value") {
- const Variant &value = p_value;
+ } else if (name == "start_offset") {
+ float value = p_value;
- if (!setting) {
- setting = true;
- undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- }
- float prev = animation->bezier_track_get_key_value(track, key);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_value", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_value", track, key, prev);
- update_obj = true;
- } else if (name == "in_handle") {
- const Variant &value = p_value;
-
- if (!setting) {
- setting = true;
- undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- }
- Vector2 prev = animation->bezier_track_get_key_in_handle(track, key);
- undo_redo->add_do_method(this, "_bezier_track_set_key_in_handle", track, key, value);
- undo_redo->add_undo_method(this, "_bezier_track_set_key_in_handle", track, key, prev);
- update_obj = true;
- } else if (name == "out_handle") {
- const Variant &value = p_value;
-
- if (!setting) {
- setting = true;
- undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- }
- Vector2 prev = animation->bezier_track_get_key_out_handle(track, key);
- undo_redo->add_do_method(this, "_bezier_track_set_key_out_handle", track, key, value);
- undo_redo->add_undo_method(this, "_bezier_track_set_key_out_handle", track, key, prev);
- update_obj = true;
- } else if (name == "handle_mode") {
- const Variant &value = p_value;
-
- if (!setting) {
- setting = true;
- undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- }
- int prev = animation->bezier_track_get_key_handle_mode(track, key);
- undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value);
- undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev);
- update_obj = true;
+ if (!setting) {
+ setting = true;
+ undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
}
- } break;
- case Animation::TYPE_AUDIO: {
- if (name == "stream") {
- Ref<AudioStream> stream = p_value;
+ float prev = animation->audio_track_get_key_start_offset(track, key);
+ undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, value);
+ undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, prev);
+ update_obj = true;
+ } else if (name == "end_offset") {
+ float value = p_value;
- if (!setting) {
- setting = true;
- undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- }
- Ref<Resource> prev = animation->audio_track_get_key_stream(track, key);
- undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream);
- undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_stream", track, key, prev);
- update_obj = true;
- } else if (name == "start_offset") {
- float value = p_value;
-
- if (!setting) {
- setting = true;
- undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- }
- float prev = animation->audio_track_get_key_start_offset(track, key);
- undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, prev);
- update_obj = true;
- } else if (name == "end_offset") {
- float value = p_value;
-
- if (!setting) {
- setting = true;
- undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- }
- float prev = animation->audio_track_get_key_end_offset(track, key);
- undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, prev);
- update_obj = true;
+ if (!setting) {
+ setting = true;
+ undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
}
- } break;
- case Animation::TYPE_ANIMATION: {
- if (name == "animation") {
- StringName anim_name = p_value;
+ float prev = animation->audio_track_get_key_end_offset(track, key);
+ undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, value);
+ undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, prev);
+ update_obj = true;
+ }
+ } break;
+ case Animation::TYPE_ANIMATION: {
+ if (name == "animation") {
+ StringName anim_name = p_value;
- if (!setting) {
- setting = true;
- undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- }
- StringName prev = animation->animation_track_get_key_animation(track, key);
- undo_redo->add_do_method(animation.ptr(), "animation_track_set_key_animation", track, key, anim_name);
- undo_redo->add_undo_method(animation.ptr(), "animation_track_set_key_animation", track, key, prev);
- update_obj = true;
+ if (!setting) {
+ setting = true;
+ undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
}
- } break;
- }
+ StringName prev = animation->animation_track_get_key_animation(track, key);
+ undo_redo->add_do_method(animation.ptr(), "animation_track_set_key_animation", track, key, anim_name);
+ undo_redo->add_undo_method(animation.ptr(), "animation_track_set_key_animation", track, key, prev);
+ update_obj = true;
+ }
+ } break;
}
}
+ }
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
- if (setting) {
- if (update_obj) {
- undo_redo->add_do_method(this, "_update_obj", animation);
- undo_redo->add_undo_method(this, "_update_obj", animation);
- }
-
- undo_redo->commit_action();
- setting = false;
+ Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ if (setting) {
+ if (update_obj) {
+ undo_redo->add_do_method(this, "_update_obj", animation);
+ undo_redo->add_undo_method(this, "_update_obj", animation);
+ }
- if (change_notify_deserved) {
- notify_change();
- }
+ undo_redo->commit_action();
+ setting = false;
- return true;
+ if (change_notify_deserved) {
+ notify_change();
}
- return false;
+ return true;
}
- bool _get(const StringName &p_name, Variant &r_ret) const {
- for (const KeyValue<int, List<float>> &E : key_ofs_map) {
- int track = E.key;
- for (const float &key_ofs : E.value) {
- int key = animation->track_find_key(track, key_ofs, true);
- ERR_CONTINUE(key == -1);
+ return false;
+}
- String name = p_name;
- if (name == "time") {
- r_ret = key_ofs;
- return true;
- }
+bool AnimationMultiTrackKeyEdit::_get(const StringName &p_name, Variant &r_ret) const {
+ for (const KeyValue<int, List<float>> &E : key_ofs_map) {
+ int track = E.key;
+ for (const float &key_ofs : E.value) {
+ int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
+ ERR_CONTINUE(key == -1);
- if (name == "frame") {
- float fps = animation->get_step();
- if (fps > 0) {
- fps = 1.0 / fps;
+ String name = p_name;
+ if (name == "easing") {
+ r_ret = animation->track_get_key_transition(track, key);
+ return true;
+ }
+
+ switch (animation->track_get_type(track)) {
+ case Animation::TYPE_POSITION_3D:
+ case Animation::TYPE_ROTATION_3D:
+ case Animation::TYPE_SCALE_3D: {
+ if (name == "position" || name == "rotation" || name == "scale") {
+ r_ret = animation->track_get_key_value(track, key);
+ return true;
}
- r_ret = key_ofs * fps;
- return true;
- }
- if (name == "easing") {
- r_ret = animation->track_get_key_transition(track, key);
- return true;
- }
+ } break;
+ case Animation::TYPE_BLEND_SHAPE:
+ case Animation::TYPE_VALUE: {
+ if (name == "value") {
+ r_ret = animation->track_get_key_value(track, key);
+ return true;
+ }
- switch (animation->track_get_type(track)) {
- case Animation::TYPE_POSITION_3D:
- case Animation::TYPE_ROTATION_3D:
- case Animation::TYPE_SCALE_3D: {
- if (name == "position" || name == "rotation" || name == "scale") {
- r_ret = animation->track_get_key_value(track, key);
- return true;
- }
+ } break;
+ case Animation::TYPE_METHOD: {
+ Dictionary d = animation->track_get_key_value(track, key);
- } break;
- case Animation::TYPE_BLEND_SHAPE:
- case Animation::TYPE_VALUE: {
- if (name == "value") {
- r_ret = animation->track_get_key_value(track, key);
- return true;
- }
+ if (name == "name") {
+ ERR_FAIL_COND_V(!d.has("method"), false);
+ r_ret = d["method"];
+ return true;
+ }
- } break;
- case Animation::TYPE_METHOD: {
- Dictionary d = animation->track_get_key_value(track, key);
+ ERR_FAIL_COND_V(!d.has("args"), false);
- if (name == "name") {
- ERR_FAIL_COND_V(!d.has("method"), false);
- r_ret = d["method"];
- return true;
- }
+ Vector<Variant> args = d["args"];
- ERR_FAIL_COND_V(!d.has("args"), false);
+ if (name == "arg_count") {
+ r_ret = args.size();
+ return true;
+ }
- Vector<Variant> args = d["args"];
+ if (name.begins_with("args/")) {
+ int idx = name.get_slice("/", 1).to_int();
+ ERR_FAIL_INDEX_V(idx, args.size(), false);
- if (name == "arg_count") {
- r_ret = args.size();
+ String what = name.get_slice("/", 2);
+ if (what == "type") {
+ r_ret = args[idx].get_type();
return true;
}
- if (name.begins_with("args/")) {
- int idx = name.get_slice("/", 1).to_int();
- ERR_FAIL_INDEX_V(idx, args.size(), false);
-
- String what = name.get_slice("/", 2);
- if (what == "type") {
- r_ret = args[idx].get_type();
- return true;
- }
-
- if (what == "value") {
- r_ret = args[idx];
- return true;
- }
- }
-
- } break;
- case Animation::TYPE_BEZIER: {
- if (name == "value") {
- r_ret = animation->bezier_track_get_key_value(track, key);
+ if (what == "value") {
+ r_ret = args[idx];
return true;
}
+ }
- if (name == "in_handle") {
- r_ret = animation->bezier_track_get_key_in_handle(track, key);
- return true;
- }
+ } break;
+ case Animation::TYPE_BEZIER: {
+ if (name == "value") {
+ r_ret = animation->bezier_track_get_key_value(track, key);
+ return true;
+ }
- if (name == "out_handle") {
- r_ret = animation->bezier_track_get_key_out_handle(track, key);
- return true;
- }
+ if (name == "in_handle") {
+ r_ret = animation->bezier_track_get_key_in_handle(track, key);
+ return true;
+ }
- if (name == "handle_mode") {
- r_ret = animation->bezier_track_get_key_handle_mode(track, key);
- return true;
- }
+ if (name == "out_handle") {
+ r_ret = animation->bezier_track_get_key_out_handle(track, key);
+ return true;
+ }
- } break;
- case Animation::TYPE_AUDIO: {
- if (name == "stream") {
- r_ret = animation->audio_track_get_key_stream(track, key);
- return true;
- }
+ if (name == "handle_mode") {
+ r_ret = animation->bezier_track_get_key_handle_mode(track, key);
+ return true;
+ }
- if (name == "start_offset") {
- r_ret = animation->audio_track_get_key_start_offset(track, key);
- return true;
- }
+ } break;
+ case Animation::TYPE_AUDIO: {
+ if (name == "stream") {
+ r_ret = animation->audio_track_get_key_stream(track, key);
+ return true;
+ }
- if (name == "end_offset") {
- r_ret = animation->audio_track_get_key_end_offset(track, key);
- return true;
- }
+ if (name == "start_offset") {
+ r_ret = animation->audio_track_get_key_start_offset(track, key);
+ return true;
+ }
- } break;
- case Animation::TYPE_ANIMATION: {
- if (name == "animation") {
- r_ret = animation->animation_track_get_key_animation(track, key);
- return true;
- }
+ if (name == "end_offset") {
+ r_ret = animation->audio_track_get_key_end_offset(track, key);
+ return true;
+ }
- } break;
- }
+ } break;
+ case Animation::TYPE_ANIMATION: {
+ if (name == "animation") {
+ r_ret = animation->animation_track_get_key_animation(track, key);
+ return true;
+ }
+
+ } break;
}
}
+ }
- return false;
+ return false;
+}
+
+void AnimationMultiTrackKeyEdit::_get_property_list(List<PropertyInfo> *p_list) const {
+ if (animation.is_null()) {
+ return;
}
- void _get_property_list(List<PropertyInfo> *p_list) const {
- if (animation.is_null()) {
- return;
- }
- int first_track = -1;
- float first_key = -1.0;
+ int first_track = -1;
+ float first_key = -1.0;
- bool show_time = true;
- bool same_track_type = true;
- bool same_key_type = true;
- for (const KeyValue<int, List<float>> &E : key_ofs_map) {
- int track = E.key;
- ERR_FAIL_INDEX(track, animation->get_track_count());
+ bool same_track_type = true;
+ bool same_key_type = true;
+ for (const KeyValue<int, List<float>> &E : key_ofs_map) {
+ int track = E.key;
+ ERR_FAIL_INDEX(track, animation->get_track_count());
- if (first_track < 0) {
- first_track = track;
- }
+ if (first_track < 0) {
+ first_track = track;
+ }
- if (show_time && E.value.size() > 1) {
- show_time = false;
+ if (same_track_type) {
+ if (animation->track_get_type(first_track) != animation->track_get_type(track)) {
+ same_track_type = false;
+ same_key_type = false;
}
- if (same_track_type) {
- if (animation->track_get_type(first_track) != animation->track_get_type(track)) {
- same_track_type = false;
- same_key_type = false;
+ for (const float &F : E.value) {
+ int key = animation->track_find_key(track, F, Animation::FIND_MODE_APPROX);
+ ERR_FAIL_COND(key == -1);
+ if (first_key < 0) {
+ first_key = key;
}
- for (const float &F : E.value) {
- int key = animation->track_find_key(track, F, true);
- ERR_FAIL_COND(key == -1);
- if (first_key < 0) {
- first_key = key;
- }
-
- if (animation->track_get_key_value(first_track, first_key).get_type() != animation->track_get_key_value(track, key).get_type()) {
- same_key_type = false;
- }
+ if (animation->track_get_key_value(first_track, first_key).get_type() != animation->track_get_key_value(track, key).get_type()) {
+ same_key_type = false;
}
}
}
+ }
- if (show_time) {
- if (use_fps && animation->get_step() > 0) {
- float max_frame = animation->get_length() / animation->get_step();
- p_list->push_back(PropertyInfo(Variant::FLOAT, "frame", PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",1"));
- } else {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "time", PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01"));
- }
- }
-
- if (same_track_type) {
- switch (animation->track_get_type(first_track)) {
- case Animation::TYPE_POSITION_3D: {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "position"));
- } break;
- case Animation::TYPE_ROTATION_3D: {
- p_list->push_back(PropertyInfo(Variant::QUATERNION, "scale"));
- } break;
- case Animation::TYPE_SCALE_3D: {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
- } break;
- case Animation::TYPE_BLEND_SHAPE: {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "value"));
- } break;
- case Animation::TYPE_VALUE: {
- if (same_key_type) {
- Variant v = animation->track_get_key_value(first_track, first_key);
+ if (same_track_type) {
+ switch (animation->track_get_type(first_track)) {
+ case Animation::TYPE_POSITION_3D: {
+ p_list->push_back(PropertyInfo(Variant::VECTOR3, "position"));
+ } break;
+ case Animation::TYPE_ROTATION_3D: {
+ p_list->push_back(PropertyInfo(Variant::QUATERNION, "scale"));
+ } break;
+ case Animation::TYPE_SCALE_3D: {
+ p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
+ } break;
+ case Animation::TYPE_BLEND_SHAPE: {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "value"));
+ } break;
+ case Animation::TYPE_VALUE: {
+ if (same_key_type) {
+ Variant v = animation->track_get_key_value(first_track, first_key);
- if (hint.type != Variant::NIL) {
- PropertyInfo pi = hint;
- pi.name = "value";
- p_list->push_back(pi);
- } else {
- PropertyHint val_hint = PROPERTY_HINT_NONE;
- String val_hint_string;
-
- if (v.get_type() == Variant::OBJECT) {
- // Could actually check the object property if exists..? Yes I will!
- Ref<Resource> res = v;
- if (res.is_valid()) {
- val_hint = PROPERTY_HINT_RESOURCE_TYPE;
- val_hint_string = res->get_class();
- }
+ if (hint.type != Variant::NIL) {
+ PropertyInfo pi = hint;
+ pi.name = "value";
+ p_list->push_back(pi);
+ } else {
+ PropertyHint val_hint = PROPERTY_HINT_NONE;
+ String val_hint_string;
+
+ if (v.get_type() == Variant::OBJECT) {
+ // Could actually check the object property if exists..? Yes I will!
+ Ref<Resource> res = v;
+ if (res.is_valid()) {
+ val_hint = PROPERTY_HINT_RESOURCE_TYPE;
+ val_hint_string = res->get_class();
}
+ }
- if (v.get_type() != Variant::NIL) {
- p_list->push_back(PropertyInfo(v.get_type(), "value", val_hint, val_hint_string));
- }
+ if (v.get_type() != Variant::NIL) {
+ p_list->push_back(PropertyInfo(v.get_type(), "value", val_hint, val_hint_string));
}
}
+ }
- p_list->push_back(PropertyInfo(Variant::FLOAT, "easing", PROPERTY_HINT_EXP_EASING));
- } break;
- case Animation::TYPE_METHOD: {
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, "name"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "easing", PROPERTY_HINT_EXP_EASING));
+ } break;
+ case Animation::TYPE_METHOD: {
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, "name"));
- p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,32,1,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,32,1,or_greater"));
- Dictionary d = animation->track_get_key_value(first_track, first_key);
- ERR_FAIL_COND(!d.has("args"));
- Vector<Variant> args = d["args"];
- String vtypes;
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (i > 0) {
- vtypes += ",";
- }
- vtypes += Variant::get_type_name(Variant::Type(i));
+ Dictionary d = animation->track_get_key_value(first_track, first_key);
+ ERR_FAIL_COND(!d.has("args"));
+ Vector<Variant> args = d["args"];
+ String vtypes;
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ if (i > 0) {
+ vtypes += ",";
}
+ vtypes += Variant::get_type_name(Variant::Type(i));
+ }
- for (int i = 0; i < args.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::INT, "args/" + itos(i) + "/type", PROPERTY_HINT_ENUM, vtypes));
- if (args[i].get_type() != Variant::NIL) {
- p_list->push_back(PropertyInfo(args[i].get_type(), "args/" + itos(i) + "/value"));
- }
- }
- } break;
- case Animation::TYPE_BEZIER: {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "value"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "in_handle"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "out_handle"));
- p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored"));
- } break;
- case Animation::TYPE_AUDIO: {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "start_offset", PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "end_offset", PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater"));
- } break;
- case Animation::TYPE_ANIMATION: {
- if (key_ofs_map.size() > 1) {
- break;
+ for (int i = 0; i < args.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::INT, "args/" + itos(i) + "/type", PROPERTY_HINT_ENUM, vtypes));
+ if (args[i].get_type() != Variant::NIL) {
+ p_list->push_back(PropertyInfo(args[i].get_type(), "args/" + itos(i) + "/value"));
}
+ }
+ } break;
+ case Animation::TYPE_BEZIER: {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "value"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "in_handle"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "out_handle"));
+ p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored"));
+ } break;
+ case Animation::TYPE_AUDIO: {
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "start_offset", PROPERTY_HINT_RANGE, "0,3600,0.0001,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "end_offset", PROPERTY_HINT_RANGE, "0,3600,0.0001,or_greater"));
+ } break;
+ case Animation::TYPE_ANIMATION: {
+ if (key_ofs_map.size() > 1) {
+ break;
+ }
- String animations;
-
- if (root_path && root_path->has_node(animation->track_get_path(first_track))) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(root_path->get_node(animation->track_get_path(first_track)));
- if (ap) {
- List<StringName> anims;
- ap->get_animation_list(&anims);
- for (List<StringName>::Element *G = anims.front(); G; G = G->next()) {
- if (!animations.is_empty()) {
- animations += ",";
- }
+ String animations;
- animations += String(G->get());
+ if (root_path && root_path->has_node(animation->track_get_path(first_track))) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(root_path->get_node(animation->track_get_path(first_track)));
+ if (ap) {
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ for (List<StringName>::Element *G = anims.front(); G; G = G->next()) {
+ if (!animations.is_empty()) {
+ animations += ",";
}
+
+ animations += String(G->get());
}
}
+ }
- if (!animations.is_empty()) {
- animations += ",";
- }
- animations += "[stop]";
+ if (!animations.is_empty()) {
+ animations += ",";
+ }
+ animations += "[stop]";
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, "animation", PROPERTY_HINT_ENUM, animations));
- } break;
- }
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, "animation", PROPERTY_HINT_ENUM, animations));
+ } break;
}
}
+}
- Ref<Animation> animation;
-
- RBMap<int, List<float>> key_ofs_map;
- RBMap<int, NodePath> base_map;
- PropertyInfo hint;
-
- Node *root_path = nullptr;
-
- bool use_fps = false;
-
- void notify_change() {
- notify_property_list_changed();
- }
+void AnimationMultiTrackKeyEdit::notify_change() {
+ notify_property_list_changed();
+}
- Node *get_root_path() {
- return root_path;
- }
+Node *AnimationMultiTrackKeyEdit::get_root_path() {
+ return root_path;
+}
- void set_use_fps(bool p_enable) {
- use_fps = p_enable;
- notify_property_list_changed();
- }
-};
+void AnimationMultiTrackKeyEdit::set_use_fps(bool p_enable) {
+ use_fps = p_enable;
+ notify_property_list_changed();
+}
void AnimationTimelineEdit::_zoom_changed(double) {
queue_redraw();
@@ -1420,7 +1246,7 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
return;
}
- p_new_len = MAX(0.001, p_new_len);
+ p_new_len = MAX(0.0001, p_new_len);
if (use_fps && animation->get_step() > 0) {
p_new_len *= animation->get_step();
}
@@ -1539,7 +1365,7 @@ void AnimationTimelineEdit::_notification(int p_what) {
float l = animation->get_length();
if (l <= 0) {
- l = 0.001; // Avoid crashor.
+ l = 0.0001; // Avoid crashor.
}
Ref<Texture2D> hsize_icon = get_theme_icon(SNAME("Hsize"), SNAME("EditorIcons"));
@@ -1600,7 +1426,7 @@ void AnimationTimelineEdit::_notification(int p_what) {
end_px = zoomw;
}
- draw_rect(Rect2(Point2(get_name_limit() + begin_px, 0), Point2(end_px - begin_px - 1, h)), timecolor);
+ draw_rect(Rect2(Point2(get_name_limit() + begin_px, 0), Point2(end_px - begin_px, h)), timecolor);
}
}
@@ -1759,7 +1585,7 @@ void AnimationTimelineEdit::update_values() {
}
} else {
length->set_value(animation->get_length());
- length->set_step(0.001);
+ length->set_step(0.0001);
length->set_tooltip_text(TTR("Animation length (seconds)"));
time_icon->set_tooltip_text(TTR("Animation length (seconds)"));
}
@@ -1950,9 +1776,9 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
time_icon->set_tooltip_text(TTR("Animation length (seconds)"));
len_hb->add_child(time_icon);
length = memnew(EditorSpinSlider);
- length->set_min(0.001);
+ length->set_min(0.0001);
length->set_max(36000);
- length->set_step(0.001);
+ length->set_step(0.0001);
length->set_allow_greater(true);
length->set_custom_minimum_size(Vector2(70 * EDSCALE, 0));
length->set_hide_slider(true);
@@ -2058,7 +1884,7 @@ void AnimationTrackEdit::_notification(int p_what) {
} else if (animation->track_get_type(track) == Animation::TYPE_AUDIO) {
text = TTR("Audio Clips:");
} else if (animation->track_get_type(track) == Animation::TYPE_ANIMATION) {
- text = TTR("Anim Clips:");
+ text = TTR("Animation Clips:");
} else {
text += anim_path.get_concatenated_subnames();
}
@@ -2670,7 +2496,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
}
if (key_idx != -1) {
- String text = TTR("Time (s):") + " " + rtos(animation->track_get_key_time(track, key_idx)) + "\n";
+ String text = TTR("Time (s):") + " " + TS->format_number(rtos(Math::snapped(animation->track_get_key_time(track, key_idx), 0.0001))) + "\n";
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D: {
Vector3 t = animation->track_get_key_value(track, key_idx);
@@ -4390,7 +4216,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
p_next_tracks.normal++;
} else {
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_id.track_idx, time);
- int existing = animation->track_find_key(p_id.track_idx, time, true);
+ int existing = animation->track_find_key(p_id.track_idx, time, Animation::FIND_MODE_APPROX);
if (existing != -1) {
Variant v = animation->track_get_key_value(p_id.track_idx, existing);
float trans = animation->track_get_key_transition(p_id.track_idx, existing);
@@ -5005,8 +4831,8 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
if (snap->is_pressed() && step->get_value() != 0) {
p_ofs = snap_time(p_ofs);
}
- while (animation->track_find_key(p_track, p_ofs, true) != -1) { // Make sure insertion point is valid.
- p_ofs += 0.001;
+ while (animation->track_find_key(p_track, p_ofs, Animation::FIND_MODE_APPROX) != -1) { // Make sure insertion point is valid.
+ p_ofs += 0.0001;
}
Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
@@ -5338,7 +5164,7 @@ void AnimationTrackEditor::_select_at_anim(const Ref<Animation> &p_anim, int p_t
return;
}
- int idx = animation->track_find_key(p_track, p_pos, true);
+ int idx = animation->track_find_key(p_track, p_pos, Animation::FIND_MODE_APPROX);
ERR_FAIL_COND(idx < 0);
SelectedKey sk;
@@ -5365,7 +5191,7 @@ void AnimationTrackEditor::_move_selection_commit() {
// 2 - Remove overlapped keys.
for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newtime = snap_time(E->get().pos + motion);
- int idx = animation->track_find_key(E->key().track, newtime, true);
+ int idx = animation->track_find_key(E->key().track, newtime, Animation::FIND_MODE_APPROX);
if (idx == -1) {
continue;
}
@@ -5625,7 +5451,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
continue;
}
- int existing_idx = animation->track_find_key(dst_track, dst_time, true);
+ int existing_idx = animation->track_find_key(dst_track, dst_time, Animation::FIND_MODE_APPROX);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", dst_track, dst_time, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", dst_track, dst_time);
@@ -5916,7 +5742,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
// 2 - Remove overlapped keys.
for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newtime = (E->get().pos - from_t) * s + from_t;
- int idx = animation->track_find_key(E->key().track, newtime, true);
+ int idx = animation->track_find_key(E->key().track, newtime, Animation::FIND_MODE_APPROX);
if (idx == -1) {
continue;
}
@@ -6127,7 +5953,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
undo_redo->add_do_method(reset.ptr(), "track_set_path", dst_track, path);
undo_redo->add_undo_method(reset.ptr(), "remove_track", dst_track);
} else {
- existing_idx = reset->track_find_key(dst_track, 0, true);
+ existing_idx = reset->track_find_key(dst_track, 0, Animation::FIND_MODE_APPROX);
}
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));
@@ -6656,7 +6482,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
step = memnew(EditorSpinSlider);
step->set_min(0);
step->set_max(1000000);
- step->set_step(0.001);
+ step->set_step(0.0001);
step->set_hide_slider(true);
step->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
step->set_tooltip_text(TTR("Animation step value."));
@@ -6946,3 +6772,103 @@ AnimationTrackEditor::~AnimationTrackEditor() {
memdelete(multi_key_edit);
}
}
+
+// AnimationTrackKeyEditEditorPlugin
+
+void AnimationTrackKeyEditEditor::_time_edit_entered() {
+ int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
+ if (key == -1) {
+ return;
+ }
+ key_data_cache.time = animation->track_get_key_time(track, key);
+ key_data_cache.transition = animation->track_get_key_transition(track, key);
+ key_data_cache.value = animation->track_get_key_value(track, key);
+}
+
+void AnimationTrackKeyEditEditor::_time_edit_exited() {
+ real_t new_time = spinner->get_value();
+
+ if (use_fps) {
+ real_t fps = animation->get_step();
+ if (fps > 0) {
+ fps = 1.0 / fps;
+ }
+ new_time /= fps;
+ }
+
+ if (Math::is_equal_approx(new_time, key_data_cache.time)) {
+ return; // No change.
+ }
+
+ int existing = animation->track_find_key(track, new_time, Animation::FIND_MODE_APPROX);
+ Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ undo_redo->create_action(TTR("Animation Change Keyframe Time"), UndoRedo::MERGE_ENDS);
+
+ if (existing != -1) {
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", track, animation->track_get_key_time(track, existing));
+ }
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", track, key_data_cache.time);
+ undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, key_data_cache.value, key_data_cache.transition);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time);
+ undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_data_cache.time, key_data_cache.value, key_data_cache.transition);
+ if (existing != -1) {
+ undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, animation->track_get_key_time(track, existing), animation->track_get_key_value(track, existing), animation->track_get_key_transition(track, existing));
+ }
+
+ // Reselect key.
+ AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
+ if (ape) {
+ AnimationTrackEditor *ate = ape->get_track_editor();
+ if (ate) {
+ undo_redo->add_do_method(ate, "_clear_selection_for_anim", animation);
+ undo_redo->add_undo_method(ate, "_clear_selection_for_anim", animation);
+ undo_redo->add_do_method(ate, "_select_at_anim", animation, track, new_time);
+ undo_redo->add_undo_method(ate, "_select_at_anim", animation, track, key_data_cache.time);
+ }
+ }
+
+ undo_redo->commit_action();
+}
+
+AnimationTrackKeyEditEditor::AnimationTrackKeyEditEditor(Ref<Animation> p_animation, int p_track, real_t p_key_ofs, bool p_use_fps) {
+ if (!p_animation.is_valid()) {
+ return;
+ }
+
+ animation = p_animation;
+ track = p_track;
+ key_ofs = p_key_ofs;
+ use_fps = p_use_fps;
+
+ set_label("Time");
+
+ spinner = memnew(EditorSpinSlider);
+ spinner->set_focus_mode(Control::FOCUS_CLICK);
+ spinner->set_min(0);
+ spinner->set_allow_greater(true);
+ spinner->set_allow_lesser(true);
+
+ if (use_fps) {
+ spinner->set_step(1);
+ spinner->set_hide_slider(true);
+ real_t fps = animation->get_step();
+ if (fps > 0) {
+ fps = 1.0 / fps;
+ }
+ spinner->set_value(key_ofs * fps);
+ } else {
+ spinner->set_step(0.0001);
+ spinner->set_value(key_ofs);
+ spinner->set_max(animation->get_length());
+ }
+
+ add_child(spinner);
+
+ spinner->connect("grabbed", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED);
+ spinner->connect("ungrabbed", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
+ spinner->connect("value_focus_entered", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED);
+ spinner->connect("value_focus_exited", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
+}
+
+AnimationTrackKeyEditEditor::~AnimationTrackKeyEditEditor() {
+}
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index 4b50424f39..5ae826bd5c 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -50,9 +50,83 @@
#include "scene/resources/animation.h"
#include "scene_tree_editor.h"
+class AnimationTrackEditor;
class AnimationTrackEdit;
class ViewPanner;
+class AnimationTrackKeyEdit : public Object {
+ GDCLASS(AnimationTrackKeyEdit, Object);
+
+public:
+ bool setting = false;
+ bool animation_read_only = false;
+
+ Ref<Animation> animation;
+ int track = -1;
+ float key_ofs = 0;
+ Node *root_path = nullptr;
+
+ PropertyInfo hint;
+ NodePath base;
+ bool use_fps = false;
+
+ bool _hide_script_from_inspector() { return true; }
+ bool _hide_metadata_from_inspector() { return true; }
+ bool _dont_undo_redo() { return true; }
+
+ bool _is_read_only() { return animation_read_only; }
+
+ void notify_change();
+ Node *get_root_path();
+ void set_use_fps(bool p_enable);
+
+protected:
+ static void _bind_methods();
+ void _fix_node_path(Variant &value);
+ void _update_obj(const Ref<Animation> &p_anim);
+ void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to);
+ 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;
+};
+
+class AnimationMultiTrackKeyEdit : public Object {
+ GDCLASS(AnimationMultiTrackKeyEdit, Object);
+
+public:
+ bool setting = false;
+ bool animation_read_only = false;
+
+ Ref<Animation> animation;
+
+ RBMap<int, List<float>> key_ofs_map;
+ RBMap<int, NodePath> base_map;
+ PropertyInfo hint;
+
+ Node *root_path = nullptr;
+
+ bool use_fps = false;
+
+ bool _hide_script_from_inspector() { return true; }
+ bool _hide_metadata_from_inspector() { return true; }
+ bool _dont_undo_redo() { return true; }
+
+ bool _is_read_only() { return animation_read_only; }
+
+ void notify_change();
+ Node *get_root_path();
+ void set_use_fps(bool p_enable);
+
+protected:
+ static void _bind_methods();
+ void _fix_node_path(Variant &value, NodePath &base);
+ void _update_obj(const Ref<Animation> &p_anim);
+ void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to);
+ 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;
+};
+
class AnimationTimelineEdit : public Range {
GDCLASS(AnimationTimelineEdit, Range);
@@ -129,8 +203,6 @@ public:
AnimationTimelineEdit();
};
-class AnimationTrackEditor;
-
class AnimationTrackEdit : public Control {
GDCLASS(AnimationTrackEdit, Control);
friend class AnimationTimelineEdit;
@@ -592,4 +664,30 @@ public:
~AnimationTrackEditor();
};
+// AnimationTrackKeyEditEditorPlugin
+
+class AnimationTrackKeyEditEditor : public EditorProperty {
+ GDCLASS(AnimationTrackKeyEditEditor, EditorProperty);
+
+ Ref<Animation> animation;
+ int track = -1;
+ real_t key_ofs = 0.0;
+ bool use_fps = false;
+
+ EditorSpinSlider *spinner = nullptr;
+
+ struct KeyDataCache {
+ real_t time = 0.0;
+ float transition = 0.0;
+ Variant value;
+ } key_data_cache;
+
+ void _time_edit_entered();
+ void _time_edit_exited();
+
+public:
+ AnimationTrackKeyEditEditor(Ref<Animation> p_animation, int p_track, real_t p_key_ofs, bool p_use_fps);
+ ~AnimationTrackKeyEditEditor();
+};
+
#endif // ANIMATION_TRACK_EDITOR_H
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index 704935e163..0ad62710eb 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -831,8 +831,8 @@ Rect2 AnimationTrackEditTypeAudio::get_key_rect(int p_index, float p_pixels_sec)
len -= end_ofs;
len -= start_ofs;
- if (len <= 0.001) {
- len = 0.001;
+ if (len <= 0.0001) {
+ len = 0.0001;
}
if (get_animation()->track_get_key_count(get_track()) > p_index + 1) {
@@ -887,8 +887,8 @@ void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int
len -= end_ofs;
len -= start_ofs;
- if (len <= 0.001) {
- len = 0.001;
+ if (len <= 0.0001) {
+ len = 0.0001;
}
int pixel_len = len * p_pixels_sec;
@@ -1014,8 +1014,8 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant
ofs = get_editor()->snap_time(ofs);
- while (get_animation()->track_find_key(get_track(), ofs, true) != -1) { //make sure insertion point is valid
- ofs += 0.001;
+ while (get_animation()->track_find_key(get_track(), ofs, Animation::FIND_MODE_APPROX) != -1) { //make sure insertion point is valid
+ ofs += 0.0001;
}
Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp
index 8b31781c5e..351af4508f 100644
--- a/editor/debugger/editor_debugger_tree.cpp
+++ b/editor/debugger/editor_debugger_tree.cpp
@@ -118,6 +118,7 @@ void EditorDebuggerTree::_scene_tree_rmb_selected(const Vector2 &p_position, Mou
item_menu->add_icon_item(get_theme_icon(SNAME("CreateNewSceneFrom"), SNAME("EditorIcons")), TTR("Save Branch as Scene"), ITEM_MENU_SAVE_REMOTE_NODE);
item_menu->add_icon_item(get_theme_icon(SNAME("CopyNodePath"), SNAME("EditorIcons")), TTR("Copy Node Path"), ITEM_MENU_COPY_NODE_PATH);
item_menu->set_position(get_screen_position() + get_local_mouse_position());
+ item_menu->reset_size();
item_menu->popup();
}
@@ -323,6 +324,8 @@ void EditorDebuggerTree::_item_menu_id_pressed(int p_option) {
file_dialog->add_filter("*." + extensions[i], extensions[i].to_upper());
}
+ String filename = get_selected_path().get_file() + "." + extensions.front()->get().to_lower();
+ file_dialog->set_current_path(filename);
file_dialog->popup_file_dialog();
} break;
case ITEM_MENU_COPY_NODE_PATH: {
diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp
index 35666a5566..0f8b2f36be 100644
--- a/editor/debugger/editor_profiler.cpp
+++ b/editor/debugger/editor_profiler.cpp
@@ -106,7 +106,7 @@ void EditorProfiler::clear() {
seeking = false;
// Ensure button text (start, stop) is correct
- _set_button_text();
+ _update_button_text();
emit_signal(SNAME("enable_profiling"), activate->is_pressed());
}
@@ -376,7 +376,7 @@ void EditorProfiler::_update_frame() {
updating_frame = false;
}
-void EditorProfiler::_set_button_text() {
+void EditorProfiler::_update_button_text() {
if (activate->is_pressed()) {
activate->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
activate->set_text(TTR("Stop"));
@@ -387,7 +387,7 @@ void EditorProfiler::_set_button_text() {
}
void EditorProfiler::_activate_pressed() {
- _set_button_text();
+ _update_button_text();
if (activate->is_pressed()) {
_clear_pressed();
@@ -510,13 +510,17 @@ void EditorProfiler::_bind_methods() {
}
void EditorProfiler::set_enabled(bool p_enable, bool p_clear) {
- activate->set_pressed(false);
activate->set_disabled(!p_enable);
if (p_clear) {
clear();
}
}
+void EditorProfiler::set_pressed(bool p_pressed) {
+ activate->set_pressed(p_pressed);
+ _update_button_text();
+}
+
bool EditorProfiler::is_profiling() {
return activate->is_pressed();
}
@@ -595,6 +599,7 @@ EditorProfiler::EditorProfiler() {
add_child(hb);
activate = memnew(Button);
activate->set_toggle_mode(true);
+ activate->set_disabled(true);
activate->set_text(TTR("Start"));
activate->connect("pressed", callable_mp(this, &EditorProfiler::_activate_pressed));
hb->add_child(activate);
diff --git a/editor/debugger/editor_profiler.h b/editor/debugger/editor_profiler.h
index e9ecc285ed..d0dd67688b 100644
--- a/editor/debugger/editor_profiler.h
+++ b/editor/debugger/editor_profiler.h
@@ -122,7 +122,7 @@ private:
Timer *frame_delay = nullptr;
Timer *plot_delay = nullptr;
- void _set_button_text();
+ void _update_button_text();
void _update_frame();
void _activate_pressed();
@@ -155,6 +155,7 @@ protected:
public:
void add_frame_metric(const Metric &p_metric, bool p_final = false);
void set_enabled(bool p_enable, bool p_clear = true);
+ void set_pressed(bool p_pressed);
bool is_profiling();
bool is_seeking() { return seeking; }
void disable_seeking();
diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp
index b8bc712ba6..fe425220c9 100644
--- a/editor/debugger/editor_visual_profiler.cpp
+++ b/editor/debugger/editor_visual_profiler.cpp
@@ -66,6 +66,7 @@ void EditorVisualProfiler::add_frame_metric(const Metric &p_metric) {
}
updating_frame = true;
+ clear_button->set_disabled(false);
cursor_metric_edit->set_max(frame_metrics[last_metric].frame_number);
cursor_metric_edit->set_min(MAX(frame_metrics[last_metric].frame_number - frame_metrics.size(), 0u));
@@ -408,6 +409,7 @@ void EditorVisualProfiler::_activate_pressed() {
activate->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
activate->set_text(TTR("Stop"));
_clear_pressed(); //always clear on start
+ clear_button->set_disabled(false);
} else {
activate->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons")));
activate->set_text(TTR("Start"));
@@ -416,6 +418,7 @@ void EditorVisualProfiler::_activate_pressed() {
}
void EditorVisualProfiler::_clear_pressed() {
+ clear_button->set_disabled(true);
clear();
_update_plot();
}
@@ -647,10 +650,25 @@ void EditorVisualProfiler::_bind_methods() {
ADD_SIGNAL(MethodInfo("enable_profiling", PropertyInfo(Variant::BOOL, "enable")));
}
+void EditorVisualProfiler::_update_button_text() {
+ if (activate->is_pressed()) {
+ activate->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
+ activate->set_text(TTR("Stop"));
+ } else {
+ activate->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons")));
+ activate->set_text(TTR("Start"));
+ }
+}
+
void EditorVisualProfiler::set_enabled(bool p_enable) {
activate->set_disabled(!p_enable);
}
+void EditorVisualProfiler::set_pressed(bool p_pressed) {
+ activate->set_pressed(p_pressed);
+ _update_button_text();
+}
+
bool EditorVisualProfiler::is_profiling() {
return activate->is_pressed();
}
@@ -714,12 +732,14 @@ EditorVisualProfiler::EditorVisualProfiler() {
add_child(hb);
activate = memnew(Button);
activate->set_toggle_mode(true);
+ activate->set_disabled(true);
activate->set_text(TTR("Start"));
activate->connect("pressed", callable_mp(this, &EditorVisualProfiler::_activate_pressed));
hb->add_child(activate);
clear_button = memnew(Button);
clear_button->set_text(TTR("Clear"));
+ clear_button->set_disabled(true);
clear_button->connect("pressed", callable_mp(this, &EditorVisualProfiler::_clear_pressed));
hb->add_child(clear_button);
diff --git a/editor/debugger/editor_visual_profiler.h b/editor/debugger/editor_visual_profiler.h
index 8aa9e7b308..8180d354e8 100644
--- a/editor/debugger/editor_visual_profiler.h
+++ b/editor/debugger/editor_visual_profiler.h
@@ -101,6 +101,8 @@ private:
Timer *frame_delay = nullptr;
Timer *plot_delay = nullptr;
+ void _update_button_text();
+
void _update_frame(bool p_focus_selected = false);
void _activate_pressed();
@@ -133,6 +135,7 @@ protected:
public:
void add_frame_metric(const Metric &p_metric);
void set_enabled(bool p_enable);
+ void set_pressed(bool p_pressed);
bool is_profiling();
bool is_seeking() { return seeking; }
void disable_seeking();
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index deca638f3b..f6b00b83b0 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -319,6 +319,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
tabs->set_current_tab(0);
}
profiler->set_enabled(false, false);
+ visual_profiler->set_enabled(false);
inspector->clear_cache(); // Take a chance to force remote objects update.
} else if (p_msg == "debug_exit") {
@@ -328,8 +329,12 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
_update_buttons_state();
_set_reason_text(TTR("Execution resumed."), MESSAGE_SUCCESS);
emit_signal(SNAME("breaked"), false, false, "", false);
+
profiler->set_enabled(true, false);
profiler->disable_seeking();
+
+ visual_profiler->set_enabled(true);
+
} else if (p_msg == "set_pid") {
ERR_FAIL_COND(p_data.size() < 1);
remote_pid = p_data[0];
@@ -751,7 +756,16 @@ void ScriptEditorDebugger::_set_reason_text(const String &p_reason, MessageType
reason->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
}
reason->set_text(p_reason);
- reason->set_tooltip_text(p_reason.word_wrap(80));
+
+ const PackedInt32Array boundaries = TS->string_get_word_breaks(p_reason, "", 80);
+ PackedStringArray lines;
+ for (int i = 0; i < boundaries.size(); i += 2) {
+ const int start = boundaries[i];
+ const int end = boundaries[i + 1];
+ lines.append(p_reason.substr(start, end - start + 1));
+ }
+
+ reason->set_tooltip_text(String("\n").join(lines));
}
void ScriptEditorDebugger::_notification(int p_what) {
@@ -892,6 +906,7 @@ void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) {
stop();
profiler->set_enabled(true, true);
+ visual_profiler->set_enabled(true);
peer = p_peer;
ERR_FAIL_COND(p_peer.is_null());
@@ -948,7 +963,11 @@ void ScriptEditorDebugger::stop() {
res_path_cache.clear();
profiler_signature.clear();
- profiler->set_enabled(true, false);
+ profiler->set_enabled(false, false);
+ profiler->set_pressed(false);
+
+ visual_profiler->set_enabled(false);
+ visual_profiler->set_pressed(false);
inspector->edit(nullptr);
_update_buttons_state();
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index f15b874c45..e593d652ad 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -947,9 +947,10 @@ Variant EditorData::script_class_instance(const String &p_class) {
if (ScriptServer::is_global_class(p_class)) {
Ref<Script> script = script_class_load_script(p_class);
if (script.is_valid()) {
- Object *obj = ClassDB::instantiate(script->get_instance_base_type());
+ // Store in a variant to initialize the refcount if needed.
+ Variant obj = ClassDB::instantiate(script->get_instance_base_type());
if (obj) {
- obj->set_script(script);
+ obj.operator Object *()->set_script(script);
}
return obj;
}
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 55c512f77d..a9c46d4d94 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -1500,7 +1500,7 @@ void EditorFileDialog::_go_back() {
}
void EditorFileDialog::_go_forward() {
- if (local_history_pos == local_history.size() - 1) {
+ if (local_history_pos >= local_history.size() - 1) {
return;
}
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index a5397a8e6a..9a3eb75416 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1172,6 +1172,36 @@ void EditorInspectorSection::_test_unfold() {
}
}
+Ref<Texture2D> EditorInspectorSection::_get_arrow() {
+ Ref<Texture2D> arrow;
+ if (foldable) {
+ if (object->editor_is_section_unfolded(section)) {
+ arrow = get_theme_icon(SNAME("arrow"), SNAME("Tree"));
+ } else {
+ if (is_layout_rtl()) {
+ arrow = get_theme_icon(SNAME("arrow_collapsed_mirrored"), SNAME("Tree"));
+ } else {
+ arrow = get_theme_icon(SNAME("arrow_collapsed"), SNAME("Tree"));
+ }
+ }
+ }
+ return arrow;
+}
+
+int EditorInspectorSection::_get_header_height() {
+ Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
+ int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
+
+ int header_height = font->get_height(font_size);
+ Ref<Texture2D> arrow = _get_arrow();
+ if (arrow.is_valid()) {
+ header_height = MAX(header_height, arrow->get_height());
+ }
+ header_height += get_theme_constant(SNAME("v_separation"), SNAME("Tree"));
+
+ return header_height;
+}
+
void EditorInspectorSection::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
@@ -1182,30 +1212,6 @@ void EditorInspectorSection::_notification(int p_what) {
if (!vbox_added) {
return;
}
- // Get the section header font.
- Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
- int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
-
- // Get the right direction arrow texture, if the section is foldable.
- Ref<Texture2D> arrow;
- if (foldable) {
- if (object->editor_is_section_unfolded(section)) {
- arrow = get_theme_icon(SNAME("arrow"), SNAME("Tree"));
- } else {
- if (is_layout_rtl()) {
- arrow = get_theme_icon(SNAME("arrow_collapsed_mirrored"), SNAME("Tree"));
- } else {
- arrow = get_theme_icon(SNAME("arrow_collapsed"), SNAME("Tree"));
- }
- }
- }
-
- // Compute the height of the section header.
- int header_height = font->get_height(font_size);
- if (arrow.is_valid()) {
- header_height = MAX(header_height, arrow->get_height());
- }
- header_height += get_theme_constant(SNAME("v_separation"), SNAME("Tree"));
int inspector_margin = get_theme_constant(SNAME("inspector_margin"), SNAME("Editor"));
int section_indent_size = get_theme_constant(SNAME("indent_size"), SNAME("EditorInspectorSection"));
@@ -1218,6 +1224,7 @@ void EditorInspectorSection::_notification(int p_what) {
}
Size2 size = get_size() - Vector2(inspector_margin, 0);
+ int header_height = _get_header_height();
Vector2 offset = Vector2(is_layout_rtl() ? 0 : inspector_margin, header_height);
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
@@ -1233,36 +1240,6 @@ void EditorInspectorSection::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
- // Get the section header font.
- Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
- int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
- Color font_color = get_theme_color(SNAME("font_color"), SNAME("Editor"));
-
- // Get the right direction arrow texture, if the section is foldable.
- Ref<Texture2D> arrow;
- bool folded = foldable;
- if (foldable) {
- if (object->editor_is_section_unfolded(section)) {
- arrow = get_theme_icon(SNAME("arrow"), SNAME("Tree"));
- folded = false;
- } else {
- if (is_layout_rtl()) {
- arrow = get_theme_icon(SNAME("arrow_collapsed_mirrored"), SNAME("Tree"));
- } else {
- arrow = get_theme_icon(SNAME("arrow_collapsed"), SNAME("Tree"));
- }
- }
- }
-
- bool rtl = is_layout_rtl();
-
- // Compute the height and width of the section header.
- int header_height = font->get_height(font_size);
- if (arrow.is_valid()) {
- header_height = MAX(header_height, arrow->get_height());
- }
- header_height += get_theme_constant(SNAME("v_separation"), SNAME("Tree"));
-
int section_indent = 0;
int section_indent_size = get_theme_constant(SNAME("indent_size"), SNAME("EditorInspectorSection"));
if (indent_depth > 0 && section_indent_size > 0) {
@@ -1275,11 +1252,13 @@ void EditorInspectorSection::_notification(int p_what) {
int header_width = get_size().width - section_indent;
int header_offset_x = 0.0;
+ bool rtl = is_layout_rtl();
if (!rtl) {
header_offset_x += section_indent;
}
// Draw header area.
+ int header_height = _get_header_height();
Rect2 header_rect = Rect2(Vector2(header_offset_x, 0.0), Vector2(header_width, header_height));
Color c = bg_color;
c.a *= 0.4;
@@ -1288,7 +1267,7 @@ void EditorInspectorSection::_notification(int p_what) {
}
draw_rect(header_rect, c);
- // Draw header title, folding arrow and coutn of revertable properties.
+ // Draw header title, folding arrow and count of revertable properties.
{
int separation = Math::round(2 * EDSCALE);
@@ -1296,6 +1275,7 @@ void EditorInspectorSection::_notification(int p_what) {
int margin_end = separation;
// - Arrow.
+ Ref<Texture2D> arrow = _get_arrow();
if (arrow.is_valid()) {
Point2 arrow_position;
if (rtl) {
@@ -1313,6 +1293,13 @@ void EditorInspectorSection::_notification(int p_what) {
// - Count of revertable properties.
String num_revertable_str;
int num_revertable_width = 0;
+
+ bool folded = foldable && !object->editor_is_section_unfolded(section);
+
+ Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
+ int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
+ Color font_color = get_theme_color(SNAME("font_color"), SNAME("Editor"));
+
if (folded && revertable_properties.size()) {
int label_width = font->get_string_size(label, HORIZONTAL_ALIGNMENT_LEFT, available, font_size, TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS).x;
@@ -1481,10 +1468,12 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Tree"));
- int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Tree"));
- if (mb->get_position().y > font->get_height(font_size)) { //clicked outside
- return;
+ if (object->editor_is_section_unfolded(section)) {
+ int header_height = _get_header_height();
+
+ if (mb->get_position().y >= header_height) {
+ return;
+ }
}
accept_event();
@@ -2597,7 +2586,7 @@ bool EditorInspector::_is_property_disabled_by_feature_profile(const StringName
return false;
}
-void EditorInspector::update_tree() {
+void EditorInspector::_update_tree() {
//to update properly if all is refreshed
StringName current_selected = property_selected;
int current_focusable = -1;
@@ -3316,6 +3305,10 @@ void EditorInspector::update_tree() {
}
}
+void EditorInspector::update_tree() {
+ update_tree_pending = true;
+}
+
void EditorInspector::update_property(const String &p_prop) {
if (!editor_property_map.has(p_prop)) {
return;
@@ -3372,7 +3365,10 @@ void EditorInspector::set_keying(bool p_active) {
return;
}
keying = p_active;
- update_tree();
+ // Propagate the keying state to its editor properties.
+ Array args;
+ args.append(keying);
+ main_vbox->propagate_call(SNAME("set_keying"), args, true);
}
void EditorInspector::set_read_only(bool p_read_only) {
@@ -3910,10 +3906,9 @@ void EditorInspector::_notification(int p_what) {
changing++;
if (update_tree_pending) {
- update_tree();
update_tree_pending = false;
pending.clear();
-
+ _update_tree();
} else {
while (pending.size()) {
StringName prop = *pending.begin();
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 41651494ce..53490f0880 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -280,6 +280,8 @@ class EditorInspectorSection : public Container {
HashSet<StringName> revertable_properties;
void _test_unfold();
+ int _get_header_height();
+ Ref<Texture2D> _get_arrow();
protected:
Object *object = nullptr;
@@ -540,6 +542,8 @@ class EditorInspector : public ScrollContainer {
void _show_add_meta_dialog();
void _check_meta_name(const String &p_name);
+ void _update_tree();
+
protected:
static void _bind_methods();
void _notification(int p_what);
diff --git a/editor/editor_layouts_dialog.cpp b/editor/editor_layouts_dialog.cpp
index 886e29a504..19b137c7fd 100644
--- a/editor/editor_layouts_dialog.cpp
+++ b/editor/editor_layouts_dialog.cpp
@@ -33,6 +33,7 @@
#include "core/io/config_file.h"
#include "core/object/class_db.h"
#include "core/os/keyboard.h"
+#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "scene/gui/item_list.h"
#include "scene/gui/line_edit.h"
@@ -97,6 +98,11 @@ void EditorLayoutsDialog::_post_popup() {
for (const String &E : layouts) {
layout_names->add_item(E);
}
+ if (name->is_visible()) {
+ name->grab_focus();
+ } else {
+ layout_names->grab_focus();
+ }
}
EditorLayoutsDialog::EditorLayoutsDialog() {
@@ -106,7 +112,9 @@ EditorLayoutsDialog::EditorLayoutsDialog() {
makevb->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5);
layout_names = memnew(ItemList);
- makevb->add_child(layout_names);
+ layout_names->set_auto_height(true);
+ makevb->add_margin_child(TTR("Select existing layout:"), layout_names);
+ layout_names->set_custom_minimum_size(Size2(300 * EDSCALE, 1));
layout_names->set_visible(true);
layout_names->set_offset(SIDE_TOP, 5);
layout_names->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5);
@@ -116,8 +124,10 @@ EditorLayoutsDialog::EditorLayoutsDialog() {
layout_names->set_allow_rmb_select(true);
name = memnew(LineEdit);
+ name->set_placeholder("Or enter new layout name");
makevb->add_child(name);
name->set_offset(SIDE_TOP, 5);
+ name->set_custom_minimum_size(Size2(300 * EDSCALE, 1));
name->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5);
name->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5);
name->connect("gui_input", callable_mp(this, &EditorLayoutsDialog::_line_gui_input));
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index 84284a7f31..a232c83783 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -286,7 +286,7 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
// Remove last line if replacing, as it will be replace by the next added line.
// Why "- 2"? RichTextLabel is weird. When you add a line with add_newline(), it also adds an element to the list of lines which is null/blank,
// but it still counts as a line. So if you remove the last line (count - 1) you are actually removing nothing...
- log->remove_line(log->get_paragraph_count() - 2);
+ log->remove_paragraph(log->get_paragraph_count() - 2);
}
switch (p_message.type) {
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 02cfd3e873..01e605880c 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -96,6 +96,7 @@
#include "editor/export/editor_export.h"
#include "editor/export/export_template_manager.h"
#include "editor/export/project_export.h"
+#include "editor/fbx_importer_manager.h"
#include "editor/filesystem_dock.h"
#include "editor/history_dock.h"
#include "editor/import/audio_stream_import_settings.h"
@@ -2981,7 +2982,11 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case SETTINGS_MANAGE_EXPORT_TEMPLATES: {
export_template_manager->popup_manager();
-
+ } break;
+ case SETTINGS_MANAGE_FBX_IMPORTER: {
+#if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
+ fbx_importer_manager->show_dialog();
+#endif
} break;
case SETTINGS_INSTALL_ANDROID_BUILD_TEMPLATE: {
custom_build_manage_templates->hide();
@@ -5189,15 +5194,15 @@ void EditorNode::_layout_menu_option(int p_id) {
current_menu_option = p_id;
layout_dialog->set_title(TTR("Save Layout"));
layout_dialog->set_ok_button_text(TTR("Save"));
- layout_dialog->popup_centered();
layout_dialog->set_name_line_enabled(true);
+ layout_dialog->popup_centered();
} break;
case SETTINGS_LAYOUT_DELETE: {
current_menu_option = p_id;
layout_dialog->set_title(TTR("Delete Layout"));
layout_dialog->set_ok_button_text(TTR("Delete"));
- layout_dialog->popup_centered();
layout_dialog->set_name_line_enabled(false);
+ layout_dialog->popup_centered();
} break;
case SETTINGS_LAYOUT_DEFAULT: {
_load_docks_from_config(default_layout, "docks");
@@ -6624,6 +6629,11 @@ EditorNode::EditorNode() {
gui_base->add_child(about);
feature_profile_manager->connect("current_feature_profile_changed", callable_mp(this, &EditorNode::_feature_profile_changed));
+#if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
+ fbx_importer_manager = memnew(FBXImporterManager);
+ gui_base->add_child(fbx_importer_manager);
+#endif
+
warning = memnew(AcceptDialog);
warning->add_button(TTR("Copy Text"), true, "copy");
gui_base->add_child(warning);
@@ -6796,6 +6806,9 @@ EditorNode::EditorNode() {
#ifndef ANDROID_ENABLED
settings_menu->add_item(TTR("Manage Export Templates..."), SETTINGS_MANAGE_EXPORT_TEMPLATES);
#endif
+#if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
+ settings_menu->add_item(TTR("Configure FBX Importer..."), SETTINGS_MANAGE_FBX_IMPORTER);
+#endif
help_menu = memnew(PopupMenu);
help_menu->set_name(TTR("Help"));
@@ -7249,6 +7262,7 @@ EditorNode::EditorNode() {
gui_base->add_child(disk_changed);
add_editor_plugin(memnew(AnimationPlayerEditorPlugin));
+ add_editor_plugin(memnew(AnimationTrackKeyEditEditorPlugin));
add_editor_plugin(memnew(CanvasItemEditorPlugin));
add_editor_plugin(memnew(Node3DEditorPlugin));
add_editor_plugin(memnew(ScriptEditorPlugin));
diff --git a/editor/editor_node.h b/editor/editor_node.h
index c430662c7f..950970379d 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -77,6 +77,7 @@ class EditorSettingsDialog;
class EditorToaster;
class EditorUndoRedoManager;
class ExportTemplateManager;
+class FBXImporterManager;
class FileDialog;
class FileSystemDock;
class HistoryDock;
@@ -209,6 +210,7 @@ private:
SETTINGS_EDITOR_DATA_FOLDER,
SETTINGS_EDITOR_CONFIG_FOLDER,
SETTINGS_MANAGE_EXPORT_TEMPLATES,
+ SETTINGS_MANAGE_FBX_IMPORTER,
SETTINGS_MANAGE_FEATURE_PROFILES,
SETTINGS_INSTALL_ANDROID_BUILD_TEMPLATE,
SETTINGS_PICK_MAIN_SCENE,
@@ -285,6 +287,8 @@ private:
ProjectExportDialog *project_export = nullptr;
ProjectSettingsEditor *project_settings_editor = nullptr;
+ FBXImporterManager *fbx_importer_manager = nullptr;
+
Vector<EditorPlugin *> editor_plugins;
bool _initializing_plugins = false;
HashMap<String, EditorPlugin *> addon_name_to_plugin;
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index fb3bf46c05..8c5db444ab 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -1384,10 +1384,11 @@ void EditorPropertyInteger::update_property() {
void EditorPropertyInteger::_bind_methods() {
}
-void EditorPropertyInteger::setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix) {
+void EditorPropertyInteger::setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_hide_slider, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix) {
spin->set_min(p_min);
spin->set_max(p_max);
spin->set_step(p_step);
+ spin->set_hide_slider(p_hide_slider);
spin->set_allow_greater(p_allow_greater);
spin->set_allow_lesser(p_allow_lesser);
spin->set_suffix(p_suffix);
@@ -2242,12 +2243,11 @@ void EditorPropertyVector2i::_notification(int p_what) {
}
}
-void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_hide_slider, bool p_link, const String &p_suffix) {
+void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_link, const String &p_suffix) {
for (int i = 0; i < 2; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(1);
- spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
@@ -2352,12 +2352,11 @@ void EditorPropertyRect2i::_notification(int p_what) {
void EditorPropertyRect2i::_bind_methods() {
}
-void EditorPropertyRect2i::setup(int p_min, int p_max, bool p_hide_slider, const String &p_suffix) {
+void EditorPropertyRect2i::setup(int p_min, int p_max, const String &p_suffix) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(1);
- spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
@@ -2496,12 +2495,12 @@ void EditorPropertyVector3i::_notification(int p_what) {
void EditorPropertyVector3i::_bind_methods() {
}
-void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_hide_slider, bool p_link, const String &p_suffix) {
+void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_link, const String &p_suffix) {
for (int i = 0; i < 3; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(1);
- spin[i]->set_hide_slider(p_hide_slider);
+ spin[i]->set_hide_slider(false);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
@@ -3004,11 +3003,11 @@ void EditorPropertyVector4i::_notification(int p_what) {
void EditorPropertyVector4i::_bind_methods() {
}
-void EditorPropertyVector4i::setup(double p_min, double p_max, bool p_hide_slider, const String &p_suffix) {
+void EditorPropertyVector4i::setup(double p_min, double p_max, const String &p_suffix) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
- spin[i]->set_hide_slider(p_hide_slider);
+ spin[i]->set_step(1);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
@@ -4122,6 +4121,8 @@ void EditorPropertyResource::update_property() {
if (use_editor) {
// Open editor directly and hide other such editors which are currently open.
+ // The opened editor is the one that edits the sub-resource, so keying state will be toggled to false.
+ sub_inspector->set_keying(false);
_open_editor_pressed();
if (is_inside_tree()) {
get_tree()->call_deferred(SNAME("call_group"), "_editor_resource_properties", "_fold_other_editors", this);
@@ -4347,7 +4348,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
- editor->setup(hint.min, hint.max, hint.step, hint.or_greater, hint.or_less, hint.suffix);
+ editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.or_greater, hint.or_less, hint.suffix);
return editor;
}
@@ -4475,7 +4476,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::VECTOR2I: {
EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
- editor->setup(hint.min, hint.max, hint.hide_slider, p_hint == PROPERTY_HINT_LINK, hint.suffix);
+ editor->setup(hint.min, hint.max, p_hint == PROPERTY_HINT_LINK, hint.suffix);
return editor;
} break;
@@ -4488,7 +4489,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::RECT2I: {
EditorPropertyRect2i *editor = memnew(EditorPropertyRect2i(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
- editor->setup(hint.min, hint.max, hint.hide_slider, hint.suffix);
+ editor->setup(hint.min, hint.max, hint.suffix);
return editor;
} break;
@@ -4502,7 +4503,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::VECTOR3I: {
EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
- editor->setup(hint.min, hint.max, hint.hide_slider, p_hint == PROPERTY_HINT_LINK, hint.suffix);
+ editor->setup(hint.min, hint.max, p_hint == PROPERTY_HINT_LINK, hint.suffix);
return editor;
} break;
@@ -4516,7 +4517,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::VECTOR4I: {
EditorPropertyVector4i *editor = memnew(EditorPropertyVector4i);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
- editor->setup(hint.min, hint.max, hint.hide_slider, hint.suffix);
+ editor->setup(hint.min, hint.max, hint.suffix);
return editor;
} break;
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index f38e33d9e3..042b94130b 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -378,7 +378,7 @@ protected:
public:
virtual void update_property() override;
- void setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix = String());
+ void setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_hide_slider, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix = String());
EditorPropertyInteger();
};
@@ -566,7 +566,7 @@ protected:
public:
virtual void update_property() override;
- void setup(int p_min, int p_max, bool p_hide_slider, bool p_link = false, const String &p_suffix = String());
+ void setup(int p_min, int p_max, bool p_link = false, const String &p_suffix = String());
EditorPropertyVector2i(bool p_force_wide = false);
};
@@ -583,7 +583,7 @@ protected:
public:
virtual void update_property() override;
- void setup(int p_min, int p_max, bool p_hide_slider, const String &p_suffix = String());
+ void setup(int p_min, int p_max, const String &p_suffix = String());
EditorPropertyRect2i(bool p_force_wide = false);
};
@@ -608,7 +608,7 @@ protected:
public:
virtual void update_property() override;
- void setup(int p_min, int p_max, bool p_hide_slider, bool p_link = false, const String &p_suffix = String());
+ void setup(int p_min, int p_max, bool p_link = false, const String &p_suffix = String());
EditorPropertyVector3i(bool p_force_wide = false);
};
@@ -693,7 +693,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, bool p_hide_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, const String &p_suffix = String());
EditorPropertyVector4i();
};
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index edda6c5d7b..451cb7cfee 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -919,7 +919,7 @@ void EditorPropertyDictionary::update_property() {
} break;
case Variant::INT: {
EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
- editor->setup(-100000, 100000, 1, true, true);
+ editor->setup(-100000, 100000, 1, false, true, true);
prop = editor;
} break;
@@ -942,7 +942,7 @@ void EditorPropertyDictionary::update_property() {
} break;
case Variant::VECTOR2I: {
EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i);
- editor->setup(-100000, 100000, true);
+ editor->setup(-100000, 100000);
prop = editor;
} break;
@@ -954,7 +954,7 @@ void EditorPropertyDictionary::update_property() {
} break;
case Variant::RECT2I: {
EditorPropertyRect2i *editor = memnew(EditorPropertyRect2i);
- editor->setup(-100000, 100000, true);
+ editor->setup(-100000, 100000);
prop = editor;
} break;
@@ -966,7 +966,7 @@ void EditorPropertyDictionary::update_property() {
} break;
case Variant::VECTOR3I: {
EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i);
- editor->setup(-100000, 100000, true);
+ editor->setup(-100000, 100000);
prop = editor;
} break;
@@ -978,7 +978,7 @@ void EditorPropertyDictionary::update_property() {
} break;
case Variant::VECTOR4I: {
EditorPropertyVector4i *editor = memnew(EditorPropertyVector4i);
- editor->setup(-100000, 100000, true);
+ editor->setup(-100000, 100000);
prop = editor;
} break;
diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp
index 9587e65cad..e8a0912d66 100644
--- a/editor/editor_property_name_processor.cpp
+++ b/editor/editor_property_name_processor.cpp
@@ -231,6 +231,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["tcp"] = "TCP";
capitalize_string_remaps["tls"] = "TLS";
capitalize_string_remaps["ui"] = "UI";
+ capitalize_string_remaps["uri"] = "URI";
capitalize_string_remaps["url"] = "URL";
capitalize_string_remaps["urls"] = "URLs";
capitalize_string_remaps["us"] = String::utf8("(µs)"); // Unit.
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 9128143619..60c46835fe 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -76,6 +76,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
pre_grab_value = get_value();
grabbing_spinner = false;
grabbing_spinner_mouse_pos = get_global_mouse_position();
+ emit_signal("grabbed");
}
} else {
if (grabbing_spinner_attempt) {
@@ -83,6 +84,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
Input::get_singleton()->warp_mouse(grabbing_spinner_mouse_pos);
queue_redraw();
+ emit_signal("ungrabbed");
} else {
_focus_entered();
}
@@ -178,9 +180,11 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
grabbing_ratio = get_as_ratio();
grabbing_from = grabber->get_transform().xform(mb->get_position()).x;
}
+ emit_signal("grabbed");
} else {
grabbing_grabber = false;
mousewheel_over_grabber = false;
+ emit_signal("ungrabbed");
}
}
@@ -299,10 +303,6 @@ void EditorSpinSlider::_draw_spin_slider() {
Ref<Texture2D> updown = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox"));
- if (get_step() == 1) {
- number_width -= updown->get_width();
- }
-
String numstr = get_text_value();
int vofs = (size.height - font->get_height(font_size)) / 2 + font->get_ascent(font_size);
@@ -359,76 +359,79 @@ void EditorSpinSlider::_draw_spin_slider() {
}
TS->free_rid(num_rid);
- if (get_step() == 1) {
- Ref<Texture2D> updown2 = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox"));
- int updown_vofs = (size.height - updown2->get_height()) / 2;
- if (rtl) {
- updown_offset = sb->get_margin(SIDE_LEFT);
- } else {
- updown_offset = size.width - sb->get_margin(SIDE_RIGHT) - updown2->get_width();
- }
- Color c(1, 1, 1);
- if (hover_updown) {
- c *= Color(1.2, 1.2, 1.2);
- }
- draw_texture(updown2, Vector2(updown_offset, updown_vofs), c);
- if (grabber->is_visible()) {
- grabber->hide();
- }
- } else if (!hide_slider) {
- const int grabber_w = 4 * EDSCALE;
- const int width = size.width - sb->get_minimum_size().width - grabber_w;
- const int ofs = sb->get_offset().x;
- const int svofs = (size.height + vofs) / 2 - 1;
- Color c = fc;
-
- // Draw the horizontal slider's background.
- c.a = 0.2;
- draw_rect(Rect2(ofs, svofs + 1, width, 2 * EDSCALE), c);
-
- // Draw the horizontal slider's filled part on the left.
- const int gofs = get_as_ratio() * width;
- c.a = 0.45;
- draw_rect(Rect2(ofs, svofs + 1, gofs, 2 * EDSCALE), c);
-
- // Draw the horizontal slider's grabber.
- c.a = 0.9;
- const Rect2 grabber_rect = Rect2(ofs + gofs, svofs, grabber_w, 4 * EDSCALE);
- draw_rect(grabber_rect, c);
-
- grabbing_spinner_mouse_pos = get_global_position() + grabber_rect.get_center();
-
- bool display_grabber = (grabbing_grabber || mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !(value_input_popup && value_input_popup->is_visible());
- if (grabber->is_visible() != display_grabber) {
- if (display_grabber) {
- grabber->show();
+ if (!hide_slider) {
+ if (get_step() == 1) {
+ number_width -= updown->get_width();
+ Ref<Texture2D> updown2 = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox"));
+ int updown_vofs = (size.height - updown2->get_height()) / 2;
+ if (rtl) {
+ updown_offset = sb->get_margin(SIDE_LEFT);
} else {
+ updown_offset = size.width - sb->get_margin(SIDE_RIGHT) - updown2->get_width();
+ }
+ Color c(1, 1, 1);
+ if (hover_updown) {
+ c *= Color(1.2, 1.2, 1.2);
+ }
+ draw_texture(updown2, Vector2(updown_offset, updown_vofs), c);
+ if (grabber->is_visible()) {
grabber->hide();
}
- }
-
- if (display_grabber) {
- Ref<Texture2D> grabber_tex;
- if (mouse_over_grabber) {
- grabber_tex = get_theme_icon(SNAME("grabber_highlight"), SNAME("HSlider"));
- } else {
- grabber_tex = get_theme_icon(SNAME("grabber"), SNAME("HSlider"));
+ } else {
+ const int grabber_w = 4 * EDSCALE;
+ const int width = size.width - sb->get_minimum_size().width - grabber_w;
+ const int ofs = sb->get_offset().x;
+ const int svofs = (size.height + vofs) / 2 - 1;
+ Color c = fc;
+
+ // Draw the horizontal slider's background.
+ c.a = 0.2;
+ draw_rect(Rect2(ofs, svofs + 1, width, 2 * EDSCALE), c);
+
+ // Draw the horizontal slider's filled part on the left.
+ const int gofs = get_as_ratio() * width;
+ c.a = 0.45;
+ draw_rect(Rect2(ofs, svofs + 1, gofs, 2 * EDSCALE), c);
+
+ // Draw the horizontal slider's grabber.
+ c.a = 0.9;
+ const Rect2 grabber_rect = Rect2(ofs + gofs, svofs, grabber_w, 4 * EDSCALE);
+ draw_rect(grabber_rect, c);
+
+ grabbing_spinner_mouse_pos = get_global_position() + grabber_rect.get_center();
+
+ bool display_grabber = (grabbing_grabber || mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !(value_input_popup && value_input_popup->is_visible());
+ if (grabber->is_visible() != display_grabber) {
+ if (display_grabber) {
+ grabber->show();
+ } else {
+ grabber->hide();
+ }
}
- if (grabber->get_texture() != grabber_tex) {
- grabber->set_texture(grabber_tex);
- }
+ if (display_grabber) {
+ Ref<Texture2D> grabber_tex;
+ if (mouse_over_grabber) {
+ grabber_tex = get_theme_icon(SNAME("grabber_highlight"), SNAME("HSlider"));
+ } else {
+ grabber_tex = get_theme_icon(SNAME("grabber"), SNAME("HSlider"));
+ }
- Vector2 scale = get_global_transform_with_canvas().get_scale();
- grabber->set_scale(scale);
- grabber->reset_size();
- grabber->set_position(get_global_position() + (grabber_rect.get_center() - grabber->get_size() * 0.5) * scale);
+ if (grabber->get_texture() != grabber_tex) {
+ grabber->set_texture(grabber_tex);
+ }
- if (mousewheel_over_grabber) {
- Input::get_singleton()->warp_mouse(grabber->get_position() + grabber_rect.size);
- }
+ Vector2 scale = get_global_transform_with_canvas().get_scale();
+ grabber->set_scale(scale);
+ grabber->reset_size();
+ grabber->set_position(get_global_position() + (grabber_rect.get_center() - grabber->get_size() * 0.5) * scale);
+
+ if (mousewheel_over_grabber) {
+ Input::get_singleton()->warp_mouse(grabber->get_position() + grabber_rect.size);
+ }
- grabber_range = width;
+ grabber_range = width;
+ }
}
}
}
@@ -584,6 +587,8 @@ void EditorSpinSlider::_value_focus_exited() {
//enter, click, esc
grab_focus();
}
+
+ emit_signal("value_focus_exited");
}
void EditorSpinSlider::_grabber_mouse_entered() {
@@ -627,6 +632,7 @@ void EditorSpinSlider::_focus_entered() {
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());
+ emit_signal("value_focus_entered");
}
void EditorSpinSlider::_bind_methods() {
@@ -650,6 +656,11 @@ void EditorSpinSlider::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "read_only"), "set_read_only", "is_read_only");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_slider"), "set_hide_slider", "is_hiding_slider");
+
+ ADD_SIGNAL(MethodInfo("grabbed"));
+ ADD_SIGNAL(MethodInfo("ungrabbed"));
+ ADD_SIGNAL(MethodInfo("value_focus_entered"));
+ ADD_SIGNAL(MethodInfo("value_focus_exited"));
}
void EditorSpinSlider::_ensure_input_popup() {
diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp
index d22c7bd149..3a6516fbfa 100644
--- a/editor/editor_vcs_interface.cpp
+++ b/editor/editor_vcs_interface.cpp
@@ -57,7 +57,7 @@ void EditorVCSInterface::set_credentials(String p_username, String p_password, S
}
List<String> EditorVCSInterface::get_remotes() {
- TypedArray<Dictionary> result;
+ TypedArray<String> result;
if (!GDVIRTUAL_CALL(_get_remotes, result)) {
UNIMPLEMENTED();
return {};
@@ -137,7 +137,7 @@ List<EditorVCSInterface::Commit> EditorVCSInterface::get_previous_commits(int p_
}
List<String> EditorVCSInterface::get_branch_list() {
- TypedArray<Dictionary> result;
+ TypedArray<String> result;
if (!GDVIRTUAL_CALL(_get_branch_list, result)) {
UNIMPLEMENTED();
return {};
diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h
index 5d4901cefa..c93fe4a672 100644
--- a/editor/editor_vcs_interface.h
+++ b/editor/editor_vcs_interface.h
@@ -117,8 +117,8 @@ protected:
GDVIRTUAL0R(bool, _shut_down);
GDVIRTUAL0R(String, _get_vcs_name);
GDVIRTUAL1R(TypedArray<Dictionary>, _get_previous_commits, int);
- GDVIRTUAL0R(TypedArray<Dictionary>, _get_branch_list);
- GDVIRTUAL0R(TypedArray<Dictionary>, _get_remotes);
+ GDVIRTUAL0R(TypedArray<String>, _get_branch_list);
+ GDVIRTUAL0R(TypedArray<String>, _get_remotes);
GDVIRTUAL1(_create_branch, String);
GDVIRTUAL1(_remove_branch, String);
GDVIRTUAL2(_create_remote, String, String);
diff --git a/editor/fbx_importer_manager.cpp b/editor/fbx_importer_manager.cpp
new file mode 100644
index 0000000000..b258fe7e09
--- /dev/null
+++ b/editor/fbx_importer_manager.cpp
@@ -0,0 +1,158 @@
+/*************************************************************************/
+/* fbx_importer_manager.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "fbx_importer_manager.h"
+
+#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
+#include "scene/gui/link_button.h"
+
+void FBXImporterManager::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_READY: {
+ connect("confirmed", callable_mp(this, &FBXImporterManager::_path_confirmed));
+ } break;
+ }
+}
+
+void FBXImporterManager::show_dialog(bool p_exclusive) {
+ String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx/fbx2gltf_path");
+ fbx_path->set_text(fbx2gltf_path);
+ _validate_path(fbx2gltf_path);
+
+ set_flag(Window::FLAG_BORDERLESS, p_exclusive); // Avoid closing accidentally .
+ set_close_on_escape(!p_exclusive);
+
+ popup_centered();
+}
+
+void FBXImporterManager::_validate_path(const String &p_path) {
+ String error;
+ bool success = false;
+
+ if (p_path == "") {
+ error = TTR("Path to FBX2glTF executable is empty.");
+ } else if (!FileAccess::exists(p_path)) {
+ error = TTR("Path to FBX2glTF executable is invalid.");
+ } else {
+ List<String> args;
+ args.push_back("--version");
+ int exitcode;
+ Error err = OS::get_singleton()->execute(p_path, args, nullptr, &exitcode);
+
+ if (err == OK && exitcode == 0) {
+ success = true;
+ } else {
+ error = TTR("Error executing this file (wrong version or architecture).");
+ }
+ }
+
+ if (success) {
+ path_status->set_text(TTR("FBX2glTF executable is valid."));
+ path_status->add_theme_color_override("font_color", path_status->get_theme_color(SNAME("success_color"), SNAME("Editor")));
+ get_ok_button()->set_disabled(false);
+ } else {
+ path_status->set_text(error);
+ path_status->add_theme_color_override("font_color", path_status->get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ get_ok_button()->set_disabled(true);
+ }
+}
+
+void FBXImporterManager::_select_file(const String &p_path) {
+ fbx_path->set_text(p_path);
+ _validate_path(p_path);
+}
+
+void FBXImporterManager::_path_confirmed() {
+ String path = fbx_path->get_text();
+ EditorSettings::get_singleton()->set("filesystem/import/fbx/fbx2gltf_path", path);
+ EditorSettings::get_singleton()->save();
+}
+
+void FBXImporterManager::_browse_install() {
+ if (fbx_path->get_text() != String()) {
+ browse_dialog->set_current_file(fbx_path->get_text());
+ }
+
+ browse_dialog->popup_centered_ratio();
+}
+
+FBXImporterManager *FBXImporterManager::singleton = nullptr;
+
+FBXImporterManager::FBXImporterManager() {
+ singleton = this;
+
+ set_title(TTR("Configure FBX Importer"));
+
+ VBoxContainer *vb = memnew(VBoxContainer);
+ vb->add_child(memnew(Label(TTR("FBX2glTF is required for importing FBX files.\nPlease download it and provide a valid path to the binary:"))));
+ LinkButton *lb = memnew(LinkButton);
+ lb->set_text(TTR("Click this link to download FBX2glTF"));
+ lb->set_uri("https://godotengine.org/fbx-import");
+ vb->add_child(lb);
+
+ HBoxContainer *hb = memnew(HBoxContainer);
+
+ fbx_path = memnew(LineEdit);
+ fbx_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hb->add_child(fbx_path);
+ fbx_path_browse = memnew(Button);
+ hb->add_child(fbx_path_browse);
+ fbx_path_browse->set_text(TTR("Browse"));
+ fbx_path_browse->connect("pressed", callable_mp(this, &FBXImporterManager::_browse_install));
+ hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hb->set_custom_minimum_size(Size2(400 * EDSCALE, 0));
+
+ vb->add_child(hb);
+
+ path_status = memnew(Label);
+ vb->add_child(path_status);
+
+ add_child(vb);
+
+ fbx_path->connect("text_changed", callable_mp(this, &FBXImporterManager::_validate_path));
+
+ get_ok_button()->set_text(TTR("Confirm Path"));
+
+ browse_dialog = memnew(EditorFileDialog);
+ browse_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
+ browse_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
+#if defined(X11_ENABLED)
+ browse_dialog->add_filter("FBX2glTF-linux-x86_64");
+#elif defined(OSX_ENABLED)
+ browse_dialog->add_filter("FBX2glTF-macos-x86_64");
+#elif defined(WINDOWS_ENABLED)
+ browse_dialog->add_filter("FBX2glTF-windows-x86_64");
+#endif
+
+ browse_dialog->connect("file_selected", callable_mp(this, &FBXImporterManager::_select_file));
+
+ add_child(browse_dialog);
+}
diff --git a/editor/fbx_importer_manager.h b/editor/fbx_importer_manager.h
new file mode 100644
index 0000000000..28de761519
--- /dev/null
+++ b/editor/fbx_importer_manager.h
@@ -0,0 +1,66 @@
+/*************************************************************************/
+/* fbx_importer_manager.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef FBX_IMPORTER_MANAGER_H
+#define FBX_IMPORTER_MANAGER_H
+
+#include "editor/editor_file_dialog.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/line_edit.h"
+
+class FBXImporterManager : public ConfirmationDialog {
+ GDCLASS(FBXImporterManager, ConfirmationDialog)
+
+ Label *message = nullptr;
+ LineEdit *fbx_path = nullptr;
+ Button *fbx_path_browse = nullptr;
+ EditorFileDialog *browse_dialog = nullptr;
+ Label *path_status = nullptr;
+
+ void _validate_path(const String &p_path);
+ void _select_file(const String &p_path);
+ void _path_confirmed();
+ void _browse_install();
+ void _link_clicked();
+
+ static FBXImporterManager *singleton;
+
+protected:
+ void _notification(int p_what);
+
+public:
+ static FBXImporterManager *get_singleton() { return singleton; }
+
+ void show_dialog(bool p_exclusive = false);
+
+ FBXImporterManager();
+};
+
+#endif // FBX_IMPORTER_MANAGER_H
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index b7e7200b11..3a6c891142 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -569,8 +569,6 @@ FindInFilesPanel::FindInFilesPanel() {
hbc->add_child(find_label);
_search_text_label = memnew(Label);
- _search_text_label->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("source"), SNAME("EditorFonts")));
- _search_text_label->add_theme_font_size_override("font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size(SNAME("source_size"), SNAME("EditorFonts")));
hbc->add_child(_search_text_label);
_progress_bar = memnew(ProgressBar);
@@ -598,8 +596,6 @@ FindInFilesPanel::FindInFilesPanel() {
}
_results_display = memnew(Tree);
- _results_display->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("source"), SNAME("EditorFonts")));
- _results_display->add_theme_font_size_override("font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size(SNAME("source_size"), SNAME("EditorFonts")));
_results_display->set_v_size_flags(SIZE_EXPAND_FILL);
_results_display->connect("item_selected", callable_mp(this, &FindInFilesPanel::_on_result_selected));
_results_display->connect("item_edited", callable_mp(this, &FindInFilesPanel::_on_item_edited));
@@ -688,13 +684,20 @@ void FindInFilesPanel::stop_search() {
void FindInFilesPanel::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_PROCESS: {
- _progress_bar->set_as_ratio(_finder->get_progress());
- } break;
-
case NOTIFICATION_THEME_CHANGED: {
_search_text_label->add_theme_font_override("font", get_theme_font(SNAME("source"), SNAME("EditorFonts")));
+ _search_text_label->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("source_size"), SNAME("EditorFonts")));
_results_display->add_theme_font_override("font", get_theme_font(SNAME("source"), SNAME("EditorFonts")));
+ _results_display->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("source_size"), SNAME("EditorFonts")));
+
+ // Rebuild search tree.
+ if (!_finder->get_search_text().is_empty()) {
+ start_search();
+ }
+ } break;
+
+ case NOTIFICATION_PROCESS: {
+ _progress_bar->set_as_ratio(_finder->get_progress());
} break;
}
}
diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp
index f635c74547..92d4397c68 100644
--- a/editor/import/audio_stream_import_settings.cpp
+++ b/editor/import/audio_stream_import_settings.cpp
@@ -465,12 +465,17 @@ void AudioStreamImportSettings::_settings_changed() {
updating_settings = true;
stream->call("set_loop", loop->is_pressed());
stream->call("set_loop_offset", loop_offset->get_value());
+ if (loop->is_pressed()) {
+ loop_offset->set_editable(true);
+ } else {
+ loop_offset->set_editable(false);
+ }
+
if (bpm_enabled->is_pressed()) {
stream->call("set_bpm", bpm_edit->get_value());
- beats_enabled->show();
- beats_edit->show();
- bar_beats_label->show();
- bar_beats_edit->show();
+ beats_enabled->set_disabled(false);
+ beats_edit->set_editable(true);
+ bar_beats_edit->set_editable(true);
double bpm = bpm_edit->get_value();
if (bpm > 0) {
float beat_size = 60 / float(bpm);
@@ -486,10 +491,9 @@ void AudioStreamImportSettings::_settings_changed() {
} else {
stream->call("set_bpm", 0);
stream->call("set_bar_beats", 4);
- beats_enabled->hide();
- beats_edit->hide();
- bar_beats_label->hide();
- bar_beats_edit->hide();
+ beats_enabled->set_disabled(true);
+ beats_edit->set_editable(false);
+ bar_beats_edit->set_editable(false);
}
if (bpm_enabled->is_pressed() && beats_enabled->is_pressed()) {
stream->call("set_beat_count", beats_edit->get_value());
@@ -552,17 +556,8 @@ AudioStreamImportSettings::AudioStreamImportSettings() {
bpm_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
interactive_hb->add_child(bpm_edit);
interactive_hb->add_spacer();
- bar_beats_label = memnew(Label(TTR("Beats/Bar:")));
- interactive_hb->add_child(bar_beats_label);
- bar_beats_edit = memnew(SpinBox);
- bar_beats_edit->set_tooltip_text(TTR("Configure the Beats Per Bar. This used for music-aware transitions between AudioStreams."));
- bar_beats_edit->set_min(2);
- bar_beats_edit->set_max(32);
- bar_beats_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
- interactive_hb->add_child(bar_beats_edit);
- interactive_hb->add_spacer();
beats_enabled = memnew(CheckBox);
- beats_enabled->set_text(TTR("Length (in beats):"));
+ beats_enabled->set_text(TTR("Beat Count:"));
beats_enabled->connect("toggled", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
interactive_hb->add_child(beats_enabled);
beats_edit = memnew(SpinBox);
@@ -570,6 +565,15 @@ AudioStreamImportSettings::AudioStreamImportSettings() {
beats_edit->set_max(99999);
beats_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
interactive_hb->add_child(beats_edit);
+ bar_beats_label = memnew(Label(TTR("Bar Beats:")));
+ interactive_hb->add_child(bar_beats_label);
+ bar_beats_edit = memnew(SpinBox);
+ bar_beats_edit->set_tooltip_text(TTR("Configure the Beats Per Bar. This used for music-aware transitions between AudioStreams."));
+ bar_beats_edit->set_min(2);
+ bar_beats_edit->set_max(32);
+ bar_beats_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
+ interactive_hb->add_child(bar_beats_edit);
+ interactive_hb->add_spacer();
main_vbox->add_margin_child(TTR("Music Playback:"), interactive_hb);
color_rect = memnew(ColorRect);
diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp
index 730aa3bd61..380a4e370c 100644
--- a/editor/import/scene_import_settings.cpp
+++ b/editor/import/scene_import_settings.cpp
@@ -555,6 +555,7 @@ void SceneImportSettings::open_settings(const String &p_path, bool p_for_animati
material_set.clear();
mesh_set.clear();
+ animation_map.clear();
material_map.clear();
mesh_map.clear();
node_map.clear();
@@ -957,15 +958,15 @@ void SceneImportSettings::_notification(int p_what) {
void SceneImportSettings::_menu_callback(int p_id) {
switch (p_id) {
case ACTION_EXTRACT_MATERIALS: {
- save_path->set_text(TTR("Select folder to extract material resources"));
+ save_path->set_title(TTR("Select folder to extract material resources"));
external_extension_type->select(0);
} break;
case ACTION_CHOOSE_MESH_SAVE_PATHS: {
- save_path->set_text(TTR("Select folder where mesh resources will save on import"));
+ save_path->set_title(TTR("Select folder where mesh resources will save on import"));
external_extension_type->select(1);
} break;
case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
- save_path->set_text(TTR("Select folder where animations will save on import"));
+ save_path->set_title(TTR("Select folder where animations will save on import"));
external_extension_type->select(1);
} break;
}
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index affb31945d..1f350f1199 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -219,6 +219,7 @@ PluginConfigDialog::PluginConfigDialog() {
GridContainer *grid = memnew(GridContainer);
grid->set_columns(3);
+ grid->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vbox->add_child(grid);
// Plugin Name
@@ -234,6 +235,7 @@ PluginConfigDialog::PluginConfigDialog() {
name_edit = memnew(LineEdit);
name_edit->connect("text_changed", callable_mp(this, &PluginConfigDialog::_on_required_text_changed));
name_edit->set_placeholder("MyPlugin");
+ name_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grid->add_child(name_edit);
// Subfolder
@@ -248,6 +250,7 @@ PluginConfigDialog::PluginConfigDialog() {
subfolder_edit = memnew(LineEdit);
subfolder_edit->set_placeholder("\"my_plugin\" -> res://addons/my_plugin");
+ subfolder_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
subfolder_edit->connect("text_changed", callable_mp(this, &PluginConfigDialog::_on_required_text_changed));
grid->add_child(subfolder_edit);
@@ -263,6 +266,8 @@ PluginConfigDialog::PluginConfigDialog() {
desc_edit = memnew(TextEdit);
desc_edit->set_custom_minimum_size(Size2(400, 80) * EDSCALE);
desc_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
+ desc_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ desc_edit->set_v_size_flags(Control::SIZE_EXPAND_FILL);
grid->add_child(desc_edit);
// Author
@@ -276,6 +281,7 @@ PluginConfigDialog::PluginConfigDialog() {
author_edit = memnew(LineEdit);
author_edit->set_placeholder("Godette");
+ author_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grid->add_child(author_edit);
// Version
@@ -289,6 +295,7 @@ PluginConfigDialog::PluginConfigDialog() {
version_edit = memnew(LineEdit);
version_edit->set_placeholder("1.0");
+ version_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grid->add_child(version_edit);
// Language dropdown
@@ -326,6 +333,7 @@ PluginConfigDialog::PluginConfigDialog() {
script_edit = memnew(LineEdit);
script_edit->connect("text_changed", callable_mp(this, &PluginConfigDialog::_on_required_text_changed));
script_edit->set_placeholder("\"plugin.gd\" -> res://addons/my_plugin/plugin.gd");
+ script_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grid->add_child(script_edit);
// Activate now checkbox
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 5183a738ae..344a800241 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -87,13 +87,13 @@ void AnimationPlayerEditor::_notification(int p_what) {
}
frame->set_value(player->get_current_animation_position());
track_editor->set_anim_pos(player->get_current_animation_position());
-
} else if (!player->is_valid()) {
// Reset timeline when the player has been stopped externally
frame->set_value(0);
} else if (last_active) {
// Need the last frame after it stopped.
frame->set_value(player->get_current_animation_position());
+ track_editor->set_anim_pos(player->get_current_animation_position());
}
last_active = player->is_playing();
@@ -423,7 +423,7 @@ void AnimationPlayerEditor::_select_anim_by_name(const String &p_anim) {
_animation_selected(idx);
}
-double AnimationPlayerEditor::_get_editor_step() const {
+float AnimationPlayerEditor::_get_editor_step() const {
// Returns the effective snapping value depending on snapping modifiers, or 0 if snapping is disabled.
if (track_editor->is_snap_enabled()) {
const String current = player->get_assigned_animation();
@@ -434,7 +434,7 @@ double AnimationPlayerEditor::_get_editor_step() const {
return Input::get_singleton()->is_key_pressed(Key::SHIFT) ? anim->get_step() * 0.25 : anim->get_step();
}
- return 0.0;
+ return 0.0f;
}
void AnimationPlayerEditor::_animation_name_edited() {
@@ -1922,10 +1922,12 @@ void AnimationPlayerEditorPlugin::_notification(int p_what) {
}
void AnimationPlayerEditorPlugin::_property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance) {
- if (!anim_editor->get_track_editor()->has_keying()) {
+ AnimationTrackEditor *te = anim_editor->get_track_editor();
+ if (!te || !te->has_keying()) {
return;
}
- anim_editor->get_track_editor()->insert_value_key(p_keyed, p_value, p_advance);
+ te->_clear_selection();
+ te->insert_value_key(p_keyed, p_value, p_advance);
}
void AnimationPlayerEditorPlugin::_transform_key_request(Object *sp, const String &p_sub, const Transform3D &p_key) {
@@ -1971,3 +1973,26 @@ AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin() {
AnimationPlayerEditorPlugin::~AnimationPlayerEditorPlugin() {
}
+
+// AnimationTrackKeyEditEditorPlugin
+
+bool EditorInspectorPluginAnimationTrackKeyEdit::can_handle(Object *p_object) {
+ return Object::cast_to<AnimationTrackKeyEdit>(p_object) != nullptr;
+}
+
+void EditorInspectorPluginAnimationTrackKeyEdit::parse_begin(Object *p_object) {
+ AnimationTrackKeyEdit *atk = Object::cast_to<AnimationTrackKeyEdit>(p_object);
+ ERR_FAIL_COND(!atk);
+
+ atk_editor = memnew(AnimationTrackKeyEditEditor(atk->animation, atk->track, atk->key_ofs, atk->use_fps));
+ add_custom_control(atk_editor);
+}
+
+AnimationTrackKeyEditEditorPlugin::AnimationTrackKeyEditEditorPlugin() {
+ atk_plugin = memnew(EditorInspectorPluginAnimationTrackKeyEdit);
+ EditorInspector::add_inspector_plugin(atk_plugin);
+}
+
+bool AnimationTrackKeyEditEditorPlugin::handles(Object *p_object) const {
+ return p_object->is_class("AnimationTrackKeyEdit");
+}
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 53d460fc9e..8539d450e6 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -162,7 +162,7 @@ class AnimationPlayerEditor : public VBoxContainer {
} onion;
void _select_anim_by_name(const String &p_anim);
- double _get_editor_step() const;
+ float _get_editor_step() const;
void _play_pressed();
void _play_from_pressed();
void _play_bw_pressed();
@@ -272,4 +272,30 @@ public:
~AnimationPlayerEditorPlugin();
};
+// AnimationTrackKeyEditEditorPlugin
+
+class EditorInspectorPluginAnimationTrackKeyEdit : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorPluginAnimationTrackKeyEdit, EditorInspectorPlugin);
+
+ AnimationTrackKeyEditEditor *atk_editor = nullptr;
+
+public:
+ virtual bool can_handle(Object *p_object) override;
+ virtual void parse_begin(Object *p_object) override;
+};
+
+class AnimationTrackKeyEditEditorPlugin : public EditorPlugin {
+ GDCLASS(AnimationTrackKeyEditEditorPlugin, EditorPlugin);
+
+ EditorInspectorPluginAnimationTrackKeyEdit *atk_plugin = nullptr;
+
+public:
+ bool has_main_screen() const override { return false; }
+ virtual bool handles(Object *p_object) const override;
+
+ virtual String get_name() const override { return "AnimationTrackKeyEdit"; }
+
+ AnimationTrackKeyEditEditorPlugin();
+};
+
#endif // ANIMATION_PLAYER_EDITOR_PLUGIN_H
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index 66a0c746d9..7b8a5d06f8 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -1097,7 +1097,8 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action
Ref<AnimationNodeStateMachineTransition> tr;
tr.instantiate();
- tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()));
+ tr->set_advance_mode(auto_advance->is_pressed() ? AnimationNodeStateMachineTransition::AdvanceMode::ADVANCE_MODE_AUTO : AnimationNodeStateMachineTransition::AdvanceMode::ADVANCE_MODE_ENABLED);
+ tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()));
Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
if (!p_nested_action) {
@@ -1326,7 +1327,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
}
}
- _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()), true, false, false, false, false);
+ _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()), true, false, false, false, false);
}
Ref<Texture2D> tr_reference_icon = get_theme_icon(SNAME("TransitionImmediateBig"), SNAME("EditorIcons"));
@@ -1349,8 +1350,8 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
tl.to = (state_machine->get_node_position(local_to) * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE;
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i);
- tl.disabled = tr->is_disabled();
- tl.auto_advance = tr->has_auto_advance();
+ tl.disabled = bool(tr->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED);
+ tl.auto_advance = bool(tr->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_AUTO);
tl.advance_condition_name = tr->get_advance_condition_name();
tl.advance_condition_state = false;
tl.mode = tr->get_switch_mode();
@@ -1590,10 +1591,12 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
tool_create->set_icon(get_theme_icon(SNAME("ToolAddNode"), SNAME("EditorIcons")));
tool_connect->set_icon(get_theme_icon(SNAME("ToolConnect"), SNAME("EditorIcons")));
- transition_mode->clear();
- transition_mode->add_icon_item(get_theme_icon(SNAME("TransitionImmediate"), SNAME("EditorIcons")), TTR("Immediate"));
- transition_mode->add_icon_item(get_theme_icon(SNAME("TransitionSync"), SNAME("EditorIcons")), TTR("Sync"));
- transition_mode->add_icon_item(get_theme_icon(SNAME("TransitionEnd"), SNAME("EditorIcons")), TTR("At End"));
+ switch_mode->clear();
+ switch_mode->add_icon_item(get_theme_icon(SNAME("TransitionImmediate"), SNAME("EditorIcons")), TTR("Immediate"));
+ switch_mode->add_icon_item(get_theme_icon(SNAME("TransitionSync"), SNAME("EditorIcons")), TTR("Sync"));
+ switch_mode->add_icon_item(get_theme_icon(SNAME("TransitionEnd"), SNAME("EditorIcons")), TTR("At End"));
+
+ auto_advance->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons")));
tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
tool_group->set_icon(get_theme_icon(SNAME("Group"), SNAME("EditorIcons")));
@@ -1652,12 +1655,12 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
break;
}
- if (transition_lines[i].disabled != state_machine->get_transition(tidx)->is_disabled()) {
+ if (transition_lines[i].disabled != bool(state_machine->get_transition(tidx)->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED)) {
state_machine_draw->queue_redraw();
break;
}
- if (transition_lines[i].auto_advance != state_machine->get_transition(tidx)->has_auto_advance()) {
+ if (transition_lines[i].auto_advance != bool(state_machine->get_transition(tidx)->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_AUTO)) {
state_machine_draw->queue_redraw();
break;
}
@@ -1904,7 +1907,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
void AnimationNodeStateMachineEditor::_update_mode() {
if (tool_select->is_pressed()) {
- tool_erase_hb->show();
+ selection_tools_hb->show();
bool nothing_selected = selected_nodes.is_empty() && selected_transition_from == StringName() && selected_transition_to == StringName();
bool start_end_selected = selected_nodes.size() == 1 && (*selected_nodes.begin() == state_machine->start_node || *selected_nodes.begin() == state_machine->end_node);
tool_erase->set_disabled(nothing_selected || start_end_selected || read_only);
@@ -1927,7 +1930,13 @@ void AnimationNodeStateMachineEditor::_update_mode() {
}
}
} else {
- tool_erase_hb->hide();
+ selection_tools_hb->hide();
+ }
+
+ if (tool_connect->is_pressed()) {
+ transition_tools_hb->show();
+ } else {
+ transition_tools_hb->hide();
}
}
@@ -1978,35 +1987,48 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
tool_connect->set_tooltip_text(TTR("Connect nodes."));
tool_connect->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), CONNECT_DEFERRED);
- tool_erase_hb = memnew(HBoxContainer);
- top_hb->add_child(tool_erase_hb);
- tool_erase_hb->add_child(memnew(VSeparator));
+ // Context-sensitive selection tools:
+ selection_tools_hb = memnew(HBoxContainer);
+ top_hb->add_child(selection_tools_hb);
+ selection_tools_hb->add_child(memnew(VSeparator));
tool_group = memnew(Button);
tool_group->set_flat(true);
tool_group->set_tooltip_text(TTR("Group Selected Node(s)") + " (Ctrl+G)");
tool_group->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_group_selected_nodes));
tool_group->set_disabled(true);
- tool_erase_hb->add_child(tool_group);
+ selection_tools_hb->add_child(tool_group);
tool_ungroup = memnew(Button);
tool_ungroup->set_flat(true);
tool_ungroup->set_tooltip_text(TTR("Ungroup Selected Node") + " (Ctrl+Shift+G)");
tool_ungroup->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_ungroup_selected_nodes));
tool_ungroup->set_visible(false);
- tool_erase_hb->add_child(tool_ungroup);
+ selection_tools_hb->add_child(tool_ungroup);
tool_erase = memnew(Button);
tool_erase->set_flat(true);
tool_erase->set_tooltip_text(TTR("Remove selected node or transition."));
tool_erase->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_erase_selected).bind(false));
tool_erase->set_disabled(true);
- tool_erase_hb->add_child(tool_erase);
+ selection_tools_hb->add_child(tool_erase);
+
+ transition_tools_hb = memnew(HBoxContainer);
+ top_hb->add_child(transition_tools_hb);
+ transition_tools_hb->add_child(memnew(VSeparator));
+
+ transition_tools_hb->add_child(memnew(Label(TTR("Transition:"))));
+ switch_mode = memnew(OptionButton);
+ transition_tools_hb->add_child(switch_mode);
+
+ auto_advance = memnew(Button);
+ auto_advance->set_flat(true);
+ auto_advance->set_tooltip_text(TTR("New Transitions Should Auto Advance"));
+ auto_advance->set_toggle_mode(true);
+ auto_advance->set_pressed(true);
+ transition_tools_hb->add_child(auto_advance);
- top_hb->add_child(memnew(VSeparator));
- top_hb->add_child(memnew(Label(TTR("Transition:"))));
- transition_mode = memnew(OptionButton);
- top_hb->add_child(transition_mode);
+ //
top_hb->add_spacer();
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index 5edf803c41..28b5f0cbcc 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -52,15 +52,18 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
Button *tool_select = nullptr;
Button *tool_create = nullptr;
Button *tool_connect = nullptr;
- Button *tool_group = nullptr;
- Button *tool_ungroup = nullptr;
Popup *name_edit_popup = nullptr;
LineEdit *name_edit = nullptr;
- HBoxContainer *tool_erase_hb = nullptr;
+ HBoxContainer *selection_tools_hb = nullptr;
+ Button *tool_group = nullptr;
+ Button *tool_ungroup = nullptr;
Button *tool_erase = nullptr;
- OptionButton *transition_mode = nullptr;
+ HBoxContainer *transition_tools_hb = nullptr;
+ OptionButton *switch_mode = nullptr;
+ Button *auto_advance = nullptr;
+
OptionButton *play_mode = nullptr;
PanelContainer *panel = nullptr;
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 7c3ecd5d4e..6483a18a4d 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -43,6 +43,11 @@
#include "editor/project_settings_editor.h"
#include "scene/gui/menu_button.h"
+#include "modules/modules_enabled.gen.h" // For svg.
+#ifdef MODULE_SVG_ENABLED
+#include "modules/svg/image_loader_svg.h"
+#endif
+
static inline void setup_http_request(HTTPRequest *request) {
request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true));
@@ -751,13 +756,30 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB
uint8_t png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
uint8_t jpg_signature[3] = { 255, 216, 255 };
+ uint8_t webp_signature[4] = { 82, 73, 70, 70 };
+ uint8_t bmp_signature[2] = { 66, 77 };
if (r) {
if ((memcmp(&r[0], &png_signature[0], 8) == 0) && Image::_png_mem_loader_func) {
image->copy_internals_from(Image::_png_mem_loader_func(r, len));
} else if ((memcmp(&r[0], &jpg_signature[0], 3) == 0) && Image::_jpg_mem_loader_func) {
image->copy_internals_from(Image::_jpg_mem_loader_func(r, len));
+ } else if ((memcmp(&r[0], &webp_signature[0], 4) == 0) && Image::_webp_mem_loader_func) {
+ image->copy_internals_from(Image::_webp_mem_loader_func(r, len));
+ } else if ((memcmp(&r[0], &bmp_signature[0], 2) == 0) && Image::_bmp_mem_loader_func) {
+ image->copy_internals_from(Image::_bmp_mem_loader_func(r, len));
}
+#ifdef MODULE_SVG_ENABLED
+ else {
+ ImageLoaderSVG svg_loader;
+ Ref<Image> img = Ref<Image>(memnew(Image));
+ Error err = svg_loader.create_image_from_utf8_buffer(img, image_data, 1.0, false);
+
+ if (err == OK) {
+ image->copy_internals_from(img);
+ }
+ }
+#endif
}
if (!image->is_empty()) {
diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp
new file mode 100644
index 0000000000..60d949cdf0
--- /dev/null
+++ b/editor/plugins/audio_stream_editor_plugin.cpp
@@ -0,0 +1,280 @@
+/*************************************************************************/
+/* audio_stream_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "audio_stream_editor_plugin.h"
+
+#include "core/core_string_names.h"
+#include "editor/audio_stream_preview.h"
+#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
+#include "scene/resources/audio_stream_wav.h"
+
+// AudioStreamEditor
+
+void AudioStreamEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_READY: {
+ AudioStreamPreviewGenerator::get_singleton()->connect(SNAME("preview_updated"), callable_mp(this, &AudioStreamEditor::_preview_changed));
+ } break;
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_ENTER_TREE: {
+ Ref<Font> font = get_theme_font(SNAME("status_source"), SNAME("EditorFonts"));
+
+ _current_label->add_theme_font_override(SNAME("font"), font);
+ _duration_label->add_theme_font_override(SNAME("font"), font);
+
+ _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ _stop_button->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
+ _preview->set_color(get_theme_color(SNAME("dark_color_2"), SNAME("Editor")));
+
+ set_color(get_theme_color(SNAME("dark_color_1"), SNAME("Editor")));
+
+ _indicator->queue_redraw();
+ _preview->queue_redraw();
+ } break;
+ case NOTIFICATION_PROCESS: {
+ _current = _player->get_playback_position();
+ _indicator->queue_redraw();
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_visible_in_tree()) {
+ _stop();
+ }
+ } break;
+ default: {
+ } break;
+ }
+}
+
+void AudioStreamEditor::_draw_preview() {
+ Rect2 rect = _preview->get_rect();
+ Size2 size = get_size();
+
+ Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(stream);
+ float preview_len = preview->get_length();
+
+ Vector<Vector2> lines;
+ lines.resize(size.width * 2);
+
+ for (int i = 0; i < size.width; i++) {
+ float ofs = i * preview_len / size.width;
+ float ofs_n = (i + 1) * preview_len / size.width;
+ float max = preview->get_max(ofs, ofs_n) * 0.5 + 0.5;
+ float min = preview->get_min(ofs, ofs_n) * 0.5 + 0.5;
+
+ int idx = i;
+ lines.write[idx * 2 + 0] = Vector2(i + 1, rect.position.y + min * rect.size.y);
+ lines.write[idx * 2 + 1] = Vector2(i + 1, rect.position.y + max * rect.size.y);
+ }
+
+ RS::get_singleton()->canvas_item_add_multiline(_preview->get_canvas_item(), lines, { get_theme_color(SNAME("contrast_color_2"), SNAME("Editor")) });
+}
+
+void AudioStreamEditor::_preview_changed(ObjectID p_which) {
+ if (stream.is_valid() && stream->get_instance_id() == p_which) {
+ _preview->queue_redraw();
+ }
+}
+
+void AudioStreamEditor::_stream_changed() {
+ if (!is_visible()) {
+ return;
+ }
+ queue_redraw();
+}
+
+void AudioStreamEditor::_play() {
+ if (_player->is_playing()) {
+ _pausing = true;
+ _player->stop();
+ _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ set_process(false);
+ } else {
+ _pausing = false;
+ _player->play(_current);
+ _play_button->set_icon(get_theme_icon(SNAME("Pause"), SNAME("EditorIcons")));
+ set_process(true);
+ }
+}
+
+void AudioStreamEditor::_stop() {
+ _player->stop();
+ _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ _current = 0;
+ _indicator->queue_redraw();
+ set_process(false);
+}
+
+void AudioStreamEditor::_on_finished() {
+ _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ if (!_pausing) {
+ _current = 0;
+ _indicator->queue_redraw();
+ } else {
+ _pausing = false;
+ }
+ set_process(false);
+}
+
+void AudioStreamEditor::_draw_indicator() {
+ if (stream.is_null()) {
+ return;
+ }
+
+ Rect2 rect = _preview->get_rect();
+ float len = stream->get_length();
+ float ofs_x = _current / len * rect.size.width;
+ const Color col = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ Ref<Texture2D> icon = get_theme_icon(SNAME("TimelineIndicator"), SNAME("EditorIcons"));
+ _indicator->draw_line(Point2(ofs_x, 0), Point2(ofs_x, rect.size.height), col, Math::round(2 * EDSCALE));
+ _indicator->draw_texture(
+ icon,
+ Point2(ofs_x - icon->get_width() * 0.5, 0),
+ col);
+
+ _current_label->set_text(String::num(_current, 2).pad_decimals(2) + " /");
+}
+
+void AudioStreamEditor::_on_input_indicator(Ref<InputEvent> p_event) {
+ const Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
+ if (mb->is_pressed()) {
+ _seek_to(mb->get_position().x);
+ }
+ _dragging = mb->is_pressed();
+ }
+
+ const Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ if (_dragging) {
+ _seek_to(mm->get_position().x);
+ }
+ }
+}
+
+void AudioStreamEditor::_seek_to(real_t p_x) {
+ _current = p_x / _preview->get_rect().size.x * stream->get_length();
+ _current = CLAMP(_current, 0, stream->get_length());
+ _player->seek(_current);
+ _indicator->queue_redraw();
+}
+
+void AudioStreamEditor::set_stream(const Ref<AudioStream> &p_stream) {
+ if (stream.is_valid()) {
+ stream->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &AudioStreamEditor::_stream_changed));
+ }
+
+ stream = p_stream;
+ if (stream.is_null()) {
+ hide();
+ return;
+ }
+ stream->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &AudioStreamEditor::_stream_changed));
+
+ _player->set_stream(stream);
+ _current = 0;
+
+ String text = String::num(stream->get_length(), 2).pad_decimals(2) + "s";
+ _duration_label->set_text(text);
+
+ queue_redraw();
+}
+
+AudioStreamEditor::AudioStreamEditor() {
+ set_custom_minimum_size(Size2(1, 100) * EDSCALE);
+
+ _player = memnew(AudioStreamPlayer);
+ _player->connect(SNAME("finished"), callable_mp(this, &AudioStreamEditor::_on_finished));
+ add_child(_player);
+
+ VBoxContainer *vbox = memnew(VBoxContainer);
+ vbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
+ add_child(vbox);
+
+ _preview = memnew(ColorRect);
+ _preview->set_v_size_flags(SIZE_EXPAND_FILL);
+ _preview->connect(SNAME("draw"), callable_mp(this, &AudioStreamEditor::_draw_preview));
+ vbox->add_child(_preview);
+
+ _indicator = memnew(Control);
+ _indicator->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
+ _indicator->connect(SNAME("draw"), callable_mp(this, &AudioStreamEditor::_draw_indicator));
+ _indicator->connect(SNAME("gui_input"), callable_mp(this, &AudioStreamEditor::_on_input_indicator));
+ _preview->add_child(_indicator);
+
+ HBoxContainer *hbox = memnew(HBoxContainer);
+ hbox->add_theme_constant_override("separation", 0);
+ vbox->add_child(hbox);
+
+ _play_button = memnew(Button);
+ hbox->add_child(_play_button);
+ _play_button->set_flat(true);
+ _play_button->set_focus_mode(Control::FOCUS_NONE);
+ _play_button->connect(SNAME("pressed"), callable_mp(this, &AudioStreamEditor::_play));
+ _play_button->set_shortcut(ED_SHORTCUT("audio_stream_editor/audio_preview_play_pause", TTR("Audio Preview Play/Pause"), Key::SPACE));
+
+ _stop_button = memnew(Button);
+ hbox->add_child(_stop_button);
+ _stop_button->set_flat(true);
+ _stop_button->set_focus_mode(Control::FOCUS_NONE);
+ _stop_button->connect(SNAME("pressed"), callable_mp(this, &AudioStreamEditor::_stop));
+
+ _current_label = memnew(Label);
+ _current_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
+ _current_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ _current_label->set_modulate(Color(1, 1, 1, 0.5));
+ hbox->add_child(_current_label);
+
+ _duration_label = memnew(Label);
+ hbox->add_child(_duration_label);
+}
+
+// EditorInspectorPluginAudioStream
+
+bool EditorInspectorPluginAudioStream::can_handle(Object *p_object) {
+ return Object::cast_to<AudioStreamWAV>(p_object) != nullptr;
+}
+
+void EditorInspectorPluginAudioStream::parse_begin(Object *p_object) {
+ AudioStream *stream = Object::cast_to<AudioStream>(p_object);
+
+ editor = memnew(AudioStreamEditor);
+ editor->set_stream(Ref<AudioStream>(stream));
+
+ add_custom_control(editor);
+}
+
+// AudioStreamEditorPlugin
+
+AudioStreamEditorPlugin::AudioStreamEditorPlugin() {
+ Ref<EditorInspectorPluginAudioStream> plugin;
+ plugin.instantiate();
+ add_inspector_plugin(plugin);
+}
diff --git a/editor/plugins/audio_stream_editor_plugin.h b/editor/plugins/audio_stream_editor_plugin.h
new file mode 100644
index 0000000000..13e52929ee
--- /dev/null
+++ b/editor/plugins/audio_stream_editor_plugin.h
@@ -0,0 +1,93 @@
+/*************************************************************************/
+/* audio_stream_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef AUDIO_STREAM_EDITOR_PLUGIN_H
+#define AUDIO_STREAM_EDITOR_PLUGIN_H
+
+#include "editor/editor_inspector.h"
+#include "editor/editor_plugin.h"
+#include "scene/audio/audio_stream_player.h"
+#include "scene/gui/button.h"
+#include "scene/gui/color_rect.h"
+#include "scene/gui/label.h"
+
+class AudioStreamEditor : public ColorRect {
+ GDCLASS(AudioStreamEditor, ColorRect);
+
+ Ref<AudioStream> stream;
+
+ AudioStreamPlayer *_player = nullptr;
+ ColorRect *_preview = nullptr;
+ Control *_indicator = nullptr;
+ Label *_current_label = nullptr;
+ Label *_duration_label = nullptr;
+
+ Button *_play_button = nullptr;
+ Button *_stop_button = nullptr;
+
+ float _current = 0;
+ bool _dragging = false;
+ bool _pausing = false;
+
+protected:
+ void _notification(int p_what);
+ void _preview_changed(ObjectID p_which);
+ void _play();
+ void _stop();
+ void _on_finished();
+ void _draw_preview();
+ void _draw_indicator();
+ void _on_input_indicator(Ref<InputEvent> p_event);
+ void _seek_to(real_t p_x);
+ void _stream_changed();
+
+public:
+ void set_stream(const Ref<AudioStream> &p_stream);
+
+ AudioStreamEditor();
+};
+
+class EditorInspectorPluginAudioStream : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorPluginAudioStream, EditorInspectorPlugin);
+ AudioStreamEditor *editor = nullptr;
+
+public:
+ virtual bool can_handle(Object *p_object) override;
+ virtual void parse_begin(Object *p_object) override;
+};
+
+class AudioStreamEditorPlugin : public EditorPlugin {
+ GDCLASS(AudioStreamEditorPlugin, EditorPlugin);
+
+public:
+ AudioStreamEditorPlugin();
+};
+
+#endif // AUDIO_STREAM_EDITOR_PLUGIN_H
diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
index e21a50a434..61b7683a05 100644
--- a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
@@ -81,7 +81,7 @@ void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_und
if (p_from_index < 0) {
undo_redo_man->add_undo_method(randomizer, "remove_stream", p_to_pos < 0 ? randomizer->get_streams_count() : p_to_pos);
} else if (p_to_pos < 0) {
- undo_redo_man->add_undo_method(randomizer, "add_stream", p_from_index);
+ undo_redo_man->add_undo_method(randomizer, "add_stream", p_from_index, Ref<AudioStream>());
}
List<PropertyInfo> properties;
@@ -107,7 +107,7 @@ void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_und
#undef ADD_UNDO
if (p_from_index < 0) {
- undo_redo_man->add_do_method(randomizer, "add_stream", p_to_pos);
+ undo_redo_man->add_do_method(randomizer, "add_stream", p_to_pos, Ref<AudioStream>());
} else if (p_to_pos < 0) {
undo_redo_man->add_do_method(randomizer, "remove_stream", p_from_index);
} else {
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index aab64587ce..30322a94f1 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -135,7 +135,7 @@ public:
label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grid_step_x = memnew(SpinBox);
- grid_step_x->set_min(0.01);
+ grid_step_x->set_min(1);
grid_step_x->set_max(SPIN_BOX_GRID_RANGE);
grid_step_x->set_allow_greater(true);
grid_step_x->set_suffix("px");
@@ -144,7 +144,7 @@ public:
child_container->add_child(grid_step_x);
grid_step_y = memnew(SpinBox);
- grid_step_y->set_min(0.01);
+ grid_step_y->set_min(1);
grid_step_y->set_max(SPIN_BOX_GRID_RANGE);
grid_step_y->set_allow_greater(true);
grid_step_y->set_suffix("px");
@@ -4977,7 +4977,7 @@ CanvasItemEditor::CanvasItemEditor() {
SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created));
SceneTreeDock::get_singleton()->connect("add_node_used", callable_mp(this, &CanvasItemEditor::_reset_create_position));
- EditorNode::get_singleton()->call_deferred(SNAME("connect"), callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true));
+ EditorNode::get_singleton()->call_deferred(SNAME("connect"), "play_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true));
EditorNode::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false));
// A fluid container for all toolbars.
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 5f9446c3b1..cbe30f7e0f 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -436,6 +436,7 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
}
EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(sphere);
RS::get_singleton()->free(sphere_instance);
RS::get_singleton()->free(viewport);
@@ -767,6 +768,7 @@ EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() {
}
EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
//RS::get_singleton()->free(sphere);
RS::get_singleton()->free(mesh_instance);
RS::get_singleton()->free(viewport);
@@ -867,6 +869,7 @@ EditorFontPreviewPlugin::EditorFontPreviewPlugin() {
}
EditorFontPreviewPlugin::~EditorFontPreviewPlugin() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(canvas_item);
RS::get_singleton()->free(canvas);
RS::get_singleton()->free(viewport);
diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h
index efb2c80cfd..0f8ed1c857 100644
--- a/editor/plugins/editor_preview_plugins.h
+++ b/editor/plugins/editor_preview_plugins.h
@@ -70,10 +70,12 @@ public:
};
class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator {
+ GDCLASS(EditorPackedScenePreviewPlugin, EditorResourcePreviewGenerator);
+
public:
- virtual bool handles(const String &p_type) const;
- virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const;
- virtual Ref<Texture2D> generate_from_path(const String &p_path, const Size2 &p_size) const;
+ virtual bool handles(const String &p_type) const override;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override;
+ virtual Ref<Texture2D> generate_from_path(const String &p_path, const Size2 &p_size) const override;
EditorPackedScenePreviewPlugin();
};
@@ -107,17 +109,21 @@ public:
};
class EditorScriptPreviewPlugin : public EditorResourcePreviewGenerator {
+ GDCLASS(EditorScriptPreviewPlugin, EditorResourcePreviewGenerator);
+
public:
- virtual bool handles(const String &p_type) const;
- virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const;
+ virtual bool handles(const String &p_type) const override;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override;
EditorScriptPreviewPlugin();
};
class EditorAudioStreamPreviewPlugin : public EditorResourcePreviewGenerator {
+ GDCLASS(EditorAudioStreamPreviewPlugin, EditorResourcePreviewGenerator);
+
public:
- virtual bool handles(const String &p_type) const;
- virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const;
+ virtual bool handles(const String &p_type) const override;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override;
EditorAudioStreamPreviewPlugin();
};
diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp
index 4370d013be..6b3db095d4 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -483,7 +483,7 @@ void EditorPropertyOTVariation::update_property() {
Vector3i range = supported.get_value_at_index(i);
EditorPropertyInteger *prop = memnew(EditorPropertyInteger);
- prop->setup(range.x, range.y, 1, false, false);
+ prop->setup(range.x, range.y, false, 1, false, false);
prop->set_object_and_property(object.ptr(), "keys/" + itos(name_tag));
String name = TS->tag_to_name(name_tag);
@@ -762,7 +762,7 @@ void EditorPropertyOTFeatures::update_property() {
} break;
case Variant::INT: {
EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
- editor->setup(0, 255, 1, false, false);
+ editor->setup(0, 255, 1, false, false, false);
prop = editor;
} break;
default: {
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index 4a8e5d9979..4b31e99f0e 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -160,23 +160,23 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
p_library->set_item_shapes(id, collisions);
- Ref<NavigationMesh> navmesh;
- Transform3D navmesh_transform;
+ Ref<NavigationMesh> navigation_mesh;
+ Transform3D navigation_mesh_transform;
for (int j = 0; j < mi->get_child_count(); j++) {
Node *child2 = mi->get_child(j);
if (!Object::cast_to<NavigationRegion3D>(child2)) {
continue;
}
NavigationRegion3D *sb = Object::cast_to<NavigationRegion3D>(child2);
- navmesh = sb->get_navigation_mesh();
- navmesh_transform = sb->get_transform();
- if (!navmesh.is_null()) {
+ navigation_mesh = sb->get_navigation_mesh();
+ navigation_mesh_transform = sb->get_transform();
+ if (!navigation_mesh.is_null()) {
break;
}
}
- if (!navmesh.is_null()) {
- p_library->set_item_navmesh(id, navmesh);
- p_library->set_item_navmesh_transform(id, navmesh_transform);
+ if (!navigation_mesh.is_null()) {
+ p_library->set_item_navigation_mesh(id, navigation_mesh);
+ p_library->set_item_navigation_mesh_transform(id, navigation_mesh_transform);
}
}
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index c8b80db334..0df53bddd1 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -100,6 +100,7 @@ bool EditorNode3DGizmo::is_editable() const {
}
void EditorNode3DGizmo::clear() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
for (int i = 0; i < instances.size(); i++) {
if (instances[i].instance.is_valid()) {
RS::get_singleton()->free(instances[i].instance);
@@ -809,6 +810,7 @@ void EditorNode3DGizmo::transform() {
}
void EditorNode3DGizmo::free() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
ERR_FAIL_COND(!spatial_node);
ERR_FAIL_COND(!valid);
@@ -1016,8 +1018,9 @@ Ref<StandardMaterial3D> EditorNode3DGizmoPlugin::get_material(const String &p_na
}
String EditorNode3DGizmoPlugin::get_gizmo_name() const {
- if (get_script_instance() && get_script_instance()->has_method("_get_gizmo_name")) {
- return get_script_instance()->call("_get_gizmo_name");
+ String ret;
+ if (GDVIRTUAL_CALL(_get_gizmo_name, ret)) {
+ return ret;
}
WARN_PRINT_ONCE("A 3D editor gizmo has no name defined (it will appear as \"Unnamed Gizmo\" in the \"View > Gizmos\" menu). To resolve this, override the `_get_gizmo_name()` function to return a String in the script that extends EditorNode3DGizmoPlugin.");
@@ -1025,8 +1028,9 @@ String EditorNode3DGizmoPlugin::get_gizmo_name() const {
}
int EditorNode3DGizmoPlugin::get_priority() const {
- if (get_script_instance() && get_script_instance()->has_method("_get_priority")) {
- return get_script_instance()->call("_get_priority");
+ int ret;
+ if (GDVIRTUAL_CALL(_get_priority, ret)) {
+ return ret;
}
return 0;
}
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 363ad273a8..8e2b9b4bce 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -2606,7 +2606,7 @@ void Node3DEditorViewport::_project_settings_changed() {
const bool use_taa = GLOBAL_GET("rendering/anti_aliasing/quality/use_taa");
viewport->set_use_taa(use_taa);
- const bool transparent_background = GLOBAL_GET("rendering/transparent_background");
+ const bool transparent_background = GLOBAL_GET("rendering/viewport/transparent_background");
viewport->set_transparent_background(transparent_background);
const bool use_debanding = GLOBAL_GET("rendering/anti_aliasing/quality/use_debanding");
@@ -3557,6 +3557,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
}
void Node3DEditorViewport::_finish_gizmo_instances() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
for (int i = 0; i < 3; i++) {
RS::get_singleton()->free(move_gizmo_instance[i]);
RS::get_singleton()->free(move_plane_gizmo_instance[i]);
@@ -5536,6 +5537,7 @@ Node3DEditorViewportContainer::Node3DEditorViewportContainer() {
Node3DEditor *Node3DEditor::singleton = nullptr;
Node3DEditorSelectedItem::~Node3DEditorSelectedItem() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
if (sbox_instance.is_valid()) {
RenderingServer::get_singleton()->free(sbox_instance);
}
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index bb5491fcb5..562eddbc64 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -3003,6 +3003,7 @@ void ScriptEditor::shortcut_input(const Ref<InputEvent> &p_event) {
_go_to_tab(script_list->get_item_metadata(next_tab));
_update_script_names();
}
+ accept_event();
}
if (ED_IS_SHORTCUT("script_editor/prev_script", p_event)) {
if (script_list->get_item_count() > 1) {
@@ -3011,12 +3012,15 @@ void ScriptEditor::shortcut_input(const Ref<InputEvent> &p_event) {
_go_to_tab(script_list->get_item_metadata(next_tab));
_update_script_names();
}
+ accept_event();
}
if (ED_IS_SHORTCUT("script_editor/window_move_up", p_event)) {
_menu_option(WINDOW_MOVE_UP);
+ accept_event();
}
if (ED_IS_SHORTCUT("script_editor/window_move_down", p_event)) {
_menu_option(WINDOW_MOVE_DOWN);
+ accept_event();
}
}
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index f79a001efb..d2dadd884b 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -153,9 +153,10 @@ void BoneTransformEditor::set_target(const String &p_prop) {
void BoneTransformEditor::_property_keyed(const String &p_path, bool p_advance) {
AnimationTrackEditor *te = AnimationPlayerEditor::get_singleton()->get_track_editor();
- if (!te->has_keying()) {
+ if (!te || !te->has_keying()) {
return;
}
+ te->_clear_selection();
PackedStringArray split = p_path.split("/");
if (split.size() == 3 && split[0] == "bones") {
int bone_idx = split[1].to_int();
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index 57f9b3135a..1fdf940a82 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -309,7 +309,22 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
case ROTATE_LEFT:
case FLIP_HORIZONTALLY:
case FLIP_VERTICALLY: {
- undo_redo->create_action(TTR("Rotate Polygons Left"));
+ switch (p_item_pressed) {
+ case ROTATE_RIGHT: {
+ undo_redo->create_action(TTR("Rotate Polygons Right"));
+ } break;
+ case ROTATE_LEFT: {
+ undo_redo->create_action(TTR("Rotate Polygons Left"));
+ } break;
+ case FLIP_HORIZONTALLY: {
+ undo_redo->create_action(TTR("Flip Polygons Horizontally"));
+ } break;
+ case FLIP_VERTICALLY: {
+ undo_redo->create_action(TTR("Flip Polygons Vertically"));
+ } break;
+ default:
+ break;
+ }
for (unsigned int i = 0; i < polygons.size(); i++) {
Vector<Point2> new_polygon;
for (int point_index = 0; point_index < polygons[i].size(); point_index++) {
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 4131c06745..414c3a2759 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -924,6 +924,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Color modulate = tile_data->get_modulate();
Color self_modulate = tile_map->get_self_modulate();
modulate *= self_modulate;
+ modulate *= tile_map->get_layer_modulate(tile_map_layer);
// Draw the tile.
p_overlay->draw_texture_rect_region(atlas_source->get_texture(), dest_rect, source_rect, modulate * Color(1.0, 1.0, 1.0, 0.5), transpose, tile_set->is_uv_clipping());
@@ -1487,13 +1488,15 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() {
}
// Selection if needed.
- for (RBSet<TileMapCell>::Element *E = tile_set_selection.front(); E; E = E->next()) {
+ for (RBSet<TileMapCell>::Element *E = tile_set_selection.front(); E;) {
+ RBSet<TileMapCell>::Element *N = E->next();
const TileMapCell *selected = &(E->get());
if (!tile_set->has_source(selected->source_id) ||
!tile_set->get_source(selected->source_id)->has_tile(selected->get_atlas_coords()) ||
!tile_set->get_source(selected->source_id)->has_alternative_tile(selected->get_atlas_coords(), selected->alternative_tile)) {
tile_set_selection.erase(E);
}
+ E = N;
}
if (!tile_map_selection.is_empty()) {
diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
index b31fb1aa58..2868c14452 100644
--- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
+++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
@@ -398,7 +398,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
source_from_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
source_from_property_editor->set_selectable(false);
source_from_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- source_from_property_editor->setup(-1, 99999, 1, true, false);
+ source_from_property_editor->setup(-1, 99999, 1, false, true, false);
vboxcontainer_from->add_child(source_from_property_editor);
coords_from_property_editor = memnew(EditorPropertyVector2i);
@@ -417,7 +417,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
alternative_from_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
alternative_from_property_editor->set_selectable(false);
alternative_from_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- alternative_from_property_editor->setup(-1, 99999, 1, true, false);
+ alternative_from_property_editor->setup(-1, 99999, 1, false, true, false);
alternative_from_property_editor->hide();
vboxcontainer_from->add_child(alternative_from_property_editor);
@@ -432,7 +432,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
source_to_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
source_to_property_editor->set_selectable(false);
source_to_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- source_to_property_editor->setup(-1, 99999, 1, true, false);
+ source_to_property_editor->setup(-1, 99999, 1, false, true, false);
vboxcontainer_to->add_child(source_to_property_editor);
coords_to_property_editor = memnew(EditorPropertyVector2i);
@@ -451,7 +451,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
alternative_to_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
alternative_to_property_editor->set_selectable(false);
alternative_to_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- alternative_to_property_editor->setup(-1, 99999, 1, true, false);
+ alternative_to_property_editor->setup(-1, 99999, 1, false, true, false);
alternative_to_property_editor->hide();
vboxcontainer_to->add_child(alternative_to_property_editor);
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index 369a59c443..e9c6184d73 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -47,43 +47,7 @@
VersionControlEditorPlugin *VersionControlEditorPlugin::singleton = nullptr;
void VersionControlEditorPlugin::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_initialize_vcs"), &VersionControlEditorPlugin::_initialize_vcs);
- ClassDB::bind_method(D_METHOD("_set_credentials"), &VersionControlEditorPlugin::_set_credentials);
- ClassDB::bind_method(D_METHOD("_update_set_up_warning"), &VersionControlEditorPlugin::_update_set_up_warning);
- ClassDB::bind_method(D_METHOD("_commit"), &VersionControlEditorPlugin::_commit);
- ClassDB::bind_method(D_METHOD("_refresh_stage_area"), &VersionControlEditorPlugin::_refresh_stage_area);
- ClassDB::bind_method(D_METHOD("_move_all"), &VersionControlEditorPlugin::_move_all);
- ClassDB::bind_method(D_METHOD("_load_diff"), &VersionControlEditorPlugin::_load_diff);
- ClassDB::bind_method(D_METHOD("_display_diff"), &VersionControlEditorPlugin::_display_diff);
- ClassDB::bind_method(D_METHOD("_item_activated"), &VersionControlEditorPlugin::_item_activated);
- ClassDB::bind_method(D_METHOD("_update_branch_create_button"), &VersionControlEditorPlugin::_update_branch_create_button);
- ClassDB::bind_method(D_METHOD("_update_remote_create_button"), &VersionControlEditorPlugin::_update_remote_create_button);
- ClassDB::bind_method(D_METHOD("_update_commit_button"), &VersionControlEditorPlugin::_update_commit_button);
- ClassDB::bind_method(D_METHOD("_refresh_branch_list"), &VersionControlEditorPlugin::_refresh_branch_list);
- ClassDB::bind_method(D_METHOD("_set_commit_list_size"), &VersionControlEditorPlugin::_set_commit_list_size);
- ClassDB::bind_method(D_METHOD("_refresh_commit_list"), &VersionControlEditorPlugin::_refresh_commit_list);
- ClassDB::bind_method(D_METHOD("_refresh_remote_list"), &VersionControlEditorPlugin::_refresh_remote_list);
- ClassDB::bind_method(D_METHOD("_ssh_public_key_selected"), &VersionControlEditorPlugin::_ssh_public_key_selected);
- ClassDB::bind_method(D_METHOD("_ssh_private_key_selected"), &VersionControlEditorPlugin::_ssh_private_key_selected);
- ClassDB::bind_method(D_METHOD("_commit_message_gui_input"), &VersionControlEditorPlugin::_commit_message_gui_input);
- ClassDB::bind_method(D_METHOD("_cell_button_pressed"), &VersionControlEditorPlugin::_cell_button_pressed);
- ClassDB::bind_method(D_METHOD("_discard_all"), &VersionControlEditorPlugin::_discard_all);
- ClassDB::bind_method(D_METHOD("_create_branch"), &VersionControlEditorPlugin::_create_branch);
- ClassDB::bind_method(D_METHOD("_create_remote"), &VersionControlEditorPlugin::_create_remote);
- ClassDB::bind_method(D_METHOD("_remove_branch"), &VersionControlEditorPlugin::_remove_branch);
- ClassDB::bind_method(D_METHOD("_remove_remote"), &VersionControlEditorPlugin::_remove_remote);
- ClassDB::bind_method(D_METHOD("_branch_item_selected"), &VersionControlEditorPlugin::_branch_item_selected);
- ClassDB::bind_method(D_METHOD("_remote_selected"), &VersionControlEditorPlugin::_remote_selected);
- ClassDB::bind_method(D_METHOD("_fetch"), &VersionControlEditorPlugin::_fetch);
- ClassDB::bind_method(D_METHOD("_pull"), &VersionControlEditorPlugin::_pull);
- ClassDB::bind_method(D_METHOD("_push"), &VersionControlEditorPlugin::_push);
- ClassDB::bind_method(D_METHOD("_extra_option_selected"), &VersionControlEditorPlugin::_extra_option_selected);
- ClassDB::bind_method(D_METHOD("_update_extra_options"), &VersionControlEditorPlugin::_update_extra_options);
- ClassDB::bind_method(D_METHOD("_popup_branch_remove_confirm"), &VersionControlEditorPlugin::_popup_branch_remove_confirm);
- ClassDB::bind_method(D_METHOD("_popup_remote_remove_confirm"), &VersionControlEditorPlugin::_popup_remote_remove_confirm);
- ClassDB::bind_method(D_METHOD("_popup_file_dialog"), &VersionControlEditorPlugin::_popup_file_dialog);
-
- ClassDB::bind_method(D_METHOD("popup_vcs_set_up_dialog"), &VersionControlEditorPlugin::popup_vcs_set_up_dialog);
+ // No binds required so far.
}
void VersionControlEditorPlugin::_create_vcs_metadata_files() {
@@ -94,12 +58,10 @@ void VersionControlEditorPlugin::_create_vcs_metadata_files() {
void VersionControlEditorPlugin::_notification(int p_what) {
if (p_what == NOTIFICATION_READY) {
String installed_plugin = GLOBAL_DEF("editor/version_control/plugin_name", "");
- String project_path = GLOBAL_DEF("editor/version_control/project_path", OS::get_singleton()->get_resource_dir());
- project_path_input->set_text(project_path);
bool has_autoload_enable = GLOBAL_DEF("editor/version_control/autoload_on_startup", false);
if (installed_plugin != "" && has_autoload_enable) {
- if (_load_plugin(installed_plugin, project_path)) {
+ if (_load_plugin(installed_plugin)) {
_set_credentials();
}
}
@@ -144,18 +106,15 @@ void VersionControlEditorPlugin::_initialize_vcs() {
const int id = set_up_choice->get_selected_id();
String selected_plugin = set_up_choice->get_item_text(id);
- if (_load_plugin(selected_plugin, project_path_input->get_text())) {
+ if (_load_plugin(selected_plugin)) {
ProjectSettings::get_singleton()->set("editor/version_control/autoload_on_startup", true);
ProjectSettings::get_singleton()->set("editor/version_control/plugin_name", selected_plugin);
- ProjectSettings::get_singleton()->set("editor/version_control/project_path", project_path_input->get_text());
ProjectSettings::get_singleton()->save();
}
}
void VersionControlEditorPlugin::_set_vcs_ui_state(bool p_enabled) {
- select_project_path_button->set_disabled(p_enabled);
set_up_dialog->get_ok_button()->set_disabled(!p_enabled);
- project_path_input->set_editable(!p_enabled);
set_up_choice->set_disabled(p_enabled);
toggle_vcs_choice->set_pressed_no_signal(p_enabled);
}
@@ -181,14 +140,14 @@ void VersionControlEditorPlugin::_set_credentials() {
EditorSettings::get_singleton()->set_setting("version_control/ssh_private_key_path", ssh_private_key);
}
-bool VersionControlEditorPlugin::_load_plugin(String p_name, String p_project_path) {
+bool VersionControlEditorPlugin::_load_plugin(String p_name) {
Object *extension_instance = ClassDB::instantiate(p_name);
ERR_FAIL_NULL_V_MSG(extension_instance, false, "Received a nullptr VCS extension instance during construction.");
EditorVCSInterface *vcs_plugin = Object::cast_to<EditorVCSInterface>(extension_instance);
ERR_FAIL_NULL_V_MSG(vcs_plugin, false, vformat("Could not cast VCS extension instance to %s.", EditorVCSInterface::get_class_static()));
- String res_dir = project_path_input->get_text();
+ String res_dir = OS::get_singleton()->get_resource_dir();
ERR_FAIL_COND_V_MSG(!vcs_plugin->initialize(res_dir), false, "Could not initialize " + p_name);
@@ -435,6 +394,10 @@ void VersionControlEditorPlugin::_discard_file(String p_file_path, EditorVCSInte
EditorFileSystem::get_singleton()->update_file(p_file_path);
}
+void VersionControlEditorPlugin::_confirm_discard_all() {
+ discard_all_confirm->popup_centered();
+}
+
void VersionControlEditorPlugin::_discard_all() {
TreeItem *file_entry = unstaged_files->get_root()->get_first_child();
while (file_entry) {
@@ -631,7 +594,6 @@ void VersionControlEditorPlugin::_display_diff(int p_idx) {
diff->pop();
diff->pop();
- diff->add_newline();
diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("status_source"), SNAME("EditorFonts")));
for (int j = 0; j < diff_file.diff_hunks.size(); j++) {
EditorVCSInterface::DiffHunk hunk = diff_file.diff_hunks[j];
@@ -641,6 +603,7 @@ void VersionControlEditorPlugin::_display_diff(int p_idx) {
String old_lines = String::num_int64(hunk.old_lines);
String new_lines = String::num_int64(hunk.new_lines);
+ diff->add_newline();
diff->append_text("[center]@@ " + old_start + "," + old_lines + " " + new_start + "," + new_lines + " @@[/center]");
diff->add_newline();
@@ -653,7 +616,6 @@ void VersionControlEditorPlugin::_display_diff(int p_idx) {
break;
}
diff->add_newline();
- diff->add_newline();
}
diff->pop();
@@ -721,12 +683,10 @@ void VersionControlEditorPlugin::_display_diff_split_view(List<EditorVCSInterfac
if (diff_line.old_line_no >= 0) {
diff->push_cell();
- diff->push_indent(1);
diff->push_color(has_change ? red : white);
diff->add_text(String::num_int64(diff_line.old_line_no));
diff->pop();
diff->pop();
- diff->pop();
diff->push_cell();
diff->push_color(has_change ? red : white);
@@ -753,12 +713,10 @@ void VersionControlEditorPlugin::_display_diff_split_view(List<EditorVCSInterfac
if (diff_line.new_line_no >= 0) {
diff->push_cell();
- diff->push_indent(1);
diff->push_color(has_change ? green : white);
diff->add_text(String::num_int64(diff_line.new_line_no));
diff->pop();
diff->pop();
- diff->pop();
diff->push_cell();
diff->push_color(has_change ? green : white);
@@ -943,10 +901,6 @@ void VersionControlEditorPlugin::_toggle_vcs_integration(bool p_toggled) {
}
}
-void VersionControlEditorPlugin::_project_path_selected(String p_project_path) {
- project_path_input->set_text(p_project_path);
-}
-
void VersionControlEditorPlugin::fetch_available_vcs_plugin_names() {
available_plugins.clear();
ClassDB::get_direct_inheriters_from_class(EditorVCSInterface::get_class_static(), &available_plugins);
@@ -1040,34 +994,6 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
set_up_choice->set_h_size_flags(Control::SIZE_EXPAND_FILL);
set_up_hbc->add_child(set_up_choice);
- HBoxContainer *project_path_hbc = memnew(HBoxContainer);
- project_path_hbc->set_h_size_flags(Control::SIZE_FILL);
- set_up_vbc->add_child(project_path_hbc);
-
- Label *project_path_label = memnew(Label);
- project_path_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- project_path_label->set_text(TTR("VCS Project Path"));
- project_path_hbc->add_child(project_path_label);
-
- project_path_input = memnew(LineEdit);
- project_path_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- project_path_input->set_text(OS::get_singleton()->get_resource_dir());
- project_path_hbc->add_child(project_path_input);
-
- FileDialog *select_project_path_file_dialog = memnew(FileDialog);
- select_project_path_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
- select_project_path_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR);
- select_project_path_file_dialog->set_show_hidden_files(true);
- select_project_path_file_dialog->set_current_dir(OS::get_singleton()->get_resource_dir());
- select_project_path_file_dialog->connect(SNAME("dir_selected"), callable_mp(this, &VersionControlEditorPlugin::_project_path_selected));
- project_path_hbc->add_child(select_project_path_file_dialog);
-
- select_project_path_button = memnew(Button);
- select_project_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons"));
- select_project_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(select_project_path_file_dialog));
- select_project_path_button->set_tooltip_text(TTR("Select VCS project path"));
- project_path_hbc->add_child(select_project_path_button);
-
HBoxContainer *toggle_vcs_hbc = memnew(HBoxContainer);
toggle_vcs_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
set_up_vbc->add_child(toggle_vcs_hbc);
@@ -1240,10 +1166,21 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_remote_list));
unstage_title->add_child(refresh_button);
+ discard_all_confirm = memnew(AcceptDialog);
+ discard_all_confirm->set_title(TTR("Discard all changes"));
+ discard_all_confirm->set_min_size(Size2i(400, 50));
+ discard_all_confirm->set_text(TTR("This operation is IRREVERSIBLE. Your changes will be deleted FOREVER."));
+ discard_all_confirm->set_hide_on_ok(true);
+ discard_all_confirm->set_ok_button_text(TTR("Permanentally delete my changes"));
+ discard_all_confirm->add_cancel_button();
+ version_commit_dock->add_child(discard_all_confirm);
+
+ discard_all_confirm->get_ok_button()->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_discard_all));
+
discard_all_button = memnew(Button);
discard_all_button->set_tooltip_text(TTR("Discard all changes"));
discard_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Close"), SNAME("EditorIcons")));
- discard_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_discard_all));
+ discard_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_confirm_discard_all));
discard_all_button->set_flat(true);
unstage_title->add_child(discard_all_button);
diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h
index 3340384a92..d73588a1bf 100644
--- a/editor/plugins/version_control_editor_plugin.h
+++ b/editor/plugins/version_control_editor_plugin.h
@@ -73,8 +73,6 @@ private:
AcceptDialog *set_up_dialog = nullptr;
CheckButton *toggle_vcs_choice = nullptr;
OptionButton *set_up_choice = nullptr;
- LineEdit *project_path_input = nullptr;
- Button *select_project_path_button = nullptr;
VBoxContainer *set_up_vbc = nullptr;
VBoxContainer *set_up_settings_vbc = nullptr;
LineEdit *set_up_username = nullptr;
@@ -86,6 +84,8 @@ private:
FileDialog *set_up_ssh_private_key_file_dialog = nullptr;
Label *set_up_warning_text = nullptr;
+ AcceptDialog *discard_all_confirm = nullptr;
+
OptionButton *commit_list_size_button = nullptr;
AcceptDialog *branch_create_confirm = nullptr;
@@ -150,13 +150,14 @@ private:
void _update_opened_tabs();
void _update_extra_options();
- bool _load_plugin(String p_name, String p_project_path);
+ bool _load_plugin(String p_name);
void _pull();
void _push();
void _force_push();
void _fetch();
void _commit();
+ void _confirm_discard_all();
void _discard_all();
void _refresh_stage_area();
void _refresh_branch_list();
@@ -193,7 +194,6 @@ private:
void _create_vcs_metadata_files();
void _popup_file_dialog(Variant p_file_dialog_variant);
void _toggle_vcs_integration(bool p_toggled);
- void _project_path_selected(String p_project_path);
friend class EditorVCSInterface;
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index cf811067c9..3d0c1acff8 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -1263,7 +1263,7 @@ Dictionary VisualShaderEditor::get_custom_node_data(Ref<VisualShaderNodeCustom>
void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) {
Ref<Script> scr = Ref<Script>(p_resource.ptr());
- if (scr.is_null() || scr->get_instance_base_type() != String("VisualShaderNodeCustom")) {
+ if (scr.is_null() || scr->get_instance_base_type() != "VisualShaderNodeCustom") {
return;
}
@@ -5383,6 +5383,10 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Binormal", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Color", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Custom0", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom0", "CUSTOM0"), { "custom0" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Custom1", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom1", "CUSTOM1"), { "custom1" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Custom2", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom2", "CUSTOM2"), { "custom2" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Custom3", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom3", "CUSTOM3"), { "custom3" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("InstanceId", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_id", "INSTANCE_ID"), { "instance_id" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("InstanceCustom", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom", "INSTANCE_CUSTOM"), { "instance_custom" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ModelViewMatrix", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview_matrix", "MODELVIEW_MATRIX"), { "modelview_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 1b169076c6..0d93c8a95e 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -447,7 +447,7 @@ private:
} else if (renderer_type == "gl_compatibility") {
renderer_info->set_text(
String::utf8("• ") + TTR("Supports desktop, mobile + web platforms.") +
- String::utf8("\n• ") + TTR("Least advanced 3D graphics.") +
+ String::utf8("\n• ") + TTR("Least advanced 3D graphics (currently work-in-progress).") +
String::utf8("\n• ") + TTR("Intended for low-end/older devices.") +
String::utf8("\n• ") + TTR("Uses OpenGL 3 backend (OpenGL 3.3/ES 3.0/WebGL2).") +
String::utf8("\n• ") + TTR("Fastest rendering of simple scenes."));
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index b406b2a1ce..b99a83a546 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -553,6 +553,14 @@ void ProjectSettingsEditor::_update_theme() {
}
}
+void ProjectSettingsEditor::_input_filter_focused() {
+ set_close_on_escape(false);
+}
+
+void ProjectSettingsEditor::_input_filter_unfocused() {
+ set_close_on_escape(true);
+}
+
void ProjectSettingsEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -683,6 +691,8 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
action_map_editor->connect("action_removed", callable_mp(this, &ProjectSettingsEditor::_action_removed));
action_map_editor->connect("action_renamed", callable_mp(this, &ProjectSettingsEditor::_action_renamed));
action_map_editor->connect("action_reordered", callable_mp(this, &ProjectSettingsEditor::_action_reordered));
+ action_map_editor->connect(SNAME("filter_focused"), callable_mp(this, &ProjectSettingsEditor::_input_filter_focused));
+ action_map_editor->connect(SNAME("filter_unfocused"), callable_mp(this, &ProjectSettingsEditor::_input_filter_unfocused));
tab_container->add_child(action_map_editor);
localization_editor = memnew(LocalizationEditor);
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index 7f6dd1b692..1687be47fb 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -107,6 +107,9 @@ class ProjectSettingsEditor : public AcceptDialog {
void _update_action_map_editor();
void _update_theme();
+ void _input_filter_focused();
+ void _input_filter_unfocused();
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp
index 247d5e1717..8ac0aa6fe3 100644
--- a/editor/register_editor_types.cpp
+++ b/editor/register_editor_types.cpp
@@ -48,6 +48,7 @@
#include "editor/import/editor_import_plugin.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
+#include "editor/plugins/audio_stream_editor_plugin.h"
#include "editor/plugins/audio_stream_randomizer_editor_plugin.h"
#include "editor/plugins/bit_map_editor_plugin.h"
#include "editor/plugins/bone_map_editor_plugin.h"
@@ -155,6 +156,7 @@ void register_editor_types() {
// This list is alphabetized, and plugins that depend on Node2D are in their own section below.
EditorPlugins::add_by_type<AnimationTreeEditorPlugin>();
+ EditorPlugins::add_by_type<AudioStreamEditorPlugin>();
EditorPlugins::add_by_type<AudioStreamRandomizerEditorPlugin>();
EditorPlugins::add_by_type<BitMapEditorPlugin>();
EditorPlugins::add_by_type<BoneMapEditorPlugin>();
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 40683e2938..5243916bd2 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -338,7 +338,7 @@ void RenameDialog::_bind_methods() {
}
void RenameDialog::_update_substitute() {
- LineEdit *focus_owner_line_edit = Object::cast_to<LineEdit>(scene_tree_editor->get_viewport()->gui_get_focus_owner());
+ LineEdit *focus_owner_line_edit = Object::cast_to<LineEdit>(get_viewport()->gui_get_focus_owner());
bool is_main_field = _is_main_field(focus_owner_line_edit);
but_insert_name->set_disabled(!is_main_field);
@@ -636,7 +636,7 @@ bool RenameDialog::_is_main_field(LineEdit *line_edit) {
}
void RenameDialog::_insert_text(String text) {
- LineEdit *focus_owner = Object::cast_to<LineEdit>(scene_tree_editor->get_viewport()->gui_get_focus_owner());
+ LineEdit *focus_owner = Object::cast_to<LineEdit>(get_viewport()->gui_get_focus_owner());
if (_is_main_field(focus_owner)) {
focus_owner->selection_delete();
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 96688a3614..4b04fd1589 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -134,6 +134,8 @@ void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) {
_tool_selected(TOOL_MOVE_DOWN);
} else if (ED_IS_SHORTCUT("scene_tree/reparent", p_event)) {
_tool_selected(TOOL_REPARENT);
+ } else if (ED_IS_SHORTCUT("scene_tree/reparent_to_new_node", p_event)) {
+ _tool_selected(TOOL_REPARENT_TO_NEW_NODE);
} else if (ED_IS_SHORTCUT("scene_tree/save_branch_as_scene", p_event)) {
_tool_selected(TOOL_NEW_SCENE_FROM);
} else if (ED_IS_SHORTCUT("scene_tree/delete_no_confirm", p_event)) {
@@ -1965,37 +1967,21 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) {
}
Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
- if (selected.size() == 1) {
- Node *node = selected.front()->get();
- Ref<Script> existing = node->get_script();
-
- undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, node);
- undo_redo->add_do_method(InspectorDock::get_singleton(), "store_script_properties", node);
- undo_redo->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", node);
- undo_redo->add_do_method(node, "set_script", p_script);
- undo_redo->add_undo_method(node, "set_script", existing);
- undo_redo->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", node);
- undo_redo->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", node);
+ undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, selected.front()->get());
+ for (Node *E : selected) {
+ Ref<Script> existing = E->get_script();
+ undo_redo->add_do_method(InspectorDock::get_singleton(), "store_script_properties", E);
+ undo_redo->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E);
+ undo_redo->add_do_method(E, "set_script", p_script);
+ undo_redo->add_undo_method(E, "set_script", existing);
+ undo_redo->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E);
+ undo_redo->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E);
undo_redo->add_do_method(this, "_update_script_button");
undo_redo->add_undo_method(this, "_update_script_button");
- undo_redo->commit_action();
- } else {
- undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, selected.front()->get());
- for (Node *E : selected) {
- Ref<Script> existing = E->get_script();
- undo_redo->add_do_method(InspectorDock::get_singleton(), "store_script_properties", E);
- undo_redo->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E);
- undo_redo->add_do_method(E, "set_script", p_script);
- undo_redo->add_undo_method(E, "set_script", existing);
- undo_redo->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E);
- undo_redo->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E);
- undo_redo->add_do_method(this, "_update_script_button");
- undo_redo->add_undo_method(this, "_update_script_button");
- }
- undo_redo->commit_action();
}
+ undo_redo->commit_action();
- _push_item(p_script.operator->());
+ _push_item(p_script.ptr());
_update_script_button();
}
@@ -3233,6 +3219,7 @@ List<Node *> SceneTreeDock::paste_nodes() {
if (!paste_parent) {
paste_parent = dup;
owner = dup;
+ dup->set_scene_file_path(String()); // Make sure the scene path is empty, to avoid accidental references.
ur->add_do_method(EditorNode::get_singleton(), "set_edited_scene", dup);
} else {
ur->add_do_method(paste_parent, "add_child", dup, true);
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 092ef30678..30a9dc5bbf 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -132,8 +132,16 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
if (config_err.is_empty()) {
return;
}
- config_err = config_err.word_wrap(80);
- warning->set_text(config_err);
+
+ const PackedInt32Array boundaries = TS->string_get_word_breaks(config_err, "", 80);
+ PackedStringArray lines;
+ for (int i = 0; i < boundaries.size(); i += 2) {
+ const int start = boundaries[i];
+ const int end = boundaries[i + 1];
+ lines.append(config_err.substr(start, end - start + 1));
+ }
+
+ warning->set_text(String("\n").join(lines));
warning->popup_centered();
} else if (p_id == BUTTON_SIGNALS) {
diff --git a/main/main.cpp b/main/main.cpp
index 1a005583af..7e1fd38e14 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -2121,7 +2121,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
MAIN_PRINT("Main: Setup Logo");
-#if defined(WEB_ENABLED) || defined(ANDROID_ENABLED)
+#if !defined(TOOLS_ENABLED) && (defined(WEB_ENABLED) || defined(ANDROID_ENABLED))
bool show_logo = false;
#else
bool show_logo = true;
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp
index 155f7809b0..8d21541341 100644
--- a/modules/basis_universal/register_types.cpp
+++ b/modules/basis_universal/register_types.cpp
@@ -277,6 +277,7 @@ void initialize_basis_universal_module(ModuleInitializationLevel p_level) {
basisu_encoder_init();
Image::basis_universal_packer = basis_universal_packer;
#endif
+ basist::basisu_transcoder_init();
Image::basis_universal_unpacker = basis_universal_unpacker;
Image::basis_universal_unpacker_ptr = basis_universal_unpacker_ptr;
}
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 4981750b7d..fd748ea569 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -106,6 +106,7 @@
<param index="0" name="instance" type="Object" />
<description>
Returns the passed [param instance] converted to a Dictionary. Can be useful for serializing.
+ [b]Note:[/b] Cannot be used to serialize objects with built-in scripts attached or objects allocated within built-in scripts.
[codeblock]
var foo = "bar"
func _ready():
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 91f31174dd..40bc2beb23 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -629,6 +629,10 @@ void GDScript::_update_doc() {
}
}
+ for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) {
+ E.value->_update_doc();
+ }
+
_add_doc(doc);
}
#endif
@@ -1111,21 +1115,27 @@ bool GDScript::inherits_script(const Ref<Script> &p_script) const {
GDScript *GDScript::find_class(const String &p_qualified_name) {
String first = p_qualified_name.get_slice("::", 0);
+ Vector<String> class_names;
GDScript *result = nullptr;
+ // Empty initial name means start here.
if (first.is_empty() || first == name) {
+ class_names = p_qualified_name.split("::");
result = this;
- } else if (first == get_root_script()->path) {
+ } else if (p_qualified_name.begins_with(get_root_script()->path)) {
+ // Script path could have a class path separator("::") in it.
+ class_names = p_qualified_name.trim_prefix(get_root_script()->path).split("::");
result = get_root_script();
} else if (HashMap<StringName, Ref<GDScript>>::Iterator E = subclasses.find(first)) {
+ class_names = p_qualified_name.split("::");
result = E->value.ptr();
} else if (_owner != nullptr) {
// Check parent scope.
return _owner->find_class(p_qualified_name);
}
- int name_count = p_qualified_name.get_slice_count("::");
- for (int i = 1; result != nullptr && i < name_count; i++) {
- String current_name = p_qualified_name.get_slice("::", i);
+ // 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];
if (HashMap<StringName, Ref<GDScript>>::Iterator E = result->subclasses.find(current_name)) {
result = E->value.ptr();
} else {
@@ -1137,11 +1147,12 @@ GDScript *GDScript::find_class(const String &p_qualified_name) {
return result;
}
-bool GDScript::is_subclass(const GDScript *p_script) {
+bool GDScript::has_class(const GDScript *p_script) {
String fqn = p_script->fully_qualified_name;
- if (!fqn.is_empty() && fqn != fully_qualified_name && fqn.begins_with(fully_qualified_name)) {
- String fqn_rest = fqn.substr(fully_qualified_name.length());
- return find_class(fqn_rest) == p_script;
+ if (fully_qualified_name.is_empty() && fqn.get_slice("::", 0).is_empty()) {
+ return p_script == this;
+ } else if (fqn.begins_with(fully_qualified_name)) {
+ return p_script == find_class(fqn.trim_prefix(fully_qualified_name));
}
return false;
}
@@ -1288,15 +1299,10 @@ String GDScript::_get_gdscript_reference_class_name(const GDScript *p_gdscript)
}
GDScript *GDScript::_get_gdscript_from_variant(const Variant &p_variant) {
- Variant::Type type = p_variant.get_type();
- if (type != Variant::Type::OBJECT)
- return nullptr;
-
Object *obj = p_variant;
- if (obj == nullptr) {
+ if (obj == nullptr || obj->get_instance_id().is_null()) {
return nullptr;
}
-
return Object::cast_to<GDScript>(obj);
}
@@ -1964,6 +1970,16 @@ void GDScriptLanguage::add_named_global_constant(const StringName &p_name, const
named_globals[p_name] = p_value;
}
+Variant GDScriptLanguage::get_any_global_constant(const StringName &p_name) {
+ if (named_globals.has(p_name)) {
+ return named_globals[p_name];
+ }
+ if (globals.has(p_name)) {
+ return _global_array[globals[p_name]];
+ }
+ ERR_FAIL_V_MSG(Variant(), vformat("Could not find any global constant with name: %s.", p_name));
+}
+
void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) {
ERR_FAIL_COND(!named_globals.has(p_name));
named_globals.erase(p_name);
@@ -2597,8 +2613,7 @@ Ref<GDScript> GDScriptLanguage::get_script_by_fully_qualified_name(const String
SelfList<GDScript> *elem = script_list.first();
while (elem) {
GDScript *scr = elem->self();
- scr = scr->find_class(p_name);
- if (scr != nullptr) {
+ if (scr->fully_qualified_name == p_name) {
return scr;
}
elem = elem->next();
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 7911ea47ec..39367e377b 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -187,7 +187,7 @@ public:
bool inherits_script(const Ref<Script> &p_script) const override;
GDScript *find_class(const String &p_qualified_name);
- bool is_subclass(const GDScript *p_script);
+ bool has_class(const GDScript *p_script);
GDScript *get_root_script();
bool is_root_script() const { return _owner == nullptr; }
String get_fully_qualified_name() const { return fully_qualified_name; }
@@ -455,6 +455,9 @@ public:
_FORCE_INLINE_ Variant *get_global_array() { return _global_array; }
_FORCE_INLINE_ const HashMap<StringName, int> &get_global_map() const { return globals; }
_FORCE_INLINE_ const HashMap<StringName, Variant> &get_named_globals_map() const { return named_globals; }
+ // These two functions should be used when behavior needs to be consistent between in-editor and running the scene
+ bool has_any_global_constant(const StringName &p_name) { return named_globals.has(p_name) || globals.has(p_name); }
+ Variant get_any_global_constant(const StringName &p_name);
_FORCE_INLINE_ static GDScriptLanguage *get_singleton() { return singleton; }
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 1149749ef7..757e602ebe 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -225,6 +225,8 @@ void GDScriptAnalyzer::get_class_node_current_scope_classes(GDScriptParser::Clas
}
p_list->push_back(p_node);
+ // TODO: Try to solve class inheritance if not yet resolving.
+
// Prioritize node base type over its outer class
if (p_node->base_type.class_type != nullptr) {
get_class_node_current_scope_classes(p_node->base_type.class_type, p_list);
@@ -235,15 +237,58 @@ void GDScriptAnalyzer::get_class_node_current_scope_classes(GDScriptParser::Clas
}
}
-Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive) {
- if (p_class->base_type.is_set()) {
- // Already resolved
+Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source) {
+ if (p_source == nullptr && parser->has_class(p_class)) {
+ p_source = p_class;
+ }
+
+ if (p_class->base_type.is_resolving()) {
+ push_error(vformat(R"(Could not resolve class "%s": Cyclic reference.)", type_from_metatype(p_class->get_datatype()).to_string()), p_source);
+ return ERR_PARSE_ERROR;
+ }
+
+ if (!p_class->base_type.has_no_type()) {
+ // Already resolved.
+ return OK;
+ }
+
+ if (!parser->has_class(p_class)) {
+ String script_path = p_class->get_datatype().script_path;
+ Ref<GDScriptParserRef> parser_ref = get_parser_for(script_path);
+ if (parser_ref.is_null()) {
+ push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
+ return ERR_PARSE_ERROR;
+ }
+
+ Error err = parser_ref->raise_status(GDScriptParserRef::PARSED);
+ if (err) {
+ push_error(vformat(R"(Could not parse script "%s": %s.)", script_path, error_names[err]), p_source);
+ return ERR_PARSE_ERROR;
+ }
+
+ ERR_FAIL_COND_V_MSG(!parser_ref->get_parser()->has_class(p_class), ERR_PARSE_ERROR, R"(Parser bug: Mismatched external parser.)");
+
+ GDScriptAnalyzer *other_analyzer = parser_ref->get_analyzer();
+ GDScriptParser *other_parser = parser_ref->get_parser();
+
+ int error_count = other_parser->errors.size();
+ other_analyzer->resolve_class_inheritance(p_class);
+ if (other_parser->errors.size() > error_count) {
+ push_error(vformat(R"(Could not resolve inheritance for class "%s".)", p_class->fqcn), p_source);
+ return ERR_PARSE_ERROR;
+ }
+
return OK;
}
+ GDScriptParser::ClassNode *previous_class = parser->current_class;
+ parser->current_class = p_class;
+
if (p_class->identifier) {
StringName class_name = p_class->identifier->name;
- if (class_exists(class_name)) {
+ if (GDScriptParser::get_builtin_type(class_name) < Variant::VARIANT_MAX) {
+ push_error(vformat(R"(Class "%s" hides a built-in type.)", class_name), p_class->identifier);
+ } else if (class_exists(class_name)) {
push_error(vformat(R"(Class "%s" hides a native class.)", class_name), p_class->identifier);
} else if (ScriptServer::is_global_class(class_name) && (ScriptServer::get_global_class_path(class_name) != parser->script_path || p_class != parser->head)) {
push_error(vformat(R"(Class "%s" hides a global script class.)", class_name), p_class->identifier);
@@ -252,7 +297,9 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
}
}
- GDScriptParser::DataType result;
+ GDScriptParser::DataType resolving_datatype;
+ resolving_datatype.kind = GDScriptParser::DataType::RESOLVING;
+ p_class->base_type = resolving_datatype;
// Set datatype for class.
GDScriptParser::DataType class_type;
@@ -265,6 +312,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
class_type.builtin_type = Variant::OBJECT;
p_class->set_datatype(class_type);
+ GDScriptParser::DataType result;
if (!p_class->extends_used) {
result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
result.kind = GDScriptParser::DataType::NATIVE;
@@ -286,7 +334,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
return ERR_PARSE_ERROR;
}
- Error err = ext_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = ext_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err != OK) {
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", p_class->extends_path), p_class);
return err;
@@ -313,7 +361,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
return ERR_PARSE_ERROR;
}
- Error err = base_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = base_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err != OK) {
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
return err;
@@ -322,7 +370,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
}
} else if (ProjectSettings::get_singleton()->has_autoload(name) && ProjectSettings::get_singleton()->get_autoload(name).is_singleton) {
const ProjectSettings::AutoloadInfo &info = ProjectSettings::get_singleton()->get_autoload(name);
- if (info.path.get_extension().to_lower() != ".gd") {
+ if (info.path.get_extension().to_lower() != GDScriptLanguage::get_singleton()->get_extension()) {
push_error(vformat(R"(Singleton %s is not a GDScript.)", info.name), p_class);
return ERR_PARSE_ERROR;
}
@@ -333,11 +381,12 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
return ERR_PARSE_ERROR;
}
- Error err = info_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = info_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err != OK) {
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
return err;
}
+ base = info_parser->get_parser()->head->get_datatype();
} else if (class_exists(name) && ClassDB::can_instantiate(name)) {
base.kind = GDScriptParser::DataType::NATIVE;
base.native_type = name;
@@ -349,7 +398,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
for (GDScriptParser::ClassNode *look_class : script_classes) {
if (look_class->identifier && look_class->identifier->name == name) {
if (!look_class->get_datatype().is_set()) {
- Error err = resolve_inheritance(look_class, false);
+ Error err = resolve_class_inheritance(look_class, p_class);
if (err) {
return err;
}
@@ -358,15 +407,9 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
found = true;
break;
}
- if (look_class->members_indices.has(name) && look_class->get_member(name).type == GDScriptParser::ClassNode::Member::CLASS) {
- GDScriptParser::ClassNode::Member member = look_class->get_member(name);
- if (!member.m_class->get_datatype().is_set()) {
- Error err = resolve_inheritance(member.m_class, false);
- if (err) {
- return err;
- }
- }
- base = member.m_class->get_datatype();
+ if (look_class->has_member(name)) {
+ resolve_class_member(look_class, name, p_class);
+ base = look_class->get_member(name).get_datatype();
found = true;
break;
}
@@ -402,7 +445,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
result = base;
}
- if (!result.is_set()) {
+ if (!result.is_set() || result.has_no_type()) {
// TODO: More specific error messages.
push_error(vformat(R"(Could not resolve inheritance for class "%s".)", p_class->identifier == nullptr ? "<main>" : p_class->identifier->name), p_class);
return ERR_PARSE_ERROR;
@@ -422,10 +465,21 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
class_type.native_type = result.native_type;
p_class->set_datatype(class_type);
+ parser->current_class = previous_class;
+
+ return OK;
+}
+
+Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive) {
+ Error err = resolve_class_inheritance(p_class);
+ if (err) {
+ return err;
+ }
+
if (p_recursive) {
for (int i = 0; i < p_class->members.size(); i++) {
if (p_class->members[i].type == GDScriptParser::ClassNode::Member::CLASS) {
- Error err = resolve_inheritance(p_class->members[i].m_class, true);
+ err = resolve_class_inheritance(p_class->members[i].m_class, true);
if (err) {
return err;
}
@@ -437,14 +491,29 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
}
GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::TypeNode *p_type) {
- GDScriptParser::DataType result;
+ GDScriptParser::DataType bad_type;
+ bad_type.kind = GDScriptParser::DataType::VARIANT;
+ bad_type.type_source = GDScriptParser::DataType::INFERRED;
if (p_type == nullptr) {
- result.kind = GDScriptParser::DataType::VARIANT;
- return result;
+ return bad_type;
}
- result.type_source = result.ANNOTATED_EXPLICIT;
+ if (p_type->get_datatype().is_resolving()) {
+ push_error(R"(Could not resolve datatype: Cyclic reference.)", p_type);
+ return bad_type;
+ }
+
+ if (!p_type->get_datatype().has_no_type()) {
+ return p_type->get_datatype();
+ }
+
+ GDScriptParser::DataType resolving_datatype;
+ resolving_datatype.kind = GDScriptParser::DataType::RESOLVING;
+ p_type->set_datatype(resolving_datatype);
+
+ GDScriptParser::DataType result;
+ result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
result.builtin_type = Variant::OBJECT;
if (p_type->type_chain.is_empty()) {
@@ -458,29 +527,21 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
StringName first = p_type->type_chain[0]->name;
if (first == SNAME("Variant")) {
- result.kind = GDScriptParser::DataType::VARIANT;
if (p_type->type_chain.size() > 1) {
- push_error(R"("Variant" type don't contain nested types.)", p_type->type_chain[1]);
- return GDScriptParser::DataType();
+ // TODO: Variant does actually have a nested Type though.
+ push_error(R"(Variant doesn't contain nested types.)", p_type->type_chain[1]);
+ return bad_type;
}
- return result;
- }
-
- if (first == SNAME("Object")) {
+ result.kind = GDScriptParser::DataType::VARIANT;
+ } else if (first == SNAME("Object")) {
+ // Object is treated like a native type, not a built-in.
result.kind = GDScriptParser::DataType::NATIVE;
result.native_type = SNAME("Object");
- if (p_type->type_chain.size() > 1) {
- push_error(R"("Object" type don't contain nested types.)", p_type->type_chain[1]);
- return GDScriptParser::DataType();
- }
- return result;
- }
-
- if (GDScriptParser::get_builtin_type(first) < Variant::VARIANT_MAX) {
+ } else if (GDScriptParser::get_builtin_type(first) < Variant::VARIANT_MAX) {
// Built-in types.
if (p_type->type_chain.size() > 1) {
push_error(R"(Built-in types don't contain nested types.)", p_type->type_chain[1]);
- return GDScriptParser::DataType();
+ return bad_type;
}
result.kind = GDScriptParser::DataType::BUILTIN;
result.builtin_type = GDScriptParser::get_builtin_type(first);
@@ -506,9 +567,9 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
String ext = path.get_extension();
if (ext == GDScriptLanguage::get_singleton()->get_extension()) {
Ref<GDScriptParserRef> ref = get_parser_for(path);
- if (!ref.is_valid() || ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
+ if (!ref.is_valid() || ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED) != OK) {
push_error(vformat(R"(Could not parse global class "%s" from "%s".)", first, ScriptServer::get_global_class_path(first)), p_type);
- return GDScriptParser::DataType();
+ return bad_type;
}
result = ref->get_parser()->head->get_datatype();
} else {
@@ -523,9 +584,9 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
} else if (ProjectSettings::get_singleton()->has_autoload(first) && ProjectSettings::get_singleton()->get_autoload(first).is_singleton) {
const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(first);
Ref<GDScriptParserRef> ref = get_parser_for(autoload.path);
- if (ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
+ if (ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED) != OK) {
push_error(vformat(R"(Could not parse singleton "%s" from "%s".)", first, autoload.path), p_type);
- return GDScriptParser::DataType();
+ return bad_type;
}
result = ref->get_parser()->head->get_datatype();
} else if (ClassDB::has_enum(parser->current_class->base_type.native_type, first)) {
@@ -541,26 +602,28 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
break;
}
if (script_class->members_indices.has(first)) {
- GDScriptParser::ClassNode::Member member = script_class->members[script_class->members_indices[first]];
+ resolve_class_member(script_class, first, p_type);
+
+ GDScriptParser::ClassNode::Member member = script_class->get_member(first);
switch (member.type) {
case GDScriptParser::ClassNode::Member::CLASS:
- result = member.m_class->get_datatype();
+ result = member.get_datatype();
break;
case GDScriptParser::ClassNode::Member::ENUM:
- result = member.m_enum->get_datatype();
+ result = member.get_datatype();
break;
case GDScriptParser::ClassNode::Member::CONSTANT:
- if (member.constant->get_datatype().is_meta_type) {
- result = member.constant->get_datatype();
+ if (member.get_datatype().is_meta_type) {
+ result = member.get_datatype();
result.is_meta_type = false;
break;
} else if (Ref<Script>(member.constant->initializer->reduced_value).is_valid()) {
Ref<GDScript> gdscript = member.constant->initializer->reduced_value;
if (gdscript.is_valid()) {
Ref<GDScriptParserRef> ref = get_parser_for(gdscript->get_script_path());
- if (ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
+ if (ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED) != OK) {
push_error(vformat(R"(Could not parse script from "%s".)", gdscript->get_script_path()), p_type);
- return GDScriptParser::DataType();
+ return bad_type;
}
result = ref->get_parser()->head->get_datatype();
result.is_meta_type = false;
@@ -578,15 +641,14 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
[[fallthrough]];
default:
push_error(vformat(R"("%s" is a %s but does not contain a type.)", first, member.get_type_name()), p_type);
- return GDScriptParser::DataType();
+ return bad_type;
}
}
}
}
if (!result.is_set()) {
push_error(vformat(R"("%s" was not found in the current scope.)", first), p_type);
- result.kind = GDScriptParser::DataType::VARIANT; // Leave Variant anyway so future type check don't use an unresolved type.
- return result;
+ return bad_type;
}
if (p_type->type_chain.size() > 1) {
@@ -597,27 +659,26 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
result = p_type->type_chain[i]->get_datatype();
if (!result.is_set()) {
push_error(vformat(R"(Could not find type "%s" under base "%s".)", p_type->type_chain[i]->name, base.to_string()), p_type->type_chain[1]);
- result.kind = GDScriptParser::DataType::VARIANT; // Leave Variant anyway so future type check don't use an unresolved type.
- return result;
+ return bad_type;
} else if (!result.is_meta_type) {
push_error(vformat(R"(Member "%s" under base "%s" is not a valid type.)", p_type->type_chain[i]->name, base.to_string()), p_type->type_chain[1]);
- result.kind = GDScriptParser::DataType::VARIANT; // Leave Variant anyway so future type check don't use an unresolved type.
- return result;
+ return bad_type;
}
}
} else if (result.kind == GDScriptParser::DataType::NATIVE) {
// Only enums allowed for native.
- if (ClassDB::has_enum(result.native_type, p_type->type_chain[1]->name)) {
- if (p_type->type_chain.size() > 2) {
- push_error(R"(Enums cannot contain nested types.)", p_type->type_chain[2]);
- } else {
- result = make_native_enum_type(result.native_type, p_type->type_chain[1]->name);
- }
+ if (!ClassDB::has_enum(result.native_type, p_type->type_chain[1]->name)) {
+ push_error(vformat(R"(Could not find nested type "%s" under base "%s".)", p_type->type_chain[1]->name, result.to_string()), p_type->type_chain[1]);
+ return bad_type;
+ }
+ if (p_type->type_chain.size() > 2) {
+ push_error(R"(Enums cannot contain nested types.)", p_type->type_chain[2]);
+ return bad_type;
}
+ result = make_native_enum_type(result.native_type, p_type->type_chain[1]->name);
} else {
push_error(vformat(R"(Could not find nested type "%s" under base "%s".)", p_type->type_chain[1]->name, result.to_string()), p_type->type_chain[1]);
- result.kind = GDScriptParser::DataType::VARIANT; // Leave Variant anyway so future type check don't use an unresolved type.
- return result;
+ return bad_type;
}
}
@@ -629,22 +690,77 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
return result;
}
-void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_class) {
- if (p_class->resolved_interface) {
+void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, 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);
+}
+
+void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, int p_index, const GDScriptParser::Node *p_source) {
+ ERR_FAIL_INDEX(p_index, p_class->members.size());
+
+ GDScriptParser::ClassNode::Member &member = p_class->members.write[p_index];
+ if (p_source == nullptr && parser->has_class(p_class)) {
+ p_source = member.get_source_node();
+ }
+
+ if (member.get_datatype().is_resolving()) {
+ push_error(vformat(R"(Could not resolve member "%s": Cyclic reference.)", member.get_name()), p_source);
return;
}
- p_class->resolved_interface = true;
+
+ if (member.get_datatype().is_set()) {
+ return;
+ }
+
+ if (!parser->has_class(p_class)) {
+ String script_path = p_class->get_datatype().script_path;
+ Ref<GDScriptParserRef> parser_ref = get_parser_for(script_path);
+ if (parser_ref.is_null()) {
+ push_error(vformat(R"(Could not find script "%s" (While resolving "%s").)", script_path, member.get_name()), p_source);
+ return;
+ }
+
+ Error err = parser_ref->raise_status(GDScriptParserRef::PARSED);
+ if (err) {
+ push_error(vformat(R"(Could not resolve script "%s": %s (While resolving "%s").)", script_path, error_names[err], member.get_name()), p_source);
+ return;
+ }
+
+ ERR_FAIL_COND_MSG(!parser_ref->get_parser()->has_class(p_class), R"(Parser bug: Mismatched external parser.)");
+
+ GDScriptAnalyzer *other_analyzer = parser_ref->get_analyzer();
+ GDScriptParser *other_parser = parser_ref->get_parser();
+
+ int error_count = other_parser->errors.size();
+ other_analyzer->resolve_class_member(p_class, p_index);
+ if (other_parser->errors.size() > error_count) {
+ push_error(vformat(R"(Could not resolve member "%s".)", member.get_name()), p_source);
+ }
+
+ return;
+ }
+
+ // If it's already resolving, that's ok.
+ if (!p_class->base_type.is_resolving()) {
+ Error err = resolve_class_inheritance(p_class);
+ if (err) {
+ return;
+ }
+ }
GDScriptParser::ClassNode *previous_class = parser->current_class;
parser->current_class = p_class;
- for (int i = 0; i < p_class->members.size(); i++) {
- GDScriptParser::ClassNode::Member member = p_class->members[i];
+ GDScriptParser::DataType resolving_datatype;
+ resolving_datatype.kind = GDScriptParser::DataType::RESOLVING;
+ {
switch (member.type) {
case GDScriptParser::ClassNode::Member::VARIABLE: {
check_class_member_name_conflict(p_class, member.variable->identifier->name, member.variable);
+ member.variable->set_datatype(resolving_datatype);
+
GDScriptParser::DataType datatype;
datatype.kind = GDScriptParser::DataType::VARIANT;
datatype.type_source = GDScriptParser::DataType::UNDETECTED;
@@ -656,7 +772,6 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
if (member.variable->initializer != nullptr) {
- member.variable->set_datatype(datatype); // Allow recursive usage.
reduce_expression(member.variable->initializer);
if ((member.variable->infer_datatype || (member.variable->datatype_specifier != nullptr && specified_type.has_container_element_type())) && member.variable->initializer->type == GDScriptParser::Node::ARRAY) {
// Typed array.
@@ -667,18 +782,14 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
}
datatype = member.variable->initializer->get_datatype();
+
if (datatype.type_source != GDScriptParser::DataType::UNDETECTED) {
datatype.type_source = GDScriptParser::DataType::INFERRED;
}
- }
- // Check if initializer is an unset identifier (ie: a variable within scope, but declared below)
- if (member.variable->initializer && !member.variable->initializer->get_datatype().is_set()) {
- if (member.variable->initializer->type == GDScriptParser::Node::IDENTIFIER) {
- GDScriptParser::IdentifierNode *initializer_identifier = static_cast<GDScriptParser::IdentifierNode *>(member.variable->initializer);
- push_error(vformat(R"(Identifier "%s" must be declared above current variable.)", initializer_identifier->name), member.variable->initializer);
- } else {
- ERR_PRINT("Parser bug (please report): tried to assign unset node without an identifier.");
+ if (!datatype.is_set()) {
+ push_error(vformat(R"(Could not resolve initializer for member "%s".)", member.variable->identifier->name), member.variable->initializer);
+ datatype.kind = GDScriptParser::DataType::VARIANT;
}
}
@@ -730,10 +841,9 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
case GDScriptParser::ClassNode::Member::CONSTANT: {
check_class_member_name_conflict(p_class, member.constant->identifier->name, member.constant);
- reduce_expression(member.constant->initializer);
+ member.constant->set_datatype(resolving_datatype);
GDScriptParser::DataType specified_type;
-
if (member.constant->datatype_specifier != nullptr) {
specified_type = resolve_datatype(member.constant->datatype_specifier);
specified_type.is_meta_type = false;
@@ -741,7 +851,9 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
GDScriptParser::DataType datatype;
if (member.constant->initializer) {
+ reduce_expression(member.constant->initializer);
datatype = member.constant->initializer->get_datatype();
+
if (member.constant->initializer->type == GDScriptParser::Node::ARRAY) {
GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(member.constant->initializer);
const_fold_array(array);
@@ -754,6 +866,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(member.constant->initializer));
}
+ if (!datatype.is_set()) {
+ push_error(vformat(R"(Could not resolve initializer for member "%s".)", member.constant->identifier->name), member.constant->initializer);
+ datatype.kind = GDScriptParser::DataType::VARIANT;
+ }
+
if (!member.constant->initializer->is_constant) {
push_error(R"(Initializer for a constant must be a constant expression.)", member.constant->initializer);
}
@@ -782,18 +899,21 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
case GDScriptParser::ClassNode::Member::SIGNAL: {
check_class_member_name_conflict(p_class, member.signal->identifier->name, member.signal);
+ member.signal->set_datatype(resolving_datatype);
+
+ // This is the _only_ way to declare a signal. Therefore, we can generate its
+ // MethodInfo inline so it's a tiny bit more efficient.
+ MethodInfo mi = MethodInfo(member.signal->identifier->name);
+
for (int j = 0; j < member.signal->parameters.size(); j++) {
- GDScriptParser::DataType signal_type = resolve_datatype(member.signal->parameters[j]->datatype_specifier);
- signal_type.is_meta_type = false;
- member.signal->parameters[j]->set_datatype(signal_type);
+ GDScriptParser::ParameterNode *param = member.signal->parameters[j];
+ GDScriptParser::DataType param_type = resolve_datatype(param->datatype_specifier);
+ param_type.is_meta_type = false;
+ param->set_datatype(param_type);
+ mi.arguments.push_back(PropertyInfo(param_type.builtin_type, param->identifier->name));
+ // TODO: add signal parameter default values
}
- // TODO: Make MethodInfo from signal.
- GDScriptParser::DataType signal_type;
- signal_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
- signal_type.kind = GDScriptParser::DataType::BUILTIN;
- signal_type.builtin_type = Variant::SIGNAL;
-
- member.signal->set_datatype(signal_type);
+ member.signal->set_datatype(make_signal_type(mi));
// Apply annotations.
for (GDScriptParser::AnnotationNode *&E : member.signal->annotations) {
@@ -803,6 +923,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
case GDScriptParser::ClassNode::Member::ENUM: {
check_class_member_name_conflict(p_class, member.m_enum->identifier->name, member.m_enum);
+ member.m_enum->set_datatype(resolving_datatype);
+
GDScriptParser::DataType enum_type;
enum_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
enum_type.kind = GDScriptParser::DataType::ENUM;
@@ -812,9 +934,10 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
enum_type.is_meta_type = true;
enum_type.is_constant = true;
- // Enums can't be nested, so we can safely override this.
+ const GDScriptParser::EnumNode *prev_enum = current_enum;
current_enum = member.m_enum;
+ Dictionary dictionary;
for (int j = 0; j < member.m_enum->values.size(); j++) {
GDScriptParser::EnumNode::Value &element = member.m_enum->values.write[j];
@@ -838,11 +961,13 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
enum_type.enum_values[element.identifier->name] = element.value;
+ dictionary[String(element.identifier->name)] = element.value;
}
- current_enum = nullptr;
+ current_enum = prev_enum;
member.m_enum->set_datatype(enum_type);
+ member.m_enum->dictionary = dictionary;
// Apply annotations.
for (GDScriptParser::AnnotationNode *&E : member.m_enum->annotations) {
@@ -850,15 +975,18 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
} break;
case GDScriptParser::ClassNode::Member::FUNCTION:
- resolve_function_signature(member.function);
+ resolve_function_signature(member.function, p_source);
break;
case GDScriptParser::ClassNode::Member::ENUM_VALUE: {
if (member.enum_value.custom_value) {
check_class_member_name_conflict(p_class, member.enum_value.identifier->name, member.enum_value.custom_value);
+ member.enum_value.identifier->set_datatype(resolving_datatype);
+
+ const GDScriptParser::EnumNode *prev_enum = current_enum;
current_enum = member.enum_value.parent_enum;
reduce_expression(member.enum_value.custom_value);
- current_enum = nullptr;
+ current_enum = prev_enum;
if (!member.enum_value.custom_value->is_constant) {
push_error(R"(Enum values must be constant.)", member.enum_value.custom_value);
@@ -872,18 +1000,30 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
check_class_member_name_conflict(p_class, member.enum_value.identifier->name, member.enum_value.parent_enum);
if (member.enum_value.index > 0) {
- member.enum_value.value = member.enum_value.parent_enum->values[member.enum_value.index - 1].value + 1;
+ const GDScriptParser::EnumNode::Value &prev_value = member.enum_value.parent_enum->values[member.enum_value.index - 1];
+ resolve_class_member(p_class, prev_value.identifier->name, member.enum_value.identifier);
+ member.enum_value.value = prev_value.value + 1;
} else {
member.enum_value.value = 0;
}
member.enum_value.resolved = true;
}
+
// Also update the original references.
- member.enum_value.parent_enum->values.write[member.enum_value.index] = member.enum_value;
- p_class->members.write[i].enum_value = member.enum_value;
+ member.enum_value.parent_enum->values.set(member.enum_value.index, member.enum_value);
+
+ GDScriptParser::DataType datatype;
+ datatype.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
+ datatype.kind = GDScriptParser::DataType::BUILTIN;
+ datatype.builtin_type = Variant::INT;
+ member.enum_value.identifier->set_datatype(datatype);
} break;
case GDScriptParser::ClassNode::Member::CLASS:
check_class_member_name_conflict(p_class, member.m_class->identifier->name, member.m_class);
+ // If it's already resolving, that's ok.
+ if (!member.m_class->base_type.is_resolving()) {
+ resolve_class_inheritance(member.m_class, p_source);
+ }
break;
case GDScriptParser::ClassNode::Member::GROUP:
// No-op, but needed to silence warnings.
@@ -894,28 +1034,123 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
}
- // Recurse nested classes.
- for (int i = 0; i < p_class->members.size(); i++) {
- GDScriptParser::ClassNode::Member member = p_class->members[i];
- if (member.type != GDScriptParser::ClassNode::Member::CLASS) {
- continue;
+ parser->current_class = previous_class;
+}
+
+void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source) {
+ if (p_source == nullptr && parser->has_class(p_class)) {
+ p_source = p_class;
+ }
+
+ if (!p_class->resolved_interface) {
+ if (!parser->has_class(p_class)) {
+ String script_path = p_class->get_datatype().script_path;
+ Ref<GDScriptParserRef> parser_ref = get_parser_for(script_path);
+ if (parser_ref.is_null()) {
+ push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
+ return;
+ }
+
+ Error err = parser_ref->raise_status(GDScriptParserRef::PARSED);
+ if (err) {
+ push_error(vformat(R"(Could not resolve script "%s": %s.)", script_path, error_names[err]), p_source);
+ return;
+ }
+
+ ERR_FAIL_COND_MSG(!parser_ref->get_parser()->has_class(p_class), R"(Parser bug: Mismatched external parser.)");
+
+ GDScriptAnalyzer *other_analyzer = parser_ref->get_analyzer();
+ GDScriptParser *other_parser = parser_ref->get_parser();
+
+ int error_count = other_parser->errors.size();
+ other_analyzer->resolve_class_interface(p_class);
+ if (other_parser->errors.size() > error_count) {
+ push_error(vformat(R"(Could not resolve class "%s".)", p_class->fqcn), p_source);
+ }
+
+ return;
+ }
+ p_class->resolved_interface = true;
+
+ if (resolve_class_inheritance(p_class) != OK) {
+ return;
+ }
+
+ GDScriptParser::DataType base_type = p_class->base_type;
+ if (base_type.kind == GDScriptParser::DataType::CLASS) {
+ GDScriptParser::ClassNode *base_class = base_type.class_type;
+ resolve_class_interface(base_class, p_class);
}
- resolve_class_interface(member.m_class);
+ for (int i = 0; i < p_class->members.size(); i++) {
+ resolve_class_member(p_class, i);
+ }
}
+}
- parser->current_class = previous_class;
+void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_class, bool p_recursive) {
+ resolve_class_interface(p_class);
+
+ if (p_recursive) {
+ for (int i = 0; i < p_class->members.size(); i++) {
+ GDScriptParser::ClassNode::Member member = p_class->members[i];
+ if (member.type == GDScriptParser::ClassNode::Member::CLASS) {
+ resolve_class_interface(member.m_class, true);
+ }
+ }
+ }
}
-void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
+void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source) {
+ if (p_source == nullptr && parser->has_class(p_class)) {
+ p_source = p_class;
+ }
+
if (p_class->resolved_body) {
return;
}
+
+ if (!parser->has_class(p_class)) {
+ String script_path = p_class->get_datatype().script_path;
+ Ref<GDScriptParserRef> parser_ref = get_parser_for(script_path);
+ if (parser_ref.is_null()) {
+ push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
+ return;
+ }
+
+ Error err = parser_ref->raise_status(GDScriptParserRef::PARSED);
+ if (err) {
+ push_error(vformat(R"(Could not resolve script "%s": %s.)", script_path, error_names[err]), p_source);
+ return;
+ }
+
+ ERR_FAIL_COND_MSG(!parser_ref->get_parser()->has_class(p_class), R"(Parser bug: Mismatched external parser.)");
+
+ GDScriptAnalyzer *other_analyzer = parser_ref->get_analyzer();
+ GDScriptParser *other_parser = parser_ref->get_parser();
+
+ int error_count = other_parser->errors.size();
+ other_analyzer->resolve_class_body(p_class);
+ if (other_parser->errors.size() > error_count) {
+ push_error(vformat(R"(Could not resolve class "%s".)", p_class->fqcn), p_source);
+ }
+
+ return;
+ }
+
p_class->resolved_body = true;
GDScriptParser::ClassNode *previous_class = parser->current_class;
parser->current_class = p_class;
+ resolve_class_interface(p_class, p_source);
+
+ GDScriptParser::DataType base_type = p_class->base_type;
+ if (base_type.kind == GDScriptParser::DataType::CLASS) {
+ GDScriptParser::ClassNode *base_class = base_type.class_type;
+ resolve_class_body(base_class, p_class);
+ }
+
// Do functions and properties now.
for (int i = 0; i < p_class->members.size(); i++) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
@@ -958,18 +1193,6 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
}
}
- parser->current_class = previous_class;
-
- // Recurse nested classes.
- for (int i = 0; i < p_class->members.size(); i++) {
- GDScriptParser::ClassNode::Member member = p_class->members[i];
- if (member.type != GDScriptParser::ClassNode::Member::CLASS) {
- continue;
- }
-
- resolve_class_body(member.m_class);
- }
-
// Check unused variables and datatypes of property getters and setters.
for (int i = 0; i < p_class->members.size(); i++) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
@@ -1057,6 +1280,21 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
}
}
}
+
+ parser->current_class = previous_class;
+}
+
+void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class, bool p_recursive) {
+ resolve_class_body(p_class);
+
+ if (p_recursive) {
+ for (int i = 0; i < p_class->members.size(); i++) {
+ GDScriptParser::ClassNode::Member member = p_class->members[i];
+ if (member.type == GDScriptParser::ClassNode::Member::CLASS) {
+ resolve_class_body(member.m_class, true);
+ }
+ }
+ }
}
void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node, bool p_is_root) {
@@ -1066,8 +1304,10 @@ void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node, bool p_is_root
case GDScriptParser::Node::NONE:
break; // Unreachable.
case GDScriptParser::Node::CLASS:
- resolve_class_interface(static_cast<GDScriptParser::ClassNode *>(p_node));
- resolve_class_body(static_cast<GDScriptParser::ClassNode *>(p_node));
+ if (OK == resolve_class_inheritance(static_cast<GDScriptParser::ClassNode *>(p_node), true)) {
+ resolve_class_interface(static_cast<GDScriptParser::ClassNode *>(p_node), true);
+ resolve_class_body(static_cast<GDScriptParser::ClassNode *>(p_node), true);
+ }
break;
case GDScriptParser::Node::CONSTANT:
resolve_constant(static_cast<GDScriptParser::ConstantNode *>(p_node));
@@ -1149,7 +1389,16 @@ void GDScriptAnalyzer::resolve_annotation(GDScriptParser::AnnotationNode *p_anno
// TODO: Add second validation function for annotations, so they can use checked types.
}
-void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *p_function) {
+void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *p_function, const GDScriptParser::Node *p_source) {
+ if (p_source == nullptr) {
+ p_source = p_function;
+ }
+
+ if (p_function->get_datatype().is_resolving()) {
+ push_error(vformat(R"(Could not resolve function "%s": Cyclic reference.)", p_function->identifier->name), p_source);
+ return;
+ }
+
if (p_function->resolved_signature) {
return;
}
@@ -1158,6 +1407,12 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
GDScriptParser::FunctionNode *previous_function = parser->current_function;
parser->current_function = p_function;
+ GDScriptParser::DataType prev_datatype = p_function->get_datatype();
+
+ GDScriptParser::DataType resolving_datatype;
+ resolving_datatype.kind = GDScriptParser::DataType::RESOLVING;
+ p_function->set_datatype(resolving_datatype);
+
#ifdef TOOLS_ENABLED
int default_value_count = 0;
#endif // TOOLS_ENABLED
@@ -1262,6 +1517,10 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
#endif // TOOLS_ENABLED
}
+ if (p_function->get_datatype().is_resolving()) {
+ p_function->set_datatype(prev_datatype);
+ }
+
parser->current_function = previous_function;
}
@@ -1505,11 +1764,6 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
} else {
type.type_source = GDScriptParser::DataType::INFERRED;
}
-#ifdef DEBUG_ENABLED
- if (p_variable->initializer->type == GDScriptParser::Node::CALL && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) {
- parser->push_warning(p_variable->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_variable->initializer)->function_name);
- }
-#endif
}
if (p_variable->datatype_specifier != nullptr) {
@@ -1586,12 +1840,6 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant
}
type = p_constant->initializer->get_datatype();
-
-#ifdef DEBUG_ENABLED
- if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) {
- parser->push_warning(p_constant->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_constant->initializer)->function_name);
- }
-#endif
}
if (p_constant->datatype_specifier != nullptr) {
@@ -1787,6 +2035,9 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
update_array_literal_element_type(expected_type, static_cast<GDScriptParser::ArrayNode *>(p_return->return_value));
}
}
+ if (has_expected_type && expected_type.is_hard_type() && expected_type.kind == GDScriptParser::DataType::BUILTIN && expected_type.builtin_type == Variant::NIL) {
+ push_error("A void function cannot return a value.", p_return);
+ }
result = p_return->return_value->get_datatype();
} else {
// Return type is null by default.
@@ -2002,30 +2253,26 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
}
p_assignment->set_datatype(op_type);
- if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) {
+ if (assignee_type.is_hard_type() && !assignee_type.is_variant() && op_type.is_hard_type()) {
if (compatible) {
compatible = is_type_compatible(assignee_type, op_type, true, p_assignment->assigned_value);
if (!compatible) {
- if (assignee_type.is_hard_type()) {
- // Try reverse test since it can be a masked subtype.
- if (!is_type_compatible(op_type, assignee_type, true, p_assignment->assigned_value)) {
- push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", assigned_value_type.to_string(), assignee_type.to_string()), p_assignment->assigned_value);
- } else {
- // TODO: Add warning.
- mark_node_unsafe(p_assignment);
- p_assignment->use_conversion_assign = true;
- }
+ // Try reverse test since it can be a masked subtype.
+ if (!is_type_compatible(op_type, assignee_type, true)) {
+ push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", assigned_value_type.to_string(), assignee_type.to_string()), p_assignment->assigned_value);
} else {
- // TODO: Warning in this case.
+ // TODO: Add warning.
mark_node_unsafe(p_assignment);
+ p_assignment->use_conversion_assign = true;
}
}
} else {
push_error(vformat(R"(Invalid operands "%s" and "%s" for assignment operator.)", assignee_type.to_string(), assigned_value_type.to_string()), p_assignment);
}
- }
-
- if (assignee_type.has_no_type() || assigned_value_type.is_variant()) {
+ } else if (assignee_type.is_hard_type() && !assignee_type.is_variant()) {
+ mark_node_unsafe(p_assignment);
+ p_assignment->use_conversion_assign = true;
+ } else {
mark_node_unsafe(p_assignment);
if (assignee_type.is_hard_type() && !assignee_type.is_variant()) {
p_assignment->use_conversion_assign = true;
@@ -2076,9 +2323,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
}
#ifdef DEBUG_ENABLED
- if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) {
- parser->push_warning(p_assignment->assigned_value, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_assignment->assigned_value)->function_name);
- } else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) {
+ if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) {
parser->push_warning(p_assignment->assigned_value, GDScriptWarning::NARROWING_CONVERSION);
}
#endif
@@ -2393,6 +2638,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
} else if (GDScriptUtilityFunctions::function_exists(function_name)) {
MethodInfo function_info = GDScriptUtilityFunctions::get_function_info(function_name);
+ if (!p_is_root && function_info.return_val.type == Variant::NIL && ((function_info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) == 0)) {
+ push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", function_name), p_call);
+ }
+
if (all_is_constant && GDScriptUtilityFunctions::is_function_constant(function_name)) {
// Can call on compilation.
Vector<const Variant *> args;
@@ -2436,6 +2685,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
} else if (Variant::has_utility_function(function_name)) {
MethodInfo function_info = info_from_utility_func(function_name);
+ if (!p_is_root && function_info.return_val.type == Variant::NIL && ((function_info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) == 0)) {
+ push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", function_name), p_call);
+ }
+
if (all_is_constant && Variant::get_utility_function_type(function_name) == Variant::UTILITY_FUNC_TYPE_MATH) {
// Can call on compilation.
Vector<const Variant *> args;
@@ -2578,6 +2831,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
mark_lambda_use_self();
}
+ if (!p_is_root && return_type.is_hard_type() && return_type.kind == GDScriptParser::DataType::BUILTIN && return_type.builtin_type == Variant::NIL) {
+ push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", p_call->function_name), p_call);
+ }
+
#ifdef DEBUG_ENABLED
if (p_is_root && return_type.kind != GDScriptParser::DataType::UNRESOLVED && return_type.builtin_type != Variant::NIL) {
parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name);
@@ -2745,7 +3002,7 @@ GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const Str
return type;
}
- Error err = ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err) {
push_error(vformat(R"(Could not resolve class "%s", because of a parser error.)", p_class_name), p_source);
type.type_source = GDScriptParser::DataType::UNDETECTED;
@@ -2768,6 +3025,10 @@ GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const Str
}
void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNode *p_identifier, GDScriptParser::DataType *p_base) {
+ if (!p_identifier->get_datatype().has_no_type()) {
+ return;
+ }
+
GDScriptParser::DataType base;
if (p_base == nullptr) {
base = type_from_metatype(parser->current_class->get_datatype());
@@ -2860,16 +3121,16 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
p_identifier->set_datatype(base_class->get_datatype());
return;
}
+
if (base_class->has_member(name)) {
- const GDScriptParser::ClassNode::Member &member = base_class->get_member(name);
+ resolve_class_member(base_class, name, p_identifier);
+
+ GDScriptParser::ClassNode::Member member = base_class->get_member(name);
p_identifier->set_datatype(member.get_datatype());
switch (member.type) {
case GDScriptParser::ClassNode::Member::CONSTANT:
- // For out-of-order resolution:
- reduce_expression(member.constant->initializer);
p_identifier->is_constant = true;
p_identifier->reduced_value = member.constant->initializer->reduced_value;
- p_identifier->set_datatype(member.constant->initializer->get_datatype());
p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
p_identifier->constant_source = member.constant;
break;
@@ -2878,6 +3139,11 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
p_identifier->reduced_value = member.enum_value.value;
p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
break;
+ case GDScriptParser::ClassNode::Member::ENUM:
+ p_identifier->is_constant = true;
+ p_identifier->reduced_value = member.m_enum->dictionary;
+ p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
+ break;
case GDScriptParser::ClassNode::Member::VARIABLE:
p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_VARIABLE;
p_identifier->variable_source = member.variable;
@@ -2887,13 +3153,19 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_SIGNAL;
break;
case GDScriptParser::ClassNode::Member::FUNCTION:
- resolve_function_signature(member.function);
p_identifier->set_datatype(make_callable_type(member.function->info));
break;
case GDScriptParser::ClassNode::Member::CLASS:
- // For out-of-order resolution:
- resolve_class_interface(member.m_class);
- p_identifier->set_datatype(member.m_class->get_datatype());
+ if (p_base != nullptr && p_base->is_constant) {
+ p_identifier->is_constant = true;
+ p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
+
+ Error err = OK;
+ GDScript *scr = GDScriptCache::get_full_script(base.script_path, err).ptr();
+ ERR_FAIL_COND_MSG(err != OK, "Error while getting subscript full script.");
+ scr = scr->find_class(p_identifier->get_datatype().class_type->fqcn);
+ p_identifier->reduced_value = scr;
+ }
break;
default:
break; // Type already set.
@@ -2904,36 +3176,32 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
// TODO: Allow outer static functions.
if (base_class->outer != nullptr) {
List<GDScriptParser::ClassNode *> script_classes;
- get_class_node_current_scope_classes(parser->current_class, &script_classes);
+ get_class_node_current_scope_classes(base_class->outer, &script_classes);
for (GDScriptParser::ClassNode *script_class : script_classes) {
if (script_class->has_member(name)) {
- const GDScriptParser::ClassNode::Member &member = script_class->get_member(name);
+ resolve_class_member(script_class, name, p_identifier);
+
+ GDScriptParser::ClassNode::Member member = script_class->get_member(name);
switch (member.type) {
- case GDScriptParser::ClassNode::Member::CONSTANT: {
+ case GDScriptParser::ClassNode::Member::CONSTANT:
// TODO: Make sure loops won't cause problem. And make special error message for those.
- // For out-of-order resolution:
- reduce_expression(member.constant->initializer);
p_identifier->set_datatype(member.get_datatype());
p_identifier->is_constant = true;
p_identifier->reduced_value = member.constant->initializer->reduced_value;
return;
- } break;
- case GDScriptParser::ClassNode::Member::ENUM_VALUE: {
+ case GDScriptParser::ClassNode::Member::ENUM_VALUE:
p_identifier->set_datatype(member.get_datatype());
p_identifier->is_constant = true;
p_identifier->reduced_value = member.enum_value.value;
return;
- } break;
- case GDScriptParser::ClassNode::Member::ENUM: {
+ case GDScriptParser::ClassNode::Member::ENUM:
p_identifier->set_datatype(member.get_datatype());
- p_identifier->is_constant = false;
+ p_identifier->is_constant = true;
+ p_identifier->reduced_value = member.m_enum->dictionary;
return;
- } break;
- case GDScriptParser::ClassNode::Member::CLASS: {
- resolve_class_interface(member.m_class);
- p_identifier->set_datatype(member.m_class->get_datatype());
+ case GDScriptParser::ClassNode::Member::CLASS:
+ p_identifier->set_datatype(member.get_datatype());
return;
- } break;
default:
break;
}
@@ -3139,21 +3407,21 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
if (ResourceLoader::get_resource_type(autoload.path) == "GDScript") {
Ref<GDScriptParserRef> singl_parser = get_parser_for(autoload.path);
if (singl_parser.is_valid()) {
- Error err = singl_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = singl_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err == OK) {
result = type_from_metatype(singl_parser->get_parser()->head->get_datatype());
}
}
} else if (ResourceLoader::get_resource_type(autoload.path) == "PackedScene") {
- if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(name)) {
- Variant constant = GDScriptLanguage::get_singleton()->get_named_globals_map()[name];
+ if (GDScriptLanguage::get_singleton()->has_any_global_constant(name)) {
+ Variant constant = GDScriptLanguage::get_singleton()->get_any_global_constant(name);
Node *node = Object::cast_to<Node>(constant);
if (node != nullptr) {
Ref<GDScript> scr = node->get_script();
if (scr.is_valid()) {
Ref<GDScriptParserRef> singl_parser = get_parser_for(scr->get_script_path());
if (singl_parser.is_valid()) {
- Error err = singl_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = singl_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err == OK) {
result = type_from_metatype(singl_parser->get_parser()->head->get_datatype());
}
@@ -3168,17 +3436,8 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
}
}
- if (GDScriptLanguage::get_singleton()->get_global_map().has(name)) {
- int idx = GDScriptLanguage::get_singleton()->get_global_map()[name];
- Variant constant = GDScriptLanguage::get_singleton()->get_global_array()[idx];
- p_identifier->set_datatype(type_from_variant(constant, p_identifier));
- p_identifier->is_constant = true;
- p_identifier->reduced_value = constant;
- return;
- }
-
- if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(name)) {
- Variant constant = GDScriptLanguage::get_singleton()->get_named_globals_map()[name];
+ if (GDScriptLanguage::get_singleton()->has_any_global_constant(name)) {
+ Variant constant = GDScriptLanguage::get_singleton()->get_any_global_constant(name);
p_identifier->set_datatype(type_from_variant(constant, p_identifier));
p_identifier->is_constant = true;
p_identifier->reduced_value = constant;
@@ -3347,53 +3606,42 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
}
GDScriptParser::DataType base_type = p_subscript->base->get_datatype();
- // If base is a class metatype, use the analyzer instead.
- if (p_subscript->base->is_constant && !(base_type.is_meta_type && base_type.kind == GDScriptParser::DataType::CLASS)) {
+ bool valid = false;
+ // If the base is a metatype, use the analyzer instead.
+ if (p_subscript->base->is_constant && !base_type.is_meta_type) {
// Just try to get it.
- bool valid = false;
Variant value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, valid);
-
- // If it's a GDScript instance, try to get the full script. Maybe it's not still completely loaded.
- Ref<GDScript> gdscr = Ref<GDScript>(p_subscript->base->reduced_value);
- if (!valid && gdscr.is_valid()) {
- Error err = OK;
- GDScriptCache::get_full_script(gdscr->get_script_path(), err);
- if (err == OK) {
- value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, valid);
- }
- }
-
- if (!valid) {
- push_error(vformat(R"(Cannot get member "%s" from "%s".)", p_subscript->attribute->name, p_subscript->base->reduced_value), p_subscript->index);
- result_type.kind = GDScriptParser::DataType::VARIANT;
- } else {
+ if (valid) {
p_subscript->is_constant = true;
p_subscript->reduced_value = value;
result_type = type_from_variant(value, p_subscript);
}
+ } else if (base_type.is_variant() || !base_type.is_hard_type()) {
+ valid = true;
+ result_type.kind = GDScriptParser::DataType::VARIANT;
+ mark_node_unsafe(p_subscript);
} else {
- if (base_type.is_variant() || !base_type.is_hard_type()) {
- result_type.kind = GDScriptParser::DataType::VARIANT;
- mark_node_unsafe(p_subscript);
- } else {
- reduce_identifier_from_base(p_subscript->attribute, &base_type);
- GDScriptParser::DataType attr_type = p_subscript->attribute->get_datatype();
- if (attr_type.is_set()) {
- result_type = attr_type;
- p_subscript->is_constant = p_subscript->attribute->is_constant;
- p_subscript->reduced_value = p_subscript->attribute->reduced_value;
- } else {
- if (base_type.kind == GDScriptParser::DataType::BUILTIN) {
- push_error(vformat(R"(Cannot find member "%s" in base "%s".)", p_subscript->attribute->name, base_type.to_string()), p_subscript->attribute);
+ reduce_identifier_from_base(p_subscript->attribute, &base_type);
+ GDScriptParser::DataType attr_type = p_subscript->attribute->get_datatype();
+ if (attr_type.is_set()) {
+ valid = true;
+ result_type = attr_type;
+ p_subscript->is_constant = p_subscript->attribute->is_constant;
+ p_subscript->reduced_value = p_subscript->attribute->reduced_value;
+ } else if (!base_type.is_meta_type || !base_type.is_constant) {
+ valid = base_type.kind != GDScriptParser::DataType::BUILTIN;
#ifdef DEBUG_ENABLED
- } else {
- parser->push_warning(p_subscript, GDScriptWarning::UNSAFE_PROPERTY_ACCESS, p_subscript->attribute->name, base_type.to_string());
-#endif
- }
- result_type.kind = GDScriptParser::DataType::VARIANT;
+ if (valid) {
+ parser->push_warning(p_subscript, GDScriptWarning::UNSAFE_PROPERTY_ACCESS, p_subscript->attribute->name, base_type.to_string());
}
+#endif
+ result_type.kind = GDScriptParser::DataType::VARIANT;
}
}
+ if (!valid) {
+ push_error(vformat(R"(Cannot find member "%s" in base "%s".)", p_subscript->attribute->name, type_from_metatype(base_type).to_string()), p_subscript->attribute);
+ result_type.kind = GDScriptParser::DataType::VARIANT;
+ }
} else {
if (p_subscript->index == nullptr) {
return;
@@ -3640,7 +3888,6 @@ void GDScriptAnalyzer::reduce_ternary_op(GDScriptParser::TernaryOpNode *p_ternar
void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op) {
reduce_expression(p_unary_op->operand);
- GDScriptParser::DataType operand_type = p_unary_op->operand->get_datatype();
GDScriptParser::DataType result;
if (p_unary_op->operand == nullptr) {
@@ -3649,6 +3896,8 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
return;
}
+ GDScriptParser::DataType operand_type = p_unary_op->operand->get_datatype();
+
if (p_unary_op->operand->is_constant) {
p_unary_op->is_constant = true;
p_unary_op->reduced_value = Variant::evaluate(p_unary_op->variant_op, p_unary_op->operand->reduced_value, Variant());
@@ -3731,10 +3980,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
result.builtin_type = p_value.get_type();
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; // Constant has explicit type.
- if (p_value.get_type() == Variant::NIL) {
- // A null value is a variant, not void.
- result.kind = GDScriptParser::DataType::VARIANT;
- } else if (p_value.get_type() == Variant::OBJECT) {
+ if (p_value.get_type() == Variant::OBJECT) {
// Object is treated as a native type, not a builtin type.
result.kind = GDScriptParser::DataType::NATIVE;
@@ -3752,43 +3998,42 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
scr = obj->get_script();
}
if (scr.is_valid()) {
- result.script_type = scr;
result.script_path = scr->get_path();
Ref<GDScript> gds = scr;
if (gds.is_valid()) {
result.kind = GDScriptParser::DataType::CLASS;
// This might be an inner class, so we want to get the parser for the root.
// But still get the inner class from that tree.
- GDScript *current = gds.ptr();
- List<StringName> class_chain;
- while (current->_owner) {
- // Push to front so it's in reverse.
- class_chain.push_front(current->name);
- current = current->_owner;
- }
-
- Ref<GDScriptParserRef> ref = get_parser_for(current->get_path());
+ String script_path = gds->get_script_path();
+ Ref<GDScriptParserRef> ref = get_parser_for(script_path);
if (ref.is_null()) {
- push_error("Could not find script in path.", p_source);
+ push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
GDScriptParser::DataType error_type;
error_type.kind = GDScriptParser::DataType::VARIANT;
return error_type;
}
- ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
-
- GDScriptParser::ClassNode *found = ref->get_parser()->head;
-
- // It should be okay to assume this exists, since we have a complete script already.
- for (const StringName &E : class_chain) {
- found = found->get_member(E).m_class;
+ Error err = ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
+ GDScriptParser::ClassNode *found = nullptr;
+ if (err == OK) {
+ found = ref->get_parser()->find_class(gds->fully_qualified_name);
+ if (found != nullptr) {
+ err = resolve_class_inheritance(found, p_source);
+ }
+ }
+ if (err || found == nullptr) {
+ push_error(vformat(R"(Could not resolve script "%s".)", script_path), p_source);
+ GDScriptParser::DataType error_type;
+ error_type.kind = GDScriptParser::DataType::VARIANT;
+ return error_type;
}
result.class_type = found;
result.script_path = ref->get_parser()->script_path;
} else {
result.kind = GDScriptParser::DataType::SCRIPT;
+ result.native_type = scr->get_instance_base_type();
}
- result.native_type = scr->get_instance_base_type();
+ result.script_type = scr;
} else {
result.kind = GDScriptParser::DataType::NATIVE;
if (result.native_type == GDScriptNativeClass::get_class_static()) {
@@ -3912,8 +4157,12 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
push_error(vformat(R"(Member "%s" is not a function.)", function_name), p_source);
return false;
}
+
+ resolve_class_member(base_class, function_name, p_source);
found_function = base_class->get_member(function_name).function;
}
+
+ resolve_class_inheritance(base_class, p_source);
base_class = base_class->base_type.class_type;
}
@@ -3925,7 +4174,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
r_default_arg_count++;
}
}
- r_return_type = found_function->get_datatype();
+ r_return_type = p_is_constructor ? p_base_type : found_function->get_datatype();
r_return_type.is_meta_type = false;
r_return_type.is_coroutine = found_function->is_coroutine;
@@ -4082,12 +4331,10 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
base_class = base_class->base_type.class_type;
}
- StringName base_native = base.native_type;
-
- ERR_FAIL_COND_V_MSG(!class_exists(base_native), false, "Non-existent native base class.");
-
- StringName parent = base_native;
+ StringName parent = base.native_type;
while (parent != StringName()) {
+ ERR_FAIL_COND_V_MSG(!class_exists(parent), false, "Non-existent native base class.");
+
if (ClassDB::has_method(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "method", parent);
return true;
@@ -4277,6 +4524,7 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
case GDScriptParser::DataType::VARIANT:
case GDScriptParser::DataType::BUILTIN:
case GDScriptParser::DataType::ENUM:
+ case GDScriptParser::DataType::RESOLVING:
case GDScriptParser::DataType::UNRESOLVED:
break; // Already solved before.
}
@@ -4313,6 +4561,7 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
case GDScriptParser::DataType::VARIANT:
case GDScriptParser::DataType::BUILTIN:
case GDScriptParser::DataType::ENUM:
+ case GDScriptParser::DataType::RESOLVING:
case GDScriptParser::DataType::UNRESOLVED:
break; // Already solved before.
}
@@ -4327,6 +4576,10 @@ void GDScriptAnalyzer::push_error(const String &p_message, const GDScriptParser:
void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) {
#ifdef DEBUG_ENABLED
+ if (p_node == nullptr) {
+ return;
+ }
+
for (int i = p_node->start_line; i <= p_node->end_line; i++) {
parser->unsafe_lines.insert(i);
}
@@ -4359,39 +4612,46 @@ Ref<GDScriptParserRef> GDScriptAnalyzer::get_parser_for(const String &p_path) {
}
Error GDScriptAnalyzer::resolve_inheritance() {
- return resolve_inheritance(parser->head);
+ return resolve_class_inheritance(parser->head, true);
}
Error GDScriptAnalyzer::resolve_interface() {
- resolve_class_interface(parser->head);
+ resolve_class_interface(parser->head, true);
return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR;
}
Error GDScriptAnalyzer::resolve_body() {
- resolve_class_body(parser->head);
+ resolve_class_body(parser->head, true);
return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR;
}
-Error GDScriptAnalyzer::resolve_program() {
- resolve_class_interface(parser->head);
- resolve_class_body(parser->head);
-
+Error GDScriptAnalyzer::resolve_dependencies() {
for (KeyValue<String, Ref<GDScriptParserRef>> &K : depended_parsers) {
if (K.value.is_null()) {
return ERR_PARSE_ERROR;
}
- K.value->raise_status(GDScriptParserRef::FULLY_SOLVED);
+ K.value->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
}
+
return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR;
}
Error GDScriptAnalyzer::analyze() {
parser->errors.clear();
- Error err = resolve_inheritance(parser->head);
+ Error err = OK;
+
+ err = resolve_inheritance();
if (err) {
return err;
}
- return resolve_program();
+
+ resolve_interface();
+ resolve_body();
+ if (!parser->errors.is_empty()) {
+ return ERR_PARSE_ERROR;
+ }
+
+ return resolve_dependencies();
}
GDScriptAnalyzer::GDScriptAnalyzer(GDScriptParser *p_parser) {
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 44ca1593ed..a4d9efb094 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -52,18 +52,20 @@ class GDScriptAnalyzer {
void get_class_node_current_scope_classes(GDScriptParser::ClassNode *p_node, List<GDScriptParser::ClassNode *> *p_list);
- Error resolve_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive = true);
+ Error resolve_class_inheritance(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source = nullptr);
+ Error resolve_class_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive);
GDScriptParser::DataType resolve_datatype(GDScriptParser::TypeNode *p_type);
void decide_suite_type(GDScriptParser::Node *p_suite, GDScriptParser::Node *p_statement);
- // This traverses the tree to resolve all TypeNodes.
- Error resolve_program();
-
void resolve_annotation(GDScriptParser::AnnotationNode *p_annotation);
- void resolve_class_interface(GDScriptParser::ClassNode *p_class);
- void resolve_class_body(GDScriptParser::ClassNode *p_class);
- void resolve_function_signature(GDScriptParser::FunctionNode *p_function);
+ 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, 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);
+ void resolve_class_body(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source = nullptr);
+ void resolve_class_body(GDScriptParser::ClassNode *p_class, bool p_recursive);
+ void resolve_function_signature(GDScriptParser::FunctionNode *p_function, const GDScriptParser::Node *p_source = nullptr);
void resolve_function_body(GDScriptParser::FunctionNode *p_function);
void resolve_node(GDScriptParser::Node *p_node, bool p_is_root = true);
void resolve_suite(GDScriptParser::SuiteNode *p_suite);
@@ -115,7 +117,7 @@ class GDScriptAnalyzer {
GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, bool &r_valid, const GDScriptParser::Node *p_source);
void update_array_literal_element_type(const GDScriptParser::DataType &p_base_type, GDScriptParser::ArrayNode *p_array_literal);
bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false, const GDScriptParser::Node *p_source_node = nullptr);
- void push_error(const String &p_message, const GDScriptParser::Node *p_origin);
+ void push_error(const String &p_message, const GDScriptParser::Node *p_origin = nullptr);
void mark_node_unsafe(const GDScriptParser::Node *p_node);
void mark_lambda_use_self();
bool class_exists(const StringName &p_class) const;
@@ -128,6 +130,7 @@ public:
Error resolve_inheritance();
Error resolve_interface();
Error resolve_body();
+ Error resolve_dependencies();
Error analyze();
GDScriptAnalyzer(GDScriptParser *p_parser);
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index d1467eea95..6faf2dde73 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -50,6 +50,13 @@ GDScriptParser *GDScriptParserRef::get_parser() const {
return parser;
}
+GDScriptAnalyzer *GDScriptParserRef::get_analyzer() {
+ if (analyzer == nullptr) {
+ analyzer = memnew(GDScriptAnalyzer(parser));
+ }
+ return analyzer;
+}
+
Error GDScriptParserRef::raise_status(Status p_new_status) {
ERR_FAIL_COND_V(parser == nullptr, ERR_INVALID_DATA);
@@ -64,23 +71,22 @@ Error GDScriptParserRef::raise_status(Status p_new_status) {
result = parser->parse(GDScriptCache::get_source_code(path), path, false);
break;
case PARSED: {
- analyzer = memnew(GDScriptAnalyzer(parser));
status = INHERITANCE_SOLVED;
- Error inheritance_result = analyzer->resolve_inheritance();
+ Error inheritance_result = get_analyzer()->resolve_inheritance();
if (result == OK) {
result = inheritance_result;
}
} break;
case INHERITANCE_SOLVED: {
status = INTERFACE_SOLVED;
- Error interface_result = analyzer->resolve_interface();
+ Error interface_result = get_analyzer()->resolve_interface();
if (result == OK) {
result = interface_result;
}
} break;
case INTERFACE_SOLVED: {
status = FULLY_SOLVED;
- Error body_result = analyzer->resolve_body();
+ Error body_result = get_analyzer()->resolve_body();
if (result == OK) {
result = body_result;
}
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index 0ee269f96c..43a45bfef6 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -65,6 +65,7 @@ public:
bool is_valid() const;
Status get_status() const;
GDScriptParser *get_parser() const;
+ GDScriptAnalyzer *get_analyzer();
Error raise_status(Status p_new_status);
void clear();
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index 5972481c3a..6a94c25c88 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -59,7 +59,7 @@ public:
type = p_type;
}
Address(AddressMode p_mode, uint32_t p_address, const GDScriptDataType &p_type = GDScriptDataType()) {
- mode = p_mode,
+ mode = p_mode;
address = p_address;
type = p_type;
}
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 2a98b856ce..3c9387a837 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -117,8 +117,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
result.builtin_type = p_datatype.builtin_type;
result.native_type = p_datatype.native_type;
- String root_name = p_datatype.class_type->fqcn.get_slice("::", 0);
- bool is_local_class = !root_name.is_empty() && root_name == main_script->fully_qualified_name;
+ bool is_local_class = parser->has_class(p_datatype.class_type);
Ref<GDScript> script;
if (is_local_class) {
@@ -157,6 +156,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
result.builtin_type = Variant::INT;
}
break;
+ case GDScriptParser::DataType::RESOLVING:
case GDScriptParser::DataType::UNRESOLVED: {
ERR_PRINT("Parser bug: converting unresolved type.");
return GDScriptDataType();
@@ -490,24 +490,29 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
} break;
case GDScriptParser::Node::CAST: {
const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression);
- GDScriptParser::DataType og_cast_type = cn->cast_type->get_datatype();
+ GDScriptParser::DataType og_cast_type = cn->get_datatype();
GDScriptDataType cast_type = _gdtype_from_datatype(og_cast_type, codegen.script);
- if (og_cast_type.kind == GDScriptParser::DataType::ENUM) {
- // Enum types are usually treated as dictionaries, but in this case we want to cast to an integer.
- cast_type.kind = GDScriptDataType::BUILTIN;
- cast_type.builtin_type = Variant::INT;
- }
+ GDScriptCodeGenerator::Address result;
+ if (cast_type.has_type) {
+ if (og_cast_type.kind == GDScriptParser::DataType::ENUM) {
+ // Enum types are usually treated as dictionaries, but in this case we want to cast to an integer.
+ cast_type.kind = GDScriptDataType::BUILTIN;
+ cast_type.builtin_type = Variant::INT;
+ }
- // Create temporary for result first since it will be deleted last.
- GDScriptCodeGenerator::Address result = codegen.add_temporary(cast_type);
+ // Create temporary for result first since it will be deleted last.
+ result = codegen.add_temporary(cast_type);
- GDScriptCodeGenerator::Address src = _parse_expression(codegen, r_error, cn->operand);
+ GDScriptCodeGenerator::Address src = _parse_expression(codegen, r_error, cn->operand);
- gen->write_cast(result, src, cast_type);
+ gen->write_cast(result, src, cast_type);
- if (src.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- gen->pop_temporary();
+ if (src.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
+ } else {
+ result = _parse_expression(codegen, r_error, cn->operand);
}
return result;
@@ -533,20 +538,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Construct a built-in type.
Variant::Type vtype = GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
- gen->write_construct(result, vtype, arguments);
+ gen->write_construct(return_addr, vtype, arguments);
} else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && Variant::has_utility_function(call->function_name)) {
// Variant utility function.
- gen->write_call_utility(result, call->function_name, arguments);
+ gen->write_call_utility(return_addr, call->function_name, arguments);
} else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptUtilityFunctions::function_exists(call->function_name)) {
// GDScript utility function.
- gen->write_call_gdscript_utility(result, GDScriptUtilityFunctions::get_function(call->function_name), arguments);
+ gen->write_call_gdscript_utility(return_addr, GDScriptUtilityFunctions::get_function(call->function_name), arguments);
} else {
// Regular function.
const GDScriptParser::ExpressionNode *callee = call->callee;
if (call->is_super) {
// Super call.
- gen->write_super_call(result, call->function_name, arguments);
+ gen->write_super_call(return_addr, call->function_name, arguments);
} else {
if (callee->type == GDScriptParser::Node::IDENTIFIER) {
// Self function call.
@@ -558,22 +563,22 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (_have_exact_arguments(method, arguments)) {
// Exact arguments, use ptrcall.
- gen->write_call_ptrcall(result, self, method, arguments);
+ gen->write_call_ptrcall(return_addr, self, method, arguments);
} else {
// Not exact arguments, but still can use method bind call.
- gen->write_call_method_bind(result, self, method, arguments);
+ gen->write_call_method_bind(return_addr, self, method, arguments);
}
} else if ((codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
GDScriptCodeGenerator::Address self;
self.mode = GDScriptCodeGenerator::Address::CLASS;
if (within_await) {
- gen->write_call_async(result, self, call->function_name, arguments);
+ gen->write_call_async(return_addr, self, call->function_name, arguments);
} else {
gen->write_call(return_addr, self, call->function_name, arguments);
}
} else {
if (within_await) {
- gen->write_call_self_async(result, call->function_name, arguments);
+ gen->write_call_self_async(return_addr, call->function_name, arguments);
} else {
gen->write_call_self(return_addr, call->function_name, arguments);
}
@@ -584,18 +589,18 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (subscript->is_attribute) {
// May be static built-in method call.
if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) {
- gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments);
+ gen->write_call_builtin_type_static(return_addr, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments);
} else if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") &&
ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) {
// It's a static native method call.
- gen->write_call_native_static(result, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments);
+ gen->write_call_native_static(return_addr, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments);
} else {
GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
if (r_error) {
return GDScriptCodeGenerator::Address();
}
if (within_await) {
- gen->write_call_async(result, base, call->function_name, arguments);
+ gen->write_call_async(return_addr, base, call->function_name, arguments);
} else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) {
// Native method, use faster path.
StringName class_name;
@@ -608,16 +613,16 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
MethodBind *method = ClassDB::get_method(class_name, call->function_name);
if (_have_exact_arguments(method, arguments)) {
// Exact arguments, use ptrcall.
- gen->write_call_ptrcall(result, base, method, arguments);
+ gen->write_call_ptrcall(return_addr, base, method, arguments);
} else {
// Not exact arguments, but still can use method bind call.
- gen->write_call_method_bind(result, base, method, arguments);
+ gen->write_call_method_bind(return_addr, base, method, arguments);
}
} else {
gen->write_call(return_addr, base, call->function_name, arguments);
}
} else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) {
- gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments);
+ gen->write_call_builtin_type(return_addr, base, base.type.builtin_type, call->function_name, arguments);
} else {
gen->write_call(return_addr, base, call->function_name, arguments);
}
@@ -2299,7 +2304,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
return ERR_COMPILATION_FAILED;
}
- if (base.ptr() == main_script || main_script->is_subclass(base.ptr())) {
+ if (main_script->has_class(base.ptr())) {
Error err = _populate_class_members(base.ptr(), p_class->base_type.class_type, p_keep_state);
if (err) {
return err;
@@ -2448,26 +2453,20 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
case GDScriptParser::ClassNode::Member::ENUM: {
const GDScriptParser::EnumNode *enum_n = member.m_enum;
+ StringName name = enum_n->identifier->name;
- // TODO: Make enums not be just a dictionary?
- Dictionary new_enum;
- for (int j = 0; j < enum_n->values.size(); j++) {
- // Needs to be string because Variant::get will convert to String.
- new_enum[String(enum_n->values[j].identifier->name)] = enum_n->values[j].value;
- }
-
- p_script->constants.insert(enum_n->identifier->name, new_enum);
+ p_script->constants.insert(name, enum_n->dictionary);
#ifdef TOOLS_ENABLED
- p_script->member_lines[enum_n->identifier->name] = enum_n->start_line;
- p_script->doc_enums[enum_n->identifier->name] = DocData::EnumDoc();
- p_script->doc_enums[enum_n->identifier->name].name = enum_n->identifier->name;
- p_script->doc_enums[enum_n->identifier->name].description = enum_n->doc_description;
+ p_script->member_lines[name] = enum_n->start_line;
+ p_script->doc_enums[name] = DocData::EnumDoc();
+ p_script->doc_enums[name].name = name;
+ p_script->doc_enums[name].description = enum_n->doc_description;
for (int j = 0; j < enum_n->values.size(); j++) {
DocData::ConstantDoc const_doc;
const_doc.name = enum_n->values[j].identifier->name;
const_doc.value = Variant(enum_n->values[j].value).operator String();
const_doc.description = enum_n->values[j].doc_description;
- p_script->doc_enums[enum_n->identifier->name].values.push_back(const_doc);
+ p_script->doc_enums[name].values.push_back(const_doc);
}
#endif
} break;
@@ -2637,10 +2636,6 @@ Error GDScriptCompiler::_compile_class(GDScript *p_script, const GDScriptParser:
}
}
-#ifdef TOOLS_ENABLED
- p_script->_update_doc();
-#endif
-
p_script->_init_rpc_methods_properties();
p_script->valid = true;
@@ -2725,6 +2720,10 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri
return err;
}
+#ifdef TOOLS_ENABLED
+ p_script->_update_doc();
+#endif
+
return GDScriptCache::finish_compiling(main_script->get_path());
}
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 79387d1bf6..d84af0c63c 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -2848,16 +2848,6 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
break;
}
- GDScriptParser::CompletionContext c = completion_context;
- c.current_function = nullptr;
- c.current_suite = nullptr;
- c.base = base.value.get_type() == Variant::OBJECT ? base.value.operator Object *() : nullptr;
- if (base.type.kind == GDScriptParser::DataType::CLASS) {
- c.current_class = base.type.class_type;
- } else {
- c.current_class = nullptr;
- }
-
_find_identifiers_in_base(base, false, options, 0);
} break;
case GDScriptParser::COMPLETION_TYPE_ATTRIBUTE: {
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index f2aafe9f0c..103269f0f5 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -642,6 +642,53 @@ void GDScriptParser::parse_program() {
clear_unused_annotations();
}
+GDScriptParser::ClassNode *GDScriptParser::find_class(const String &p_qualified_name) const {
+ String first = p_qualified_name.get_slice("::", 0);
+
+ Vector<String> class_names;
+ GDScriptParser::ClassNode *result = nullptr;
+ // Empty initial name means start at the head.
+ if (first.is_empty() || (head->identifier && first == head->identifier->name)) {
+ class_names = p_qualified_name.split("::");
+ result = head;
+ } else if (p_qualified_name.begins_with(script_path)) {
+ // Script path could have a class path separator("::") in it.
+ class_names = p_qualified_name.trim_prefix(script_path).split("::");
+ result = head;
+ } else if (head->has_member(first)) {
+ class_names = p_qualified_name.split("::");
+ GDScriptParser::ClassNode::Member member = head->get_member(first);
+ if (member.type == GDScriptParser::ClassNode::Member::CLASS) {
+ result = member.m_class;
+ }
+ }
+
+ // 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];
+ GDScriptParser::ClassNode *next = nullptr;
+ if (result->has_member(current_name)) {
+ GDScriptParser::ClassNode::Member member = result->get_member(current_name);
+ if (member.type == GDScriptParser::ClassNode::Member::CLASS) {
+ next = member.m_class;
+ }
+ }
+ result = next;
+ }
+
+ return result;
+}
+
+bool GDScriptParser::has_class(const GDScriptParser::ClassNode *p_class) const {
+ if (head->fqcn.is_empty() && p_class->fqcn.get_slice("::", 0).is_empty()) {
+ return p_class == head;
+ } else if (p_class->fqcn.begins_with(head->fqcn)) {
+ return find_class(p_class->fqcn.trim_prefix(head->fqcn)) == p_class;
+ }
+
+ return false;
+}
+
GDScriptParser::ClassNode *GDScriptParser::parse_class() {
ClassNode *n_class = alloc_node<ClassNode>();
@@ -2240,7 +2287,7 @@ GDScriptParser::IdentifierNode *GDScriptParser::parse_identifier() {
GDScriptParser::ExpressionNode *GDScriptParser::parse_identifier(ExpressionNode *p_previous_operand, bool p_can_assign) {
if (!previous.is_identifier()) {
- ERR_FAIL_V_MSG(nullptr, "Parser bug: parsing literal node without literal token.");
+ ERR_FAIL_V_MSG(nullptr, "Parser bug: parsing identifier node without identifier token.");
}
IdentifierNode *identifier = alloc_node<IdentifierNode>();
complete_extents(identifier);
@@ -4042,11 +4089,12 @@ String GDScriptParser::DataType::to_string() const {
}
case ENUM:
return enum_type.operator String() + " (enum)";
+ case RESOLVING:
case UNRESOLVED:
return "<unresolved type>";
}
- ERR_FAIL_V_MSG("<unresolved type", "Kind set outside the enum range.");
+ ERR_FAIL_V_MSG("<unresolved type>", "Kind set outside the enum range.");
}
static Variant::Type _variant_type_to_typed_array_element_type(Variant::Type p_type) {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index d092a2a5e9..fd2f7b3288 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -107,6 +107,7 @@ public:
CLASS, // GDScript.
ENUM, // Enumeration.
VARIANT, // Can be any type.
+ RESOLVING, // Currently resolving.
UNRESOLVED,
};
Kind kind = UNRESOLVED;
@@ -133,9 +134,10 @@ public:
MethodInfo method_info; // For callable/signals.
HashMap<StringName, int64_t> enum_values; // For enums.
- _FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; }
+ _FORCE_INLINE_ bool is_set() const { return kind != RESOLVING && kind != UNRESOLVED; }
+ _FORCE_INLINE_ bool is_resolving() const { return kind == RESOLVING; }
_FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; }
- _FORCE_INLINE_ bool is_variant() const { return kind == VARIANT || kind == UNRESOLVED; }
+ _FORCE_INLINE_ bool is_variant() const { return kind == VARIANT || kind == RESOLVING || kind == UNRESOLVED; }
_FORCE_INLINE_ bool is_hard_type() const { return type_source > INFERRED; }
String to_string() const;
@@ -188,6 +190,7 @@ public:
return script_type == p_other.script_type;
case CLASS:
return class_type == p_other.class_type;
+ case RESOLVING:
case UNRESOLVED:
break;
}
@@ -480,6 +483,7 @@ public:
IdentifierNode *identifier = nullptr;
Vector<Value> values;
+ Variant dictionary;
#ifdef TOOLS_ENABLED
String doc_description;
#endif // TOOLS_ENABLED
@@ -516,6 +520,32 @@ public:
};
EnumNode::Value enum_value;
+ String get_name() const {
+ switch (type) {
+ case UNDEFINED:
+ return "<undefined member>";
+ case CLASS:
+ // All class-type members have an id.
+ return m_class->identifier->name;
+ case CONSTANT:
+ return constant->identifier->name;
+ case FUNCTION:
+ return function->identifier->name;
+ case SIGNAL:
+ return signal->identifier->name;
+ case VARIABLE:
+ return variable->identifier->name;
+ case ENUM:
+ // All enum-type members have an id.
+ return m_enum->identifier->name;
+ case ENUM_VALUE:
+ return enum_value.identifier->name;
+ case GROUP:
+ return annotation->export_info.name;
+ }
+ return "";
+ }
+
String get_type_name() const {
switch (type) {
case UNDEFINED:
@@ -576,31 +606,42 @@ public:
return variable->get_datatype();
case ENUM:
return m_enum->get_datatype();
- case ENUM_VALUE: {
- // Always integer.
- DataType out_type;
- out_type.type_source = DataType::ANNOTATED_EXPLICIT;
- out_type.kind = DataType::BUILTIN;
- out_type.builtin_type = Variant::INT;
- return out_type;
- }
- case SIGNAL: {
- DataType out_type;
- out_type.type_source = DataType::ANNOTATED_EXPLICIT;
- out_type.kind = DataType::BUILTIN;
- out_type.builtin_type = Variant::SIGNAL;
- // TODO: Add parameter info.
- return out_type;
- }
- case GROUP: {
+ case ENUM_VALUE:
+ return enum_value.identifier->get_datatype();
+ case SIGNAL:
+ return signal->get_datatype();
+ case GROUP:
return DataType();
- }
case UNDEFINED:
return DataType();
}
ERR_FAIL_V_MSG(DataType(), "Reaching unhandled type.");
}
+ Node *get_source_node() const {
+ switch (type) {
+ case CLASS:
+ return m_class;
+ case CONSTANT:
+ return constant;
+ case FUNCTION:
+ return function;
+ case VARIABLE:
+ return variable;
+ case ENUM:
+ return m_enum;
+ case ENUM_VALUE:
+ return enum_value.identifier;
+ case SIGNAL:
+ return signal;
+ case GROUP:
+ return annotation;
+ case UNDEFINED:
+ return nullptr;
+ }
+ ERR_FAIL_V_MSG(nullptr, "Reaching unhandled type.");
+ }
+
Member() {}
Member(ClassNode *p_class) {
@@ -1430,6 +1471,8 @@ public:
Error parse(const String &p_source_code, const String &p_script_path, bool p_for_completion);
ClassNode *get_tree() const { return head; }
bool is_tool() const { return _is_tool; }
+ ClassNode *find_class(const String &p_qualified_name) const;
+ bool has_class(const GDScriptParser::ClassNode *p_class) const;
static Variant::Type get_builtin_type(const StringName &p_type);
CompletionContext get_completion_context() const { return completion_context; }
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index fdcc0625d7..bc8e33b01a 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -1533,8 +1533,28 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
Callable::CallError err;
if (call_ret) {
GET_INSTRUCTION_ARG(ret, argc + 1);
+#ifdef DEBUG_ENABLED
+ Variant::Type base_type = base->get_type();
+ Object *base_obj = base->get_validated_object();
+ StringName base_class = base_obj ? base_obj->get_class_name() : StringName();
+#endif
base->callp(*methodname, (const Variant **)argptrs, argc, *ret, err);
#ifdef DEBUG_ENABLED
+ if (ret->get_type() == Variant::NIL) {
+ if (base_type == Variant::OBJECT) {
+ if (base_obj) {
+ MethodBind *method = ClassDB::get_method(base_class, *methodname);
+ if (*methodname == CoreStringNames::get_singleton()->_free || (method && !method->has_return())) {
+ err_text = R"(Trying to get a return value of a method that returns "void")";
+ OPCODE_BREAK;
+ }
+ }
+ } else if (Variant::has_builtin_method(base_type, *methodname) && !Variant::has_builtin_method_return_value(base_type, *methodname)) {
+ err_text = R"(Trying to get a return value of a method that returns "void")";
+ OPCODE_BREAK;
+ }
+ }
+
if (!call_async && ret->get_type() == Variant::OBJECT) {
// Check if getting a function state without await.
bool was_freed = false;
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index 36bc051643..9ae4bdae56 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -80,10 +80,6 @@ String GDScriptWarning::get_message() const {
case STANDALONE_EXPRESSION: {
return "Standalone expression (the line has no effect).";
} break;
- case VOID_ASSIGNMENT: {
- CHECK_SYMBOLS(1);
- return "Assignment operation, but the function '" + symbols[0] + "()' returns void.";
- } break;
case NARROWING_CONVERSION: {
return "Narrowing conversion (float is converted to int and loses precision).";
} break;
@@ -202,7 +198,6 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"UNREACHABLE_CODE",
"UNREACHABLE_PATTERN",
"STANDALONE_EXPRESSION",
- "VOID_ASSIGNMENT",
"NARROWING_CONVERSION",
"INCOMPATIBLE_TERNARY",
"UNUSED_SIGNAL",
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index 7e4e975510..df6ee71425 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -57,7 +57,6 @@ public:
UNREACHABLE_CODE, // Code after a return statement.
UNREACHABLE_PATTERN, // Pattern in a match statement after a catch all pattern (wildcard or bind).
STANDALONE_EXPRESSION, // Expression not assigned to a variable.
- VOID_ASSIGNMENT, // Function returns void but it's assigned to a variable.
NARROWING_CONVERSION, // Float value into an integer slot, precision is lost.
INCOMPATIBLE_TERNARY, // Possible values of a ternary if are not mutually compatible.
UNUSED_SIGNAL, // Signal is defined but never emitted.
diff --git a/modules/gdscript/language_server/godot_lsp.h b/modules/gdscript/language_server/godot_lsp.h
index 024da1cab7..8b58d7731e 100644
--- a/modules/gdscript/language_server/godot_lsp.h
+++ b/modules/gdscript/language_server/godot_lsp.h
@@ -702,7 +702,7 @@ struct DiagnosticRelatedInformation {
Dictionary to_json() const {
Dictionary dict;
- dict["location"] = location.to_json(),
+ dict["location"] = location.to_json();
dict["message"] = message;
return dict;
}
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd
new file mode 100644
index 0000000000..0e1f7256f8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd
@@ -0,0 +1,4 @@
+signal your_base
+signal my_base
+func test():
+ your_base = my_base
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out
new file mode 100644
index 0000000000..5275183da2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot assign a new value to a constant.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out b/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out
index 87863baf75..b9a1d301ad 100644
--- a/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out
+++ b/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out
@@ -1,2 +1,2 @@
GDTEST_ANALYZER_ERROR
-The member "Vector2" cannot have the same name as a builtin type.
+Class "Vector2" hides a built-in type.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.gd
new file mode 100644
index 0000000000..251be70088
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.gd
@@ -0,0 +1,10 @@
+class A:
+ func _init():
+ pass
+
+class B extends A: pass
+class C extends A: pass
+
+func test():
+ var x := B.new()
+ print(x is C)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.out b/modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.out
new file mode 100644
index 0000000000..91d5125ec0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "B" so it can't be of type "C".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.gd
new file mode 100644
index 0000000000..d2f6404cd2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.gd
@@ -0,0 +1,8 @@
+func test():
+ print(InnerA.new())
+
+class InnerA extends InnerB:
+ pass
+
+class InnerB extends InnerA:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.out
new file mode 100644
index 0000000000..75a94baa17
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cyclic inheritance.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.gd
new file mode 100644
index 0000000000..4292534951
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.gd
@@ -0,0 +1,5 @@
+func test():
+ print(c1)
+
+const c1 = c2
+const c2 = c1
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.out
new file mode 100644
index 0000000000..e71b3fc56a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "c1": Cyclic reference.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.gd
new file mode 100644
index 0000000000..1caef3d366
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.gd
@@ -0,0 +1,5 @@
+func test():
+ print(E1.V)
+
+enum E1 {V = E2.V}
+enum E2 {V = E1.V}
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.out
new file mode 100644
index 0000000000..1b6569ba3a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "E1": Cyclic reference.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.gd
new file mode 100644
index 0000000000..237758f340
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.gd
@@ -0,0 +1,5 @@
+func test():
+ print(EV1)
+
+enum {EV1 = EV2}
+enum {EV2 = EV1}
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.out
new file mode 100644
index 0000000000..233f5fee25
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "EV1": Cyclic reference.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.gd
new file mode 100644
index 0000000000..52e0d60389
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.gd
@@ -0,0 +1,6 @@
+func test():
+ print(v)
+
+var v = A.v
+
+const A = preload("cyclic_ref_external_a.notest.gd")
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.out
new file mode 100644
index 0000000000..64a6bd417d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "v".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external_a.notest.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external_a.notest.gd
new file mode 100644
index 0000000000..9ef1769250
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external_a.notest.gd
@@ -0,0 +1,3 @@
+const B = preload("cyclic_ref_external.gd")
+
+var v = B.v
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.gd
new file mode 100644
index 0000000000..b610464c44
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.gd
@@ -0,0 +1,9 @@
+func test():
+ print(f1())
+ print(f2())
+
+static func f1(p := f2()) -> int:
+ return 1
+
+static func f2(p := f1()) -> int:
+ return 2
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.out
new file mode 100644
index 0000000000..d3ec4b0692
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "f1": Cyclic reference.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.gd
new file mode 100644
index 0000000000..f750715838
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.gd
@@ -0,0 +1,12 @@
+func test():
+ print(v)
+
+var v := InnerA.new().f()
+
+class InnerA:
+ func f(p := InnerB.new().f()) -> int:
+ return 1
+
+class InnerB extends InnerA:
+ func f(p := 1) -> int:
+ return super.f()
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.out
new file mode 100644
index 0000000000..6bca25b330
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "f": Cyclic reference.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.gd
new file mode 100644
index 0000000000..6913888724
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.gd
@@ -0,0 +1,5 @@
+func test():
+ print(v1)
+
+var v1 := v2
+var v2 := v1
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.out
new file mode 100644
index 0000000000..c337882d9c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "v1": Cyclic reference.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.gd b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.gd
new file mode 100644
index 0000000000..65c0d9dabc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.gd
@@ -0,0 +1,12 @@
+class A:
+ class B:
+ func test():
+ print(A.B.D)
+
+class C:
+ class D:
+ pass
+
+func test():
+ var inst = A.B.new()
+ inst.test()
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.out b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.out
new file mode 100644
index 0000000000..6baed366f6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot find member "D" in base "B".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd
new file mode 100644
index 0000000000..63587942f7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd
@@ -0,0 +1,2 @@
+func test() -> void:
+ return null
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.out b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.out
new file mode 100644
index 0000000000..3c09f44ba9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+A void function cannot return a value.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd
new file mode 100644
index 0000000000..0ee4e7ea36
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd
@@ -0,0 +1,4 @@
+func test() -> void:
+ var a
+ a = 1
+ return a
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.out b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.out
new file mode 100644
index 0000000000..3c09f44ba9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+A void function cannot return a value.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.gd
new file mode 100644
index 0000000000..a3450966cc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.gd
@@ -0,0 +1,3 @@
+func test():
+ var builtin := []
+ print(builtin.reverse()) # Built-in type method.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.out
new file mode 100644
index 0000000000..225c85e9c7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "reverse()" because it returns "void".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.gd
new file mode 100644
index 0000000000..2162a181ac
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.gd
@@ -0,0 +1,5 @@
+func foo() -> void:
+ pass
+
+func test():
+ print(foo()) # Custom method.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.out
new file mode 100644
index 0000000000..2b1a607883
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "foo()" because it returns "void".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.gd
new file mode 100644
index 0000000000..f3443d985e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.gd
@@ -0,0 +1,2 @@
+func test():
+ print(print_debug()) # GDScript utility function.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.out
new file mode 100644
index 0000000000..502c18ab9d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "print_debug()" because it returns "void".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.gd
new file mode 100644
index 0000000000..b8e81b160a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.gd
@@ -0,0 +1,3 @@
+func test():
+ var obj := Node.new()
+ print(obj.free()) # Native type method.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.out
new file mode 100644
index 0000000000..88be39345b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "free()" because it returns "void".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.gd
new file mode 100644
index 0000000000..8eabed4271
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.gd
@@ -0,0 +1,2 @@
+func test():
+ print(print()) # Built-in utility function.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.out
new file mode 100644
index 0000000000..ebf43186be
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "print()" because it returns "void".
diff --git a/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.gd b/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.gd
new file mode 100644
index 0000000000..ba1b198cbf
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.gd
@@ -0,0 +1,5 @@
+# https://github.com/godotengine/godot/issues/69504#issuecomment-1345725988
+
+func test():
+ print("cast to Variant == null: ", 1 as Variant == null)
+ print("cast to Object == null: ", self as Object == null)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.out b/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.out
new file mode 100644
index 0000000000..541de99b8e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+cast to Variant == null: false
+cast to Object == null: false
diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_as_const.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_as_const.gd
new file mode 100644
index 0000000000..2ce588373b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/enum_as_const.gd
@@ -0,0 +1,29 @@
+class Outer:
+ enum OuterEnum { OuterValue = 3 }
+ const OuterConst := OuterEnum
+
+ class Inner:
+ enum InnerEnum { InnerValue = 7 }
+ const InnerConst := InnerEnum
+
+ static func test() -> void:
+ print(OuterEnum.size());
+ print(OuterEnum.OuterValue);
+ print(OuterConst.size());
+ print(OuterConst.OuterValue);
+ print(Outer.OuterEnum.size());
+ print(Outer.OuterEnum.OuterValue);
+ print(Outer.OuterConst.size());
+ print(Outer.OuterConst.OuterValue);
+
+ print(InnerEnum.size());
+ print(InnerEnum.InnerValue);
+ print(InnerConst.size());
+ print(InnerConst.InnerValue);
+ print(Inner.InnerEnum.size());
+ print(Inner.InnerEnum.InnerValue);
+ print(Inner.InnerConst.size());
+ print(Inner.InnerConst.InnerValue);
+
+func test():
+ Outer.Inner.test()
diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_as_const.out b/modules/gdscript/tests/scripts/analyzer/features/enum_as_const.out
new file mode 100644
index 0000000000..e049f85b6e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/enum_as_const.out
@@ -0,0 +1,17 @@
+GDTEST_OK
+1
+3
+1
+3
+1
+3
+1
+3
+1
+7
+1
+7
+1
+7
+1
+7
diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd
new file mode 100644
index 0000000000..757744b6f1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd
@@ -0,0 +1,6 @@
+const External = preload("external_enum_as_constant_external.notest.gd")
+const MyEnum = External.MyEnum
+
+func test():
+ print(MyEnum.WAITING == 0)
+ print(MyEnum.GODOT == 1)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.out b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.out
new file mode 100644
index 0000000000..9d111a8322
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+true
+true
diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd
new file mode 100644
index 0000000000..7c090844d0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd
@@ -0,0 +1,4 @@
+enum MyEnum {
+ WAITING,
+ GODOT
+}
diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.gd b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.gd
new file mode 100644
index 0000000000..18dca109fb
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.gd
@@ -0,0 +1,7 @@
+const External = preload("external_inner_class_as_constant_external.notest.gd")
+const ExternalInnerClass = External.InnerClass
+
+func test():
+ var inst_external: ExternalInnerClass = ExternalInnerClass.new()
+ inst_external.x = 4.0
+ print(inst_external.x)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out
new file mode 100644
index 0000000000..15666c46ad
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+4
diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant_external.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant_external.notest.gd
new file mode 100644
index 0000000000..788c99d469
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant_external.notest.gd
@@ -0,0 +1,2 @@
+class InnerClass:
+ var x: = 3.0
diff --git a/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd
new file mode 100644
index 0000000000..39ced354df
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd
@@ -0,0 +1,9 @@
+# https://github.com/godotengine/godot/issues/61159
+
+func get_param():
+ return null
+
+func test():
+ var v = get_param()
+ v = get_param()
+ print(v)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out
new file mode 100644
index 0000000000..f0c83a69b3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+<null>
diff --git a/modules/gdscript/tests/scripts/analyzer/features/out_of_order.gd b/modules/gdscript/tests/scripts/analyzer/features/out_of_order.gd
new file mode 100644
index 0000000000..11349cc916
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/out_of_order.gd
@@ -0,0 +1,51 @@
+func test():
+ print("v1: ", v1)
+ print("v1 is String: ", v1 is String)
+ print("v2: ", v2)
+ print("v2 is bool: ", v2 is bool)
+ print("c1: ", c1)
+ print("c1 is int: ", c1 is int)
+ print("c2: ", c2)
+ print("c2 is int: ", c2 is int)
+ print("E1.V1: ", E1.V1)
+ print("E1.V2: ", E1.V2)
+ print("E2.V: ", E2.V)
+ print("EV1: ", EV1)
+ print("EV2: ", EV2)
+ print("EV3: ", EV3)
+
+var v1 := InnerA.new().fn()
+
+class InnerA extends InnerAB:
+ func fn(p2 := E1.V2) -> String:
+ return "%s, p2=%s" % [super.fn(), p2]
+
+ class InnerAB:
+ func fn(p1 := c1) -> String:
+ return "p1=%s" % p1
+
+var v2 := f()
+
+func f() -> bool:
+ return true
+
+const c1 := E1.V1
+
+enum E1 {
+ V1 = E2.V + 2,
+ V2 = V1 - 1
+}
+
+enum E2 {V = 2}
+
+const c2 := EV2
+
+enum {
+ EV1 = 42,
+ UNUSED = EV3,
+ EV2
+}
+
+enum {
+ EV3 = EV1 + 1
+}
diff --git a/modules/gdscript/tests/scripts/analyzer/features/out_of_order.out b/modules/gdscript/tests/scripts/analyzer/features/out_of_order.out
new file mode 100644
index 0000000000..b1e75d611d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/out_of_order.out
@@ -0,0 +1,15 @@
+GDTEST_OK
+v1: p1=4, p2=3
+v1 is String: true
+v2: true
+v2 is bool: true
+c1: 4
+c1 is int: true
+c2: 44
+c2 is int: true
+E1.V1: 4
+E1.V2: 3
+E2.V: 2
+EV1: 42
+EV2: 44
+EV3: 43
diff --git a/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.gd b/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.gd
new file mode 100644
index 0000000000..0b162bdff8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.gd
@@ -0,0 +1,39 @@
+const B = preload("out_of_order_external_a.notest.gd")
+
+func test():
+ print("v1: ", v1)
+ print("v1 is String: ", v1 is String)
+ print("v2: ", v2)
+ print("v2 is bool: ", v2 is bool)
+ print("c1: ", c1)
+ print("c1 is int: ", c1 is int)
+ print("c2: ", c2)
+ print("c2 is int: ", c2 is int)
+ print("E1.V1: ", E1.V1)
+ print("E1.V2: ", E1.V2)
+ print("B.E2.V: ", B.E2.V)
+ print("EV1: ", EV1)
+ print("EV2: ", EV2)
+ print("B.EV3: ", B.EV3)
+
+var v1 := Inner.new().fn()
+
+class Inner extends B.Inner:
+ func fn(p2 := E1.V2) -> String:
+ return "%s, p2=%s" % [super.fn(), p2]
+
+var v2 := B.new().f()
+
+const c1 := E1.V1
+
+enum E1 {
+ V1 = B.E2.V + 2,
+ V2 = V1 - 1
+}
+
+const c2 := EV2
+
+enum {
+ EV1 = 42,
+ EV2 = B.EV3 + 1
+}
diff --git a/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.out b/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.out
new file mode 100644
index 0000000000..437f782fe6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.out
@@ -0,0 +1,15 @@
+GDTEST_OK
+v1: p1=4, p2=3
+v1 is String: true
+v2: true
+v2 is bool: true
+c1: 4
+c1 is int: true
+c2: 44
+c2 is int: true
+E1.V1: 4
+E1.V2: 3
+B.E2.V: 2
+EV1: 42
+EV2: 44
+B.EV3: 43
diff --git a/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external_a.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external_a.notest.gd
new file mode 100644
index 0000000000..d276f72fcf
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external_a.notest.gd
@@ -0,0 +1,12 @@
+const A = preload("out_of_order_external.gd")
+
+class Inner:
+ func fn(p1 := A.c1) -> String:
+ return "p1=%s" % p1
+
+func f(p := A.c1) -> bool:
+ return p is int
+
+enum E2 {V = 2}
+
+enum {EV3 = A.EV1 + 1}
diff --git a/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd
new file mode 100644
index 0000000000..c9caef7d7c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd
@@ -0,0 +1,5 @@
+func variant() -> Variant:
+ return 'variant'
+
+func test():
+ print(variant())
diff --git a/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.out b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.out
new file mode 100644
index 0000000000..57fe608cc5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+variant
diff --git a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd
deleted file mode 100644
index b4a42b3e3d..0000000000
--- a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd
+++ /dev/null
@@ -1,6 +0,0 @@
-func i_return_void() -> void:
- return
-
-
-func test():
- var __ = i_return_void()
diff --git a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out
deleted file mode 100644
index 84c9598f9a..0000000000
--- a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out
+++ /dev/null
@@ -1,5 +0,0 @@
-GDTEST_OK
->> WARNING
->> Line: 6
->> VOID_ASSIGNMENT
->> Assignment operation, but the function 'i_return_void()' returns void.
diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.gd b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.gd
new file mode 100644
index 0000000000..a3daf70627
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.gd
@@ -0,0 +1,4 @@
+func test():
+ var obj
+ obj = Node.new()
+ print(obj.free())
diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.out b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.out
new file mode 100644
index 0000000000..5edaf19442
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/use_return_value_of_free_call.gd
+>> 4
+>> Trying to get a return value of a method that returns "void"
diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.gd b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.gd
new file mode 100644
index 0000000000..49fb76ad1f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.gd
@@ -0,0 +1,4 @@
+func test():
+ var value
+ value = []
+ print(value.reverse())
diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.out b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.out
new file mode 100644
index 0000000000..128356ff8a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/use_return_value_of_void_builtin_method_call.gd
+>> 4
+>> Trying to get a return value of a method that returns "void"
diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.gd b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.gd
new file mode 100644
index 0000000000..44f9aa467a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.gd
@@ -0,0 +1,4 @@
+func test():
+ var obj
+ obj = RefCounted.new()
+ print(obj.notify_property_list_changed())
diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.out b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.out
new file mode 100644
index 0000000000..e02c206778
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/use_return_value_of_void_native_method_call.gd
+>> 4
+>> Trying to get a return value of a method that returns "void"
diff --git a/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd b/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd
index 5303fb04e2..9b64084fa6 100644
--- a/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd
@@ -15,10 +15,10 @@ func test():
var string_array: Array[String] = []
var stringname_array: Array[StringName] = []
- assert(!string_array.push_back(&"abc"))
+ string_array.push_back(&"abc")
print("Array[String] insert converted: ", typeof(string_array[0]) == TYPE_STRING)
- assert(!stringname_array.push_back("abc"))
+ stringname_array.push_back("abc")
print("Array[StringName] insert converted: ", typeof(stringname_array[0]) == TYPE_STRING_NAME)
print("StringName in Array[String]: ", &"abc" in string_array)
@@ -28,8 +28,8 @@ func test():
assert(!packed_string_array.push_back("abc"))
print("StringName in PackedStringArray: ", &"abc" in packed_string_array)
- assert(!string_array.push_back("abc"))
+ string_array.push_back("abc")
print("StringName finds String in Array: ", string_array.find(&"abc"))
- assert(!stringname_array.push_back(&"abc"))
+ stringname_array.push_back(&"abc")
print("String finds StringName in Array: ", stringname_array.find("abc"))
diff --git a/modules/gdscript/tests/scripts/runtime/features/typed_assignment.gd b/modules/gdscript/tests/scripts/runtime/features/typed_assignment.gd
new file mode 100644
index 0000000000..22e54cf91c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/typed_assignment.gd
@@ -0,0 +1,9 @@
+func test():
+ var x: int = 2
+ var y = 3.14
+ var z := 2.72
+ print(typeof(x))
+ x = y
+ print(typeof(x))
+ x = z
+ print(typeof(x))
diff --git a/modules/gdscript/tests/scripts/runtime/features/typed_assignment.out b/modules/gdscript/tests/scripts/runtime/features/typed_assignment.out
new file mode 100644
index 0000000000..4a268dd8e0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/typed_assignment.out
@@ -0,0 +1,12 @@
+GDTEST_OK
+>> WARNING
+>> Line: 6
+>> NARROWING_CONVERSION
+>> Narrowing conversion (float is converted to int and loses precision).
+>> WARNING
+>> Line: 8
+>> NARROWING_CONVERSION
+>> Narrowing conversion (float is converted to int and loses precision).
+2
+2
+2
diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp
index fb5fb455b8..27e0052c1a 100644
--- a/modules/gltf/editor/editor_scene_importer_fbx.cpp
+++ b/modules/gltf/editor/editor_scene_importer_fbx.cpp
@@ -36,6 +36,7 @@
#include "core/config/project_settings.h"
#include "editor/editor_settings.h"
+#include "main/main.h"
uint32_t EditorSceneFormatImporterFBX::get_import_flags() const {
return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
@@ -111,4 +112,30 @@ void EditorSceneFormatImporterFBX::get_import_options(const String &p_path,
List<ResourceImporter::ImportOption> *r_options) {
}
+bool EditorFileSystemImportFormatSupportQueryFBX::is_active() const {
+ String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx/fbx2gltf_path");
+ return !FileAccess::exists(fbx2gltf_path);
+}
+
+Vector<String> EditorFileSystemImportFormatSupportQueryFBX::get_file_extensions() const {
+ Vector<String> ret;
+ ret.push_back("fbx");
+ return ret;
+}
+
+bool EditorFileSystemImportFormatSupportQueryFBX::query() {
+ FBXImporterManager::get_singleton()->show_dialog(true);
+
+ while (true) {
+ OS::get_singleton()->delay_usec(1);
+ DisplayServer::get_singleton()->process_events();
+ Main::iteration();
+ if (!FBXImporterManager::get_singleton()->is_visible()) {
+ break;
+ }
+ }
+
+ return false;
+}
+
#endif // TOOLS_ENABLED
diff --git a/modules/gltf/editor/editor_scene_importer_fbx.h b/modules/gltf/editor/editor_scene_importer_fbx.h
index 6bf9f3e033..82179cc460 100644
--- a/modules/gltf/editor/editor_scene_importer_fbx.h
+++ b/modules/gltf/editor/editor_scene_importer_fbx.h
@@ -33,6 +33,8 @@
#ifdef TOOLS_ENABLED
+#include "editor/editor_file_system.h"
+#include "editor/fbx_importer_manager.h"
#include "editor/import/resource_importer_scene.h"
class Animation;
@@ -53,6 +55,15 @@ public:
const HashMap<StringName, Variant> &p_options) override;
};
+class EditorFileSystemImportFormatSupportQueryFBX : public EditorFileSystemImportFormatSupportQuery {
+ GDCLASS(EditorFileSystemImportFormatSupportQueryFBX, EditorFileSystemImportFormatSupportQuery);
+
+public:
+ virtual bool is_active() const override;
+ virtual Vector<String> get_file_extensions() const override;
+ virtual bool query() override;
+};
+
#endif // TOOLS_ENABLED
#endif // EDITOR_SCENE_IMPORTER_FBX_H
diff --git a/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp
index cfa498af65..4b71511582 100644
--- a/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp
+++ b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp
@@ -59,6 +59,7 @@ Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFState> p_sta
mesh_instance_node_3d->set_skeleton_path(mesh_3d->get_skeleton_path());
node->replace_by(mesh_instance_node_3d);
delete_queue.push_back(node);
+ node = mesh_instance_node_3d;
} else {
memdelete(mesh_instance_node_3d);
}
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index f4db576b0c..d858f76b28 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -3384,177 +3384,179 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
if (!material->get_name().is_empty()) {
d["name"] = _gen_unique_name(p_state, material->get_name());
}
+
Ref<BaseMaterial3D> base_material = material;
- if (base_material.is_valid()) {
- Dictionary mr;
- {
- Array arr;
- const Color c = base_material->get_albedo().srgb_to_linear();
- arr.push_back(c.r);
- arr.push_back(c.g);
- arr.push_back(c.b);
- arr.push_back(c.a);
- mr["baseColorFactor"] = arr;
+ if (base_material.is_null()) {
+ materials.push_back(d);
+ continue;
+ }
+
+ Dictionary mr;
+ {
+ Array arr;
+ const Color c = base_material->get_albedo().srgb_to_linear();
+ arr.push_back(c.r);
+ arr.push_back(c.g);
+ arr.push_back(c.b);
+ arr.push_back(c.a);
+ mr["baseColorFactor"] = arr;
+ }
+ {
+ Dictionary bct;
+ Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
+ GLTFTextureIndex gltf_texture_index = -1;
+
+ if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) {
+ albedo_texture->set_name(material->get_name() + "_albedo");
+ gltf_texture_index = _set_texture(p_state, albedo_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
}
- {
- Dictionary bct;
- if (base_material.is_valid()) {
- Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
- GLTFTextureIndex gltf_texture_index = -1;
-
- if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) {
- albedo_texture->set_name(material->get_name() + "_albedo");
- gltf_texture_index = _set_texture(p_state, albedo_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
- }
- if (gltf_texture_index != -1) {
- bct["index"] = gltf_texture_index;
- Dictionary extensions = _serialize_texture_transform_uv1(material);
- if (!extensions.is_empty()) {
- bct["extensions"] = extensions;
- p_state->use_khr_texture_transform = true;
- }
- mr["baseColorTexture"] = bct;
- }
+ if (gltf_texture_index != -1) {
+ bct["index"] = gltf_texture_index;
+ Dictionary extensions = _serialize_texture_transform_uv1(material);
+ if (!extensions.is_empty()) {
+ bct["extensions"] = extensions;
+ p_state->use_khr_texture_transform = true;
+ }
+ mr["baseColorTexture"] = bct;
+ }
+ }
+
+ 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();
}
}
- if (base_material.is_valid()) {
- 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;
+ 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();
+ }
+ }
+ 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) {
- 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();
+ 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 (roughness_image->is_compressed()) {
- roughness_image->decompress();
+ 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;
}
}
- 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();
- }
- }
- 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->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;
+ 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;
}
- mr["metallicRoughnessTexture"] = mrt;
}
+ orm_image->set_pixel(w, h, c);
}
}
- d["pbrMetallicRoughness"] = mr;
+ 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;
+ }
}
+
+ d["pbrMetallicRoughness"] = mr;
if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) {
Dictionary nt;
Ref<ImageTexture> tex;
@@ -3607,6 +3609,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
arr.push_back(c.b);
d["emissiveFactor"] = arr;
}
+
if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) {
Dictionary et;
Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION);
@@ -3621,16 +3624,19 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
d["emissiveTexture"] = et;
}
}
+
const bool ds = base_material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED;
if (ds) {
d["doubleSided"] = ds;
}
+
if (base_material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) {
d["alphaMode"] = "MASK";
d["alphaCutoff"] = base_material->get_alpha_scissor_threshold();
} else if (base_material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) {
d["alphaMode"] = "BLEND";
}
+
materials.push_back(d);
}
if (!materials.size()) {
diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp
index cd7a23fbb2..2322e13ae2 100644
--- a/modules/gltf/register_types.cpp
+++ b/modules/gltf/register_types.cpp
@@ -80,16 +80,13 @@ static void _editor_init() {
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,
"filesystem/import/fbx/fbx2gltf_path", PROPERTY_HINT_GLOBAL_FILE));
if (fbx_enabled) {
- Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- if (fbx2gltf_path.is_empty()) {
- WARN_PRINT("FBX file import is enabled in the project settings, but no FBX2glTF path is configured in the editor settings. FBX files will not be imported.");
- } else if (!da->file_exists(fbx2gltf_path)) {
- WARN_PRINT("FBX file import is enabled, but the FBX2glTF path doesn't point to an accessible file. FBX files will not be imported.");
- } else {
- Ref<EditorSceneFormatImporterFBX> importer;
- importer.instantiate();
- ResourceImporterScene::add_importer(importer);
- }
+ Ref<EditorSceneFormatImporterFBX> importer;
+ importer.instantiate();
+ ResourceImporterScene::get_scene_singleton()->add_importer(importer);
+
+ Ref<EditorFileSystemImportFormatSupportQueryFBX> fbx_import_query;
+ fbx_import_query.instantiate();
+ EditorFileSystem::get_singleton()->add_import_format_support_query(fbx_import_query);
}
}
#endif // TOOLS_ENABLED
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index bd5c938364..e0fc4e2697 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -89,13 +89,6 @@
Returns an array of [Transform3D] and [Mesh] references corresponding to the non-empty cells in the grid. The transforms are specified in local space.
</description>
</method>
- <method name="get_navigation_layer_value" qualifiers="const">
- <return type="bool" />
- <param index="0" name="layer_number" type="int" />
- <description>
- Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [code]layer_number[/code] between 1 and 32.
- </description>
- </method>
<method name="get_navigation_map" qualifiers="const">
<return type="RID" />
<description>
@@ -179,14 +172,6 @@
Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="set_navigation_layer_value">
- <return type="void" />
- <param index="0" name="layer_number" type="int" />
- <param index="1" name="value" type="bool" />
- <description>
- Based on [code]value[/code], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [code]layer_number[/code] between 1 and 32.
- </description>
- </method>
<method name="set_navigation_map">
<return type="void" />
<param index="0" name="navigation_map" type="RID" />
@@ -197,7 +182,7 @@
</methods>
<members>
<member name="bake_navigation" type="bool" setter="set_bake_navigation" getter="is_baking_navigation" default="false">
- If [code]true[/code], this GridMap bakes a navigation region.
+ If [code]true[/code], this GridMap creates a navigation region for each cell that uses a [member mesh_library] item with a navigation mesh. The created navigation region will use the navigation layers bitmask assigned to the [MeshLibrary]'s item.
</member>
<member name="cell_center_x" type="bool" setter="set_center_x" getter="get_center_x" default="true">
If [code]true[/code], grid items are centered on the X axis.
@@ -226,12 +211,12 @@
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
The physics layers this GridMap detects collisions in. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
+ <member name="collision_priority" type="float" setter="set_collision_priority" getter="get_collision_priority" default="1.0">
+ The priority used to solve colliding when occurring penetration. The higher the priority is, the lower the penetration into the object will be. This can for example be used to prevent the player from breaking through the boundaries of a level.
+ </member>
<member name="mesh_library" type="MeshLibrary" setter="set_mesh_library" getter="get_mesh_library">
The assigned [MeshLibrary].
</member>
- <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
- A bitmask determining all navigation layers the GridMap generated navigation regions belong to. These navigation layers can be checked upon when requesting a path with [method NavigationServer3D.map_get_path].
- </member>
<member name="physics_material" type="PhysicsMaterial" setter="set_physics_material" getter="get_physics_material">
Overrides the default friction and bounce physics properties for the whole [GridMap].
</member>
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index 89ef9ddd90..186e6a504f 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -1405,6 +1405,7 @@ GridMapEditor::GridMapEditor() {
}
GridMapEditor::~GridMapEditor() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
_clear_clipboard_data();
for (int i = 0; i < 3; i++) {
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 06ad806afc..d23d68ffba 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -74,7 +74,7 @@ bool GridMap::_set(const StringName &p_name, const Variant &p_value) {
bm.mesh = meshes[i];
ERR_CONTINUE(!bm.mesh.is_valid());
bm.instance = RS::get_singleton()->instance_create();
- RS::get_singleton()->get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
+ RS::get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
RS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id());
if (is_inside_tree()) {
RS::get_singleton()->instance_set_scenario(bm.instance, get_world_3d()->get_scenario());
@@ -138,7 +138,7 @@ void GridMap::_get_property_list(List<PropertyInfo> *p_list) const {
void GridMap::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
- _reset_physic_bodies_collision_filters();
+ _update_physics_bodies_collision_properties();
}
uint32_t GridMap::get_collision_layer() const {
@@ -147,7 +147,7 @@ uint32_t GridMap::get_collision_layer() const {
void GridMap::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
- _reset_physic_bodies_collision_filters();
+ _update_physics_bodies_collision_properties();
}
uint32_t GridMap::get_collision_mask() const {
@@ -184,6 +184,15 @@ void GridMap::set_collision_mask_value(int p_layer_number, bool p_value) {
set_collision_mask(mask);
}
+void GridMap::set_collision_priority(real_t p_priority) {
+ collision_priority = p_priority;
+ _update_physics_bodies_collision_properties();
+}
+
+real_t GridMap::get_collision_priority() const {
+ return collision_priority;
+}
+
void GridMap::set_physics_material(Ref<PhysicsMaterial> p_material) {
physics_material = p_material;
_recreate_octant_data();
@@ -230,7 +239,7 @@ void GridMap::set_navigation_map(RID p_navigation_map) {
map_override = p_navigation_map;
for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
Octant &g = *octant_map[E.key];
- for (KeyValue<IndexKey, Octant::NavMesh> &F : g.navmesh_ids) {
+ for (KeyValue<IndexKey, Octant::NavigationCell> &F : g.navigation_cell_ids) {
if (F.value.region.is_valid()) {
NavigationServer3D::get_singleton()->region_set_map(F.value.region, map_override);
}
@@ -247,33 +256,6 @@ RID GridMap::get_navigation_map() const {
return RID();
}
-void GridMap::set_navigation_layers(uint32_t p_navigation_layers) {
- navigation_layers = p_navigation_layers;
- _recreate_octant_data();
-}
-
-uint32_t GridMap::get_navigation_layers() const {
- return navigation_layers;
-}
-
-void GridMap::set_navigation_layer_value(int p_layer_number, bool p_value) {
- ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive.");
- ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive.");
- uint32_t _navigation_layers = get_navigation_layers();
- if (p_value) {
- _navigation_layers |= 1 << (p_layer_number - 1);
- } else {
- _navigation_layers &= ~(1 << (p_layer_number - 1));
- }
- set_navigation_layers(_navigation_layers);
-}
-
-bool GridMap::get_navigation_layer_value(int p_layer_number) const {
- ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive.");
- ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive.");
- return get_navigation_layers() & (1 << (p_layer_number - 1));
-}
-
void GridMap::set_mesh_library(const Ref<MeshLibrary> &p_mesh_library) {
if (!mesh_library.is_null()) {
mesh_library->unregister_owner(this);
@@ -385,6 +367,7 @@ void GridMap::set_cell_item(const Vector3i &p_position, int p_item, int p_rot) {
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(g->static_body, get_instance_id());
PhysicsServer3D::get_singleton()->body_set_collision_layer(g->static_body, collision_layer);
PhysicsServer3D::get_singleton()->body_set_collision_mask(g->static_body, collision_mask);
+ PhysicsServer3D::get_singleton()->body_set_collision_priority(g->static_body, collision_priority);
if (physics_material.is_valid()) {
PhysicsServer3D::get_singleton()->body_set_param(g->static_body, PhysicsServer3D::BODY_PARAM_FRICTION, physics_material->get_friction());
PhysicsServer3D::get_singleton()->body_set_param(g->static_body, PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material->get_bounce());
@@ -542,13 +525,13 @@ void GridMap::_octant_transform(const OctantKey &p_key) {
}
// update transform for NavigationServer regions and navigation debugmesh instances
- for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) {
+ for (const KeyValue<IndexKey, Octant::NavigationCell> &E : g.navigation_cell_ids) {
if (bake_navigation) {
if (E.value.region.is_valid()) {
NavigationServer3D::get_singleton()->region_set_transform(E.value.region, get_global_transform() * E.value.xform);
}
- if (E.value.navmesh_debug_instance.is_valid()) {
- RS::get_singleton()->instance_set_transform(E.value.navmesh_debug_instance, get_global_transform() * E.value.xform);
+ if (E.value.navigation_mesh_debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_transform(E.value.navigation_mesh_debug_instance, get_global_transform() * E.value.xform);
}
}
}
@@ -574,13 +557,13 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
}
//erase navigation
- for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) {
+ for (const KeyValue<IndexKey, Octant::NavigationCell> &E : g.navigation_cell_ids) {
NavigationServer3D::get_singleton()->free(E.value.region);
- if (E.value.navmesh_debug_instance.is_valid()) {
- RS::get_singleton()->free(E.value.navmesh_debug_instance);
+ if (E.value.navigation_mesh_debug_instance.is_valid()) {
+ RS::get_singleton()->free(E.value.navigation_mesh_debug_instance);
}
}
- g.navmesh_ids.clear();
+ g.navigation_cell_ids.clear();
//erase multimeshes
@@ -648,17 +631,18 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
}
}
- // add the item's navmesh at given xform to GridMap's Navigation ancestor
- Ref<NavigationMesh> navmesh = mesh_library->get_item_navmesh(c.item);
- if (navmesh.is_valid()) {
- Octant::NavMesh nm;
- nm.xform = xform * mesh_library->get_item_navmesh_transform(c.item);
+ // add the item's navigation_mesh at given xform to GridMap's Navigation ancestor
+ Ref<NavigationMesh> navigation_mesh = mesh_library->get_item_navigation_mesh(c.item);
+ if (navigation_mesh.is_valid()) {
+ Octant::NavigationCell nm;
+ nm.xform = xform * mesh_library->get_item_navigation_mesh_transform(c.item);
+ nm.navigation_layers = mesh_library->get_item_navigation_layers(c.item);
if (bake_navigation) {
RID region = NavigationServer3D::get_singleton()->region_create();
NavigationServer3D::get_singleton()->region_set_owner_id(region, get_instance_id());
- NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
- NavigationServer3D::get_singleton()->region_set_navmesh(region, navmesh);
+ NavigationServer3D::get_singleton()->region_set_navigation_layers(region, nm.navigation_layers);
+ NavigationServer3D::get_singleton()->region_set_navigation_mesh(region, navigation_mesh);
NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * nm.xform);
if (is_inside_tree()) {
if (map_override.is_valid()) {
@@ -673,19 +657,19 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
// add navigation debugmesh visual instances if debug is enabled
SceneTree *st = SceneTree::get_singleton();
if (st && st->is_debugging_navigation_hint()) {
- if (!nm.navmesh_debug_instance.is_valid()) {
- RID navmesh_debug_rid = navmesh->get_debug_mesh()->get_rid();
- nm.navmesh_debug_instance = RS::get_singleton()->instance_create();
- RS::get_singleton()->instance_set_base(nm.navmesh_debug_instance, navmesh_debug_rid);
+ if (!nm.navigation_mesh_debug_instance.is_valid()) {
+ RID navigation_mesh_debug_rid = navigation_mesh->get_debug_mesh()->get_rid();
+ nm.navigation_mesh_debug_instance = RS::get_singleton()->instance_create();
+ RS::get_singleton()->instance_set_base(nm.navigation_mesh_debug_instance, navigation_mesh_debug_rid);
}
if (is_inside_tree()) {
- RS::get_singleton()->instance_set_scenario(nm.navmesh_debug_instance, get_world_3d()->get_scenario());
- RS::get_singleton()->instance_set_transform(nm.navmesh_debug_instance, get_global_transform() * nm.xform);
+ RS::get_singleton()->instance_set_scenario(nm.navigation_mesh_debug_instance, get_world_3d()->get_scenario());
+ RS::get_singleton()->instance_set_transform(nm.navigation_mesh_debug_instance, get_global_transform() * nm.xform);
}
}
#endif // DEBUG_ENABLED
}
- g.navmesh_ids[E] = nm;
+ g.navigation_cell_ids[E] = nm;
}
}
@@ -751,10 +735,11 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
return false;
}
-void GridMap::_reset_physic_bodies_collision_filters() {
+void GridMap::_update_physics_bodies_collision_properties() {
for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
PhysicsServer3D::get_singleton()->body_set_collision_layer(E.value->static_body, collision_layer);
PhysicsServer3D::get_singleton()->body_set_collision_mask(E.value->static_body, collision_mask);
+ PhysicsServer3D::get_singleton()->body_set_collision_priority(E.value->static_body, collision_priority);
}
}
@@ -775,14 +760,14 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
}
if (bake_navigation && mesh_library.is_valid()) {
- for (KeyValue<IndexKey, Octant::NavMesh> &F : g.navmesh_ids) {
+ for (KeyValue<IndexKey, Octant::NavigationCell> &F : g.navigation_cell_ids) {
if (cell_map.has(F.key) && F.value.region.is_valid() == false) {
- Ref<NavigationMesh> nm = mesh_library->get_item_navmesh(cell_map[F.key].item);
- if (nm.is_valid()) {
+ Ref<NavigationMesh> navigation_mesh = mesh_library->get_item_navigation_mesh(cell_map[F.key].item);
+ if (navigation_mesh.is_valid()) {
RID region = NavigationServer3D::get_singleton()->region_create();
NavigationServer3D::get_singleton()->region_set_owner_id(region, get_instance_id());
- NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
- NavigationServer3D::get_singleton()->region_set_navmesh(region, nm);
+ NavigationServer3D::get_singleton()->region_set_navigation_layers(region, F.value.navigation_layers);
+ NavigationServer3D::get_singleton()->region_set_navigation_mesh(region, navigation_mesh);
NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * F.value.xform);
if (map_override.is_valid()) {
NavigationServer3D::get_singleton()->region_set_map(region, map_override);
@@ -811,6 +796,10 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
}
void GridMap::_octant_exit_world(const OctantKey &p_key) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
+ ERR_FAIL_NULL(NavigationServer3D::get_singleton());
+
ERR_FAIL_COND(!octant_map.has(p_key));
Octant &g = *octant_map[p_key];
PhysicsServer3D::get_singleton()->body_set_state(g.static_body, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
@@ -824,14 +813,14 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
RS::get_singleton()->instance_set_scenario(g.multimesh_instances[i].instance, RID());
}
- for (KeyValue<IndexKey, Octant::NavMesh> &F : g.navmesh_ids) {
+ for (KeyValue<IndexKey, Octant::NavigationCell> &F : g.navigation_cell_ids) {
if (F.value.region.is_valid()) {
NavigationServer3D::get_singleton()->free(F.value.region);
F.value.region = RID();
}
- if (F.value.navmesh_debug_instance.is_valid()) {
- RS::get_singleton()->free(F.value.navmesh_debug_instance);
- F.value.navmesh_debug_instance = RID();
+ if (F.value.navigation_mesh_debug_instance.is_valid()) {
+ RS::get_singleton()->free(F.value.navigation_mesh_debug_instance);
+ F.value.navigation_mesh_debug_instance = RID();
}
}
@@ -849,6 +838,10 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
}
void GridMap::_octant_clean_up(const OctantKey &p_key) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
+ ERR_FAIL_NULL(NavigationServer3D::get_singleton());
+
ERR_FAIL_COND(!octant_map.has(p_key));
Octant &g = *octant_map[p_key];
@@ -862,15 +855,15 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) {
PhysicsServer3D::get_singleton()->free(g.static_body);
// Erase navigation
- for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) {
+ for (const KeyValue<IndexKey, Octant::NavigationCell> &E : g.navigation_cell_ids) {
if (E.value.region.is_valid()) {
NavigationServer3D::get_singleton()->free(E.value.region);
}
- if (E.value.navmesh_debug_instance.is_valid()) {
- RS::get_singleton()->free(E.value.navmesh_debug_instance);
+ if (E.value.navigation_mesh_debug_instance.is_valid()) {
+ RS::get_singleton()->free(E.value.navigation_mesh_debug_instance);
}
}
- g.navmesh_ids.clear();
+ g.navigation_cell_ids.clear();
#ifdef DEBUG_ENABLED
if (bake_navigation) {
@@ -1047,6 +1040,9 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &GridMap::set_collision_layer_value);
ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &GridMap::get_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &GridMap::set_collision_priority);
+ ClassDB::bind_method(D_METHOD("get_collision_priority"), &GridMap::get_collision_priority);
+
ClassDB::bind_method(D_METHOD("set_physics_material", "material"), &GridMap::set_physics_material);
ClassDB::bind_method(D_METHOD("get_physics_material"), &GridMap::get_physics_material);
@@ -1056,12 +1052,6 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &GridMap::set_navigation_map);
ClassDB::bind_method(D_METHOD("get_navigation_map"), &GridMap::get_navigation_map);
- ClassDB::bind_method(D_METHOD("set_navigation_layers", "layers"), &GridMap::set_navigation_layers);
- ClassDB::bind_method(D_METHOD("get_navigation_layers"), &GridMap::get_navigation_layers);
-
- ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &GridMap::set_navigation_layer_value);
- ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &GridMap::get_navigation_layer_value);
-
ClassDB::bind_method(D_METHOD("set_mesh_library", "mesh_library"), &GridMap::set_mesh_library);
ClassDB::bind_method(D_METHOD("get_mesh_library"), &GridMap::get_mesh_library);
@@ -1118,9 +1108,9 @@ void GridMap::_bind_methods() {
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority");
ADD_GROUP("Navigation", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_navigation"), "set_bake_navigation", "is_baking_navigation");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
BIND_CONSTANT(INVALID_CELL_ITEM);
@@ -1204,6 +1194,7 @@ Vector3 GridMap::_get_offset() const {
}
void GridMap::clear_baked_meshes() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
for (int i = 0; i < baked_meshes.size(); i++) {
RS::get_singleton()->free(baked_meshes[i].instance);
}
@@ -1281,7 +1272,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
BakedMesh bm;
bm.mesh = mesh;
bm.instance = RS::get_singleton()->instance_create();
- RS::get_singleton()->get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
+ RS::get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
RS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id());
if (is_inside_tree()) {
RS::get_singleton()->instance_set_scenario(bm.instance, get_world_3d()->get_scenario());
@@ -1390,7 +1381,7 @@ void GridMap::_update_octant_navigation_debug_edge_connections_mesh(const Octant
Vector<Vector3> vertex_array;
- for (KeyValue<IndexKey, Octant::NavMesh> &F : g.navmesh_ids) {
+ for (KeyValue<IndexKey, Octant::NavigationCell> &F : g.navigation_cell_ids) {
if (cell_map.has(F.key) && F.value.region.is_valid()) {
int connections_count = NavigationServer3D::get_singleton()->region_get_connections_count(F.value.region);
if (connections_count == 0) {
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index 6a53457d25..2a9f34bdda 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -95,10 +95,11 @@ class GridMap : public Node3D {
* A GridMap can have multiple Octants.
*/
struct Octant {
- struct NavMesh {
+ struct NavigationCell {
RID region;
Transform3D xform;
- RID navmesh_debug_instance;
+ RID navigation_mesh_debug_instance;
+ uint32_t navigation_layers = 1;
};
struct MultimeshInstance {
@@ -124,7 +125,7 @@ class GridMap : public Node3D {
bool dirty = false;
RID static_body;
- HashMap<IndexKey, NavMesh> navmesh_ids;
+ HashMap<IndexKey, NavigationCell> navigation_cell_ids;
};
union OctantKey {
@@ -150,6 +151,7 @@ class GridMap : public Node3D {
uint32_t collision_layer = 1;
uint32_t collision_mask = 1;
+ real_t collision_priority = 1.0;
Ref<PhysicsMaterial> physics_material;
bool bake_navigation = false;
RID map_override;
@@ -185,7 +187,7 @@ class GridMap : public Node3D {
return Vector3(p_key.x, p_key.y, p_key.z) * cell_size * octant_size;
}
- void _reset_physic_bodies_collision_filters();
+ void _update_physics_bodies_collision_properties();
void _octant_enter_world(const OctantKey &p_key);
void _octant_exit_world(const OctantKey &p_key);
bool _octant_update(const OctantKey &p_key);
@@ -240,6 +242,9 @@ public:
void set_collision_mask_value(int p_layer_number, bool p_value);
bool get_collision_mask_value(int p_layer_number) const;
+ void set_collision_priority(real_t p_priority);
+ real_t get_collision_priority() const;
+
void set_physics_material(Ref<PhysicsMaterial> p_material);
Ref<PhysicsMaterial> get_physics_material() const;
@@ -251,12 +256,6 @@ public:
void set_navigation_map(RID p_navigation_map);
RID get_navigation_map() const;
- void set_navigation_layers(uint32_t p_navigation_layers);
- uint32_t get_navigation_layers() const;
-
- void set_navigation_layer_value(int p_layer_number, bool p_value);
- bool get_navigation_layer_value(int p_layer_number) const;
-
void set_mesh_library(const Ref<MeshLibrary> &p_mesh_library);
Ref<MeshLibrary> get_mesh_library() const;
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index d0f52488bb..26739bcdea 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -451,7 +451,7 @@ static String variant_type_to_managed_name(const String &p_var_type_name) {
}
if (p_var_type_name == Variant::get_type_name(Variant::SIGNAL)) {
- return "SignalInfo";
+ return "Signal";
}
Variant::Type var_types[] = {
@@ -2292,7 +2292,7 @@ bool CSharpScript::can_instantiate() const {
// For tool scripts, this will never fire if the class is not found. That's because we
// don't know if it's a tool script if we can't find the class to access the attributes.
if (extra_cond && !valid) {
- ERR_FAIL_V_MSG(false, "Cannot instance script because the associated class could not be found. Script: '" + get_path() + "'.");
+ ERR_FAIL_V_MSG(false, "Cannot instance script because the associated class could not be found. Script: '" + get_path() + "'. Make sure the script exists and contains a class definition with a name that matches the filename of the script exactly (it's case-sensitive).");
}
return valid && extra_cond;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
index 0c0feb3901..5afaeb736f 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
@@ -91,7 +91,7 @@ namespace Godot.SourceGenerators.Sample
}
}
- // Lamda Property
+ // Lambda Property
private String _lamdaProperty_String = "LamdaProperty_String";
[Export]
public String LamdaProperty_String
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
index d67e57edc2..8852b7ebad 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -295,8 +295,8 @@ namespace Godot.SourceGenerators
foreach (var property in properties)
{
// TODO: We should still restore read-only properties after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload.
- // Ignore properties without a getter or without a setter. Godot properties must be both readable and writable.
- if (property.IsWriteOnly || property.IsReadOnly)
+ // Ignore properties without a getter, without a setter or with an init-only setter. Godot properties must be both readable and writable.
+ if (property.IsWriteOnly || property.IsReadOnly || property.SetMethod!.IsInitOnly)
continue;
var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(property.Type, typeCache);
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs
index 88c0e71155..7f1231dbcb 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs
@@ -114,22 +114,21 @@ namespace Godot.SourceGenerators
RestartIfChanged = 2048,
ScriptVariable = 4096,
StoreIfNull = 8192,
- AnimateAsTrigger = 16384,
- UpdateAllIfModified = 32768,
- ScriptDefaultValue = 65536,
- ClassIsEnum = 131072,
- NilIsVariant = 262144,
- Internal = 524288,
- DoNotShareOnDuplicate = 1048576,
- HighEndGfx = 2097152,
- NodePathFromSceneRoot = 4194304,
- ResourceNotPersistent = 8388608,
- KeyingIncrements = 16777216,
- DeferredSetResource = 33554432,
- EditorInstantiateObject = 67108864,
- EditorBasicSetting = 134217728,
- ReadOnly = 268435456,
- Array = 536870912,
+ UpdateAllIfModified = 16384,
+ ScriptDefaultValue = 32768,
+ ClassIsEnum = 65536,
+ NilIsVariant = 131072,
+ Internal = 262144,
+ DoNotShareOnDuplicate = 524288,
+ HighEndGfx = 1048576,
+ NodePathFromSceneRoot = 2097152,
+ ResourceNotPersistent = 4194304,
+ KeyingIncrements = 8388608,
+ DeferredSetResource = 16777216,
+ EditorInstantiateObject = 33554432,
+ EditorBasicSetting = 67108864,
+ ReadOnly = 134217728,
+ Array = 268435456,
Default = 6,
DefaultIntl = 38,
NoEditor = 2
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
index 8b2f96036b..f0a6a72281 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
@@ -311,12 +311,12 @@ namespace Godot.SourceGenerators
inputExpr, ")"),
// We need a special case for generic Godot collections and GodotObjectOrDerived[], because VariantUtils.ConvertTo<T> is slower
MarshalType.GodotGenericDictionary =>
- source.Append(VariantUtils, ".ConvertToDictionaryObject<",
+ source.Append(VariantUtils, ".ConvertToDictionary<",
((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ", ",
((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedNameIncludeGlobal(), ">(",
inputExpr, ")"),
MarshalType.GodotGenericArray =>
- source.Append(VariantUtils, ".ConvertToArrayObject<",
+ source.Append(VariantUtils, ".ConvertToArray<",
((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ">(",
inputExpr, ")"),
_ => source.Append(VariantUtils, ".ConvertTo<",
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
index fb32f6192f..eae7e41da8 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
@@ -45,8 +45,11 @@ namespace Godot.SourceGenerators
return false;
})
)
- // Ignore classes whose name is not the same as the file name
- .Where(x => Path.GetFileNameWithoutExtension(x.cds.SyntaxTree.FilePath) == x.symbol.Name)
+ .Where(x =>
+ // Ignore classes whose name is not the same as the file name
+ Path.GetFileNameWithoutExtension(x.cds.SyntaxTree.FilePath) == x.symbol.Name &&
+ // Ignore generic classes
+ !x.symbol.IsGenericType)
.GroupBy(x => x.symbol)
.ToDictionary(g => g.Key, g => g.Select(x => x.cds));
@@ -150,8 +153,6 @@ namespace Godot.SourceGenerators
first = false;
sourceBuilder.Append("typeof(");
sourceBuilder.Append(qualifiedName);
- if (godotClass.Key.IsGenericType)
- sourceBuilder.Append($"<{new string(',', godotClass.Key.TypeParameters.Count() - 1)}>");
sourceBuilder.Append(")");
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
index 6c4206a575..b64b843b7c 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -158,7 +158,7 @@ namespace Godot.SourceGenerators
// Generate SetGodotClassPropertyValue
bool allPropertiesAreReadOnly = godotClassFields.All(fi => fi.FieldSymbol.IsReadOnly) &&
- godotClassProperties.All(pi => pi.PropertySymbol.IsReadOnly);
+ godotClassProperties.All(pi => pi.PropertySymbol.IsReadOnly || pi.PropertySymbol.SetMethod!.IsInitOnly);
if (!allPropertiesAreReadOnly)
{
@@ -168,7 +168,7 @@ namespace Godot.SourceGenerators
isFirstEntry = true;
foreach (var property in godotClassProperties)
{
- if (property.PropertySymbol.IsReadOnly)
+ if (property.PropertySymbol.IsReadOnly || property.PropertySymbol.SetMethod!.IsInitOnly)
continue;
GeneratePropertySetter(property.PropertySymbol.Name,
@@ -407,7 +407,7 @@ namespace Godot.SourceGenerators
return null;
}
- if (propertySymbol.SetMethod == null)
+ if (propertySymbol.SetMethod == null || propertySymbol.SetMethod.IsInitOnly)
{
// This should never happen, as we filtered ReadOnly properties, but just in case.
Common.ReportExportedMemberIsReadOnly(context, propertySymbol);
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
index aa9dd9583e..99a4c95e73 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
@@ -138,14 +138,14 @@ namespace Godot.SourceGenerators
}
// TODO: We should still restore read-only properties after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload.
- // Ignore properties without a getter or without a setter. Godot properties must be both readable and writable.
+ // Ignore properties without a getter, without a setter or with an init-only setter. Godot properties must be both readable and writable.
if (property.IsWriteOnly)
{
Common.ReportExportedMemberIsWriteOnly(context, property);
continue;
}
- if (property.IsReadOnly)
+ if (property.IsReadOnly || property.SetMethod!.IsInitOnly)
{
Common.ReportExportedMemberIsReadOnly(context, property);
continue;
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 6559cbf75d..6cfdb15627 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -3650,7 +3650,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype = TypeInterface();
itype.name = "Signal";
itype.cname = itype.name;
- itype.proxy_name = "SignalInfo";
+ itype.proxy_name = "Signal";
itype.cs_type = itype.proxy_name;
itype.cs_in_expr = "%0";
itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(in %1);\n";
@@ -3732,7 +3732,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.cs_out = "%5return new %2(%0(%1));";
// For generic Godot collections, Variant.From<T>/As<T> is slower, so we need this special case
- itype.cs_variant_to_managed = "VariantUtils.ConvertToArrayObject(%0)";
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToArray(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromArray(%0)";
builtin_types.insert(itype.cname, itype);
@@ -3759,7 +3759,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.cs_out = "%5return new %2(%0(%1));";
// For generic Godot collections, Variant.From<T>/As<T> is slower, so we need this special case
- itype.cs_variant_to_managed = "VariantUtils.ConvertToDictionaryObject(%0)";
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToDictionary(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromDictionary(%0)";
builtin_types.insert(itype.cname, itype);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index 130776499b..df306e5244 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -499,7 +499,7 @@ namespace Godot.Collections
VariantUtils.CreateFromArray(godotArray);
private static Array<T> FromVariantFunc(in godot_variant variant) =>
- VariantUtils.ConvertToArrayObject<T>(variant);
+ VariantUtils.ConvertToArray<T>(variant);
static unsafe Array()
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index e6a8054ae2..dafa83431b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -297,7 +297,7 @@ namespace Godot.Bridge
foreach (var type in assembly.GetTypes())
{
- if (type.IsNested)
+ if (type.IsNested || type.IsGenericType)
continue;
if (!typeOfGodotObject.IsAssignableFrom(type))
@@ -314,9 +314,12 @@ namespace Godot.Bridge
if (scriptTypes != null)
{
- for (int i = 0; i < scriptTypes.Length; i++)
+ foreach (var type in scriptTypes)
{
- LookupScriptForClass(scriptTypes[i]);
+ if (type.IsGenericType)
+ continue;
+
+ LookupScriptForClass(type);
}
}
}
@@ -729,6 +732,7 @@ namespace Godot.Bridge
{
ExceptionUtils.LogException(e);
*outTool = godot_bool.False;
+ *outMethodsDest = NativeFuncs.godotsharp_array_new();
*outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new();
*outEventSignalsDest = NativeFuncs.godotsharp_dictionary_new();
*outBaseScript = default;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index f49023555b..4075a878d2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -187,6 +188,19 @@ namespace Godot
}
/// <summary>
+ /// Returns the light intensity of the color, as a value between 0.0 and 1.0 (inclusive).
+ /// This is useful when determining light or dark color. Colors with a luminance smaller
+ /// than 0.5 can be generally considered dark.
+ /// Note: <see cref="Luminance"/> relies on the color being in the linear color space to
+ /// return an accurate relative luminance value. If the color is in the sRGB color space
+ /// use <see cref="SrgbToLinear"/> to convert it to the linear color space first.
+ /// </summary>
+ public readonly float Luminance
+ {
+ get { return 0.2126f * r + 0.7152f * g + 0.0722f * b; }
+ }
+
+ /// <summary>
/// Access color components using their index.
/// </summary>
/// <value>
@@ -363,6 +377,35 @@ namespace Godot
}
/// <summary>
+ /// Returns the color converted to the sRGB color space.
+ /// This method assumes the original color is in the linear color space.
+ /// See also <see cref="SrgbToLinear"/> which performs the opposite operation.
+ /// </summary>
+ /// <returns>The sRGB color.</returns>
+ public readonly Color LinearToSrgb()
+ {
+ return new Color(
+ r < 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * (float)Mathf.Pow(r, 1.0f / 2.4f) - 0.055f,
+ g < 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * (float)Mathf.Pow(g, 1.0f / 2.4f) - 0.055f,
+ b < 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * (float)Mathf.Pow(b, 1.0f / 2.4f) - 0.055f, a);
+ }
+
+ /// <summary>
+ /// Returns the color converted to linear color space.
+ /// This method assumes the original color already is in sRGB color space.
+ /// See also <see cref="LinearToSrgb"/> which performs the opposite operation.
+ /// </summary>
+ /// <returns>The color in linear color space.</returns>
+ public readonly Color SrgbToLinear()
+ {
+ return new Color(
+ r < 0.04045f ? r * (1.0f / 12.92f) : (float)Mathf.Pow((r + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+ g < 0.04045f ? g * (1.0f / 12.92f) : (float)Mathf.Pow((g + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+ b < 0.04045f ? b * (1.0f / 12.92f) : (float)Mathf.Pow((b + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+ a);
+ }
+
+ /// <summary>
/// Returns the color converted to an unsigned 32-bit integer in ABGR
/// format (each byte represents a color channel).
/// ABGR is the reversed version of the default format.
@@ -565,6 +608,10 @@ namespace Godot
/// <see cref="Colors"/> constants.
/// </summary>
/// <param name="code">The HTML color code or color name to construct from.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// A color cannot be inferred from the given <paramref name="code"/>.
+ /// It was invalid HTML and a color with that name was not found.
+ /// </exception>
public Color(string code)
{
if (HtmlIsValid(code))
@@ -597,7 +644,7 @@ namespace Godot
/// <exception name="ArgumentOutOfRangeException">
/// <paramref name="rgba"/> color code is invalid.
/// </exception>
- private static Color FromHTML(ReadOnlySpan<char> rgba)
+ public static Color FromHTML(ReadOnlySpan<char> rgba)
{
Color c;
if (rgba.Length == 0)
@@ -705,28 +752,59 @@ namespace Godot
/// the constants defined in <see cref="Colors"/>.
/// </summary>
/// <param name="name">The name of the color.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// A color with the given name is not found.
+ /// </exception>
/// <returns>The constructed color.</returns>
private static Color Named(string name)
{
+ if (!FindNamedColor(name, out Color color))
+ {
+ throw new ArgumentOutOfRangeException($"Invalid Color Name: {name}");
+ }
+
+ return color;
+ }
+
+ /// <summary>
+ /// Returns a color according to the standardized name, with the
+ /// specified alpha value. Supported color names are the same as
+ /// the constants defined in <see cref="Colors"/>.
+ /// If a color with the given name is not found, it returns
+ /// <paramref name="default"/>.
+ /// </summary>
+ /// <param name="name">The name of the color.</param>
+ /// <param name="default">
+ /// The default color to return when a color with the given name
+ /// is not found.
+ /// </param>
+ /// <returns>The constructed color.</returns>
+ private static Color Named(string name, Color @default)
+ {
+ if (!FindNamedColor(name, out Color color))
+ {
+ return @default;
+ }
+
+ return color;
+ }
+
+ private static bool FindNamedColor(string name, out Color color)
+ {
name = name.Replace(" ", string.Empty);
name = name.Replace("-", string.Empty);
name = name.Replace("_", string.Empty);
name = name.Replace("'", string.Empty);
name = name.Replace(".", string.Empty);
- name = name.ToUpper();
-
- if (!Colors.namedColors.ContainsKey(name))
- {
- throw new ArgumentOutOfRangeException($"Invalid Color Name: {name}");
- }
+ name = name.ToUpperInvariant();
- return Colors.namedColors[name];
+ return Colors.namedColors.TryGetValue(name, out color);
}
/// <summary>
- /// Constructs a color from an HSV profile, with values on the
- /// range of 0 to 1. This is equivalent to using each of
- /// the <c>h</c>/<c>s</c>/<c>v</c> properties, but much more efficient.
+ /// Constructs a color from an HSV profile. The <paramref name="hue"/>,
+ /// <paramref name="saturation"/>, and <paramref name="value"/> are typically
+ /// between 0.0 and 1.0.
/// </summary>
/// <param name="hue">The HSV hue, typically on the range of 0 to 1.</param>
/// <param name="saturation">The HSV saturation, typically on the range of 0 to 1.</param>
@@ -841,13 +919,78 @@ namespace Godot
return ParseCol4(str, index) * 16 + ParseCol4(str, index + 1);
}
+ /// <summary>
+ /// Constructs a color from an OK HSL profile. The <paramref name="hue"/>,
+ /// <paramref name="saturation"/>, and <paramref name="lightness"/> are typically
+ /// between 0.0 and 1.0.
+ /// </summary>
+ /// <param name="hue">The OK HSL hue, typically on the range of 0 to 1.</param>
+ /// <param name="saturation">The OK HSL saturation, typically on the range of 0 to 1.</param>
+ /// <param name="lightness">The OK HSL lightness, typically on the range of 0 to 1.</param>
+ /// <param name="alpha">The alpha (transparency) value, typically on the range of 0 to 1.</param>
+ /// <returns>The constructed color.</returns>
+ public static Color FromOkHsl(float hue, float saturation, float lightness, float alpha = 1.0f)
+ {
+ return NativeFuncs.godotsharp_color_from_ok_hsl(hue, saturation, lightness, alpha);
+ }
+
+ /// <summary>
+ /// Encodes a <see cref="Color"/> from a RGBE9995 format integer.
+ /// See <see cref="Image.Format.Rgbe9995"/>.
+ /// </summary>
+ /// <param name="rgbe">The RGBE9995 encoded color.</param>
+ /// <returns>The constructed color.</returns>
+ public static Color FromRgbe9995(uint rgbe)
+ {
+ float r = rgbe & 0x1ff;
+ float g = (rgbe >> 9) & 0x1ff;
+ float b = (rgbe >> 18) & 0x1ff;
+ float e = rgbe >> 27;
+ float m = (float)Mathf.Pow(2.0f, e - 15.0f - 9.0f);
+
+ float rd = r * m;
+ float gd = g * m;
+ float bd = b * m;
+
+ return new Color(rd, gd, bd, 1.0f);
+ }
+
+ /// <summary>
+ /// Constructs a color from the given string, which can be either an HTML color
+ /// code or a named color. Returns <paramref name="default"/> if the color cannot
+ /// be inferred from the string. Supported color names are the same as the
+ /// <see cref="Colors"/> constants.
+ /// </summary>
+ /// <param name="str">The HTML color code or color name.</param>
+ /// <param name="default">The fallback color to return if the color cannot be inferred.</param>
+ /// <returns>The constructed color.</returns>
+ public static Color FromString(string str, Color @default)
+ {
+ if (HtmlIsValid(str))
+ {
+ return FromHTML(str);
+ }
+ else
+ {
+ return Named(str, @default);
+ }
+ }
+
private static string ToHex32(float val)
{
byte b = (byte)Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255));
return b.HexEncode();
}
- internal static bool HtmlIsValid(ReadOnlySpan<char> color)
+ /// <summary>
+ /// Returns <see langword="true"/> if <paramref name="color"/> is a valid HTML hexadecimal
+ /// color string. The string must be a hexadecimal value (case-insensitive) of either 3,
+ /// 4, 6 or 8 digits, and may be prefixed by a hash sign (<c>#</c>). This method is
+ /// identical to <see cref="StringExtensions.IsValidHtmlColor(string)"/>.
+ /// </summary>
+ /// <param name="color">The HTML hexadecimal color string.</param>
+ /// <returns>Whether or not the string was a valid HTML hexadecimal color string.</returns>
+ public static bool HtmlIsValid(ReadOnlySpan<char> color)
{
if (color.IsEmpty)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index cf25e1f0ae..b5a8742d3d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -366,7 +366,7 @@ namespace Godot.Collections
VariantUtils.CreateFromDictionary(godotDictionary);
private static Dictionary<TKey, TValue> FromVariantFunc(in godot_variant variant) =>
- VariantUtils.ConvertToDictionaryObject<TKey, TValue>(variant);
+ VariantUtils.ConvertToDictionary<TKey, TValue>(variant);
static unsafe Dictionary()
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
index c7deb6423b..57488bd586 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -153,6 +153,8 @@ namespace Godot.NativeInterop
internal static partial void godotsharp_callable_call_deferred(in godot_callable p_callable,
godot_variant** p_args, int p_arg_count);
+ internal static partial Color godotsharp_color_from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha);
+
// GDNative functions
// gdnative.h
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
index 6a4717f2c3..9c9258dd9e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
@@ -170,39 +170,66 @@ namespace Godot.NativeInterop
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedByteArray(Span<byte> from)
- => CreateFromPackedByteArray(Marshaling.ConvertSystemArrayToNativePackedByteArray(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedByteArray(from);
+ return CreateFromPackedByteArray(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedInt32Array(Span<int> from)
- => CreateFromPackedInt32Array(Marshaling.ConvertSystemArrayToNativePackedInt32Array(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedInt32Array(from);
+ return CreateFromPackedInt32Array(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedInt64Array(Span<long> from)
- => CreateFromPackedInt64Array(Marshaling.ConvertSystemArrayToNativePackedInt64Array(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedInt64Array(from);
+ return CreateFromPackedInt64Array(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedFloat32Array(Span<float> from)
- => CreateFromPackedFloat32Array(Marshaling.ConvertSystemArrayToNativePackedFloat32Array(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedFloat32Array(from);
+ return CreateFromPackedFloat32Array(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedFloat64Array(Span<double> from)
- => CreateFromPackedFloat64Array(Marshaling.ConvertSystemArrayToNativePackedFloat64Array(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedFloat64Array(from);
+ return CreateFromPackedFloat64Array(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedStringArray(Span<string> from)
- => CreateFromPackedStringArray(Marshaling.ConvertSystemArrayToNativePackedStringArray(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedStringArray(from);
+ return CreateFromPackedStringArray(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedVector2Array(Span<Vector2> from)
- => CreateFromPackedVector2Array(Marshaling.ConvertSystemArrayToNativePackedVector2Array(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedVector2Array(from);
+ return CreateFromPackedVector2Array(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedVector3Array(Span<Vector3> from)
- => CreateFromPackedVector3Array(Marshaling.ConvertSystemArrayToNativePackedVector3Array(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedVector3Array(from);
+ return CreateFromPackedVector3Array(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedColorArray(Span<Color> from)
- => CreateFromPackedColorArray(Marshaling.ConvertSystemArrayToNativePackedColorArray(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedColorArray(from);
+ return CreateFromPackedColorArray(nativePackedArray);
+ }
public static godot_variant CreateFromSystemArrayOfStringName(Span<StringName> from)
=> CreateFromArray(new Collections.Array(from));
@@ -436,7 +463,7 @@ namespace Godot.NativeInterop
public static Godot.Object ConvertToGodotObject(in godot_variant p_var)
=> InteropUtils.UnmanagedGetManaged(ConvertToGodotObjectPtr(p_var));
- public static string ConvertToStringObject(in godot_variant p_var)
+ public static string ConvertToString(in godot_variant p_var)
{
switch (p_var.Type)
{
@@ -455,65 +482,65 @@ namespace Godot.NativeInterop
}
}
- public static godot_string_name ConvertToStringName(in godot_variant p_var)
+ public static godot_string_name ConvertToNativeStringName(in godot_variant p_var)
=> p_var.Type == Variant.Type.StringName ?
NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName) :
NativeFuncs.godotsharp_variant_as_string_name(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static StringName ConvertToStringNameObject(in godot_variant p_var)
- => StringName.CreateTakingOwnershipOfDisposableValue(ConvertToStringName(p_var));
+ public static StringName ConvertToStringName(in godot_variant p_var)
+ => StringName.CreateTakingOwnershipOfDisposableValue(ConvertToNativeStringName(p_var));
- public static godot_node_path ConvertToNodePath(in godot_variant p_var)
+ public static godot_node_path ConvertToNativeNodePath(in godot_variant p_var)
=> p_var.Type == Variant.Type.NodePath ?
NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath) :
NativeFuncs.godotsharp_variant_as_node_path(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static NodePath ConvertToNodePathObject(in godot_variant p_var)
- => NodePath.CreateTakingOwnershipOfDisposableValue(ConvertToNodePath(p_var));
+ public static NodePath ConvertToNodePath(in godot_variant p_var)
+ => NodePath.CreateTakingOwnershipOfDisposableValue(ConvertToNativeNodePath(p_var));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static godot_callable ConvertToCallable(in godot_variant p_var)
+ public static godot_callable ConvertToNativeCallable(in godot_variant p_var)
=> NativeFuncs.godotsharp_variant_as_callable(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Callable ConvertToCallableManaged(in godot_variant p_var)
- => Marshaling.ConvertCallableToManaged(ConvertToCallable(p_var));
+ public static Callable ConvertToCallable(in godot_variant p_var)
+ => Marshaling.ConvertCallableToManaged(ConvertToNativeCallable(p_var));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static godot_signal ConvertToSignal(in godot_variant p_var)
+ public static godot_signal ConvertToNativeSignal(in godot_variant p_var)
=> NativeFuncs.godotsharp_variant_as_signal(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Signal ConvertToSignalManaged(in godot_variant p_var)
- => Marshaling.ConvertSignalToManaged(ConvertToSignal(p_var));
+ public static Signal ConvertToSignal(in godot_variant p_var)
+ => Marshaling.ConvertSignalToManaged(ConvertToNativeSignal(p_var));
- public static godot_array ConvertToArray(in godot_variant p_var)
+ public static godot_array ConvertToNativeArray(in godot_variant p_var)
=> p_var.Type == Variant.Type.Array ?
NativeFuncs.godotsharp_array_new_copy(p_var.Array) :
NativeFuncs.godotsharp_variant_as_array(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Collections.Array ConvertToArrayObject(in godot_variant p_var)
- => Collections.Array.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var));
+ public static Collections.Array ConvertToArray(in godot_variant p_var)
+ => Collections.Array.CreateTakingOwnershipOfDisposableValue(ConvertToNativeArray(p_var));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Array<T> ConvertToArrayObject<T>(in godot_variant p_var)
- => Array<T>.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var));
+ public static Array<T> ConvertToArray<T>(in godot_variant p_var)
+ => Array<T>.CreateTakingOwnershipOfDisposableValue(ConvertToNativeArray(p_var));
- public static godot_dictionary ConvertToDictionary(in godot_variant p_var)
+ public static godot_dictionary ConvertToNativeDictionary(in godot_variant p_var)
=> p_var.Type == Variant.Type.Dictionary ?
NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary) :
NativeFuncs.godotsharp_variant_as_dictionary(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Dictionary ConvertToDictionaryObject(in godot_variant p_var)
- => Dictionary.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var));
+ public static Dictionary ConvertToDictionary(in godot_variant p_var)
+ => Dictionary.CreateTakingOwnershipOfDisposableValue(ConvertToNativeDictionary(p_var));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Dictionary<TKey, TValue> ConvertToDictionaryObject<TKey, TValue>(in godot_variant p_var)
- => Dictionary<TKey, TValue>.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var));
+ public static Dictionary<TKey, TValue> ConvertToDictionary<TKey, TValue>(in godot_variant p_var)
+ => Dictionary<TKey, TValue>.CreateTakingOwnershipOfDisposableValue(ConvertToNativeDictionary(p_var));
public static byte[] ConvertAsPackedByteArrayToSystemArray(in godot_variant p_var)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs
index 9a3ed85e66..3d64533269 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs
@@ -92,6 +92,9 @@ public partial class VariantUtils
if (typeof(T) == typeof(Transform2D))
return CreateFromTransform2D(UnsafeAs<Transform2D>(from));
+ if (typeof(T) == typeof(Projection))
+ return CreateFromProjection(UnsafeAs<Projection>(from));
+
if (typeof(T) == typeof(Vector3))
return CreateFromVector3(UnsafeAs<Vector3>(from));
@@ -293,6 +296,9 @@ public partial class VariantUtils
if (typeof(T) == typeof(Transform3D))
return UnsafeAsT(ConvertToTransform3D(variant));
+ if (typeof(T) == typeof(Projection))
+ return UnsafeAsT(ConvertToProjection(variant));
+
if (typeof(T) == typeof(Vector4))
return UnsafeAsT(ConvertToVector4(variant));
@@ -309,13 +315,13 @@ public partial class VariantUtils
return UnsafeAsT(ConvertToPlane(variant));
if (typeof(T) == typeof(Callable))
- return UnsafeAsT(ConvertToCallableManaged(variant));
+ return UnsafeAsT(ConvertToCallable(variant));
if (typeof(T) == typeof(Signal))
- return UnsafeAsT(ConvertToSignalManaged(variant));
+ return UnsafeAsT(ConvertToSignal(variant));
if (typeof(T) == typeof(string))
- return UnsafeAsT(ConvertToStringObject(variant));
+ return UnsafeAsT(ConvertToString(variant));
if (typeof(T) == typeof(byte[]))
return UnsafeAsT(ConvertAsPackedByteArrayToSystemArray(variant));
@@ -354,19 +360,19 @@ public partial class VariantUtils
return UnsafeAsT(ConvertToSystemArrayOfRID(variant));
if (typeof(T) == typeof(StringName))
- return UnsafeAsT(ConvertToStringNameObject(variant));
+ return UnsafeAsT(ConvertToStringName(variant));
if (typeof(T) == typeof(NodePath))
- return UnsafeAsT(ConvertToNodePathObject(variant));
+ return UnsafeAsT(ConvertToNodePath(variant));
if (typeof(T) == typeof(RID))
return UnsafeAsT(ConvertToRID(variant));
if (typeof(T) == typeof(Godot.Collections.Dictionary))
- return UnsafeAsT(ConvertToDictionaryObject(variant));
+ return UnsafeAsT(ConvertToDictionary(variant));
if (typeof(T) == typeof(Godot.Collections.Array))
- return UnsafeAsT(ConvertToArrayObject(variant));
+ return UnsafeAsT(ConvertToArray(variant));
if (typeof(T) == typeof(Variant))
return UnsafeAsT(Variant.CreateCopyingBorrowed(variant));
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
index 8b1b73fcc3..fd37f8d9e8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
@@ -652,7 +652,7 @@ namespace Godot
/// added to the first and second values of the final column respectively.
/// </summary>
/// <param name="offset">The offset to apply to the projection.</param>
- /// <returns>The offseted projection.</returns>
+ /// <returns>The offsetted projection.</returns>
public readonly Projection JitterOffseted(Vector2 offset)
{
Projection proj = this;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs
index c4c53a39f9..da12309217 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs
@@ -212,7 +212,7 @@ public partial struct Variant : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string AsString() =>
- VariantUtils.ConvertToStringObject((godot_variant)NativeVar);
+ VariantUtils.ConvertToString((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector2 AsVector2() =>
@@ -280,11 +280,11 @@ public partial struct Variant : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Callable AsCallable() =>
- VariantUtils.ConvertToCallableManaged((godot_variant)NativeVar);
+ VariantUtils.ConvertToCallable((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Signal AsSignal() =>
- VariantUtils.ConvertToSignalManaged((godot_variant)NativeVar);
+ VariantUtils.ConvertToSignal((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte[] AsByteArray() =>
@@ -329,11 +329,11 @@ public partial struct Variant : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Collections.Dictionary<TKey, TValue> AsGodotDictionary<TKey, TValue>() =>
- VariantUtils.ConvertToDictionaryObject<TKey, TValue>((godot_variant)NativeVar);
+ VariantUtils.ConvertToDictionary<TKey, TValue>((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Collections.Array<T> AsGodotArray<T>() =>
- VariantUtils.ConvertToArrayObject<T>((godot_variant)NativeVar);
+ VariantUtils.ConvertToArray<T>((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public StringName[] AsSystemArrayOfStringName() =>
@@ -353,11 +353,11 @@ public partial struct Variant : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public StringName AsStringName() =>
- VariantUtils.ConvertToStringNameObject((godot_variant)NativeVar);
+ VariantUtils.ConvertToStringName((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public NodePath AsNodePath() =>
- VariantUtils.ConvertToNodePathObject((godot_variant)NativeVar);
+ VariantUtils.ConvertToNodePath((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RID AsRID() =>
@@ -365,11 +365,11 @@ public partial struct Variant : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Collections.Dictionary AsGodotDictionary() =>
- VariantUtils.ConvertToDictionaryObject((godot_variant)NativeVar);
+ VariantUtils.ConvertToDictionary((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Collections.Array AsGodotArray() =>
- VariantUtils.ConvertToArrayObject((godot_variant)NativeVar);
+ VariantUtils.ConvertToArray((godot_variant)NativeVar);
// Explicit conversion operators to supported types
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index c471eceded..4c60080ee9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -139,7 +139,7 @@ namespace Godot
/// <returns>The angle between the two vectors, in radians.</returns>
public readonly real_t AngleToPoint(Vector2 to)
{
- return Mathf.Atan2(y - to.y, x - to.x);
+ return Mathf.Atan2(to.y - y, to.x - x);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
index 08f2a3a8af..91be548a21 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
@@ -123,7 +123,7 @@ namespace Godot
/// <returns>The angle between the two vectors, in radians.</returns>
public readonly real_t AngleToPoint(Vector2i to)
{
- return Mathf.Atan2(y - to.y, x - to.x);
+ return Mathf.Atan2(to.y - y, to.x - x);
}
/// <summary>
diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp
index 338e5a0147..a3280a0739 100644
--- a/modules/mono/glue/runtime_interop.cpp
+++ b/modules/mono/glue/runtime_interop.cpp
@@ -514,6 +514,13 @@ void godotsharp_callable_call_deferred(Callable *p_callable, const Variant **p_a
p_callable->call_deferredp(p_args, p_arg_count);
}
+godot_color godotsharp_color_from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha) {
+ godot_color ret;
+ Color *dest = (Color *)&ret;
+ memnew_placement(dest, Color(Color::from_ok_hsl(p_h, p_s, p_l, p_alpha)));
+ return ret;
+}
+
// GDNative functions
// gdnative.h
@@ -1345,6 +1352,7 @@ static const void *unmanaged_callbacks[]{
(void *)godotsharp_callable_get_data_for_marshalling,
(void *)godotsharp_callable_call,
(void *)godotsharp_callable_call_deferred,
+ (void *)godotsharp_color_from_ok_hsl,
(void *)godotsharp_method_bind_ptrcall,
(void *)godotsharp_method_bind_call,
(void *)godotsharp_variant_new_string_name,
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index e5949c935b..58a0982425 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -36,6 +36,8 @@
#include "navigation_mesh_generator.h"
#endif
+using namespace NavigationUtilities;
+
/// Creates a struct for each function and a function that once called creates
/// an instance of that struct with the submitted parameters.
/// Then, that struct is stored in an array; the `sync` function consume that array.
@@ -228,7 +230,7 @@ Vector<Vector3> GodotNavigationServer::map_get_path(RID p_map, Vector3 p_origin,
const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, Vector<Vector3>());
- return map->get_path(p_origin, p_destination, p_optimize, p_navigation_layers);
+ return map->get_path(p_origin, p_destination, p_optimize, p_navigation_layers, nullptr, nullptr, nullptr);
}
Vector3 GodotNavigationServer::map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const {
@@ -421,20 +423,20 @@ uint32_t GodotNavigationServer::region_get_navigation_layers(RID p_region) const
return region->get_navigation_layers();
}
-COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh) {
+COMMAND_2(region_set_navigation_mesh, RID, p_region, Ref<NavigationMesh>, p_navigation_mesh) {
NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND(region == nullptr);
- region->set_mesh(p_nav_mesh);
+ region->set_mesh(p_navigation_mesh);
}
-void GodotNavigationServer::region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const {
- ERR_FAIL_COND(r_mesh.is_null());
- ERR_FAIL_COND(p_node == nullptr);
+void GodotNavigationServer::region_bake_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) const {
+ ERR_FAIL_COND(p_navigation_mesh.is_null());
+ ERR_FAIL_COND(p_root_node == nullptr);
#ifndef _3D_DISABLED
- NavigationMeshGenerator::get_singleton()->clear(r_mesh);
- NavigationMeshGenerator::get_singleton()->bake(r_mesh, p_node);
+ NavigationMeshGenerator::get_singleton()->clear(p_navigation_mesh);
+ NavigationMeshGenerator::get_singleton()->bake(p_navigation_mesh, p_root_node);
#endif
}
@@ -838,20 +840,34 @@ void GodotNavigationServer::process(real_t p_delta_time) {
}
}
-NavigationUtilities::PathQueryResult GodotNavigationServer::_query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const {
- NavigationUtilities::PathQueryResult r_query_result;
+PathQueryResult GodotNavigationServer::_query_path(const PathQueryParameters &p_parameters) const {
+ PathQueryResult r_query_result;
const NavMap *map = map_owner.get_or_null(p_parameters.map);
ERR_FAIL_COND_V(map == nullptr, r_query_result);
// run the pathfinding
- if (p_parameters.pathfinding_algorithm == NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR) {
+ if (p_parameters.pathfinding_algorithm == PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR) {
// while postprocessing is still part of map.get_path() need to check and route it here for the correct "optimize" post-processing
- if (p_parameters.path_postprocessing == NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL) {
- r_query_result.path = map->get_path(p_parameters.start_position, p_parameters.target_position, true, p_parameters.navigation_layers);
- } else if (p_parameters.path_postprocessing == NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED) {
- r_query_result.path = map->get_path(p_parameters.start_position, p_parameters.target_position, false, p_parameters.navigation_layers);
+ if (p_parameters.path_postprocessing == PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL) {
+ r_query_result.path = map->get_path(
+ p_parameters.start_position,
+ p_parameters.target_position,
+ true,
+ p_parameters.navigation_layers,
+ p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES) ? &r_query_result.path_types : nullptr,
+ p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS) ? &r_query_result.path_rids : nullptr,
+ p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS) ? &r_query_result.path_owner_ids : nullptr);
+ } else if (p_parameters.path_postprocessing == PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED) {
+ r_query_result.path = map->get_path(
+ p_parameters.start_position,
+ p_parameters.target_position,
+ false,
+ p_parameters.navigation_layers,
+ p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES) ? &r_query_result.path_types : nullptr,
+ p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS) ? &r_query_result.path_rids : nullptr,
+ p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS) ? &r_query_result.path_owner_ids : nullptr);
}
} else {
return r_query_result;
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index 18431e39b8..6f39420c67 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -135,8 +135,8 @@ public:
COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers);
virtual uint32_t region_get_navigation_layers(RID p_region) const override;
COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform);
- COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh);
- virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const override;
+ COMMAND_2(region_set_navigation_mesh, RID, p_region, Ref<NavigationMesh>, p_navigation_mesh);
+ virtual void region_bake_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) const override;
virtual int region_get_connections_count(RID p_region) const override;
virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override;
virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override;
diff --git a/modules/navigation/nav_base.h b/modules/navigation/nav_base.h
index f5d2880d36..a3ab77301b 100644
--- a/modules/navigation/nav_base.h
+++ b/modules/navigation/nav_base.h
@@ -33,6 +33,7 @@
#include "nav_rid.h"
#include "nav_utils.h"
+#include "servers/navigation/navigation_utilities.h"
class NavMap;
@@ -42,8 +43,11 @@ protected:
float enter_cost = 0.0;
float travel_cost = 1.0;
ObjectID owner_id;
+ NavigationUtilities::PathSegmentType type;
public:
+ NavigationUtilities::PathSegmentType get_type() const { return type; }
+
void set_navigation_layers(uint32_t p_navigation_layers) { navigation_layers = p_navigation_layers; }
uint32_t get_navigation_layers() const { return navigation_layers; }
diff --git a/modules/navigation/nav_link.h b/modules/navigation/nav_link.h
index 8f51a63951..e9c69286f9 100644
--- a/modules/navigation/nav_link.h
+++ b/modules/navigation/nav_link.h
@@ -43,6 +43,10 @@ class NavLink : public NavBase {
bool link_dirty = true;
public:
+ NavLink() {
+ type = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_LINK;
+ }
+
void set_map(NavMap *p_map);
NavMap *get_map() const {
return map;
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 83862e1e34..8d58c9335d 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -38,6 +38,18 @@
#define THREE_POINTS_CROSS_PRODUCT(m_a, m_b, m_c) (((m_c) - (m_a)).cross((m_b) - (m_a)))
+// Helper macro
+#define APPEND_METADATA(poly) \
+ if (r_path_types) { \
+ r_path_types->push_back(poly->owner->get_type()); \
+ } \
+ if (r_path_rids) { \
+ r_path_rids->push_back(poly->owner->get_self()); \
+ } \
+ if (r_path_owners) { \
+ r_path_owners->push_back(poly->owner->get_owner_id()); \
+ }
+
void NavMap::set_up(Vector3 p_up) {
up = p_up;
regenerate_polygons = true;
@@ -71,7 +83,18 @@ gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const {
return p;
}
-Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers) const {
+Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const {
+ // Clear metadata outputs.
+ if (r_path_types) {
+ r_path_types->clear();
+ }
+ if (r_path_rids) {
+ r_path_rids->clear();
+ }
+ if (r_path_owners) {
+ r_path_owners->clear();
+ }
+
// Find the start poly and the end poly on this map.
const gd::Polygon *begin_poly = nullptr;
const gd::Polygon *end_poly = nullptr;
@@ -115,6 +138,24 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
return Vector<Vector3>();
}
if (begin_poly == end_poly) {
+ if (r_path_types) {
+ r_path_types->resize(2);
+ r_path_types->write[0] = begin_poly->owner->get_type();
+ r_path_types->write[1] = end_poly->owner->get_type();
+ }
+
+ if (r_path_rids) {
+ r_path_rids->resize(2);
+ (*r_path_rids)[0] = begin_poly->owner->get_self();
+ (*r_path_rids)[1] = end_poly->owner->get_self();
+ }
+
+ if (r_path_owners) {
+ r_path_owners->resize(2);
+ r_path_owners->write[0] = begin_poly->owner->get_owner_id();
+ r_path_owners->write[1] = end_poly->owner->get_owner_id();
+ }
+
Vector<Vector3> path;
path.resize(2);
path.write[0] = begin_point;
@@ -296,6 +337,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
gd::NavigationPoly *p = apex_poly;
path.push_back(end_point);
+ APPEND_METADATA(end_poly);
while (p) {
// Set left and right points of the pathway between polygons.
@@ -312,7 +354,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
left_poly = p;
left_portal = left;
} else {
- clip_path(navigation_polys, path, apex_poly, right_portal, right_poly);
+ clip_path(navigation_polys, path, apex_poly, right_portal, right_poly, r_path_types, r_path_rids, r_path_owners);
apex_point = right_portal;
p = right_poly;
@@ -320,7 +362,9 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
apex_poly = p;
left_portal = apex_point;
right_portal = apex_point;
+
path.push_back(apex_point);
+ APPEND_METADATA(apex_poly->poly);
skip = true;
}
}
@@ -331,7 +375,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
right_poly = p;
right_portal = right;
} else {
- clip_path(navigation_polys, path, apex_poly, left_portal, left_poly);
+ clip_path(navigation_polys, path, apex_poly, left_portal, left_poly, r_path_types, r_path_rids, r_path_owners);
apex_point = left_portal;
p = left_poly;
@@ -339,7 +383,9 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
apex_poly = p;
right_portal = apex_point;
left_portal = apex_point;
+
path.push_back(apex_point);
+ APPEND_METADATA(apex_poly->poly);
}
}
@@ -355,12 +401,23 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// If the last point is not the begin point, add it to the list.
if (path[path.size() - 1] != begin_point) {
path.push_back(begin_point);
+ APPEND_METADATA(begin_poly);
}
path.reverse();
+ if (r_path_types) {
+ r_path_types->reverse();
+ }
+ if (r_path_rids) {
+ r_path_rids->reverse();
+ }
+ if (r_path_owners) {
+ r_path_owners->reverse();
+ }
} else {
path.push_back(end_point);
+ APPEND_METADATA(end_poly);
// Add mid points
int np_id = least_cost_id;
@@ -369,18 +426,37 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
int prev = navigation_polys[np_id].back_navigation_edge;
int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size();
Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5;
+
path.push_back(point);
+ APPEND_METADATA(navigation_polys[np_id].poly);
} else {
path.push_back(navigation_polys[np_id].entry);
+ APPEND_METADATA(navigation_polys[np_id].poly);
}
np_id = navigation_polys[np_id].back_navigation_poly_id;
}
path.push_back(begin_point);
+ APPEND_METADATA(begin_poly);
+
path.reverse();
+ if (r_path_types) {
+ r_path_types->reverse();
+ }
+ if (r_path_rids) {
+ r_path_rids->reverse();
+ }
+ if (r_path_owners) {
+ r_path_owners->reverse();
+ }
}
+ // Ensure post conditions (path arrays MUST match in size).
+ CRASH_COND(r_path_types && path.size() != r_path_types->size());
+ CRASH_COND(r_path_rids && path.size() != r_path_rids->size());
+ CRASH_COND(r_path_owners && path.size() != r_path_owners->size());
+
return path;
}
@@ -837,7 +913,7 @@ void NavMap::dispatch_callbacks() {
}
}
-void NavMap::clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly) const {
+void NavMap::clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const {
Vector3 from = path[path.size() - 1];
if (from.is_equal_approx(p_to_point)) {
@@ -863,6 +939,7 @@ void NavMap::clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys
if (cut_plane.intersects_segment(pathway_start, pathway_end, &inters)) {
if (!inters.is_equal_approx(p_to_point) && !inters.is_equal_approx(path[path.size() - 1])) {
path.push_back(inters);
+ APPEND_METADATA(from_poly->poly);
}
}
}
diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h
index a3da9fa727..3be13133d2 100644
--- a/modules/navigation/nav_map.h
+++ b/modules/navigation/nav_map.h
@@ -115,7 +115,7 @@ public:
gd::PointKey get_point_key(const Vector3 &p_pos) const;
- Vector<Vector3> get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const;
+ Vector<Vector3> get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const;
Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const;
Vector3 get_closest_point(const Vector3 &p_point) const;
Vector3 get_closest_point_normal(const Vector3 &p_point) const;
@@ -154,7 +154,7 @@ public:
private:
void compute_single_step(uint32_t index, RvoAgent **agent);
- void clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly) const;
+ void clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const;
};
#endif // NAV_MAP_H
diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h
index 8d2b5aa9eb..3ef3ef5748 100644
--- a/modules/navigation/nav_region.h
+++ b/modules/navigation/nav_region.h
@@ -48,7 +48,9 @@ class NavRegion : public NavBase {
LocalVector<gd::Polygon> polygons;
public:
- NavRegion() {}
+ NavRegion() {
+ type = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_REGION;
+ }
void scratch_polygons() {
polygons_dirty = true;
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index f0d3e329ce..62db6ff4e9 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -470,14 +470,14 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
}
}
-void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh) {
+void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_navigation_mesh) {
Vector<Vector3> nav_vertices;
for (int i = 0; i < p_detail_mesh->nverts; i++) {
const float *v = &p_detail_mesh->verts[i * 3];
nav_vertices.push_back(Vector3(v[0], v[1], v[2]));
}
- p_nav_mesh->set_vertices(nav_vertices);
+ p_navigation_mesh->set_vertices(nav_vertices);
for (int i = 0; i < p_detail_mesh->nmeshes; i++) {
const unsigned int *m = &p_detail_mesh->meshes[i * 4];
@@ -492,13 +492,13 @@ void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(con
nav_indices.write[0] = ((int)(bverts + tris[j * 4 + 0]));
nav_indices.write[1] = ((int)(bverts + tris[j * 4 + 2]));
nav_indices.write[2] = ((int)(bverts + tris[j * 4 + 1]));
- p_nav_mesh->add_polygon(nav_indices);
+ p_navigation_mesh->add_polygon(nav_indices);
}
}
}
void NavigationMeshGenerator::_build_recast_navigation_mesh(
- Ref<NavigationMesh> p_nav_mesh,
+ Ref<NavigationMesh> p_navigation_mesh,
#ifdef TOOLS_ENABLED
EditorProgress *ep,
#endif
@@ -528,42 +528,42 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
rcConfig cfg;
memset(&cfg, 0, sizeof(cfg));
- cfg.cs = p_nav_mesh->get_cell_size();
- cfg.ch = p_nav_mesh->get_cell_height();
- cfg.walkableSlopeAngle = p_nav_mesh->get_agent_max_slope();
- cfg.walkableHeight = (int)Math::ceil(p_nav_mesh->get_agent_height() / cfg.ch);
- cfg.walkableClimb = (int)Math::floor(p_nav_mesh->get_agent_max_climb() / cfg.ch);
- cfg.walkableRadius = (int)Math::ceil(p_nav_mesh->get_agent_radius() / cfg.cs);
- cfg.maxEdgeLen = (int)(p_nav_mesh->get_edge_max_length() / p_nav_mesh->get_cell_size());
- cfg.maxSimplificationError = p_nav_mesh->get_edge_max_error();
- cfg.minRegionArea = (int)(p_nav_mesh->get_region_min_size() * p_nav_mesh->get_region_min_size());
- cfg.mergeRegionArea = (int)(p_nav_mesh->get_region_merge_size() * p_nav_mesh->get_region_merge_size());
- cfg.maxVertsPerPoly = (int)p_nav_mesh->get_verts_per_poly();
- cfg.detailSampleDist = MAX(p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance(), 0.1f);
- cfg.detailSampleMaxError = p_nav_mesh->get_cell_height() * p_nav_mesh->get_detail_sample_max_error();
-
- if (!Math::is_equal_approx((float)cfg.walkableHeight * cfg.ch, p_nav_mesh->get_agent_height())) {
+ cfg.cs = p_navigation_mesh->get_cell_size();
+ cfg.ch = p_navigation_mesh->get_cell_height();
+ cfg.walkableSlopeAngle = p_navigation_mesh->get_agent_max_slope();
+ cfg.walkableHeight = (int)Math::ceil(p_navigation_mesh->get_agent_height() / cfg.ch);
+ cfg.walkableClimb = (int)Math::floor(p_navigation_mesh->get_agent_max_climb() / cfg.ch);
+ cfg.walkableRadius = (int)Math::ceil(p_navigation_mesh->get_agent_radius() / cfg.cs);
+ cfg.maxEdgeLen = (int)(p_navigation_mesh->get_edge_max_length() / p_navigation_mesh->get_cell_size());
+ cfg.maxSimplificationError = p_navigation_mesh->get_edge_max_error();
+ cfg.minRegionArea = (int)(p_navigation_mesh->get_region_min_size() * p_navigation_mesh->get_region_min_size());
+ cfg.mergeRegionArea = (int)(p_navigation_mesh->get_region_merge_size() * p_navigation_mesh->get_region_merge_size());
+ cfg.maxVertsPerPoly = (int)p_navigation_mesh->get_vertices_per_polygon();
+ cfg.detailSampleDist = MAX(p_navigation_mesh->get_cell_size() * p_navigation_mesh->get_detail_sample_distance(), 0.1f);
+ cfg.detailSampleMaxError = p_navigation_mesh->get_cell_height() * p_navigation_mesh->get_detail_sample_max_error();
+
+ if (!Math::is_equal_approx((float)cfg.walkableHeight * cfg.ch, p_navigation_mesh->get_agent_height())) {
WARN_PRINT("Property agent_height is ceiled to cell_height voxel units and loses precision.");
}
- if (!Math::is_equal_approx((float)cfg.walkableClimb * cfg.ch, p_nav_mesh->get_agent_max_climb())) {
+ if (!Math::is_equal_approx((float)cfg.walkableClimb * cfg.ch, p_navigation_mesh->get_agent_max_climb())) {
WARN_PRINT("Property agent_max_climb is floored to cell_height voxel units and loses precision.");
}
- if (!Math::is_equal_approx((float)cfg.walkableRadius * cfg.cs, p_nav_mesh->get_agent_radius())) {
+ if (!Math::is_equal_approx((float)cfg.walkableRadius * cfg.cs, p_navigation_mesh->get_agent_radius())) {
WARN_PRINT("Property agent_radius is ceiled to cell_size voxel units and loses precision.");
}
- if (!Math::is_equal_approx((float)cfg.maxEdgeLen * cfg.cs, p_nav_mesh->get_edge_max_length())) {
+ if (!Math::is_equal_approx((float)cfg.maxEdgeLen * cfg.cs, p_navigation_mesh->get_edge_max_length())) {
WARN_PRINT("Property edge_max_length is rounded to cell_size voxel units and loses precision.");
}
- if (!Math::is_equal_approx((float)cfg.minRegionArea, p_nav_mesh->get_region_min_size() * p_nav_mesh->get_region_min_size())) {
+ if (!Math::is_equal_approx((float)cfg.minRegionArea, p_navigation_mesh->get_region_min_size() * p_navigation_mesh->get_region_min_size())) {
WARN_PRINT("Property region_min_size is converted to int and loses precision.");
}
- if (!Math::is_equal_approx((float)cfg.mergeRegionArea, p_nav_mesh->get_region_merge_size() * p_nav_mesh->get_region_merge_size())) {
+ if (!Math::is_equal_approx((float)cfg.mergeRegionArea, p_navigation_mesh->get_region_merge_size() * p_navigation_mesh->get_region_merge_size())) {
WARN_PRINT("Property region_merge_size is converted to int and loses precision.");
}
- if (!Math::is_equal_approx((float)cfg.maxVertsPerPoly, p_nav_mesh->get_verts_per_poly())) {
- WARN_PRINT("Property verts_per_poly is converted to int and loses precision.");
+ if (!Math::is_equal_approx((float)cfg.maxVertsPerPoly, p_navigation_mesh->get_vertices_per_polygon())) {
+ WARN_PRINT("Property vertices_per_polygon is converted to int and loses precision.");
}
- if (p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance() < 0.1f) {
+ if (p_navigation_mesh->get_cell_size() * p_navigation_mesh->get_detail_sample_distance() < 0.1f) {
WARN_PRINT("Property detail_sample_distance is clamped to 0.1 world units as the resulting value from multiplying with cell_size is too low.");
}
@@ -574,9 +574,9 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
cfg.bmax[1] = bmax[1];
cfg.bmax[2] = bmax[2];
- AABB baking_aabb = p_nav_mesh->get_filter_baking_aabb();
+ AABB baking_aabb = p_navigation_mesh->get_filter_baking_aabb();
if (baking_aabb.has_volume()) {
- Vector3 baking_aabb_offset = p_nav_mesh->get_filter_baking_aabb_offset();
+ Vector3 baking_aabb_offset = p_navigation_mesh->get_filter_baking_aabb_offset();
cfg.bmin[0] = baking_aabb.position[0] + baking_aabb_offset.x;
cfg.bmin[1] = baking_aabb.position[1] + baking_aabb_offset.y;
cfg.bmin[2] = baking_aabb.position[2] + baking_aabb_offset.z;
@@ -627,13 +627,13 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
ERR_FAIL_COND(!rcRasterizeTriangles(&ctx, verts, nverts, tris, tri_areas.ptr(), ntris, *hf, cfg.walkableClimb));
}
- if (p_nav_mesh->get_filter_low_hanging_obstacles()) {
+ if (p_navigation_mesh->get_filter_low_hanging_obstacles()) {
rcFilterLowHangingWalkableObstacles(&ctx, cfg.walkableClimb, *hf);
}
- if (p_nav_mesh->get_filter_ledge_spans()) {
+ if (p_navigation_mesh->get_filter_ledge_spans()) {
rcFilterLedgeSpans(&ctx, cfg.walkableHeight, cfg.walkableClimb, *hf);
}
- if (p_nav_mesh->get_filter_walkable_low_height_spans()) {
+ if (p_navigation_mesh->get_filter_walkable_low_height_spans()) {
rcFilterWalkableLowHeightSpans(&ctx, cfg.walkableHeight, *hf);
}
@@ -665,10 +665,10 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
}
#endif
- if (p_nav_mesh->get_sample_partition_type() == NavigationMesh::SAMPLE_PARTITION_WATERSHED) {
+ if (p_navigation_mesh->get_sample_partition_type() == NavigationMesh::SAMPLE_PARTITION_WATERSHED) {
ERR_FAIL_COND(!rcBuildDistanceField(&ctx, *chf));
ERR_FAIL_COND(!rcBuildRegions(&ctx, *chf, 0, cfg.minRegionArea, cfg.mergeRegionArea));
- } else if (p_nav_mesh->get_sample_partition_type() == NavigationMesh::SAMPLE_PARTITION_MONOTONE) {
+ } else if (p_navigation_mesh->get_sample_partition_type() == NavigationMesh::SAMPLE_PARTITION_MONOTONE) {
ERR_FAIL_COND(!rcBuildRegionsMonotone(&ctx, *chf, 0, cfg.minRegionArea, cfg.mergeRegionArea));
} else {
ERR_FAIL_COND(!rcBuildLayerRegions(&ctx, *chf, 0, cfg.minRegionArea));
@@ -710,7 +710,7 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
}
#endif
- _convert_detail_mesh_to_native_navigation_mesh(detail_mesh, p_nav_mesh);
+ _convert_detail_mesh_to_native_navigation_mesh(detail_mesh, p_navigation_mesh);
rcFreePolyMesh(poly_mesh);
poly_mesh = nullptr;
@@ -729,8 +729,8 @@ NavigationMeshGenerator::NavigationMeshGenerator() {
NavigationMeshGenerator::~NavigationMeshGenerator() {
}
-void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) {
- ERR_FAIL_COND_MSG(!p_nav_mesh.is_valid(), "Invalid navigation mesh.");
+void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) {
+ ERR_FAIL_COND_MSG(!p_navigation_mesh.is_valid(), "Invalid navigation mesh.");
#ifdef TOOLS_ENABLED
EditorProgress *ep(nullptr);
@@ -755,17 +755,17 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node)
List<Node *> parse_nodes;
- if (p_nav_mesh->get_source_geometry_mode() == NavigationMesh::SOURCE_GEOMETRY_NAVMESH_CHILDREN) {
- parse_nodes.push_back(p_node);
+ if (p_navigation_mesh->get_source_geometry_mode() == NavigationMesh::SOURCE_GEOMETRY_ROOT_NODE_CHILDREN) {
+ parse_nodes.push_back(p_root_node);
} else {
- p_node->get_tree()->get_nodes_in_group(p_nav_mesh->get_source_group_name(), &parse_nodes);
+ p_root_node->get_tree()->get_nodes_in_group(p_navigation_mesh->get_source_group_name(), &parse_nodes);
}
- Transform3D navmesh_xform = Object::cast_to<Node3D>(p_node)->get_global_transform().affine_inverse();
+ Transform3D navmesh_xform = Object::cast_to<Node3D>(p_root_node)->get_global_transform().affine_inverse();
for (Node *E : parse_nodes) {
- NavigationMesh::ParsedGeometryType geometry_type = p_nav_mesh->get_parsed_geometry_type();
- uint32_t collision_mask = p_nav_mesh->get_collision_mask();
- bool recurse_children = p_nav_mesh->get_source_geometry_mode() != NavigationMesh::SOURCE_GEOMETRY_GROUPS_EXPLICIT;
+ NavigationMesh::ParsedGeometryType geometry_type = p_navigation_mesh->get_parsed_geometry_type();
+ uint32_t collision_mask = p_navigation_mesh->get_collision_mask();
+ bool recurse_children = p_navigation_mesh->get_source_geometry_mode() != NavigationMesh::SOURCE_GEOMETRY_GROUPS_EXPLICIT;
_parse_geometry(navmesh_xform, E, vertices, indices, geometry_type, collision_mask, recurse_children);
}
@@ -777,7 +777,7 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node)
rcPolyMeshDetail *detail_mesh = nullptr;
_build_recast_navigation_mesh(
- p_nav_mesh,
+ p_navigation_mesh,
#ifdef TOOLS_ENABLED
ep,
#endif
@@ -816,16 +816,16 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node)
#endif
}
-void NavigationMeshGenerator::clear(Ref<NavigationMesh> p_nav_mesh) {
- if (p_nav_mesh.is_valid()) {
- p_nav_mesh->clear_polygons();
- p_nav_mesh->set_vertices(Vector<Vector3>());
+void NavigationMeshGenerator::clear(Ref<NavigationMesh> p_navigation_mesh) {
+ if (p_navigation_mesh.is_valid()) {
+ p_navigation_mesh->clear_polygons();
+ p_navigation_mesh->set_vertices(Vector<Vector3>());
}
}
void NavigationMeshGenerator::_bind_methods() {
- ClassDB::bind_method(D_METHOD("bake", "nav_mesh", "root_node"), &NavigationMeshGenerator::bake);
- ClassDB::bind_method(D_METHOD("clear", "nav_mesh"), &NavigationMeshGenerator::clear);
+ ClassDB::bind_method(D_METHOD("bake", "navigation_mesh", "root_node"), &NavigationMeshGenerator::bake);
+ ClassDB::bind_method(D_METHOD("clear", "navigation_mesh"), &NavigationMeshGenerator::clear);
}
#endif
diff --git a/modules/navigation/navigation_mesh_generator.h b/modules/navigation/navigation_mesh_generator.h
index 8cc1531b53..f6bf39d714 100644
--- a/modules/navigation/navigation_mesh_generator.h
+++ b/modules/navigation/navigation_mesh_generator.h
@@ -55,9 +55,9 @@ protected:
static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices);
static void _parse_geometry(const Transform3D &p_navmesh_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children);
- static void _convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh);
+ static void _convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_navigation_mesh);
static void _build_recast_navigation_mesh(
- Ref<NavigationMesh> p_nav_mesh,
+ Ref<NavigationMesh> p_navigation_mesh,
#ifdef TOOLS_ENABLED
EditorProgress *ep,
#endif
@@ -75,8 +75,8 @@ public:
NavigationMeshGenerator();
~NavigationMeshGenerator();
- void bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node);
- void clear(Ref<NavigationMesh> p_nav_mesh);
+ void bake(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node);
+ void clear(Ref<NavigationMesh> p_navigation_mesh);
};
#endif
diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp
index 8c785d7591..1b6f1d7897 100644
--- a/modules/noise/noise_texture_2d.cpp
+++ b/modules/noise/noise_texture_2d.cpp
@@ -40,6 +40,7 @@ NoiseTexture2D::NoiseTexture2D() {
}
NoiseTexture2D::~NoiseTexture2D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
if (texture.is_valid()) {
RS::get_singleton()->free(texture);
}
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
index a2c33a91c4..71fcd3ce7f 100644
--- a/modules/openxr/editor/openxr_action_map_editor.cpp
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -57,7 +57,7 @@ void OpenXRActionMapEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
for (int i = 0; i < tabs->get_child_count(); i++) {
- Control *tab = static_cast<Control *>(tabs->get_child(i));
+ Control *tab = Object::cast_to<Control>(tabs->get_child(i));
if (tab) {
tab->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
}
@@ -205,11 +205,12 @@ void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) {
action_map->set_edited(true);
}
-void OpenXRActionMapEditor::_on_action_removed() {
+void OpenXRActionMapEditor::_on_action_removed(Ref<OpenXRAction> p_action) {
for (int i = 0; i < tabs->get_tab_count(); i++) {
// First tab won't be an interaction profile editor, but being thorough..
- OpenXRInteractionProfileEditorBase *interaction_profile_editor = static_cast<OpenXRInteractionProfileEditorBase *>(tabs->get_tab_control(i));
+ OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to<OpenXRInteractionProfileEditorBase>(tabs->get_tab_control(i));
if (interaction_profile_editor) {
+ interaction_profile_editor->remove_all_bindings_for_action(p_action);
}
}
}
@@ -309,7 +310,7 @@ void OpenXRActionMapEditor::_on_tabs_tab_changed(int p_tab) {
}
void OpenXRActionMapEditor::_on_tab_button_pressed(int p_tab) {
- OpenXRInteractionProfileEditorBase *interaction_profile_editor = static_cast<OpenXRInteractionProfileEditorBase *>(tabs->get_tab_control(p_tab));
+ OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to<OpenXRInteractionProfileEditorBase>(tabs->get_tab_control(p_tab));
ERR_FAIL_NULL(interaction_profile_editor);
undo_redo->create_action(TTR("Remove interaction profile"));
@@ -375,9 +376,9 @@ void OpenXRActionMapEditor::_clear_action_map() {
child->queue_free();
}
- for (int i = 0; i < tabs->get_tab_count(); i++) {
+ for (int i = tabs->get_tab_count() - 1; i >= 0; --i) {
// First tab won't be an interaction profile editor, but being thorough..
- OpenXRInteractionProfileEditorBase *interaction_profile_editor = static_cast<OpenXRInteractionProfileEditorBase *>(tabs->get_tab_control(i));
+ OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to<OpenXRInteractionProfileEditorBase>(tabs->get_tab_control(i));
if (interaction_profile_editor) {
tabs->remove_child(interaction_profile_editor);
interaction_profile_editor->queue_free();
diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h
index 8e3210a8e9..2ff6ddf785 100644
--- a/modules/openxr/editor/openxr_action_map_editor.h
+++ b/modules/openxr/editor/openxr_action_map_editor.h
@@ -75,7 +75,7 @@ private:
void _on_add_action_set();
void _set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor);
void _on_remove_action_set(Object *p_action_set_editor);
- void _on_action_removed();
+ void _on_action_removed(Ref<OpenXRAction> p_action);
void _on_add_interaction_profile();
void _on_interaction_profile_selected(const String p_path);
diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp
index d3b6945635..7f4da8b312 100644
--- a/modules/openxr/editor/openxr_action_set_editor.cpp
+++ b/modules/openxr/editor/openxr_action_set_editor.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "openxr_action_set_editor.h"
+#include "editor/editor_node.h"
#include "openxr_action_editor.h"
void OpenXRActionSetEditor::_bind_methods() {
@@ -211,6 +212,7 @@ void OpenXRActionSetEditor::set_focus_on_entry() {
}
OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set) {
+ undo_redo = EditorNode::get_undo_redo();
action_map = p_action_map;
action_set = p_action_set;
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
index 3eca1967f5..9d8ac76187 100644
--- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
@@ -124,8 +124,8 @@ void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Ref<Open
undo_redo->create_action(TTR("Remove action from interaction profile"));
PackedStringArray paths = binding->get_paths();
for (const String &path : paths) {
- undo_redo->add_do_method(this, "_remove_binding", p_action, path);
- undo_redo->add_undo_method(this, "_add_binding", p_action, path);
+ undo_redo->add_do_method(this, "_remove_binding", action_name, path);
+ undo_redo->add_undo_method(this, "_add_binding", action_name, path);
}
undo_redo->commit_action(false);
@@ -308,7 +308,7 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() {
void OpenXRInteractionProfileEditor::_theme_changed() {
for (int i = 0; i < main_hb->get_child_count(); i++) {
- Control *panel = static_cast<Control *>(main_hb->get_child(i));
+ Control *panel = Object::cast_to<Control>(main_hb->get_child(i));
if (panel) {
panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
}
diff --git a/modules/openxr/editor/openxr_select_action_dialog.cpp b/modules/openxr/editor/openxr_select_action_dialog.cpp
index 5f018291d5..c4b2ef95c5 100644
--- a/modules/openxr/editor/openxr_select_action_dialog.cpp
+++ b/modules/openxr/editor/openxr_select_action_dialog.cpp
@@ -47,7 +47,7 @@ void OpenXRSelectActionDialog::_notification(int p_what) {
void OpenXRSelectActionDialog::_on_select_action(const String p_action) {
if (selected_action != "") {
NodePath button_path = action_buttons[selected_action];
- Button *button = static_cast<Button *>(get_node(button_path));
+ Button *button = Object::cast_to<Button>(get_node(button_path));
if (button != nullptr) {
button->set_flat(true);
}
@@ -57,7 +57,7 @@ void OpenXRSelectActionDialog::_on_select_action(const String p_action) {
if (selected_action != "") {
NodePath button_path = action_buttons[selected_action];
- Button *button = static_cast<Button *>(get_node(button_path));
+ Button *button = Object::cast_to<Button>(get_node(button_path));
if (button != nullptr) {
button->set_flat(false);
}
diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
index 6ce26a62db..b871840cb2 100644
--- a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
+++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
@@ -46,7 +46,7 @@ void OpenXRSelectInteractionProfileDialog::_notification(int p_what) {
void OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile(const String p_interaction_profile) {
if (selected_interaction_profile != "") {
NodePath button_path = ip_buttons[selected_interaction_profile];
- Button *button = static_cast<Button *>(get_node(button_path));
+ Button *button = Object::cast_to<Button>(get_node(button_path));
if (button != nullptr) {
button->set_flat(true);
}
@@ -56,7 +56,7 @@ void OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile(const
if (selected_interaction_profile != "") {
NodePath button_path = ip_buttons[selected_interaction_profile];
- Button *button = static_cast<Button *>(get_node(button_path));
+ Button *button = Object::cast_to<Button>(get_node(button_path));
if (button != nullptr) {
button->set_flat(false);
}
diff --git a/modules/openxr/extensions/openxr_android_extension.cpp b/modules/openxr/extensions/openxr_android_extension.cpp
index 753fc5fa89..402a2ee707 100644
--- a/modules/openxr/extensions/openxr_android_extension.cpp
+++ b/modules/openxr/extensions/openxr_android_extension.cpp
@@ -74,7 +74,7 @@ void OpenXRAndroidExtension::on_before_instance_created() {
}
// We're keeping the Android create info struct here to avoid including openxr_platform.h in a header, which would break other extensions.
-// This is reasonably safe as the struct is only used during intialization and the extension is a singleton.
+// This is reasonably safe as the struct is only used during initialization and the extension is a singleton.
static XrInstanceCreateInfoAndroidKHR instance_create_info;
void *OpenXRAndroidExtension::set_instance_create_info_and_get_next_pointer(void *p_next_pointer) {
diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub
index 51d75d45b0..37c8a95905 100644
--- a/modules/raycast/SCsub
+++ b/modules/raycast/SCsub
@@ -68,10 +68,10 @@ if env["builtin_embree"]:
if not env.msvc:
if env["arch"] in ["x86_64", "x86_32"]:
- env_raycast.Append(CPPFLAGS=["-msse2", "-mxsave"])
+ env_raycast.Append(CCFLAGS=["-msse2", "-mxsave"])
if env["platform"] == "windows":
- env_raycast.Append(CPPFLAGS=["-mstackrealign"])
+ env_raycast.Append(CCFLAGS=["-mstackrealign"])
if env["platform"] == "windows":
if env.msvc:
@@ -92,11 +92,15 @@ if env["builtin_embree"]:
env_thirdparty.Append(CPPDEFINES=["__SSE2__", "__SSE__"])
if env["platform"] == "web":
- env_thirdparty.Append(CPPFLAGS=["-msimd128"])
+ env_thirdparty.Append(CXXFLAGS=["-msimd128"])
if not env.msvc:
+ # Flags synced with upstream gnu.cmake.
+ if env["arch"] == "arm64" and env["platform"] == "linuxbsd":
+ env_thirdparty.Append(CXXFLAGS=["-flax-vector-conversions"])
+
env_thirdparty.Append(
- CPPFLAGS=[
+ CXXFLAGS=[
"-fno-strict-overflow",
"-fno-delete-null-pointer-checks",
"-fwrapv",
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index 2dba4916a0..b194e7cb3f 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -67,19 +67,12 @@ void ImageLoaderSVG::_replace_color_property(const HashMap<Color, Color> &p_colo
}
}
-Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map) {
+Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const PackedByteArray &p_buffer, float p_scale, bool p_upsample) {
ERR_FAIL_COND_V_MSG(Math::is_zero_approx(p_scale), ERR_INVALID_PARAMETER, "ImageLoaderSVG: Can't load SVG with a scale of 0.");
- if (p_color_map.size()) {
- _replace_color_property(p_color_map, "stop-color=\"", p_string);
- _replace_color_property(p_color_map, "fill=\"", p_string);
- _replace_color_property(p_color_map, "stroke=\"", p_string);
- }
-
std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen();
- PackedByteArray bytes = p_string.to_utf8_buffer();
- tvg::Result result = picture->load((const char *)bytes.ptr(), bytes.size(), "svg", true);
+ tvg::Result result = picture->load((const char *)p_buffer.ptr(), p_buffer.size(), "svg", true);
if (result != tvg::Result::Success) {
return ERR_INVALID_DATA;
}
@@ -149,6 +142,18 @@ Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_stri
return OK;
}
+Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map) {
+ if (p_color_map.size()) {
+ _replace_color_property(p_color_map, "stop-color=\"", p_string);
+ _replace_color_property(p_color_map, "fill=\"", p_string);
+ _replace_color_property(p_color_map, "stroke=\"", p_string);
+ }
+
+ PackedByteArray bytes = p_string.to_utf8_buffer();
+
+ return create_image_from_utf8_buffer(p_image, bytes, p_scale, p_upsample);
+}
+
void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("svg");
}
diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h
index 84511f1708..d955a04f1e 100644
--- a/modules/svg/image_loader_svg.h
+++ b/modules/svg/image_loader_svg.h
@@ -41,6 +41,7 @@ class ImageLoaderSVG : public ImageFormatLoader {
public:
static void set_forced_color_map(const HashMap<Color, Color> &p_color_map);
+ Error create_image_from_utf8_buffer(Ref<Image> p_image, const PackedByteArray &p_buffer, float p_scale, bool p_upsample);
Error create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map);
virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) override;
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 512643867b..1c744afec0 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -385,11 +385,17 @@ void TextServerAdvanced::_free_rid(const RID &p_rid) {
_THREAD_SAFE_METHOD_
if (font_owner.owns(p_rid)) {
FontAdvanced *fd = font_owner.get_or_null(p_rid);
- font_owner.free(p_rid);
+ {
+ MutexLock lock(fd->mutex);
+ font_owner.free(p_rid);
+ }
memdelete(fd);
} else if (shaped_owner.owns(p_rid)) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_rid);
- shaped_owner.free(p_rid);
+ {
+ MutexLock lock(sd->mutex);
+ shaped_owner.free(p_rid);
+ }
memdelete(sd);
}
}
@@ -3296,7 +3302,7 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
Point2 cpos = p_pos;
cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size;
Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size;
- RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
+ RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
} else {
double scale = _font_get_scale(p_font_rid, p_size);
Point2 cpos = p_pos;
@@ -3388,7 +3394,7 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R
Point2 cpos = p_pos;
cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size;
Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size;
- RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
+ RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
} else {
Point2 cpos = p_pos;
double scale = _font_get_scale(p_font_rid, p_size);
@@ -3915,7 +3921,7 @@ bool TextServerAdvanced::_shaped_text_add_string(const RID &p_shaped, const Stri
return true;
}
-bool TextServerAdvanced::_shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) {
+bool TextServerAdvanced::_shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length, float p_baseline) {
_THREAD_SAFE_METHOD_
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -3935,6 +3941,7 @@ bool TextServerAdvanced::_shaped_text_add_object(const RID &p_shaped, const Vari
obj.inline_align = p_inline_align;
obj.rect.size = p_size;
obj.pos = span.start;
+ obj.baseline = p_baseline;
sd->spans.push_back(span);
sd->text = sd->text + String::chr(0xfffc).repeat(p_length);
@@ -3945,7 +3952,7 @@ bool TextServerAdvanced::_shaped_text_add_object(const RID &p_shaped, const Vari
return true;
}
-bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
+bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, float p_baseline) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -3953,6 +3960,7 @@ bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const V
ERR_FAIL_COND_V(!sd->objects.has(p_key), false);
sd->objects[p_key].rect.size = p_size;
sd->objects[p_key].inline_align = p_inline_align;
+ sd->objects[p_key].baseline = p_baseline;
if (sd->valid) {
// Recalc string metrics.
sd->ascent = 0;
@@ -4039,6 +4047,9 @@ void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const {
case INLINE_ALIGNMENT_CENTER_TO: {
E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
+ case INLINE_ALIGNMENT_BASELINE_TO: {
+ E.value.rect.position.y -= E.value.baseline;
+ } break;
case INLINE_ALIGNMENT_TOP_TO: {
// NOP
} break;
@@ -4067,6 +4078,9 @@ void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const {
case INLINE_ALIGNMENT_CENTER_TO: {
E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
+ case INLINE_ALIGNMENT_BASELINE_TO: {
+ E.value.rect.position.x -= E.value.baseline;
+ } break;
case INLINE_ALIGNMENT_TOP_TO: {
// NOP
} break;
@@ -6238,7 +6252,7 @@ String TextServerAdvanced::_string_to_lower(const String &p_string, const String
return String::utf16(lower.ptr(), len);
}
-PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_string, const String &p_language) const {
+PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_string, const String &p_language, int p_chars_per_line) const {
const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
// Convert to UTF-16.
Char16String utf16 = p_string.utf16();
@@ -6246,15 +6260,7 @@ PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_str
HashSet<int> breaks;
UErrorCode err = U_ZERO_ERROR;
UBreakIterator *bi = ubrk_open(UBRK_LINE, lang.ascii().get_data(), (const UChar *)utf16.get_data(), utf16.length(), &err);
- if (U_FAILURE(err)) {
- // No data loaded - use fallback.
- for (int i = 0; i < p_string.length(); i++) {
- char32_t c = p_string[i];
- if (is_whitespace(c) || is_linebreak(c)) {
- breaks.insert(i);
- }
- }
- } else {
+ if (U_SUCCESS(err)) {
while (ubrk_next(bi) != UBRK_DONE) {
int pos = _convert_pos(p_string, utf16, ubrk_current(bi)) - 1;
if (pos != p_string.length() - 1) {
@@ -6265,24 +6271,80 @@ PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_str
ubrk_close(bi);
PackedInt32Array ret;
+
+ int line_start = 0;
+ int line_end = 0; // End of last word on current line.
+ int word_start = 0; // -1 if no word encountered. Leading spaces are part of a word.
+ int word_length = 0;
+
for (int i = 0; i < p_string.length(); i++) {
- char32_t c = p_string[i];
- if (c == 0xfffc) {
- continue;
- }
- if (u_ispunct(c) && c != 0x005F) {
- ret.push_back(i);
- continue;
- }
- if (is_underscore(c)) {
- ret.push_back(i);
- continue;
- }
- if (breaks.has(i)) {
+ const char32_t c = p_string[i];
+
+ if (is_linebreak(c)) {
+ // Force newline.
+ ret.push_back(line_start);
ret.push_back(i);
+ line_start = i + 1;
+ line_end = line_start;
+ word_start = line_start;
+ word_length = 0;
+ } else if (c == 0xfffc) {
continue;
+ } else if ((u_ispunct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || is_whitespace(c)) {
+ // A whitespace ends current word.
+ if (word_length > 0) {
+ line_end = i - 1;
+ word_start = -1;
+ word_length = 0;
+ }
+ } else if (breaks.has(i)) {
+ // End current word, no space.
+ if (word_length > 0) {
+ line_end = i;
+ word_start = i + 1;
+ word_length = 0;
+ }
+ if (p_chars_per_line <= 0) {
+ ret.push_back(line_start);
+ ret.push_back(line_end + 1);
+ line_start = word_start;
+ line_end = line_start;
+ }
+ } else {
+ if (word_start == -1) {
+ word_start = i;
+ if (p_chars_per_line <= 0) {
+ ret.push_back(line_start);
+ ret.push_back(line_end + 1);
+ line_start = word_start;
+ line_end = line_start;
+ }
+ }
+ word_length += 1;
+
+ if (p_chars_per_line > 0) {
+ if (word_length > p_chars_per_line) {
+ // Word too long: wrap before current character.
+ ret.push_back(line_start);
+ ret.push_back(i);
+ line_start = i;
+ line_end = i;
+ word_start = i;
+ word_length = 1;
+ } else if (i - line_start + 1 > p_chars_per_line) {
+ // Line too long: wrap after the last word.
+ ret.push_back(line_start);
+ ret.push_back(line_end + 1);
+ line_start = word_start;
+ line_end = line_start;
+ }
+ }
}
}
+ if (line_start < p_string.length()) {
+ ret.push_back(line_start);
+ ret.push_back(p_string.length());
+ }
return ret;
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 5e6d2cc2c0..59f44cf142 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -467,6 +467,7 @@ class TextServerAdvanced : public TextServerExtension {
int pos = 0;
InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER;
Rect2 rect;
+ float baseline = 0;
};
HashMap<Variant, EmbeddedObject, VariantHasher, VariantComparator> objects;
@@ -868,8 +869,8 @@ public:
MODBIND2RC(int64_t, shaped_text_get_spacing, const RID &, SpacingType);
MODBIND7R(bool, shaped_text_add_string, const RID &, const String &, const TypedArray<RID> &, int64_t, const Dictionary &, const String &, const Variant &);
- MODBIND5R(bool, shaped_text_add_object, const RID &, const Variant &, const Size2 &, InlineAlignment, int64_t);
- MODBIND4R(bool, shaped_text_resize_object, const RID &, const Variant &, const Size2 &, InlineAlignment);
+ MODBIND6R(bool, shaped_text_add_object, const RID &, const Variant &, const Size2 &, InlineAlignment, int64_t, float);
+ MODBIND5R(bool, shaped_text_resize_object, const RID &, const Variant &, const Size2 &, InlineAlignment, float);
MODBIND1RC(int64_t, shaped_get_span_count, const RID &);
MODBIND2RC(Variant, shaped_get_span_meta, const RID &, int64_t);
@@ -914,7 +915,7 @@ public:
MODBIND2RC(String, parse_number, const String &, const String &);
MODBIND1RC(String, percent_sign, const String &);
- MODBIND2RC(PackedInt32Array, string_get_word_breaks, const String &, const String &);
+ MODBIND3RC(PackedInt32Array, string_get_word_breaks, const String &, const String &, int);
MODBIND2RC(int64_t, is_confusable, const String &, const PackedStringArray &);
MODBIND1RC(bool, spoof_check, const String &);
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 353d370f14..9fd8c8fb37 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -115,11 +115,17 @@ void TextServerFallback::_free_rid(const RID &p_rid) {
_THREAD_SAFE_METHOD_
if (font_owner.owns(p_rid)) {
FontFallback *fd = font_owner.get_or_null(p_rid);
- font_owner.free(p_rid);
+ {
+ MutexLock lock(fd->mutex);
+ font_owner.free(p_rid);
+ }
memdelete(fd);
} else if (shaped_owner.owns(p_rid)) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_rid);
- shaped_owner.free(p_rid);
+ {
+ MutexLock lock(sd->mutex);
+ shaped_owner.free(p_rid);
+ }
memdelete(sd);
}
}
@@ -2359,7 +2365,7 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
Point2 cpos = p_pos;
cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size;
Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size;
- RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
+ RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
} else {
Point2 cpos = p_pos;
double scale = _font_get_scale(p_font_rid, p_size);
@@ -2451,7 +2457,7 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R
Point2 cpos = p_pos;
cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size;
Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size;
- RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
+ RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
} else {
Point2 cpos = p_pos;
double scale = _font_get_scale(p_font_rid, p_size);
@@ -2917,7 +2923,7 @@ bool TextServerFallback::_shaped_text_add_string(const RID &p_shaped, const Stri
return true;
}
-bool TextServerFallback::_shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) {
+bool TextServerFallback::_shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length, float p_baseline) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2938,6 +2944,7 @@ bool TextServerFallback::_shaped_text_add_object(const RID &p_shaped, const Vari
obj.inline_align = p_inline_align;
obj.rect.size = p_size;
obj.pos = span.start;
+ obj.baseline = p_baseline;
sd->spans.push_back(span);
sd->text = sd->text + String::chr(0xfffc).repeat(p_length);
@@ -2948,7 +2955,7 @@ bool TextServerFallback::_shaped_text_add_object(const RID &p_shaped, const Vari
return true;
}
-bool TextServerFallback::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
+bool TextServerFallback::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, float p_baseline) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2956,6 +2963,7 @@ bool TextServerFallback::_shaped_text_resize_object(const RID &p_shaped, const V
ERR_FAIL_COND_V(!sd->objects.has(p_key), false);
sd->objects[p_key].rect.size = p_size;
sd->objects[p_key].inline_align = p_inline_align;
+ sd->objects[p_key].baseline = p_baseline;
if (sd->valid) {
// Recalc string metrics.
sd->ascent = 0;
@@ -3042,6 +3050,9 @@ void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const {
case INLINE_ALIGNMENT_CENTER_TO: {
E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
+ case INLINE_ALIGNMENT_BASELINE_TO: {
+ E.value.rect.position.y -= E.value.baseline;
+ } break;
case INLINE_ALIGNMENT_TOP_TO: {
// NOP
} break;
@@ -3070,6 +3081,9 @@ void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const {
case INLINE_ALIGNMENT_CENTER_TO: {
E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
+ case INLINE_ALIGNMENT_BASELINE_TO: {
+ E.value.rect.position.x -= E.value.baseline;
+ } break;
case INLINE_ALIGNMENT_TOP_TO: {
// NOP
} break;
@@ -4091,26 +4105,69 @@ String TextServerFallback::_string_to_lower(const String &p_string, const String
return lower;
}
-PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language) const {
+PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language, int p_chars_per_line) const {
PackedInt32Array ret;
+
+ int line_start = 0;
+ int line_end = 0; // End of last word on current line.
+ int word_start = 0; // -1 if no word encountered. Leading spaces are part of a word.
+ int word_length = 0;
+
for (int i = 0; i < p_string.length(); i++) {
- char32_t c = p_string[i];
- if (c == 0xfffc) {
- continue;
- }
- if (is_punct(c) && c != 0x005F) {
- ret.push_back(i);
- continue;
- }
- if (is_underscore(c)) {
- ret.push_back(i);
- continue;
- }
- if (is_whitespace(c) || is_linebreak(c)) {
+ const char32_t c = p_string[i];
+
+ if (is_linebreak(c)) {
+ // Force newline.
+ ret.push_back(line_start);
ret.push_back(i);
+ line_start = i + 1;
+ line_end = line_start;
+ word_start = line_start;
+ word_length = 0;
+ } else if (c == 0xfffc) {
continue;
+ } else if ((is_punct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || is_whitespace(c)) {
+ // A whitespace ends current word.
+ if (word_length > 0) {
+ line_end = i - 1;
+ word_start = -1;
+ word_length = 0;
+ }
+ } else {
+ if (word_start == -1) {
+ word_start = i;
+ if (p_chars_per_line <= 0) {
+ ret.push_back(line_start);
+ ret.push_back(line_end + 1);
+ line_start = word_start;
+ line_end = line_start;
+ }
+ }
+ word_length += 1;
+
+ if (p_chars_per_line > 0) {
+ if (word_length > p_chars_per_line) {
+ // Word too long: wrap before current character.
+ ret.push_back(line_start);
+ ret.push_back(i);
+ line_start = i;
+ line_end = i;
+ word_start = i;
+ word_length = 1;
+ } else if (i - line_start + 1 > p_chars_per_line) {
+ // Line too long: wrap after the last word.
+ ret.push_back(line_start);
+ ret.push_back(line_end + 1);
+ line_start = word_start;
+ line_end = line_start;
+ }
+ }
}
}
+ if (line_start < p_string.length()) {
+ ret.push_back(line_start);
+ ret.push_back(p_string.length());
+ }
return ret;
}
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index f8a05f9433..49e89214ec 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -417,6 +417,7 @@ class TextServerFallback : public TextServerExtension {
int pos = 0;
InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER;
Rect2 rect;
+ float baseline = 0;
};
HashMap<Variant, EmbeddedObject, VariantHasher, VariantComparator> objects;
@@ -743,8 +744,8 @@ public:
MODBIND2RC(int64_t, shaped_text_get_spacing, const RID &, SpacingType);
MODBIND7R(bool, shaped_text_add_string, const RID &, const String &, const TypedArray<RID> &, int64_t, const Dictionary &, const String &, const Variant &);
- MODBIND5R(bool, shaped_text_add_object, const RID &, const Variant &, const Size2 &, InlineAlignment, int64_t);
- MODBIND4R(bool, shaped_text_resize_object, const RID &, const Variant &, const Size2 &, InlineAlignment);
+ MODBIND6R(bool, shaped_text_add_object, const RID &, const Variant &, const Size2 &, InlineAlignment, int64_t, float);
+ MODBIND5R(bool, shaped_text_resize_object, const RID &, const Variant &, const Size2 &, InlineAlignment, float);
MODBIND1RC(int64_t, shaped_get_span_count, const RID &);
MODBIND2RC(Variant, shaped_get_span_meta, const RID &, int64_t);
@@ -785,7 +786,7 @@ public:
MODBIND1RC(double, shaped_text_get_underline_position, const RID &);
MODBIND1RC(double, shaped_text_get_underline_thickness, const RID &);
- MODBIND2RC(PackedInt32Array, string_get_word_breaks, const String &, const String &);
+ MODBIND3RC(PackedInt32Array, string_get_word_breaks, const String &, const String &, int);
MODBIND2RC(String, string_to_upper, const String &, const String &);
MODBIND2RC(String, string_to_lower, const String &, const String &);
diff --git a/platform/android/api/jni_singleton.h b/platform/android/api/jni_singleton.h
index 895bc70103..afe7dcaeff 100644
--- a/platform/android/api/jni_singleton.h
+++ b/platform/android/api/jni_singleton.h
@@ -137,6 +137,18 @@ public:
ret = sarr;
env->DeleteLocalRef(arr);
} break;
+ case Variant::PACKED_INT64_ARRAY: {
+ jlongArray arr = (jlongArray)env->CallObjectMethodA(instance, E->get().method, v);
+
+ int fCount = env->GetArrayLength(arr);
+ Vector<int64_t> sarr;
+ sarr.resize(fCount);
+
+ int64_t *w = sarr.ptrw();
+ env->GetLongArrayRegion(arr, 0, fCount, w);
+ ret = sarr;
+ env->DeleteLocalRef(arr);
+ } break;
case Variant::PACKED_FLOAT32_ARRAY: {
jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v);
@@ -149,9 +161,18 @@ public:
ret = sarr;
env->DeleteLocalRef(arr);
} break;
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ jdoubleArray arr = (jdoubleArray)env->CallObjectMethodA(instance, E->get().method, v);
- // TODO: This is missing 64 bits arrays, I have no idea how to do it in JNI.
+ int fCount = env->GetArrayLength(arr);
+ Vector<double> sarr;
+ sarr.resize(fCount);
+ double *w = sarr.ptrw();
+ env->GetDoubleArrayRegion(arr, 0, fCount, w);
+ ret = sarr;
+ env->DeleteLocalRef(arr);
+ } break;
case Variant::DICTIONARY: {
jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
ret = _jobject_to_variant(env, obj);
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 3cea8e5c0c..41d2579ac0 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -873,7 +873,7 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
int hand_tracking_frequency_index = p_preset->get("xr_features/hand_tracking_frequency");
bool backup_allowed = p_preset->get("user_data_backup/allow");
- bool classify_as_game = p_preset->get("package/classify_as_game");
+ int app_category = p_preset->get("package/app_category");
bool retain_data_on_uninstall = p_preset->get("package/retain_data_on_uninstall");
bool exclude_from_recents = p_preset->get("package/exclude_from_recents");
bool is_resizeable = bool(GLOBAL_GET("display/window/size/resizable"));
@@ -972,8 +972,12 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
encode_uint32(backup_allowed, &p_manifest.write[iofs + 16]);
}
+ if (tname == "application" && attrname == "appCategory") {
+ encode_uint32(_get_app_category_value(app_category), &p_manifest.write[iofs + 16]);
+ }
+
if (tname == "application" && attrname == "isGame") {
- encode_uint32(classify_as_game, &p_manifest.write[iofs + 16]);
+ encode_uint32(app_category == APP_CATEGORY_GAME, &p_manifest.write[iofs + 16]);
}
if (tname == "application" && attrname == "hasFragileUserData") {
@@ -1731,7 +1735,7 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/classify_as_game"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "package/app_category", PROPERTY_HINT_ENUM, "Accessibility,Audio,Game,Image,Maps,News,Productivity,Social,Video"), APP_CATEGORY_GAME));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/retain_data_on_uninstall"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/exclude_from_recents"), false));
@@ -2011,7 +2015,10 @@ String EditorExportPlatformAndroid::get_adb_path() {
return sdk_path.path_join("platform-tools/adb" + exe_ext);
}
-String EditorExportPlatformAndroid::get_apksigner_path() {
+String EditorExportPlatformAndroid::get_apksigner_path(int p_target_sdk, bool p_check_executes) {
+ if (p_target_sdk == -1) {
+ p_target_sdk = DEFAULT_TARGET_SDK_VERSION;
+ }
String exe_ext = "";
if (OS::get_singleton()->get_name() == "Windows") {
exe_ext = ".bat";
@@ -2029,23 +2036,89 @@ String EditorExportPlatformAndroid::get_apksigner_path() {
}
// There are additional versions directories we need to go through.
- da->list_dir_begin();
- String sub_dir = da->get_next();
- while (!sub_dir.is_empty()) {
- if (!sub_dir.begins_with(".") && da->current_is_dir()) {
- // Check if the tool is here.
- String tool_path = build_tools_dir.path_join(sub_dir).path_join(apksigner_command_name);
- if (FileAccess::exists(tool_path)) {
- apksigner_path = tool_path;
- break;
+ Vector<String> dir_list = da->get_directories();
+
+ // We need to use the version of build_tools that matches the Target SDK
+ // If somehow we can't find that, we see if a version between 28 and the default target SDK exists.
+ // We need to avoid versions <= 27 because they fail on Java versions >9
+ // If we can't find that, we just use the first valid version.
+ Vector<String> ideal_versions;
+ Vector<String> other_versions;
+ Vector<String> versions;
+ bool found_target_sdk = false;
+ // We only allow for versions <= 27 if specifically set
+ int min_version = p_target_sdk <= 27 ? p_target_sdk : 28;
+ for (String sub_dir : dir_list) {
+ if (!sub_dir.begins_with(".")) {
+ Vector<String> ver_numbers = sub_dir.split(".");
+ // Dir not a version number, will use as last resort
+ if (!ver_numbers.size() || !ver_numbers[0].is_valid_int()) {
+ other_versions.push_back(sub_dir);
+ continue;
+ }
+ int ver_number = ver_numbers[0].to_int();
+ if (ver_number == p_target_sdk) {
+ found_target_sdk = true;
+ //ensure this is in front of the ones we check
+ versions.push_back(sub_dir);
+ } else {
+ if (ver_number >= min_version && ver_number <= DEFAULT_TARGET_SDK_VERSION) {
+ ideal_versions.push_back(sub_dir);
+ } else {
+ other_versions.push_back(sub_dir);
+ }
}
}
- sub_dir = da->get_next();
}
- da->list_dir_end();
+ // we will check ideal versions first, then other versions.
+ versions.append_array(ideal_versions);
+ versions.append_array(other_versions);
- if (apksigner_path.is_empty()) {
+ if (!versions.size()) {
print_error("Unable to find the 'apksigner' tool.");
+ return apksigner_path;
+ }
+
+ int i;
+ bool failed = false;
+ String version_to_use;
+
+ List<String> args;
+ args.push_back("--version");
+ String output;
+ int retval;
+ Error err;
+ for (i = 0; i < versions.size(); i++) {
+ // Check if the tool is here.
+ apksigner_path = build_tools_dir.path_join(versions[i]).path_join(apksigner_command_name);
+ if (FileAccess::exists(apksigner_path)) {
+ version_to_use = versions[i];
+ // If we aren't exporting, just break here.
+ if (!p_check_executes) {
+ break;
+ }
+ // we only check to see if it executes on export because it is slow to load
+ err = OS::get_singleton()->execute(apksigner_path, args, &output, &retval, false);
+ if (err || retval) {
+ failed = true;
+ } else {
+ break;
+ }
+ }
+ }
+ if (i == versions.size()) {
+ if (failed) {
+ print_error("All located 'apksigner' tools in " + build_tools_dir + " failed to execute");
+ return "<FAILED>";
+ } else {
+ print_error("Unable to find the 'apksigner' tool.");
+ return "";
+ }
+ }
+ if (!found_target_sdk) {
+ print_line("Could not find version of build tools that matches Target SDK, using " + version_to_use);
+ } else if (failed && found_target_sdk) {
+ print_line("Version of build tools that matches Target SDK failed to execute, using " + version_to_use);
}
return apksigner_path;
@@ -2165,8 +2238,12 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
valid = false;
}
+ String target_sdk_version = p_preset->get("custom_build/target_sdk");
+ if (!target_sdk_version.is_valid_int()) {
+ target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION);
+ }
// Validate that apksigner is available
- String apksigner_path = get_apksigner_path();
+ String apksigner_path = get_apksigner_path(target_sdk_version.to_int());
if (!FileAccess::exists(apksigner_path)) {
err += TTR("Unable to find Android SDK build-tools' apksigner command.");
err += TTR("Please check in the Android SDK directory specified in Editor Settings.");
@@ -2389,9 +2466,16 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
String release_keystore = p_preset->get("keystore/release");
String release_username = p_preset->get("keystore/release_user");
String release_password = p_preset->get("keystore/release_password");
-
- String apksigner = get_apksigner_path();
+ String target_sdk_version = p_preset->get("custom_build/target_sdk");
+ if (!target_sdk_version.is_valid_int()) {
+ target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION);
+ }
+ String apksigner = get_apksigner_path(target_sdk_version.to_int(), true);
print_verbose("Starting signing of the " + export_label + " binary using " + apksigner);
+ if (apksigner == "<FAILED>") {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("All 'apksigner' tools located in Android SDK 'build-tools' directory failed to execute. Please check that you have the correct version installed for your target sdk version. The resulting %s is unsigned."), export_label));
+ return OK;
+ }
if (!FileAccess::exists(apksigner)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("'apksigner' could not be found. Please check that the command is available in the Android SDK build-tools directory. The resulting %s is unsigned."), export_label));
return OK;
@@ -2441,20 +2525,27 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
args.push_back("--ks-key-alias");
args.push_back(user);
args.push_back(export_path);
- if (p_debug) {
- // We only print verbose logs for debug builds to avoid leaking release keystore credentials.
+ if (OS::get_singleton()->is_stdout_verbose() && p_debug) {
+ // We only print verbose logs with credentials for debug builds to avoid leaking release keystore credentials.
print_verbose("Signing debug binary using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
+ } else {
+ List<String> redacted_args = List<String>(args);
+ redacted_args.find(keystore)->set("<REDACTED>");
+ redacted_args.find("pass:" + password)->set("pass:<REDACTED>");
+ redacted_args.find(user)->set("<REDACTED>");
+ print_line("Signing binary using: " + String("\n") + apksigner + " " + join_list(redacted_args, String(" ")));
}
int retval;
- output.clear();
Error err = OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
if (err != OK) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start apksigner executable."));
return err;
}
- print_verbose(output);
+ // By design, apksigner does not output credentials in its output unless --verbose is used
+ print_line(output);
if (retval) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("'apksigner' returned with error #%d"), retval));
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("output: \n%s"), output));
return ERR_CANT_CREATE;
}
@@ -2479,6 +2570,7 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
print_verbose(output);
if (retval) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("'apksigner' verification of %s failed."), export_label));
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("output: \n%s"), output));
return ERR_CANT_CREATE;
}
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index c8fcb761fe..b9630858d3 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -201,7 +201,7 @@ public:
static String get_adb_path();
- static String get_apksigner_path();
+ static String get_apksigner_path(int p_target_sdk = -1, bool p_check_executes = false);
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
index 8d016d3fac..1cbed4b3bb 100644
--- a/platform/android/export/gradle_export_util.cpp
+++ b/platform/android/export/gradle_export_util.cpp
@@ -72,6 +72,54 @@ String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_or
}
}
+int _get_app_category_value(int category_index) {
+ switch (category_index) {
+ case APP_CATEGORY_ACCESSIBILITY:
+ return 8;
+ case APP_CATEGORY_AUDIO:
+ return 1;
+ case APP_CATEGORY_IMAGE:
+ return 3;
+ case APP_CATEGORY_MAPS:
+ return 6;
+ case APP_CATEGORY_NEWS:
+ return 5;
+ case APP_CATEGORY_PRODUCTIVITY:
+ return 7;
+ case APP_CATEGORY_SOCIAL:
+ return 4;
+ case APP_CATEGORY_VIDEO:
+ return 2;
+ case APP_CATEGORY_GAME:
+ default:
+ return 0;
+ }
+}
+
+String _get_app_category_label(int category_index) {
+ switch (category_index) {
+ case APP_CATEGORY_ACCESSIBILITY:
+ return "accessibility";
+ case APP_CATEGORY_AUDIO:
+ return "audio";
+ case APP_CATEGORY_IMAGE:
+ return "image";
+ case APP_CATEGORY_MAPS:
+ return "maps";
+ case APP_CATEGORY_NEWS:
+ return "news";
+ case APP_CATEGORY_PRODUCTIVITY:
+ return "productivity";
+ case APP_CATEGORY_SOCIAL:
+ return "social";
+ case APP_CATEGORY_VIDEO:
+ return "video";
+ case APP_CATEGORY_GAME:
+ default:
+ return "game";
+ }
+}
+
// Utility method used to create a directory.
Error create_directory(const String &p_dir) {
if (!DirAccess::exists(p_dir)) {
@@ -253,21 +301,27 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
}
String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_read_write_storage_permission) {
+ int app_category_index = (int)(p_preset->get("package/app_category"));
+ bool is_game = app_category_index == APP_CATEGORY_GAME;
+
int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode"));
bool uses_xr = xr_mode_index == XR_MODE_OPENXR;
+
String manifest_application_text = vformat(
" <application android:label=\"@string/godot_project_name_string\"\n"
" android:allowBackup=\"%s\"\n"
" android:icon=\"@mipmap/icon\"\n"
+ " android:appCategory=\"%s\"\n"
" android:isGame=\"%s\"\n"
" android:hasFragileUserData=\"%s\"\n"
" android:requestLegacyExternalStorage=\"%s\"\n"
- " tools:replace=\"android:allowBackup,android:isGame,android:hasFragileUserData,android:requestLegacyExternalStorage\"\n"
+ " tools:replace=\"android:allowBackup,android:appCategory,android:isGame,android:hasFragileUserData,android:requestLegacyExternalStorage\"\n"
" tools:ignore=\"GoogleAppIndexingWarning\">\n\n"
" <meta-data tools:node=\"remove\" android:name=\"xr_hand_tracking_version_name\" />\n"
" <meta-data tools:node=\"remove\" android:name=\"xr_hand_tracking_metadata_name\" />\n",
bool_to_string(p_preset->get("user_data_backup/allow")),
- bool_to_string(p_preset->get("package/classify_as_game")),
+ _get_app_category_label(app_category_index),
+ bool_to_string(is_game),
bool_to_string(p_preset->get("package/retain_data_on_uninstall")),
bool_to_string(p_has_read_write_storage_permission));
diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h
index 232b4458c6..9c9c5923f7 100644
--- a/platform/android/export/gradle_export_util.h
+++ b/platform/android/export/gradle_export_util.h
@@ -44,6 +44,18 @@ const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="ut
</resources>
)";
+// Application category.
+// See https://developer.android.com/guide/topics/manifest/application-element#appCategory for standards
+static const int APP_CATEGORY_ACCESSIBILITY = 0;
+static const int APP_CATEGORY_AUDIO = 1;
+static const int APP_CATEGORY_GAME = 2;
+static const int APP_CATEGORY_IMAGE = 3;
+static const int APP_CATEGORY_MAPS = 4;
+static const int APP_CATEGORY_NEWS = 5;
+static const int APP_CATEGORY_PRODUCTIVITY = 6;
+static const int APP_CATEGORY_SOCIAL = 7;
+static const int APP_CATEGORY_VIDEO = 8;
+
// Supported XR modes.
// This should match the entries in 'platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java'
static const int XR_MODE_REGULAR = 0;
@@ -73,6 +85,10 @@ int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orien
String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_orientation);
+int _get_app_category_value(int category_index);
+
+String _get_app_category_label(int category_index);
+
// Utility method used to create a directory.
Error create_directory(const String &p_dir);
diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml
index 1db135826a..8c8608cbbb 100644
--- a/platform/android/java/app/AndroidManifest.xml
+++ b/platform/android/java/app/AndroidManifest.xml
@@ -20,6 +20,7 @@
android:label="@string/godot_project_name_string"
android:allowBackup="false"
android:icon="@mipmap/icon"
+ android:appCategory="game"
android:isGame="true"
android:hasFragileUserData="false"
android:requestLegacyExternalStorage="false"
diff --git a/platform/android/java/editor/src/main/AndroidManifest.xml b/platform/android/java/editor/src/main/AndroidManifest.xml
index f3ddaafd0e..80ef10b6a4 100644
--- a/platform/android/java/editor/src/main/AndroidManifest.xml
+++ b/platform/android/java/editor/src/main/AndroidManifest.xml
@@ -27,6 +27,7 @@
android:icon="@mipmap/icon"
android:label="@string/godot_editor_name_string"
tools:ignore="GoogleAppIndexingWarning"
+ android:theme="@style/GodotEditorTheme"
android:requestLegacyExternalStorage="true">
<activity
@@ -35,7 +36,6 @@
android:launchMode="singleTask"
android:screenOrientation="userLandscape"
android:exported="true"
- android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
android:process=":GodotProjectManager">
<layout android:defaultHeight="@dimen/editor_default_window_height"
@@ -53,8 +53,7 @@
android:process=":GodotEditor"
android:launchMode="singleTask"
android:screenOrientation="userLandscape"
- android:exported="false"
- android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
+ android:exported="false">
<layout android:defaultHeight="@dimen/editor_default_window_height"
android:defaultWidth="@dimen/editor_default_window_width" />
</activity>
@@ -66,8 +65,7 @@
android:process=":GodotGame"
android:launchMode="singleTask"
android:exported="false"
- android:screenOrientation="userLandscape"
- android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
+ android:screenOrientation="userLandscape">
<layout android:defaultHeight="@dimen/editor_default_window_height"
android:defaultWidth="@dimen/editor_default_window_width" />
</activity>
diff --git a/platform/android/java/editor/src/main/res/values/themes.xml b/platform/android/java/editor/src/main/res/values/themes.xml
new file mode 100644
index 0000000000..fda04d6dc7
--- /dev/null
+++ b/platform/android/java/editor/src/main/res/values/themes.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <style name="GodotEditorTheme" parent="@android:style/Theme.Black.NoTitleBar.Fullscreen">
+ </style>
+</resources>
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index 2f26497cc8..0ba86e4316 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -422,7 +422,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
private static boolean isMouseEvent(int eventSource) {
- boolean mouseSource = ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS);
+ boolean mouseSource = ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & (InputDevice.SOURCE_TOUCHSCREEN | InputDevice.SOURCE_STYLUS)) == InputDevice.SOURCE_STYLUS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mouseSource = mouseSource || ((eventSource & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE);
}
diff --git a/platform/android/jni_utils.cpp b/platform/android/jni_utils.cpp
index 2b0ee50570..8b29670542 100644
--- a/platform/android/jni_utils.cpp
+++ b/platform/android/jni_utils.cpp
@@ -149,6 +149,15 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_a
v.obj = arr;
} break;
+ case Variant::PACKED_INT64_ARRAY: {
+ Vector<int64_t> array = *p_arg;
+ jlongArray arr = env->NewLongArray(array.size());
+ const int64_t *r = array.ptr();
+ env->SetLongArrayRegion(arr, 0, array.size(), r);
+ v.val.l = arr;
+ v.obj = arr;
+
+ } break;
case Variant::PACKED_BYTE_ARRAY: {
Vector<uint8_t> array = *p_arg;
jbyteArray arr = env->NewByteArray(array.size());
@@ -167,8 +176,15 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_a
v.obj = arr;
} break;
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ Vector<double> array = *p_arg;
+ jdoubleArray arr = env->NewDoubleArray(array.size());
+ const double *r = array.ptr();
+ env->SetDoubleArrayRegion(arr, 0, array.size(), r);
+ v.val.l = arr;
+ v.obj = arr;
- // TODO: This is missing 64 bits arrays, I have no idea how to do it in JNI.
+ } break;
default: {
v.val.i = 0;
@@ -244,6 +260,17 @@ Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
return sarr;
}
+ if (name == "[J") {
+ jlongArray arr = (jlongArray)obj;
+ int fCount = env->GetArrayLength(arr);
+ Vector<int64_t> sarr;
+ sarr.resize(fCount);
+
+ int64_t *w = sarr.ptrw();
+ env->GetLongArrayRegion(arr, 0, fCount, w);
+ return sarr;
+ }
+
if (name == "[B") {
jbyteArray arr = (jbyteArray)obj;
int fCount = env->GetArrayLength(arr);
@@ -344,12 +371,15 @@ Variant::Type get_jni_type(const String &p_type) {
{ "void", Variant::NIL },
{ "boolean", Variant::BOOL },
{ "int", Variant::INT },
+ { "long", Variant::INT },
{ "float", Variant::FLOAT },
{ "double", Variant::FLOAT },
{ "java.lang.String", Variant::STRING },
{ "[I", Variant::PACKED_INT32_ARRAY },
+ { "[J", Variant::PACKED_INT64_ARRAY },
{ "[B", Variant::PACKED_BYTE_ARRAY },
{ "[F", Variant::PACKED_FLOAT32_ARRAY },
+ { "[D", Variant::PACKED_FLOAT64_ARRAY },
{ "[Ljava.lang.String;", Variant::PACKED_STRING_ARRAY },
{ "org.godotengine.godot.Dictionary", Variant::DICTIONARY },
{ nullptr, Variant::NIL }
@@ -376,13 +406,16 @@ const char *get_jni_sig(const String &p_type) {
{ "void", "V" },
{ "boolean", "Z" },
{ "int", "I" },
+ { "long", "J" },
{ "float", "F" },
{ "double", "D" },
{ "java.lang.String", "Ljava/lang/String;" },
{ "org.godotengine.godot.Dictionary", "Lorg/godotengine/godot/Dictionary;" },
{ "[I", "[I" },
+ { "[J", "[J" },
{ "[B", "[B" },
{ "[F", "[F" },
+ { "[D", "[D" },
{ "[Ljava.lang.String;", "[Ljava/lang/String;" },
{ nullptr, "V" }
};
diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h
index 0ca0d3d1fe..82351a536b 100644
--- a/platform/ios/display_server_ios.h
+++ b/platform/ios/display_server_ios.h
@@ -105,10 +105,10 @@ public:
// MARK: - Input
- // MARK: Touches
+ // MARK: Touches and Apple Pencil
void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click);
- void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y);
+ void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt);
void touches_cancelled(int p_idx);
// MARK: Keyboard
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index 23b70fbc28..789364494d 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -227,27 +227,25 @@ void DisplayServerIOS::_window_callback(const Callable &p_callable, const Varian
// MARK: Touches
void DisplayServerIOS::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) {
- if (!GLOBAL_GET("debug/disable_touch")) {
- Ref<InputEventScreenTouch> ev;
- ev.instantiate();
-
- ev->set_index(p_idx);
- ev->set_pressed(p_pressed);
- ev->set_position(Vector2(p_x, p_y));
- ev->set_double_tap(p_double_click);
- perform_event(ev);
- }
+ Ref<InputEventScreenTouch> ev;
+ ev.instantiate();
+
+ ev->set_index(p_idx);
+ ev->set_pressed(p_pressed);
+ ev->set_position(Vector2(p_x, p_y));
+ ev->set_double_tap(p_double_click);
+ perform_event(ev);
}
-void DisplayServerIOS::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) {
- if (!GLOBAL_GET("debug/disable_touch")) {
- Ref<InputEventScreenDrag> ev;
- ev.instantiate();
- ev->set_index(p_idx);
- ev->set_position(Vector2(p_x, p_y));
- ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y));
- perform_event(ev);
- }
+void DisplayServerIOS::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt) {
+ Ref<InputEventScreenDrag> ev;
+ ev.instantiate();
+ ev->set_index(p_idx);
+ ev->set_pressure(p_pressure);
+ ev->set_tilt(p_tilt);
+ ev->set_position(Vector2(p_x, p_y));
+ ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y));
+ perform_event(ev);
}
void DisplayServerIOS::perform_event(const Ref<InputEvent> &p_event) {
@@ -441,7 +439,7 @@ float DisplayServerIOS::screen_get_refresh_rate(int p_screen) const {
}
float DisplayServerIOS::screen_get_scale(int p_screen) const {
- return [UIScreen mainScreen].nativeScale;
+ return [UIScreen mainScreen].scale;
}
Vector<DisplayServer::WindowID> DisplayServerIOS::get_window_list() const {
diff --git a/platform/ios/godot_view.mm b/platform/ios/godot_view.mm
index 4537dc2985..5aff75ea04 100644
--- a/platform/ios/godot_view.mm
+++ b/platform/ios/godot_view.mm
@@ -151,7 +151,7 @@ static const float earth_gravity = 9.80665;
}
- (void)godot_commonInit {
- self.contentScaleFactor = [UIScreen mainScreen].nativeScale;
+ self.contentScaleFactor = [UIScreen mainScreen].scale;
[self initTouches];
@@ -363,7 +363,9 @@ static const float earth_gravity = 9.80665;
ERR_FAIL_COND(tid == -1);
CGPoint touchPoint = [touch locationInView:self];
CGPoint prev_point = [touch previousLocationInView:self];
- DisplayServerIOS::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor);
+ CGFloat alt = [touch altitudeAngle];
+ CGVector azim = [touch azimuthUnitVectorInView:self];
+ DisplayServerIOS::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, [touch force] / [touch maximumPossibleForce], Vector2(azim.dx, azim.dy) * Math::cos(alt));
}
}
}
diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h
index 186efd14a8..3589dd17c9 100644
--- a/platform/ios/os_ios.h
+++ b/platform/ios/os_ios.h
@@ -77,6 +77,8 @@ private:
CGFloat _stretch_to_ct(int p_stretch) const;
String _get_default_fontname(const String &p_font_name) const;
+ static _FORCE_INLINE_ String get_framework_executable(const String &p_path);
+
void deinitialize_modules();
public:
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index 9617627b6f..d0c367cc45 100644
--- a/platform/ios/os_ios.mm
+++ b/platform/ios/os_ios.mm
@@ -198,8 +198,31 @@ void OS_IOS::finalize() {
// MARK: Dynamic Libraries
+_FORCE_INLINE_ String OS_IOS::get_framework_executable(const String &p_path) {
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+ // Read framework bundle to get executable name.
+ NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())];
+ NSBundle *bundle = [NSBundle bundleWithURL:url];
+ if (bundle) {
+ String exe_path = String::utf8([[bundle executablePath] UTF8String]);
+ if (da->file_exists(exe_path)) {
+ return exe_path;
+ }
+ }
+
+ // Try default executable name (invalid framework).
+ if (da->dir_exists(p_path) && da->file_exists(p_path.path_join(p_path.get_file().get_basename()))) {
+ return p_path.path_join(p_path.get_file().get_basename());
+ }
+
+ // Not a framework, try loading as .dylib.
+ return p_path;
+}
+
Error OS_IOS::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
if (p_path.length() == 0) {
+ // Static xcframework.
p_library_handle = RTLD_SELF;
if (r_resolved_path != nullptr) {
@@ -208,7 +231,27 @@ Error OS_IOS::open_dynamic_library(const String p_path, void *&p_library_handle,
return OK;
}
- return OS_Unix::open_dynamic_library(p_path, p_library_handle, p_also_set_library_path, r_resolved_path);
+
+ String path = get_framework_executable(p_path);
+
+ if (!FileAccess::exists(path)) {
+ // Load .dylib or framework from within the executable path.
+ path = get_framework_executable(get_executable_path().get_base_dir().path_join(p_path.get_file()));
+ }
+
+ if (!FileAccess::exists(path)) {
+ // Load .dylib or framework from a standard iOS location.
+ path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file()));
+ }
+
+ p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
+ ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + ".");
+
+ if (r_resolved_path != nullptr) {
+ *r_resolved_path = path;
+ }
+
+ return OK;
}
Error OS_IOS::close_dynamic_library(void *p_library_handle) {
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 844b15e9fb..747dcbd76c 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -339,9 +339,6 @@ def configure(env: "Environment"):
env.Prepend(CPPPATH=["#platform/linuxbsd"])
if env["x11"]:
- if not env["vulkan"]:
- print("Error: X11 support requires vulkan=yes")
- env.Exit(255)
env.Append(CPPDEFINES=["X11_ENABLED"])
env.Append(CPPDEFINES=["UNIX_ENABLED"])
diff --git a/platform/linuxbsd/tts_linux.cpp b/platform/linuxbsd/tts_linux.cpp
index aea1183d3d..8fa708aad6 100644
--- a/platform/linuxbsd/tts_linux.cpp
+++ b/platform/linuxbsd/tts_linux.cpp
@@ -117,13 +117,12 @@ void TTS_Linux::speech_event_callback(size_t p_msg_id, size_t p_client_id, SPDNo
free_spd_voices(voices);
}
PackedInt32Array breaks = TS->string_get_word_breaks(message.text, language);
- int prev = 0;
- for (int i = 0; i < breaks.size(); i++) {
- text += message.text.substr(prev, breaks[i] - prev);
- text += "<mark name=\"" + String::num_int64(breaks[i], 10) + "\"/>";
- prev = breaks[i];
+ for (int i = 0; i < breaks.size(); i += 2) {
+ const int start = breaks[i];
+ const int end = breaks[i + 1];
+ text += message.text.substr(start, end - start + 1);
+ text += "<mark name=\"" + String::num_int64(end, 10) + "\"/>";
}
- text += message.text.substr(prev, -1);
spd_set_synthesis_voice(tts->synth, message.voice.utf8().get_data());
spd_set_volume(tts->synth, message.volume * 2 - 100);
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 1c5c8b2d19..c44c3635cf 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -1235,10 +1235,10 @@ Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const {
return ret;
}
-DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
+DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) {
_THREAD_SAFE_METHOD_
- WindowID id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect);
+ WindowID id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect, p_screen);
for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
if (p_flags & (1 << i)) {
window_set_flag(WindowFlags(i), true, id);
@@ -1257,6 +1257,8 @@ void DisplayServerX11::show_window(WindowID p_id) {
DEBUG_LOG_X11("show_window: %lu (%u) \n", wd.x11_window, p_id);
XMapWindow(x11_display, wd.x11_window);
+ XSync(x11_display, False);
+ _validate_mode_on_map(p_id);
}
void DisplayServerX11::delete_sub_window(WindowID p_id) {
@@ -1505,16 +1507,24 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window
// Check if screen is valid
ERR_FAIL_INDEX(p_screen, get_screen_count());
+ if (window_get_current_screen(p_window) == p_screen) {
+ return;
+ }
+
if (window_get_mode(p_window) == WINDOW_MODE_FULLSCREEN) {
Point2i position = screen_get_position(p_screen);
Size2i size = screen_get_size(p_screen);
XMoveResizeWindow(x11_display, wd.x11_window, position.x, position.y, size.x, size.y);
} else {
- if (p_screen != window_get_current_screen(p_window)) {
- Vector2 ofs = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
- window_set_position(ofs + screen_get_position(p_screen), p_window);
- }
+ Rect2i srect = screen_get_usable_rect(p_screen);
+ Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
+ Size2i wsize = window_get_size(p_window);
+ wpos += srect.position;
+
+ wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3);
+ wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3);
+ window_set_position(wpos, p_window);
}
}
@@ -3985,29 +3995,41 @@ void DisplayServerX11::process_events() {
} else {
DEBUG_LOG_X11("[%u] ButtonRelease window=%lu (%u), button_index=%u \n", frame, event.xbutton.window, window_id, mb->get_button_index());
- if (!wd.focused) {
+ WindowID window_id_other = INVALID_WINDOW_ID;
+ Window wd_other_x11_window;
+ if (wd.focused) {
+ // Handle cases where an unfocused popup is open that needs to receive button-up events.
+ WindowID popup_id = _get_focused_window_or_popup();
+ if (popup_id != INVALID_WINDOW_ID && popup_id != window_id) {
+ window_id_other = popup_id;
+ wd_other_x11_window = windows[popup_id].x11_window;
+ }
+ } else {
// Propagate the event to the focused window,
// because it's received only on the topmost window.
// Note: This is needed for drag & drop to work between windows,
// because the engine expects events to keep being processed
// on the same window dragging started.
for (const KeyValue<WindowID, WindowData> &E : windows) {
- const WindowData &wd_other = E.value;
- WindowID window_id_other = E.key;
- if (wd_other.focused) {
- if (window_id_other != window_id) {
- int x, y;
- Window child;
- XTranslateCoordinates(x11_display, wd.x11_window, wd_other.x11_window, event.xbutton.x, event.xbutton.y, &x, &y, &child);
-
- mb->set_window_id(window_id_other);
- mb->set_position(Vector2(x, y));
- mb->set_global_position(mb->get_position());
+ if (E.value.focused) {
+ if (E.key != window_id) {
+ window_id_other = E.key;
+ wd_other_x11_window = E.value.x11_window;
}
break;
}
}
}
+
+ if (window_id_other != INVALID_WINDOW_ID) {
+ int x, y;
+ Window child;
+ XTranslateCoordinates(x11_display, wd.x11_window, wd_other_x11_window, event.xbutton.x, event.xbutton.y, &x, &y, &child);
+
+ mb->set_window_id(window_id_other);
+ mb->set_position(Vector2(x, y));
+ mb->set_global_position(mb->get_position());
+ }
}
Input::get_singleton()->parse_input_event(mb);
@@ -4519,7 +4541,7 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W
return ds;
}
-DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
+DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) {
//Create window
XVisualInfo visualInfo;
@@ -4595,8 +4617,38 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
valuemask |= CWOverrideRedirect | CWSaveUnder;
}
+ Rect2i win_rect = p_rect;
+ if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
+ Rect2i screen_rect = Rect2i(screen_get_position(p_screen), screen_get_size(p_screen));
+
+ win_rect = screen_rect;
+ } else {
+ int nearest_area = 0;
+ int pos_screen = -1;
+ for (int i = 0; i < get_screen_count(); i++) {
+ Rect2i r;
+ r.position = screen_get_position(i);
+ r.size = screen_get_size(i);
+ Rect2 inters = r.intersection(p_rect);
+
+ int area = inters.size.width * inters.size.height;
+ if (area > nearest_area) {
+ pos_screen = i;
+ nearest_area = area;
+ }
+ }
+
+ Rect2i srect = screen_get_usable_rect(p_screen);
+ Point2i wpos = p_rect.position - ((pos_screen >= 0) ? screen_get_position(pos_screen) : Vector2i());
+ wpos += srect.position;
+ wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3);
+ wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3);
+
+ win_rect.position = wpos;
+ }
+
{
- wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo.screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes);
+ wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo.screen), win_rect.position.x, win_rect.position.y, win_rect.size.width > 0 ? win_rect.size.width : 1, win_rect.size.height > 0 ? win_rect.size.height : 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes);
// Enable receiving notification when the window is initialized (MapNotify)
// so the focus can be set at the right time.
@@ -4717,13 +4769,13 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
#if defined(VULKAN_ENABLED)
if (context_vulkan) {
- Error err = context_vulkan->window_create(id, p_vsync_mode, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height);
+ Error err = context_vulkan->window_create(id, p_vsync_mode, wd.x11_window, x11_display, win_rect.size.width, win_rect.size.height);
ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan window");
}
#endif
#ifdef GLES3_ENABLED
if (gl_manager) {
- Error err = gl_manager->window_create(id, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height);
+ Error err = gl_manager->window_create(id, wd.x11_window, x11_display, win_rect.size.width, win_rect.size.height);
ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL window");
window_set_vsync_mode(p_vsync_mode, id);
}
@@ -5026,12 +5078,13 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
Point2i window_position(
(screen_get_size(0).width - p_resolution.width) / 2,
(screen_get_size(0).height - p_resolution.height) / 2);
+ window_position += screen_get_position(0);
if (p_position != nullptr) {
window_position = *p_position;
}
- WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution));
+ WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution), 0);
if (main_window == INVALID_WINDOW_ID) {
r_error = ERR_CANT_CREATE;
return;
@@ -5042,8 +5095,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
}
show_window(main_window);
- XSync(x11_display, False);
- _validate_mode_on_map(main_window);
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index 2578ca06fd..d8d914bffc 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -185,7 +185,7 @@ class DisplayServerX11 : public DisplayServer {
WindowID last_focused_window = INVALID_WINDOW_ID;
WindowID window_id_counter = MAIN_WINDOW_ID;
- WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect);
+ WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen);
String internal_clipboard;
String internal_clipboard_primary;
@@ -365,7 +365,7 @@ public:
virtual Vector<DisplayServer::WindowID> get_window_list() const override;
- virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override;
+ virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0) override;
virtual void show_window(WindowID p_id) override;
virtual void delete_sub_window(WindowID p_id) override;
diff --git a/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c
index d689ff1aa8..7042a60d47 100644
--- a/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c
@@ -5,7 +5,7 @@
//
// NOTE: Generated from Xcursor 1.2.0.
// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existant symbols inherited from
+// will be eventually fixed. In this case, non-existent symbols inherited from
// libX11, but absent in libXcursor.so.1, were removed.
#include <stdint.h>
diff --git a/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h
index 43bbcf62c5..d00fccffda 100644
--- a/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h
@@ -7,7 +7,7 @@
//
// NOTE: Generated from Xcursor 1.2.0.
// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existant symbols inherited from
+// will be eventually fixed. In this case, non-existent symbols inherited from
// libX11, but absent in libXcursor.so.1, were removed.
#include <stdint.h>
diff --git a/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c
index 711dd3fa5e..c8e87a6b85 100644
--- a/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c
@@ -5,10 +5,10 @@
//
// NOTE: Generated from Xext 1.3.5.
// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existant symbols inherited from
+// will be eventually fixed. In this case, non-existent symbols inherited from
// libX11, but absent in libXext.so.6, were removed and an include needed for
// proper parsing was added (this had also to be temporarily added to the
-// original header, as dynload-wrapper would complain otherwsise)
+// original header, as dynload-wrapper would complain otherwise)
#include <stdint.h>
// HANDPATCH: Needed for a successful compilation.
diff --git a/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h
index 991d07b405..aee92b593e 100644
--- a/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h
@@ -7,10 +7,10 @@
//
// NOTE: Generated from Xext 1.3.5.
// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existant symbols inherited from
+// will be eventually fixed. In this case, non-existent symbols inherited from
// libX11, but absent in libXext.so.6, were removed and an include needed for
// proper parsing was added (this had also to be temporarily added to the
-// original header, as dynload-wrapper would complain otherwsise)
+// original header, as dynload-wrapper would complain otherwise)
#include <stdint.h>
// HANDPATCH: Needed for a successful compilation.
diff --git a/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c
index 42af983345..85ac80e3f2 100644
--- a/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c
@@ -5,7 +5,7 @@
//
// NOTE: Generated from Xinerama 1.1.4.
// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existant symbols inherited from
+// will be eventually fixed. In this case, non-existent symbols inherited from
// libX11, but absent in libXinerama.so.1, were removed.
#include <stdint.h>
diff --git a/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h
index 891d9f21fd..9139421cd6 100644
--- a/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h
@@ -7,7 +7,7 @@
//
// NOTE: Generated from Xinerama 1.1.4.
// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existant symbols inherited from
+// will be eventually fixed. In this case, non-existent symbols inherited from
// libX11, but absent in libXinerama.so.1, were removed.
#include <stdint.h>
diff --git a/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c
index 5e1f0999fc..5f16bc6111 100644
--- a/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c
@@ -5,7 +5,7 @@
//
// NOTE: Generated from Xi 1.7.10.
// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existant symbols inherited from
+// will be eventually fixed. In this case, non-existent symbols inherited from
// libX11, liXext and libXfixes, but absent in libXi.so.6, were removed.
#include <stdint.h>
diff --git a/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h
index 95740cee58..ecb7aa5048 100644
--- a/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h
@@ -7,7 +7,7 @@
//
// NOTE: Generated from Xi 1.7.10.
// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existant symbols inherited from
+// will be eventually fixed. In this case, non-existent symbols inherited from
// libX11, liXext and libXfixes, but absent in libXi.so.6, were removed.
#include <stdint.h>
diff --git a/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c
index eb0f9abf15..f37f3a9db0 100644
--- a/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c
@@ -5,7 +5,7 @@
//
// NOTE: Generated from Xrandr 1.5.2.
// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existant symbols inherited from
+// will be eventually fixed. In this case, non-existent symbols inherited from
// libX11 and libXrender, but absent in libXrandr.so.2, were removed.
#include <stdint.h>
diff --git a/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h
index f1ca9f94a5..046d4c7de3 100644
--- a/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h
@@ -7,7 +7,7 @@
//
// NOTE: Generated from Xrandr 1.5.2.
// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existant symbols inherited from
+// will be eventually fixed. In this case, non-existent symbols inherited from
// libX11 and libXrender, but absent in libXrandr.so.2, were removed.
#include <stdint.h>
diff --git a/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c
index b63a1eca8d..2d3847e584 100644
--- a/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c
@@ -5,7 +5,7 @@
//
// NOTE: Generated from Xrender 0.9.10.
// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existant symbols inherited from
+// will be eventually fixed. In this case, non-existent symbols inherited from
// libX11, but absent in libXrender.so.1, were removed.
#include <stdint.h>
diff --git a/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h
index d3862ed459..e873448ec5 100644
--- a/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h
@@ -7,7 +7,7 @@
//
// NOTE: Generated from Xrender 0.9.10.
// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existant symbols inherited from
+// will be eventually fixed. In this case, non-existent symbols inherited from
// libX11, but absent in libXrender.so.1, were removed.
#include <stdint.h>
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index bd26f6e417..4a2d6032b9 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -99,6 +99,8 @@ public:
Callable drop_files_callback;
ObjectID instance_id;
+ bool fs_transition = false;
+ bool initial_size = true;
WindowID transient_parent = INVALID_WINDOW_ID;
bool exclusive = false;
@@ -189,7 +191,7 @@ private:
const NSMenu *_get_menu_root(const String &p_menu_root) const;
NSMenu *_get_menu_root(const String &p_menu_root);
- WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect);
+ WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect, int p_screen);
void _update_window_style(WindowData p_wd);
void _set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window);
@@ -334,7 +336,7 @@ public:
virtual Vector<int> get_window_list() const override;
- virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override;
+ virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0) override;
virtual void show_window(WindowID p_id) override;
virtual void delete_sub_window(WindowID p_id) override;
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 5c979dbf22..5421739971 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -109,7 +109,7 @@ NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) {
return menu;
}
-DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect) {
+DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect, int p_screen) {
WindowID id;
const float scale = screen_get_max_scale();
{
@@ -119,19 +119,36 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
ERR_FAIL_COND_V_MSG(wd.window_delegate == nil, INVALID_WINDOW_ID, "Can't create a window delegate");
[wd.window_delegate setWindowID:window_id_counter];
- Point2i position = p_rect.position;
+ int nearest_area = 0;
+ int pos_screen = -1;
+ for (int i = 0; i < get_screen_count(); i++) {
+ Rect2i r = screen_get_usable_rect(i);
+ Rect2 inters = r.intersection(p_rect);
+ int area = inters.size.width * inters.size.height;
+ if (area > nearest_area && area > 0) {
+ pos_screen = i;
+ nearest_area = area;
+ }
+ }
+
+ Rect2i srect = screen_get_usable_rect(p_screen);
+ Point2i wpos = p_rect.position - ((pos_screen >= 0) ? screen_get_position(pos_screen) : Vector2i());
+ wpos += srect.position;
+ wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3);
+ wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3);
// OS X native y-coordinate relative to _get_screens_origin() is negative,
// Godot passes a positive value.
- position.y *= -1;
- position += _get_screens_origin();
+ wpos.y *= -1;
+ wpos += _get_screens_origin();
// initWithContentRect uses bottom-left corner of the window’s frame as origin.
wd.window_object = [[GodotWindow alloc]
- initWithContentRect:NSMakeRect(position.x / scale, (position.y - p_rect.size.height) / scale, p_rect.size.width / scale, p_rect.size.height / scale)
+ initWithContentRect:NSMakeRect(0, 0, p_rect.size.width / scale, p_rect.size.height / scale)
styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable
backing:NSBackingStoreBuffered
defer:NO];
ERR_FAIL_COND_V_MSG(wd.window_object == nil, INVALID_WINDOW_ID, "Can't create a window");
+ [wd.window_object setFrameTopLeftPoint:NSMakePoint(wpos.x / scale, wpos.y / scale)];
[wd.window_object setWindowID:window_id_counter];
wd.window_view = [[GodotContentView alloc] init];
@@ -2208,10 +2225,10 @@ Vector<DisplayServer::WindowID> DisplayServerMacOS::get_window_list() const {
return ret;
}
-DisplayServer::WindowID DisplayServerMacOS::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
+DisplayServer::WindowID DisplayServerMacOS::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) {
_THREAD_SAFE_METHOD_
- WindowID id = _create_window(p_mode, p_vsync_mode, p_rect);
+ WindowID id = _create_window(p_mode, p_vsync_mode, p_rect, p_screen);
for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
if (p_flags & (1 << i)) {
window_set_flag(WindowFlags(i), true, id);
@@ -2328,8 +2345,14 @@ void DisplayServerMacOS::window_set_current_screen(int p_screen, WindowID p_wind
was_fullscreen = true;
}
+ Rect2i srect = screen_get_usable_rect(p_screen);
Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
- window_set_position(wpos + screen_get_position(p_screen), p_window);
+ Size2i wsize = window_get_size(p_window);
+ wpos += srect.position;
+
+ wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3);
+ wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3);
+ window_set_position(wpos, p_window);
if (was_fullscreen) {
// Re-enter fullscreen mode.
@@ -3781,7 +3804,7 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
window_position = *p_position;
}
- WindowID main_window = _create_window(p_mode, p_vsync_mode, Rect2i(window_position, p_resolution));
+ WindowID main_window = _create_window(p_mode, p_vsync_mode, Rect2i(window_position, p_resolution), 0);
ERR_FAIL_COND(main_window == INVALID_WINDOW_ID);
for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
if (p_flags & (1 << i)) {
diff --git a/platform/macos/export/plist.cpp b/platform/macos/export/plist.cpp
index 82ecd41d9c..c88b6e1077 100644
--- a/platform/macos/export/plist.cpp
+++ b/platform/macos/export/plist.cpp
@@ -30,6 +30,119 @@
#include "plist.h"
+PList::PLNodeType PListNode::get_type() const {
+ return data_type;
+}
+
+Variant PListNode::get_value() const {
+ switch (data_type) {
+ case PList::PL_NODE_TYPE_NIL: {
+ return Variant();
+ } break;
+ case PList::PL_NODE_TYPE_STRING: {
+ return String::utf8(data_string.get_data());
+ } break;
+ case PList::PL_NODE_TYPE_ARRAY: {
+ Array arr;
+ for (const Ref<PListNode> &E : data_array) {
+ arr.push_back(E);
+ }
+ return arr;
+ } break;
+ case PList::PL_NODE_TYPE_DICT: {
+ Dictionary dict;
+ for (const KeyValue<String, Ref<PListNode>> &E : data_dict) {
+ dict[E.key] = E.value;
+ }
+ return dict;
+ } break;
+ case PList::PL_NODE_TYPE_BOOLEAN: {
+ return data_bool;
+ } break;
+ case PList::PL_NODE_TYPE_INTEGER: {
+ return data_int;
+ } break;
+ case PList::PL_NODE_TYPE_REAL: {
+ return data_real;
+ } break;
+ case PList::PL_NODE_TYPE_DATA: {
+ int strlen = data_string.length();
+
+ size_t arr_len = 0;
+ Vector<uint8_t> buf;
+ {
+ buf.resize(strlen / 4 * 3 + 1);
+ uint8_t *w = buf.ptrw();
+
+ ERR_FAIL_COND_V(CryptoCore::b64_decode(&w[0], buf.size(), &arr_len, (unsigned char *)data_string.get_data(), strlen) != OK, Vector<uint8_t>());
+ }
+ buf.resize(arr_len);
+ return buf;
+ } break;
+ case PList::PL_NODE_TYPE_DATE: {
+ return String(data_string.get_data());
+ } break;
+ }
+ return Variant();
+}
+
+Ref<PListNode> PListNode::new_node(const Variant &p_value) {
+ Ref<PListNode> node;
+ node.instantiate();
+
+ switch (p_value.get_type()) {
+ case Variant::NIL: {
+ node->data_type = PList::PL_NODE_TYPE_NIL;
+ } break;
+ case Variant::BOOL: {
+ node->data_type = PList::PL_NODE_TYPE_BOOLEAN;
+ node->data_bool = p_value;
+ } break;
+ case Variant::INT: {
+ node->data_type = PList::PL_NODE_TYPE_INTEGER;
+ node->data_int = p_value;
+ } break;
+ case Variant::FLOAT: {
+ node->data_type = PList::PL_NODE_TYPE_REAL;
+ node->data_real = p_value;
+ } break;
+ case Variant::STRING_NAME:
+ case Variant::STRING: {
+ node->data_type = PList::PL_NODE_TYPE_STRING;
+ node->data_string = p_value.operator String().utf8();
+ } break;
+ case Variant::DICTIONARY: {
+ node->data_type = PList::PL_NODE_TYPE_DICT;
+ Dictionary dict = p_value;
+ const Variant *next = dict.next(nullptr);
+ while (next) {
+ Ref<PListNode> sub_node = dict[*next];
+ ERR_FAIL_COND_V_MSG(sub_node.is_null(), Ref<PListNode>(), "Invalid dictionary element, should be PListNode.");
+ node->data_dict[*next] = sub_node;
+ next = dict.next(next);
+ }
+ } break;
+ case Variant::ARRAY: {
+ node->data_type = PList::PL_NODE_TYPE_ARRAY;
+ Array ar = p_value;
+ for (int i = 0; i < ar.size(); i++) {
+ Ref<PListNode> sub_node = ar[i];
+ ERR_FAIL_COND_V_MSG(sub_node.is_null(), Ref<PListNode>(), "Invalid array element, should be PListNode.");
+ node->data_array.push_back(sub_node);
+ }
+ } break;
+ case Variant::PACKED_BYTE_ARRAY: {
+ node->data_type = PList::PL_NODE_TYPE_DATA;
+ PackedByteArray buf = p_value;
+ node->data_string = CryptoCore::b64_encode_str(buf.ptr(), buf.size()).utf8();
+ } break;
+ default: {
+ ERR_FAIL_V_MSG(Ref<PListNode>(), "Unsupported data type.");
+ } break;
+ }
+ return node;
+}
+
Ref<PListNode> PListNode::new_array() {
Ref<PListNode> node = memnew(PListNode());
ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
@@ -65,6 +178,7 @@ Ref<PListNode> PListNode::new_date(const String &p_string) {
ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
node->data_type = PList::PLNodeType::PL_NODE_TYPE_DATE;
node->data_string = p_string.utf8();
+ node->data_real = (double)Time::get_singleton()->get_unix_time_from_datetime_string(p_string) - 978307200.0;
return node;
}
@@ -76,7 +190,7 @@ Ref<PListNode> PListNode::new_bool(bool p_bool) {
return node;
}
-Ref<PListNode> PListNode::new_int(int32_t p_int) {
+Ref<PListNode> PListNode::new_int(int64_t p_int) {
Ref<PListNode> node = memnew(PListNode());
ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
node->data_type = PList::PLNodeType::PL_NODE_TYPE_INTEGER;
@@ -84,7 +198,7 @@ Ref<PListNode> PListNode::new_int(int32_t p_int) {
return node;
}
-Ref<PListNode> PListNode::new_real(float p_real) {
+Ref<PListNode> PListNode::new_real(double p_real) {
Ref<PListNode> node = memnew(PListNode());
ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
node->data_type = PList::PLNodeType::PL_NODE_TYPE_REAL;
@@ -337,6 +451,168 @@ PList::PList(const String &p_string) {
load_string(p_string);
}
+uint64_t PList::read_bplist_var_size_int(Ref<FileAccess> p_file, uint8_t p_size) {
+ uint64_t pos = p_file->get_position();
+ uint64_t ret = 0;
+ switch (p_size) {
+ case 1: {
+ ret = p_file->get_8();
+ } break;
+ case 2: {
+ ret = BSWAP16(p_file->get_16());
+ } break;
+ case 3: {
+ ret = BSWAP32(p_file->get_32() & 0x00FFFFFF);
+ } break;
+ case 4: {
+ ret = BSWAP32(p_file->get_32());
+ } break;
+ case 5: {
+ ret = BSWAP64(p_file->get_64() & 0x000000FFFFFFFFFF);
+ } break;
+ case 6: {
+ ret = BSWAP64(p_file->get_64() & 0x0000FFFFFFFFFFFF);
+ } break;
+ case 7: {
+ ret = BSWAP64(p_file->get_64() & 0x00FFFFFFFFFFFFFF);
+ } break;
+ case 8: {
+ ret = BSWAP64(p_file->get_64());
+ } break;
+ default: {
+ ret = 0;
+ }
+ }
+ p_file->seek(pos + p_size);
+
+ return ret;
+}
+
+Ref<PListNode> PList::read_bplist_obj(Ref<FileAccess> p_file, uint64_t p_offset_idx) {
+ Ref<PListNode> node;
+ node.instantiate();
+
+ uint64_t ot_off = trailer.offset_table_start + p_offset_idx * trailer.offset_size;
+ p_file->seek(ot_off);
+ uint64_t marker_off = read_bplist_var_size_int(p_file, trailer.offset_size);
+ ERR_FAIL_COND_V_MSG(marker_off == 0, Ref<PListNode>(), "Invalid marker size.");
+
+ p_file->seek(marker_off);
+ uint8_t marker = p_file->get_8();
+ uint8_t marker_type = marker & 0xF0;
+ uint64_t marker_size = marker & 0x0F;
+
+ switch (marker_type) {
+ case 0x00: {
+ if (marker_size == 0x00) {
+ node->data_type = PL_NODE_TYPE_NIL;
+ } else if (marker_size == 0x08) {
+ node->data_type = PL_NODE_TYPE_BOOLEAN;
+ node->data_bool = false;
+ } else if (marker_size == 0x09) {
+ node->data_type = PL_NODE_TYPE_BOOLEAN;
+ node->data_bool = true;
+ } else {
+ ERR_FAIL_V_MSG(Ref<PListNode>(), "Invalid nil/bool marker value.");
+ }
+ } break;
+ case 0x10: {
+ node->data_type = PL_NODE_TYPE_INTEGER;
+ node->data_int = static_cast<int64_t>(read_bplist_var_size_int(p_file, pow(2, marker_size)));
+ } break;
+ case 0x20: {
+ node->data_type = PL_NODE_TYPE_REAL;
+ node->data_int = static_cast<int64_t>(read_bplist_var_size_int(p_file, pow(2, marker_size)));
+ } break;
+ case 0x30: {
+ node->data_type = PL_NODE_TYPE_DATE;
+ node->data_int = BSWAP64(p_file->get_64());
+ node->data_string = Time::get_singleton()->get_datetime_string_from_unix_time(node->data_real + 978307200.0).utf8();
+ } break;
+ case 0x40: {
+ if (marker_size == 0x0F) {
+ uint8_t ext = p_file->get_8() & 0xF;
+ marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
+ }
+ node->data_type = PL_NODE_TYPE_DATA;
+ PackedByteArray buf;
+ buf.resize(marker_size + 1);
+ p_file->get_buffer(reinterpret_cast<uint8_t *>(buf.ptrw()), marker_size);
+ node->data_string = CryptoCore::b64_encode_str(buf.ptr(), buf.size()).utf8();
+ } break;
+ case 0x50: {
+ if (marker_size == 0x0F) {
+ uint8_t ext = p_file->get_8() & 0xF;
+ marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
+ }
+ node->data_type = PL_NODE_TYPE_STRING;
+ node->data_string.resize(marker_size + 1);
+ p_file->get_buffer(reinterpret_cast<uint8_t *>(node->data_string.ptrw()), marker_size);
+ } break;
+ case 0x60: {
+ if (marker_size == 0x0F) {
+ uint8_t ext = p_file->get_8() & 0xF;
+ marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
+ }
+ Char16String cs16;
+ cs16.resize(marker_size + 1);
+ for (uint64_t i = 0; i < marker_size; i++) {
+ cs16[i] = BSWAP16(p_file->get_16());
+ }
+ node->data_type = PL_NODE_TYPE_STRING;
+ node->data_string = String::utf16(cs16.ptr(), cs16.length()).utf8();
+ } break;
+ case 0x80: {
+ node->data_type = PL_NODE_TYPE_INTEGER;
+ node->data_int = static_cast<int64_t>(read_bplist_var_size_int(p_file, marker_size + 1));
+ } break;
+ case 0xA0:
+ case 0xC0: {
+ if (marker_size == 0x0F) {
+ uint8_t ext = p_file->get_8() & 0xF;
+ marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
+ }
+ uint64_t pos = p_file->get_position();
+
+ node->data_type = PL_NODE_TYPE_ARRAY;
+ for (uint64_t i = 0; i < marker_size; i++) {
+ p_file->seek(pos + trailer.ref_size * i);
+ uint64_t ref = read_bplist_var_size_int(p_file, trailer.ref_size);
+
+ Ref<PListNode> element = read_bplist_obj(p_file, ref);
+ ERR_FAIL_COND_V(element.is_null(), Ref<PListNode>());
+ node->data_array.push_back(element);
+ }
+ } break;
+ case 0xD0: {
+ if (marker_size == 0x0F) {
+ uint8_t ext = p_file->get_8() & 0xF;
+ marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
+ }
+ uint64_t pos = p_file->get_position();
+
+ node->data_type = PL_NODE_TYPE_DICT;
+ for (uint64_t i = 0; i < marker_size; i++) {
+ p_file->seek(pos + trailer.ref_size * i);
+ uint64_t key_ref = read_bplist_var_size_int(p_file, trailer.ref_size);
+
+ p_file->seek(pos + trailer.ref_size * (i + marker_size));
+ uint64_t obj_ref = read_bplist_var_size_int(p_file, trailer.ref_size);
+
+ Ref<PListNode> element_key = read_bplist_obj(p_file, key_ref);
+ ERR_FAIL_COND_V(element_key.is_null() || element_key->data_type != PL_NODE_TYPE_STRING, Ref<PListNode>());
+ Ref<PListNode> element = read_bplist_obj(p_file, obj_ref);
+ ERR_FAIL_COND_V(element.is_null(), Ref<PListNode>());
+ node->data_dict[String::utf8(element_key->data_string.ptr(), element_key->data_string.length())] = element;
+ }
+ } break;
+ default: {
+ ERR_FAIL_V_MSG(Ref<PListNode>(), "Invalid marker type.");
+ }
+ }
+ return node;
+}
+
bool PList::load_file(const String &p_filename) {
root = Ref<PListNode>();
@@ -349,7 +625,15 @@ bool PList::load_file(const String &p_filename) {
fb->get_buffer(magic, 8);
if (String((const char *)magic, 8) == "bplist00") {
- ERR_FAIL_V_MSG(false, "PList: Binary property lists are not supported.");
+ fb->seek_end(-26);
+ trailer.offset_size = fb->get_8();
+ trailer.ref_size = fb->get_8();
+ trailer.object_num = BSWAP64(fb->get_64());
+ trailer.root_offset_idx = BSWAP64(fb->get_64());
+ trailer.offset_table_start = BSWAP64(fb->get_64());
+ root = read_bplist_obj(fb, trailer.root_offset_idx);
+
+ return root.is_valid();
} else {
// Load text plist.
Error err;
diff --git a/platform/macos/export/plist.h b/platform/macos/export/plist.h
index 97331a3629..d53e88832f 100644
--- a/platform/macos/export/plist.h
+++ b/platform/macos/export/plist.h
@@ -35,6 +35,7 @@
#include "core/crypto/crypto_core.h"
#include "core/io/file_access.h"
+#include "core/os/time.h"
class PListNode;
@@ -55,8 +56,20 @@ public:
};
private:
+ struct PListTrailer {
+ uint8_t offset_size;
+ uint8_t ref_size;
+ uint64_t object_num;
+ uint64_t root_offset_idx;
+ uint64_t offset_table_start;
+ };
+
+ PListTrailer trailer;
Ref<PListNode> root;
+ uint64_t read_bplist_var_size_int(Ref<FileAccess> p_file, uint8_t p_size);
+ Ref<PListNode> read_bplist_obj(Ref<FileAccess> p_file, uint64_t p_offset_idx);
+
public:
PList();
PList(const String &p_string);
@@ -82,19 +95,23 @@ public:
Vector<Ref<PListNode>> data_array;
HashMap<String, Ref<PListNode>> data_dict;
union {
- int32_t data_int;
+ int64_t data_int;
bool data_bool;
- float data_real;
+ double data_real;
};
+ PList::PLNodeType get_type() const;
+ Variant get_value() const;
+
+ static Ref<PListNode> new_node(const Variant &p_value);
static Ref<PListNode> new_array();
static Ref<PListNode> new_dict();
static Ref<PListNode> new_string(const String &p_string);
static Ref<PListNode> new_data(const String &p_string);
static Ref<PListNode> new_date(const String &p_string);
static Ref<PListNode> new_bool(bool p_bool);
- static Ref<PListNode> new_int(int32_t p_int);
- static Ref<PListNode> new_real(float p_real);
+ static Ref<PListNode> new_int(int64_t p_int);
+ static Ref<PListNode> new_real(double p_real);
bool push_subnode(const Ref<PListNode> &p_node, const String &p_key = "");
diff --git a/platform/macos/godot_content_view.mm b/platform/macos/godot_content_view.mm
index cb70a5db86..27afa60bed 100644
--- a/platform/macos/godot_content_view.mm
+++ b/platform/macos/godot_content_view.mm
@@ -65,16 +65,28 @@
if (ds && ds->has_window(window_id)) {
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
NSRect frameRect = [wd.window_object frame];
- bool left = (wd.last_frame_rect.origin.x != frameRect.origin.x);
- bool top = (wd.last_frame_rect.origin.y == frameRect.origin.y);
- if (left && top) {
- self.layerContentsPlacement = NSViewLayerContentsPlacementBottomRight;
- } else if (left && !top) {
- self.layerContentsPlacement = NSViewLayerContentsPlacementTopRight;
- } else if (!left && top) {
- self.layerContentsPlacement = NSViewLayerContentsPlacementBottomLeft;
+ if (wd.fs_transition || wd.initial_size) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementScaleAxesIndependently;
+ wd.initial_size = false;
} else {
- self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
+ bool left = (wd.last_frame_rect.origin.x != frameRect.origin.x);
+ bool bottom = (wd.last_frame_rect.origin.y != frameRect.origin.y);
+ bool right = (wd.last_frame_rect.origin.x + wd.last_frame_rect.size.width != frameRect.origin.x + frameRect.size.width);
+ bool top = (wd.last_frame_rect.origin.y + wd.last_frame_rect.size.height != frameRect.origin.y + frameRect.size.height);
+
+ if (left && top) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementBottomRight;
+ } else if (left && bottom) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementTopRight;
+ } else if (left) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementRight;
+ } else if (right && top) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementBottomLeft;
+ } else if (right && bottom) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
+ } else if (right) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementLeft;
+ }
}
wd.last_frame_rect = frameRect;
}
@@ -440,7 +452,7 @@
NSEventSubtype subtype = [event subtype];
if (subtype == NSEventSubtypeTabletPoint) {
const NSPoint p = [event tilt];
- mm->set_tilt(Vector2(p.x, p.y));
+ mm->set_tilt(Vector2(p.x, -p.y));
mm->set_pen_inverted(last_pen_inverted);
} else if (subtype == NSEventSubtypeTabletProximity) {
// Check if using the eraser end of pen only on proximity event.
diff --git a/platform/macos/godot_window_delegate.h b/platform/macos/godot_window_delegate.h
index 01cc13a016..98c226aa2f 100644
--- a/platform/macos/godot_window_delegate.h
+++ b/platform/macos/godot_window_delegate.h
@@ -38,8 +38,6 @@
@interface GodotWindowDelegate : NSObject <NSWindowDelegate> {
DisplayServer::WindowID window_id;
- NSRect old_frame;
- NSWindowStyleMask old_style_mask;
}
- (void)setWindowID:(DisplayServer::WindowID)wid;
diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm
index 27efd3ebb2..aa5da14651 100644
--- a/platform/macos/godot_window_delegate.mm
+++ b/platform/macos/godot_window_delegate.mm
@@ -70,24 +70,24 @@
ds->window_destroy(window_id);
}
-- (NSArray<NSWindow *> *)customWindowsToEnterFullScreenForWindow:(NSWindow *)window {
+- (void)windowWillEnterFullScreen:(NSNotification *)notification {
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
if (!ds || !ds->has_window(window_id)) {
- return nullptr;
+ return;
}
- old_frame = [window frame];
- old_style_mask = [window styleMask];
-
- NSMutableArray<NSWindow *> *windows = [[NSMutableArray alloc] init];
- [windows addObject:window];
-
- return windows;
+ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ wd.fs_transition = true;
}
-- (void)window:(NSWindow *)window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration {
- [(GodotWindow *)window setAnimDuration:duration];
- [window setFrame:[[window screen] frame] display:YES animate:YES];
+- (void)windowDidFailToEnterFullScreen:(NSWindow *)window {
+ DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
+ if (!ds || !ds->has_window(window_id)) {
+ return;
+ }
+
+ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ wd.fs_transition = false;
}
- (void)windowDidEnterFullScreen:(NSNotification *)notification {
@@ -98,29 +98,31 @@
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
wd.fullscreen = true;
+ wd.fs_transition = false;
// Reset window size limits.
[wd.window_object setContentMinSize:NSMakeSize(0, 0)];
[wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
- [(GodotWindow *)wd.window_object setAnimDuration:-1.0f];
// Reset custom window buttons.
if ([wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView) {
ds->window_set_custom_window_buttons(wd, false);
}
- // Force window resize event.
- [self windowDidResize:notification];
ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE);
+
+ // Force window resize event and redraw.
+ [self windowDidResize:notification];
}
-- (NSArray<NSWindow *> *)customWindowsToExitFullScreenForWindow:(NSWindow *)window {
+- (void)windowWillExitFullScreen:(NSNotification *)notification {
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
if (!ds || !ds->has_window(window_id)) {
- return nullptr;
+ return;
}
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ wd.fs_transition = true;
// Restore custom window buttons.
if ([wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView) {
@@ -128,16 +130,22 @@
}
ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE);
-
- NSMutableArray<NSWindow *> *windows = [[NSMutableArray alloc] init];
- [windows addObject:wd.window_object];
- return windows;
}
-- (void)window:(NSWindow *)window startCustomAnimationToExitFullScreenWithDuration:(NSTimeInterval)duration {
- [(GodotWindow *)window setAnimDuration:duration];
- [window setStyleMask:old_style_mask];
- [window setFrame:old_frame display:YES animate:YES];
+- (void)windowDidFailToExitFullScreen:(NSWindow *)window {
+ DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
+ if (!ds || !ds->has_window(window_id)) {
+ return;
+ }
+
+ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ wd.fs_transition = false;
+
+ if ([wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView) {
+ ds->window_set_custom_window_buttons(wd, false);
+ }
+
+ ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE);
}
- (void)windowDidExitFullScreen:(NSNotification *)notification {
@@ -153,8 +161,7 @@
wd.fullscreen = false;
wd.exclusive_fullscreen = false;
-
- [(GodotWindow *)wd.window_object setAnimDuration:-1.0f];
+ wd.fs_transition = false;
// Set window size limits.
const float scale = ds->screen_get_max_scale();
@@ -177,7 +184,7 @@
[wd.window_object setLevel:NSFloatingWindowLevel];
}
- // Force window resize event.
+ // Force window resize event and redraw.
[self windowDidResize:notification];
}
@@ -305,6 +312,8 @@
ds->update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
}
+ [self windowDidResize:notification]; // Emit resize event, to ensure content is resized if the window was resized while it was hidden.
+
ds->set_last_focused_window(window_id);
ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN);
}
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index 8f2f9f6cf5..fd8ba38808 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -45,16 +45,6 @@
#include <os/log.h>
#include <sys/sysctl.h>
-_FORCE_INLINE_ String OS_MacOS::get_framework_executable(const String &p_path) {
- // Append framework executable name, or return as is if p_path is not a framework.
- Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- if (da->dir_exists(p_path) && da->file_exists(p_path.path_join(p_path.get_file().get_basename()))) {
- return p_path.path_join(p_path.get_file().get_basename());
- } else {
- return p_path;
- }
-}
-
void OS_MacOS::pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context) {
// Prevent main loop from sleeping and redraw window during modal popup display.
// Do not redraw when rendering is done from the separate thread, it will conflict with the OpenGL context updates.
@@ -162,6 +152,28 @@ void OS_MacOS::alert(const String &p_alert, const String &p_title) {
}
}
+_FORCE_INLINE_ String OS_MacOS::get_framework_executable(const String &p_path) {
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+ // Read framework bundle to get executable name.
+ NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())];
+ NSBundle *bundle = [NSBundle bundleWithURL:url];
+ if (bundle) {
+ String exe_path = String::utf8([[bundle executablePath] UTF8String]);
+ if (da->file_exists(exe_path)) {
+ return exe_path;
+ }
+ }
+
+ // Try default executable name (invalid framework).
+ if (da->dir_exists(p_path) && da->file_exists(p_path.path_join(p_path.get_file().get_basename()))) {
+ return p_path.path_join(p_path.get_file().get_basename());
+ }
+
+ // Not a framework, try loading as .dylib.
+ return p_path;
+}
+
Error OS_MacOS::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
String path = get_framework_executable(p_path);
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index e7864ebac0..fb996ec1ff 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -625,10 +625,10 @@ DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(cons
return INVALID_WINDOW_ID;
}
-DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
+DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) {
_THREAD_SAFE_METHOD_
- WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect);
+ WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect, p_screen);
ERR_FAIL_COND_V_MSG(window_id == INVALID_WINDOW_ID, INVALID_WINDOW_ID, "Failed to create sub window.");
WindowData &wd = windows[window_id];
@@ -865,19 +865,24 @@ void DisplayServerWindows::window_set_current_screen(int p_screen, WindowID p_wi
ERR_FAIL_COND(!windows.has(p_window));
ERR_FAIL_INDEX(p_screen, get_screen_count());
+ if (window_get_current_screen(p_window) == p_screen) {
+ return;
+ }
const WindowData &wd = windows[p_window];
if (wd.fullscreen) {
- int cs = window_get_current_screen(p_window);
- if (cs == p_screen) {
- return;
- }
Point2 pos = screen_get_position(p_screen);
Size2 size = screen_get_size(p_screen);
MoveWindow(wd.hWnd, pos.x, pos.y, size.width, size.height, TRUE);
} else {
- Vector2 ofs = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
- window_set_position(ofs + screen_get_position(p_screen), p_window);
+ Rect2i srect = screen_get_usable_rect(p_screen);
+ Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
+ Size2i wsize = window_get_size(p_window);
+ wpos += srect.position;
+
+ wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3);
+ wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3);
+ window_set_position(wpos, p_window);
}
// Don't let the mouse leave the window when resizing to a smaller resolution.
@@ -3534,7 +3539,7 @@ void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const
}
}
-DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
+DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) {
DWORD dwExStyle;
DWORD dwStyle;
@@ -3548,24 +3553,37 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
WindowRect.bottom = p_rect.position.y + p_rect.size.y;
if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
+ Rect2i screen_rect = Rect2i(screen_get_position(p_screen), screen_get_size(p_screen));
+
+ WindowRect.left = screen_rect.position.x;
+ WindowRect.right = screen_rect.position.x + screen_rect.size.x;
+ WindowRect.top = screen_rect.position.y;
+ WindowRect.bottom = screen_rect.position.y + screen_rect.size.y;
+ } else {
int nearest_area = 0;
- Rect2i screen_rect;
+ int pos_screen = -1;
for (int i = 0; i < get_screen_count(); i++) {
Rect2i r;
r.position = screen_get_position(i);
r.size = screen_get_size(i);
Rect2 inters = r.intersection(p_rect);
int area = inters.size.width * inters.size.height;
- if (area >= nearest_area) {
- screen_rect = r;
+ if (area > nearest_area) {
+ pos_screen = i;
nearest_area = area;
}
}
- WindowRect.left = screen_rect.position.x;
- WindowRect.right = screen_rect.position.x + screen_rect.size.x;
- WindowRect.top = screen_rect.position.y;
- WindowRect.bottom = screen_rect.position.y + screen_rect.size.y;
+ Rect2i srect = screen_get_usable_rect(p_screen);
+ Point2i wpos = p_rect.position - ((pos_screen >= 0) ? screen_get_position(pos_screen) : Vector2i());
+ wpos += srect.position;
+ wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3);
+ wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3);
+
+ WindowRect.left = wpos.x;
+ WindowRect.right = wpos.x + p_rect.size.x;
+ WindowRect.top = wpos.y;
+ WindowRect.bottom = wpos.y + p_rect.size.y;
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
@@ -3709,7 +3727,6 @@ WTEnablePtr DisplayServerWindows::wintab_WTEnable = nullptr;
// UXTheme API.
bool DisplayServerWindows::dark_title_available = false;
bool DisplayServerWindows::ux_theme_available = false;
-IsDarkModeAllowedForAppPtr DisplayServerWindows::IsDarkModeAllowedForApp = nullptr;
ShouldAppsUseDarkModePtr DisplayServerWindows::ShouldAppsUseDarkMode = nullptr;
GetImmersiveColorFromColorSetExPtr DisplayServerWindows::GetImmersiveColorFromColorSetEx = nullptr;
GetImmersiveColorTypeFromNamePtr DisplayServerWindows::GetImmersiveColorTypeFromName = nullptr;
@@ -3727,7 +3744,7 @@ typedef enum _SHC_PROCESS_DPI_AWARENESS {
} SHC_PROCESS_DPI_AWARENESS;
bool DisplayServerWindows::is_dark_mode_supported() const {
- return ux_theme_available && IsDarkModeAllowedForApp();
+ return ux_theme_available;
}
bool DisplayServerWindows::is_dark_mode() const {
@@ -3817,13 +3834,12 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
// Load UXTheme.
HMODULE ux_theme_lib = LoadLibraryW(L"uxtheme.dll");
if (ux_theme_lib) {
- IsDarkModeAllowedForApp = (IsDarkModeAllowedForAppPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(136));
ShouldAppsUseDarkMode = (ShouldAppsUseDarkModePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(132));
GetImmersiveColorFromColorSetEx = (GetImmersiveColorFromColorSetExPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(95));
GetImmersiveColorTypeFromName = (GetImmersiveColorTypeFromNamePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(96));
GetImmersiveUserColorSetPreference = (GetImmersiveUserColorSetPreferencePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(98));
- ux_theme_available = IsDarkModeAllowedForApp && ShouldAppsUseDarkMode && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName && GetImmersiveUserColorSetPreference;
+ ux_theme_available = ShouldAppsUseDarkMode && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName && GetImmersiveUserColorSetPreference;
if (os_ver.dwBuildNumber >= 22000) {
dark_title_available = true;
}
@@ -3933,7 +3949,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
window_position = *p_position;
}
- WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution));
+ WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution), 0);
ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window.");
joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd);
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 4702bb7765..fe67febe40 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -152,7 +152,6 @@ typedef UINT(WINAPI *WTInfoPtr)(UINT p_category, UINT p_index, LPVOID p_output);
typedef BOOL(WINAPI *WTPacketPtr)(HANDLE p_ctx, UINT p_param, LPVOID p_packets);
typedef BOOL(WINAPI *WTEnablePtr)(HANDLE p_ctx, BOOL p_enable);
-typedef bool(WINAPI *IsDarkModeAllowedForAppPtr)();
typedef bool(WINAPI *ShouldAppsUseDarkModePtr)();
typedef DWORD(WINAPI *GetImmersiveColorFromColorSetExPtr)(UINT dwImmersiveColorSet, UINT dwImmersiveColorType, bool bIgnoreHighContrast, UINT dwHighContrastCacheMode);
typedef int(WINAPI *GetImmersiveColorTypeFromNamePtr)(const WCHAR *name);
@@ -288,7 +287,6 @@ class DisplayServerWindows : public DisplayServer {
// UXTheme API
static bool dark_title_available;
static bool ux_theme_available;
- static IsDarkModeAllowedForAppPtr IsDarkModeAllowedForApp;
static ShouldAppsUseDarkModePtr ShouldAppsUseDarkMode;
static GetImmersiveColorFromColorSetExPtr GetImmersiveColorFromColorSetEx;
static GetImmersiveColorTypeFromNamePtr GetImmersiveColorTypeFromName;
@@ -428,7 +426,7 @@ class DisplayServerWindows : public DisplayServer {
uint64_t time_since_popup = 0;
Ref<Image> icon;
- WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect);
+ WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen);
WindowID window_id_counter = MAIN_WINDOW_ID;
RBMap<WindowID, WindowData> windows;
@@ -524,7 +522,7 @@ public:
virtual Vector<DisplayServer::WindowID> get_window_list() const override;
- virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override;
+ virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0) override;
virtual void show_window(WindowID p_window) override;
virtual void delete_sub_window(WindowID p_window) override;
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index f04177d79a..89f56ffd93 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -226,7 +226,7 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/modify_resources"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico.*.png,*.webp,*.svg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), ""));
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::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), ""));
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index a083a98c72..f8633d29ac 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -1164,8 +1164,11 @@ bool OS_Windows::set_environment(const String &p_var, const String &p_value) con
String OS_Windows::get_stdin_string(bool p_block) {
if (p_block) {
- char buff[1024];
- return fgets(buff, 1024, stdin);
+ WCHAR buff[1024];
+ DWORD count = 0;
+ if (ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), buff, 1024, &count, nullptr)) {
+ return String::utf16((const char16_t *)buff, count);
+ }
}
return String();
diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py
index 33ca2e8ffa..b522a75a9c 100644
--- a/platform/windows/platform_windows_builders.py
+++ b/platform/windows/platform_windows_builders.py
@@ -4,18 +4,15 @@ All such functions are invoked in a subprocess on Windows to prevent build flaki
"""
import os
+from detect import get_mingw_bin_prefix
from platform_methods import subprocess_main
def make_debug_mingw(target, source, env):
- mingw_prefix = ""
- if env["arch"] == "x86_32":
- mingw_prefix = env["mingw_prefix_32"]
- else:
- mingw_prefix = env["mingw_prefix_64"]
- os.system(mingw_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
- os.system(mingw_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0]))
- os.system(mingw_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
+ mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
+ os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
+ os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0]))
+ os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
if __name__ == "__main__":
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index df75d34e0f..fccaf63319 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -661,5 +661,6 @@ CollisionObject2D::CollisionObject2D() {
}
CollisionObject2D::~CollisionObject2D() {
+ ERR_FAIL_NULL(PhysicsServer2D::get_singleton());
PhysicsServer2D::get_singleton()->free(rid);
}
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index c6296f4732..68dc85486d 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -1507,6 +1507,7 @@ CPUParticles2D::CPUParticles2D() {
}
CPUParticles2D::~CPUParticles2D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(multimesh);
RS::get_singleton()->free(mesh);
}
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index ccbc080768..95e24028a6 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -688,6 +688,7 @@ GPUParticles2D::GPUParticles2D() {
}
GPUParticles2D::~GPUParticles2D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(particles);
RS::get_singleton()->free(mesh);
}
diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp
index 8de4c281f4..9e12c7aa3b 100644
--- a/scene/2d/joint_2d.cpp
+++ b/scene/2d/joint_2d.cpp
@@ -112,7 +112,7 @@ void Joint2D::_update_joint(bool p_only_free) {
ERR_FAIL_COND_MSG(!joint.is_valid(), "Failed to configure the joint.");
- PhysicsServer2D::get_singleton()->get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias);
+ PhysicsServer2D::get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias);
ba = body_a->get_rid();
bb = body_b->get_rid();
@@ -188,7 +188,7 @@ void Joint2D::_notification(int p_what) {
void Joint2D::set_bias(real_t p_bias) {
bias = p_bias;
if (joint.is_valid()) {
- PhysicsServer2D::get_singleton()->get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias);
+ PhysicsServer2D::get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias);
}
}
@@ -246,6 +246,7 @@ Joint2D::Joint2D() {
}
Joint2D::~Joint2D() {
+ ERR_FAIL_NULL(PhysicsServer2D::get_singleton());
PhysicsServer2D::get_singleton()->free(joint);
}
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 78b5199358..e07393a9c7 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -321,6 +321,7 @@ Light2D::Light2D() {
}
Light2D::~Light2D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(canvas_light);
}
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 67e82140e4..e7997c6eff 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -148,6 +148,7 @@ OccluderPolygon2D::OccluderPolygon2D() {
}
OccluderPolygon2D::~OccluderPolygon2D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(occ_polygon);
}
@@ -291,5 +292,7 @@ LightOccluder2D::LightOccluder2D() {
}
LightOccluder2D::~LightOccluder2D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+
RS::get_singleton()->free(occluder);
}
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index 2bbe88b0e0..3936724dd4 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -380,7 +380,7 @@ void LineBuilder::build() {
current_distance1 += pos0.distance_to(pos1);
}
if (_interpolate_color) {
- color1 = gradient->get_color(gradient->get_points_count() - 1);
+ color1 = gradient->get_color(gradient->get_point_count() - 1);
}
if (retrieve_curve) {
width_factor = curve->sample_baked(1.f);
@@ -406,7 +406,7 @@ void LineBuilder::build() {
// End cap (round)
if (end_cap_mode == Line2D::LINE_CAP_ROUND) {
// Note: color is not used in case we don't interpolate...
- Color color = _interpolate_color ? gradient->get_color(gradient->get_points_count() - 1) : Color(0, 0, 0);
+ Color color = _interpolate_color ? gradient->get_color(gradient->get_point_count() - 1) : Color(0, 0, 0);
float dist = 0;
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
dist = width_factor / tile_aspect;
diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp
index 68d529fd32..fa72fc5b8b 100644
--- a/scene/2d/multimesh_instance_2d.cpp
+++ b/scene/2d/multimesh_instance_2d.cpp
@@ -30,6 +30,7 @@
#include "multimesh_instance_2d.h"
+#include "core/core_string_names.h"
#include "scene/scene_string_names.h"
void MultiMeshInstance2D::_notification(int p_what) {
@@ -60,7 +61,16 @@ void MultiMeshInstance2D::_bind_methods() {
}
void MultiMeshInstance2D::set_multimesh(const Ref<MultiMesh> &p_multimesh) {
+ // Cleanup previous connection if any.
+ if (multimesh.is_valid()) {
+ multimesh->disconnect(CoreStringNames::get_singleton()->changed, callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ }
multimesh = p_multimesh;
+
+ // Connect to the multimesh so the AABB can update when instance transforms are changed.
+ if (multimesh.is_valid()) {
+ multimesh->connect(CoreStringNames::get_singleton()->changed, callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ }
queue_redraw();
}
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index 904b6564bd..4455142a6c 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -70,6 +70,9 @@ void NavigationAgent2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationAgent2D::set_navigation_layer_value);
ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationAgent2D::get_navigation_layer_value);
+ ClassDB::bind_method(D_METHOD("set_path_metadata_flags", "flags"), &NavigationAgent2D::set_path_metadata_flags);
+ ClassDB::bind_method(D_METHOD("get_path_metadata_flags"), &NavigationAgent2D::get_path_metadata_flags);
+
ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationAgent2D::set_navigation_map);
ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationAgent2D::get_navigation_map);
@@ -79,8 +82,9 @@ void NavigationAgent2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent2D::get_next_location);
ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent2D::distance_to_target);
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent2D::set_velocity);
- ClassDB::bind_method(D_METHOD("get_nav_path"), &NavigationAgent2D::get_nav_path);
- ClassDB::bind_method(D_METHOD("get_nav_path_index"), &NavigationAgent2D::get_nav_path_index);
+ ClassDB::bind_method(D_METHOD("get_current_navigation_result"), &NavigationAgent2D::get_current_navigation_result);
+ ClassDB::bind_method(D_METHOD("get_current_navigation_path"), &NavigationAgent2D::get_current_navigation_path);
+ ClassDB::bind_method(D_METHOD("get_current_navigation_path_index"), &NavigationAgent2D::get_current_navigation_path_index);
ClassDB::bind_method(D_METHOD("is_target_reached"), &NavigationAgent2D::is_target_reached);
ClassDB::bind_method(D_METHOD("is_target_reachable"), &NavigationAgent2D::is_target_reachable);
ClassDB::bind_method(D_METHOD("is_navigation_finished"), &NavigationAgent2D::is_navigation_finished);
@@ -94,6 +98,7 @@ void NavigationAgent2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:px"), "set_target_desired_distance", "get_target_desired_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,100,1,suffix:px"), "set_path_max_distance", "get_path_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "path_metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_path_metadata_flags", "get_path_metadata_flags");
ADD_GROUP("Avoidance", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled");
@@ -105,6 +110,8 @@ void NavigationAgent2D::_bind_methods() {
ADD_SIGNAL(MethodInfo("path_changed"));
ADD_SIGNAL(MethodInfo("target_reached"));
+ ADD_SIGNAL(MethodInfo("waypoint_reached", PropertyInfo(Variant::DICTIONARY, "details")));
+ ADD_SIGNAL(MethodInfo("link_reached", PropertyInfo(Variant::DICTIONARY, "details")));
ADD_SIGNAL(MethodInfo("navigation_finished"));
ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR2, "safe_velocity")));
}
@@ -161,7 +168,7 @@ void NavigationAgent2D::_notification(int p_what) {
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- if (agent_parent) {
+ if (agent_parent && target_position_submitted) {
if (avoidance_enabled) {
// agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding
// no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used
@@ -190,6 +197,7 @@ NavigationAgent2D::NavigationAgent2D() {
}
NavigationAgent2D::~NavigationAgent2D() {
+ ERR_FAIL_NULL(NavigationServer2D::get_singleton());
NavigationServer2D::get_singleton()->free(agent);
agent = RID(); // Pointless
}
@@ -256,6 +264,14 @@ bool NavigationAgent2D::get_navigation_layer_value(int p_layer_number) const {
return get_navigation_layers() & (1 << (p_layer_number - 1));
}
+void NavigationAgent2D::set_path_metadata_flags(BitField<NavigationPathQueryParameters2D::PathMetadataFlags> p_path_metadata_flags) {
+ if (path_metadata_flags == p_path_metadata_flags) {
+ return;
+ }
+
+ path_metadata_flags = p_path_metadata_flags;
+}
+
void NavigationAgent2D::set_navigation_map(RID p_navigation_map) {
map_override = p_navigation_map;
NavigationServer2D::get_singleton()->agent_set_map(agent, map_override);
@@ -314,6 +330,7 @@ real_t NavigationAgent2D::get_path_max_distance() {
void NavigationAgent2D::set_target_location(Vector2 p_location) {
target_location = p_location;
+ target_position_submitted = true;
_request_repath();
}
@@ -329,14 +346,10 @@ Vector2 NavigationAgent2D::get_next_location() {
ERR_FAIL_COND_V_MSG(agent_parent == nullptr, Vector2(), "The agent has no parent.");
return agent_parent->get_global_position();
} else {
- return navigation_path[nav_path_index];
+ return navigation_path[navigation_path_index];
}
}
-const Vector<Vector2> &NavigationAgent2D::get_nav_path() const {
- return navigation_result->get_path();
-}
-
real_t NavigationAgent2D::distance_to_target() const {
ERR_FAIL_COND_V_MSG(agent_parent == nullptr, 0.0, "The agent has no parent.");
return agent_parent->get_global_position().distance_to(target_location);
@@ -402,6 +415,9 @@ void NavigationAgent2D::update_navigation() {
if (!agent_parent->is_inside_tree()) {
return;
}
+ if (!target_position_submitted) {
+ return;
+ }
if (update_frame_id == Engine::get_singleton()->get_physics_frames()) {
return;
}
@@ -418,12 +434,12 @@ void NavigationAgent2D::update_navigation() {
reload_path = true;
} else {
// Check if too far from the navigation path
- if (nav_path_index > 0) {
+ if (navigation_path_index > 0) {
const Vector<Vector2> &navigation_path = navigation_result->get_path();
Vector2 segment[2];
- segment[0] = navigation_path[nav_path_index - 1];
- segment[1] = navigation_path[nav_path_index];
+ segment[0] = navigation_path[navigation_path_index - 1];
+ segment[1] = navigation_path[navigation_path_index];
Vector2 p = Geometry2D::get_closest_point_to_segment(origin, segment);
if (origin.distance_to(p) >= path_max_distance) {
// To faraway, reload path
@@ -436,6 +452,7 @@ void NavigationAgent2D::update_navigation() {
navigation_query->set_start_position(origin);
navigation_query->set_target_position(target_location);
navigation_query->set_navigation_layers(navigation_layers);
+ navigation_query->set_metadata_flags(path_metadata_flags);
if (map_override.is_valid()) {
navigation_query->set_map(map_override);
@@ -445,7 +462,7 @@ void NavigationAgent2D::update_navigation() {
NavigationServer2D::get_singleton()->query_path(navigation_query, navigation_result);
navigation_finished = false;
- nav_path_index = 0;
+ navigation_path_index = 0;
emit_signal(SNAME("path_changed"));
}
@@ -457,12 +474,57 @@ void NavigationAgent2D::update_navigation() {
if (navigation_finished == false) {
// Advances to the next far away location.
const Vector<Vector2> &navigation_path = navigation_result->get_path();
- while (origin.distance_to(navigation_path[nav_path_index]) < path_desired_distance) {
- nav_path_index += 1;
- if (nav_path_index == navigation_path.size()) {
+ const Vector<int32_t> &navigation_path_types = navigation_result->get_path_types();
+ const TypedArray<RID> &navigation_path_rids = navigation_result->get_path_rids();
+ const Vector<int64_t> &navigation_path_owners = navigation_result->get_path_owner_ids();
+
+ while (origin.distance_to(navigation_path[navigation_path_index]) < path_desired_distance) {
+ Dictionary details;
+
+ const Vector2 waypoint = navigation_path[navigation_path_index];
+ details[SNAME("location")] = waypoint;
+
+ int waypoint_type = -1;
+ if (path_metadata_flags.has_flag(NavigationPathQueryParameters2D::PathMetadataFlags::PATH_METADATA_INCLUDE_TYPES)) {
+ const NavigationPathQueryResult2D::PathSegmentType type = NavigationPathQueryResult2D::PathSegmentType(navigation_path_types[navigation_path_index]);
+
+ details[SNAME("type")] = type;
+ waypoint_type = type;
+ }
+
+ if (path_metadata_flags.has_flag(NavigationPathQueryParameters2D::PathMetadataFlags::PATH_METADATA_INCLUDE_RIDS)) {
+ details[SNAME("rid")] = navigation_path_rids[navigation_path_index];
+ }
+
+ if (path_metadata_flags.has_flag(NavigationPathQueryParameters2D::PathMetadataFlags::PATH_METADATA_INCLUDE_OWNERS)) {
+ const ObjectID waypoint_owner_id = ObjectID(navigation_path_owners[navigation_path_index]);
+
+ // Get a reference to the owning object.
+ Object *owner = nullptr;
+ if (waypoint_owner_id.is_valid()) {
+ owner = ObjectDB::get_instance(waypoint_owner_id);
+ }
+
+ details[SNAME("owner")] = owner;
+ }
+
+ // Emit a signal for the waypoint
+ emit_signal(SNAME("waypoint_reached"), details);
+
+ // Emit a signal if we've reached a navigation link
+ if (waypoint_type == NavigationPathQueryResult2D::PATH_SEGMENT_TYPE_LINK) {
+ emit_signal(SNAME("link_reached"), details);
+ }
+
+ // Move to the next waypoint on the list
+ navigation_path_index += 1;
+
+ // Check to see if we've finished our route
+ if (navigation_path_index == navigation_path.size()) {
_check_distance_to_target();
- nav_path_index -= 1;
+ navigation_path_index -= 1;
navigation_finished = true;
+ target_position_submitted = false;
emit_signal(SNAME("navigation_finished"));
break;
}
diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h
index 5abd3c0317..439192cce7 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -32,10 +32,10 @@
#define NAVIGATION_AGENT_2D_H
#include "scene/main/node.h"
+#include "servers/navigation/navigation_path_query_parameters_2d.h"
+#include "servers/navigation/navigation_path_query_result_2d.h"
class Node2D;
-class NavigationPathQueryParameters2D;
-class NavigationPathQueryResult2D;
class NavigationAgent2D : public Node {
GDCLASS(NavigationAgent2D, Node);
@@ -48,6 +48,7 @@ class NavigationAgent2D : public Node {
bool avoidance_enabled = false;
uint32_t navigation_layers = 1;
+ BitField<NavigationPathQueryParameters2D::PathMetadataFlags> path_metadata_flags = NavigationPathQueryParameters2D::PathMetadataFlags::PATH_METADATA_INCLUDE_ALL;
real_t path_desired_distance = 1.0;
real_t target_desired_distance = 1.0;
@@ -60,9 +61,10 @@ class NavigationAgent2D : public Node {
real_t path_max_distance = 3.0;
Vector2 target_location;
+ bool target_position_submitted = false;
Ref<NavigationPathQueryParameters2D> navigation_query;
Ref<NavigationPathQueryResult2D> navigation_result;
- int nav_path_index = 0;
+ int navigation_path_index = 0;
bool velocity_submitted = false;
Vector2 prev_safe_velocity;
/// The submitted target velocity
@@ -95,6 +97,11 @@ public:
void set_navigation_layer_value(int p_layer_number, bool p_value);
bool get_navigation_layer_value(int p_layer_number) const;
+ void set_path_metadata_flags(BitField<NavigationPathQueryParameters2D::PathMetadataFlags> p_flags);
+ BitField<NavigationPathQueryParameters2D::PathMetadataFlags> get_path_metadata_flags() const {
+ return path_metadata_flags;
+ }
+
void set_navigation_map(RID p_navigation_map);
RID get_navigation_map() const;
@@ -141,10 +148,14 @@ public:
Vector2 get_next_location();
- const Vector<Vector2> &get_nav_path() const;
-
- int get_nav_path_index() const {
- return nav_path_index;
+ Ref<NavigationPathQueryResult2D> get_current_navigation_result() const {
+ return navigation_result;
+ }
+ const Vector<Vector2> &get_current_navigation_path() const {
+ return navigation_result->get_path();
+ }
+ int get_current_navigation_path_index() const {
+ return navigation_path_index;
}
real_t distance_to_target() const;
diff --git a/scene/2d/navigation_link_2d.cpp b/scene/2d/navigation_link_2d.cpp
index d639e1cc89..34005dbd9e 100644
--- a/scene/2d/navigation_link_2d.cpp
+++ b/scene/2d/navigation_link_2d.cpp
@@ -285,6 +285,7 @@ NavigationLink2D::NavigationLink2D() {
}
NavigationLink2D::~NavigationLink2D() {
+ ERR_FAIL_NULL(NavigationServer2D::get_singleton());
NavigationServer2D::get_singleton()->free(link);
link = RID();
}
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index cbec4db4c5..4d9d46fb06 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -116,6 +116,7 @@ NavigationObstacle2D::NavigationObstacle2D() {
}
NavigationObstacle2D::~NavigationObstacle2D() {
+ ERR_FAIL_NULL(NavigationServer2D::get_singleton());
NavigationServer2D::get_singleton()->free(agent);
agent = RID(); // Pointless
}
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 7bf3eec79b..78c65256e8 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -31,333 +31,10 @@
#include "navigation_region_2d.h"
#include "core/core_string_names.h"
-#include "core/math/geometry_2d.h"
-#include "core/os/mutex.h"
#include "scene/resources/world_2d.h"
#include "servers/navigation_server_2d.h"
#include "servers/navigation_server_3d.h"
-#include "thirdparty/misc/polypartition.h"
-
-#ifdef TOOLS_ENABLED
-Rect2 NavigationPolygon::_edit_get_rect() const {
- if (rect_cache_dirty) {
- item_rect = Rect2();
- bool first = true;
-
- for (int i = 0; i < outlines.size(); i++) {
- const Vector<Vector2> &outline = outlines[i];
- const int outline_size = outline.size();
- if (outline_size < 3) {
- continue;
- }
- const Vector2 *p = outline.ptr();
- for (int j = 0; j < outline_size; j++) {
- if (first) {
- item_rect = Rect2(p[j], Vector2(0, 0));
- first = false;
- } else {
- item_rect.expand_to(p[j]);
- }
- }
- }
-
- rect_cache_dirty = false;
- }
- return item_rect;
-}
-
-bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
- for (int i = 0; i < outlines.size(); i++) {
- const Vector<Vector2> &outline = outlines[i];
- const int outline_size = outline.size();
- if (outline_size < 3) {
- continue;
- }
- if (Geometry2D::is_point_in_polygon(p_point, Variant(outline))) {
- return true;
- }
- }
- return false;
-}
-#endif
-
-void NavigationPolygon::set_vertices(const Vector<Vector2> &p_vertices) {
- {
- MutexLock lock(navmesh_generation);
- navmesh.unref();
- }
- vertices = p_vertices;
- rect_cache_dirty = true;
-}
-
-Vector<Vector2> NavigationPolygon::get_vertices() const {
- return vertices;
-}
-
-void NavigationPolygon::_set_polygons(const TypedArray<Vector<int32_t>> &p_array) {
- {
- MutexLock lock(navmesh_generation);
- navmesh.unref();
- }
- polygons.resize(p_array.size());
- for (int i = 0; i < p_array.size(); i++) {
- polygons.write[i].indices = p_array[i];
- }
-}
-
-TypedArray<Vector<int32_t>> NavigationPolygon::_get_polygons() const {
- TypedArray<Vector<int32_t>> ret;
- ret.resize(polygons.size());
- for (int i = 0; i < ret.size(); i++) {
- ret[i] = polygons[i].indices;
- }
-
- return ret;
-}
-
-void NavigationPolygon::_set_outlines(const TypedArray<Vector<Vector2>> &p_array) {
- outlines.resize(p_array.size());
- for (int i = 0; i < p_array.size(); i++) {
- outlines.write[i] = p_array[i];
- }
- rect_cache_dirty = true;
-}
-
-TypedArray<Vector<Vector2>> NavigationPolygon::_get_outlines() const {
- TypedArray<Vector<Vector2>> ret;
- ret.resize(outlines.size());
- for (int i = 0; i < ret.size(); i++) {
- ret[i] = outlines[i];
- }
-
- return ret;
-}
-
-void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) {
- Polygon polygon;
- polygon.indices = p_polygon;
- polygons.push_back(polygon);
- {
- MutexLock lock(navmesh_generation);
- navmesh.unref();
- }
-}
-
-void NavigationPolygon::add_outline_at_index(const Vector<Vector2> &p_outline, int p_index) {
- outlines.insert(p_index, p_outline);
- rect_cache_dirty = true;
-}
-
-int NavigationPolygon::get_polygon_count() const {
- return polygons.size();
-}
-
-Vector<int> NavigationPolygon::get_polygon(int p_idx) {
- ERR_FAIL_INDEX_V(p_idx, polygons.size(), Vector<int>());
- return polygons[p_idx].indices;
-}
-
-void NavigationPolygon::clear_polygons() {
- polygons.clear();
- {
- MutexLock lock(navmesh_generation);
- navmesh.unref();
- }
-}
-
-Ref<NavigationMesh> NavigationPolygon::get_mesh() {
- MutexLock lock(navmesh_generation);
-
- if (navmesh.is_null()) {
- navmesh.instantiate();
- Vector<Vector3> verts;
- {
- verts.resize(get_vertices().size());
- Vector3 *w = verts.ptrw();
-
- const Vector2 *r = get_vertices().ptr();
-
- for (int i(0); i < get_vertices().size(); i++) {
- w[i] = Vector3(r[i].x, 0.0, r[i].y);
- }
- }
- navmesh->set_vertices(verts);
-
- for (int i(0); i < get_polygon_count(); i++) {
- navmesh->add_polygon(get_polygon(i));
- }
- }
-
- return navmesh;
-}
-
-void NavigationPolygon::add_outline(const Vector<Vector2> &p_outline) {
- outlines.push_back(p_outline);
- rect_cache_dirty = true;
-}
-
-int NavigationPolygon::get_outline_count() const {
- return outlines.size();
-}
-
-void NavigationPolygon::set_outline(int p_idx, const Vector<Vector2> &p_outline) {
- ERR_FAIL_INDEX(p_idx, outlines.size());
- outlines.write[p_idx] = p_outline;
- rect_cache_dirty = true;
-}
-
-void NavigationPolygon::remove_outline(int p_idx) {
- ERR_FAIL_INDEX(p_idx, outlines.size());
- outlines.remove_at(p_idx);
- rect_cache_dirty = true;
-}
-
-Vector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, outlines.size(), Vector<Vector2>());
- return outlines[p_idx];
-}
-
-void NavigationPolygon::clear_outlines() {
- outlines.clear();
- rect_cache_dirty = true;
-}
-
-void NavigationPolygon::make_polygons_from_outlines() {
- {
- MutexLock lock(navmesh_generation);
- navmesh.unref();
- }
- List<TPPLPoly> in_poly, out_poly;
-
- Vector2 outside_point(-1e10, -1e10);
-
- for (int i = 0; i < outlines.size(); i++) {
- Vector<Vector2> ol = outlines[i];
- int olsize = ol.size();
- if (olsize < 3) {
- continue;
- }
- const Vector2 *r = ol.ptr();
- for (int j = 0; j < olsize; j++) {
- outside_point.x = MAX(r[j].x, outside_point.x);
- outside_point.y = MAX(r[j].y, outside_point.y);
- }
- }
-
- outside_point += Vector2(0.7239784, 0.819238); //avoid precision issues
-
- for (int i = 0; i < outlines.size(); i++) {
- Vector<Vector2> ol = outlines[i];
- int olsize = ol.size();
- if (olsize < 3) {
- continue;
- }
- const Vector2 *r = ol.ptr();
-
- int interscount = 0;
- //test if this is an outer outline
- for (int k = 0; k < outlines.size(); k++) {
- if (i == k) {
- continue; //no self intersect
- }
-
- Vector<Vector2> ol2 = outlines[k];
- int olsize2 = ol2.size();
- if (olsize2 < 3) {
- continue;
- }
- const Vector2 *r2 = ol2.ptr();
-
- for (int l = 0; l < olsize2; l++) {
- if (Geometry2D::segment_intersects_segment(r[0], outside_point, r2[l], r2[(l + 1) % olsize2], nullptr)) {
- interscount++;
- }
- }
- }
-
- bool outer = (interscount % 2) == 0;
-
- TPPLPoly tp;
- tp.Init(olsize);
- for (int j = 0; j < olsize; j++) {
- tp[j] = r[j];
- }
-
- if (outer) {
- tp.SetOrientation(TPPL_ORIENTATION_CCW);
- } else {
- tp.SetOrientation(TPPL_ORIENTATION_CW);
- tp.SetHole(true);
- }
-
- in_poly.push_back(tp);
- }
-
- TPPLPartition tpart;
- if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
- ERR_PRINT("NavigationPolygon: Convex partition failed! Failed to convert outlines to a valid NavigationMesh."
- "\nNavigationPolygon outlines can not overlap vertices or edges inside same outline or with other outlines or have any intersections."
- "\nAdd the outmost and largest outline first. To add holes inside this outline add the smaller outlines with opposite winding order.");
- return;
- }
-
- polygons.clear();
- vertices.clear();
-
- HashMap<Vector2, int> points;
- for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) {
- TPPLPoly &tp = I->get();
-
- struct Polygon p;
-
- for (int64_t i = 0; i < tp.GetNumPoints(); i++) {
- HashMap<Vector2, int>::Iterator E = points.find(tp[i]);
- if (!E) {
- E = points.insert(tp[i], vertices.size());
- vertices.push_back(tp[i]);
- }
- p.indices.push_back(E->value);
- }
-
- polygons.push_back(p);
- }
-
- emit_signal(CoreStringNames::get_singleton()->changed);
-}
-
-void NavigationPolygon::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices);
- ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices);
-
- ClassDB::bind_method(D_METHOD("add_polygon", "polygon"), &NavigationPolygon::add_polygon);
- ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationPolygon::get_polygon_count);
- ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationPolygon::get_polygon);
- ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationPolygon::clear_polygons);
- ClassDB::bind_method(D_METHOD("get_mesh"), &NavigationPolygon::get_mesh);
-
- ClassDB::bind_method(D_METHOD("add_outline", "outline"), &NavigationPolygon::add_outline);
- ClassDB::bind_method(D_METHOD("add_outline_at_index", "outline", "index"), &NavigationPolygon::add_outline_at_index);
- ClassDB::bind_method(D_METHOD("get_outline_count"), &NavigationPolygon::get_outline_count);
- ClassDB::bind_method(D_METHOD("set_outline", "idx", "outline"), &NavigationPolygon::set_outline);
- ClassDB::bind_method(D_METHOD("get_outline", "idx"), &NavigationPolygon::get_outline);
- ClassDB::bind_method(D_METHOD("remove_outline", "idx"), &NavigationPolygon::remove_outline);
- ClassDB::bind_method(D_METHOD("clear_outlines"), &NavigationPolygon::clear_outlines);
- ClassDB::bind_method(D_METHOD("make_polygons_from_outlines"), &NavigationPolygon::make_polygons_from_outlines);
-
- ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationPolygon::_set_polygons);
- ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationPolygon::_get_polygons);
-
- ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines);
- ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines);
-
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines");
-}
-
-/////////////////////////////
-
void NavigationRegion2D::set_enabled(bool p_enabled) {
if (enabled == p_enabled) {
return;
@@ -460,11 +137,11 @@ RID NavigationRegion2D::get_region_rid() const {
#ifdef TOOLS_ENABLED
Rect2 NavigationRegion2D::_edit_get_rect() const {
- return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2();
+ return navigation_polygon.is_valid() ? navigation_polygon->_edit_get_rect() : Rect2();
}
bool NavigationRegion2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
- return navpoly.is_valid() ? navpoly->_edit_is_selected_on_click(p_point, p_tolerance) : false;
+ return navigation_polygon.is_valid() ? navigation_polygon->_edit_is_selected_on_click(p_point, p_tolerance) : false;
}
#endif
@@ -490,8 +167,8 @@ void NavigationRegion2D::_notification(int p_what) {
case NOTIFICATION_DRAW: {
#ifdef DEBUG_ENABLED
- if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_enabled()) && navpoly.is_valid()) {
- Vector<Vector2> verts = navpoly->get_vertices();
+ if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_enabled()) && navigation_polygon.is_valid()) {
+ Vector<Vector2> verts = navigation_polygon->get_vertices();
if (verts.size() < 3) {
return;
}
@@ -506,9 +183,9 @@ void NavigationRegion2D::_notification(int p_what) {
RandomPCG rand;
- for (int i = 0; i < navpoly->get_polygon_count(); i++) {
+ for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) {
// An array of vertices for this polygon.
- Vector<int> polygon = navpoly->get_polygon(i);
+ Vector<int> polygon = navigation_polygon->get_polygon(i);
Vector<Vector2> vertices;
vertices.resize(polygon.size());
for (int j = 0; j < polygon.size(); j++) {
@@ -549,36 +226,36 @@ void NavigationRegion2D::_notification(int p_what) {
}
}
-void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly) {
- if (p_navpoly == navpoly) {
+void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_navigation_polygon) {
+ if (p_navigation_polygon == navigation_polygon) {
return;
}
- if (navpoly.is_valid()) {
- navpoly->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed));
+ if (navigation_polygon.is_valid()) {
+ navigation_polygon->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navigation_polygon_changed));
}
- navpoly = p_navpoly;
- NavigationServer2D::get_singleton()->region_set_navpoly(region, p_navpoly);
+ navigation_polygon = p_navigation_polygon;
+ NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, p_navigation_polygon);
- if (navpoly.is_valid()) {
- navpoly->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed));
+ if (navigation_polygon.is_valid()) {
+ navigation_polygon->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navigation_polygon_changed));
}
- _navpoly_changed();
+ _navigation_polygon_changed();
update_configuration_warnings();
}
Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const {
- return navpoly;
+ return navigation_polygon;
}
-void NavigationRegion2D::_navpoly_changed() {
+void NavigationRegion2D::_navigation_polygon_changed() {
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) {
queue_redraw();
}
- if (navpoly.is_valid()) {
- NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly);
+ if (navigation_polygon.is_valid()) {
+ NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, navigation_polygon);
}
}
@@ -594,7 +271,7 @@ PackedStringArray NavigationRegion2D::get_configuration_warnings() const {
PackedStringArray warnings = Node2D::get_configuration_warnings();
if (is_visible_in_tree() && is_inside_tree()) {
- if (!navpoly.is_valid()) {
+ if (!navigation_polygon.is_valid()) {
warnings.push_back(RTR("A NavigationMesh resource must be set or created for this node to work. Please set a property or draw a polygon."));
}
}
@@ -603,7 +280,7 @@ PackedStringArray NavigationRegion2D::get_configuration_warnings() const {
}
void NavigationRegion2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_navigation_polygon", "navpoly"), &NavigationRegion2D::set_navigation_polygon);
+ ClassDB::bind_method(D_METHOD("set_navigation_polygon", "navigation_polygon"), &NavigationRegion2D::set_navigation_polygon);
ClassDB::bind_method(D_METHOD("get_navigation_polygon"), &NavigationRegion2D::get_navigation_polygon);
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion2D::set_enabled);
@@ -623,15 +300,34 @@ void NavigationRegion2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationRegion2D::set_travel_cost);
ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion2D::get_travel_cost);
- ClassDB::bind_method(D_METHOD("_navpoly_changed"), &NavigationRegion2D::_navpoly_changed);
+ ClassDB::bind_method(D_METHOD("_navigation_polygon_changed"), &NavigationRegion2D::_navigation_polygon_changed);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navigation_polygon", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost");
}
+#ifndef DISABLE_DEPRECATED
+// Compatibility with earlier 4.0 betas.
+bool NavigationRegion2D::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "navpoly") {
+ set_navigation_polygon(p_value);
+ return true;
+ }
+ return false;
+}
+
+bool NavigationRegion2D::_get(const StringName &p_name, Variant &r_ret) const {
+ if (p_name == "navpoly") {
+ r_ret = get_navigation_polygon();
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
NavigationRegion2D::NavigationRegion2D() {
set_notify_transform(true);
@@ -647,6 +343,7 @@ NavigationRegion2D::NavigationRegion2D() {
}
NavigationRegion2D::~NavigationRegion2D() {
+ ERR_FAIL_NULL(NavigationServer2D::get_singleton());
NavigationServer2D::get_singleton()->free(region);
#ifdef DEBUG_ENABLED
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index c630e20780..45029fd95f 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -31,65 +31,7 @@
#ifndef NAVIGATION_REGION_2D_H
#define NAVIGATION_REGION_2D_H
-#include "scene/2d/node_2d.h"
-#include "scene/resources/navigation_mesh.h"
-
-class NavigationPolygon : public Resource {
- GDCLASS(NavigationPolygon, Resource);
-
- Vector<Vector2> vertices;
- struct Polygon {
- Vector<int> indices;
- };
- Vector<Polygon> polygons;
- Vector<Vector<Vector2>> outlines;
-
- mutable Rect2 item_rect;
- mutable bool rect_cache_dirty = true;
-
- Mutex navmesh_generation;
- // Navigation mesh
- Ref<NavigationMesh> navmesh;
-
-protected:
- static void _bind_methods();
-
- void _set_polygons(const TypedArray<Vector<int32_t>> &p_array);
- TypedArray<Vector<int32_t>> _get_polygons() const;
-
- void _set_outlines(const TypedArray<Vector<Vector2>> &p_array);
- TypedArray<Vector<Vector2>> _get_outlines() const;
-
-public:
-#ifdef TOOLS_ENABLED
- Rect2 _edit_get_rect() const;
- bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
-#endif
-
- void set_vertices(const Vector<Vector2> &p_vertices);
- Vector<Vector2> get_vertices() const;
-
- void add_polygon(const Vector<int> &p_polygon);
- int get_polygon_count() const;
-
- void add_outline(const Vector<Vector2> &p_outline);
- void add_outline_at_index(const Vector<Vector2> &p_outline, int p_index);
- void set_outline(int p_idx, const Vector<Vector2> &p_outline);
- Vector<Vector2> get_outline(int p_idx) const;
- void remove_outline(int p_idx);
- int get_outline_count() const;
-
- void clear_outlines();
- void make_polygons_from_outlines();
-
- Vector<int> get_polygon(int p_idx);
- void clear_polygons();
-
- Ref<NavigationMesh> get_mesh();
-
- NavigationPolygon() {}
- ~NavigationPolygon() {}
-};
+#include "scene/resources/navigation_polygon.h"
class NavigationRegion2D : public Node2D {
GDCLASS(NavigationRegion2D, Node2D);
@@ -99,15 +41,20 @@ class NavigationRegion2D : public Node2D {
uint32_t navigation_layers = 1;
real_t enter_cost = 0.0;
real_t travel_cost = 1.0;
- Ref<NavigationPolygon> navpoly;
+ Ref<NavigationPolygon> navigation_polygon;
- void _navpoly_changed();
+ void _navigation_polygon_changed();
void _map_changed(RID p_RID);
protected:
void _notification(int p_what);
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+#endif // DISABLE_DEPRECATED
+
public:
#ifdef TOOLS_ENABLED
virtual Rect2 _edit_get_rect() const override;
@@ -131,7 +78,7 @@ public:
void set_travel_cost(real_t p_travel_cost);
real_t get_travel_cost() const;
- void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly);
+ void set_navigation_polygon(const Ref<NavigationPolygon> &p_navigation_polygon);
Ref<NavigationPolygon> get_navigation_polygon() const;
PackedStringArray get_configuration_warnings() const override;
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 4788a1b813..166bc26848 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -149,6 +149,10 @@ void Node2D::set_rotation(real_t p_radians) {
_update_transform();
}
+void Node2D::set_rotation_degrees(real_t p_degrees) {
+ set_rotation(Math::deg_to_rad(p_degrees));
+}
+
void Node2D::set_skew(real_t p_radians) {
if (_xform_dirty) {
const_cast<Node2D *>(this)->_update_xform_values();
@@ -187,6 +191,10 @@ real_t Node2D::get_rotation() const {
return rotation;
}
+real_t Node2D::get_rotation_degrees() const {
+ return Math::rad_to_deg(get_rotation());
+}
+
real_t Node2D::get_skew() const {
if (_xform_dirty) {
const_cast<Node2D *>(this)->_update_xform_values();
@@ -259,6 +267,10 @@ real_t Node2D::get_global_rotation() const {
return get_global_transform().get_rotation();
}
+real_t Node2D::get_global_rotation_degrees() const {
+ return Math::rad_to_deg(get_global_rotation());
+}
+
real_t Node2D::get_global_skew() const {
return get_global_transform().get_skew();
}
@@ -276,6 +288,10 @@ void Node2D::set_global_rotation(const real_t p_radians) {
}
}
+void Node2D::set_global_rotation_degrees(const real_t p_degrees) {
+ set_global_rotation(Math::deg_to_rad(p_degrees));
+}
+
void Node2D::set_global_skew(const real_t p_radians) {
CanvasItem *parent = get_parent_item();
if (parent) {
@@ -372,11 +388,13 @@ void Node2D::_notification(int p_notification) {
void Node2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_position", "position"), &Node2D::set_position);
ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Node2D::set_rotation);
+ ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &Node2D::set_rotation_degrees);
ClassDB::bind_method(D_METHOD("set_skew", "radians"), &Node2D::set_skew);
ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Node2D::set_scale);
ClassDB::bind_method(D_METHOD("get_position"), &Node2D::get_position);
ClassDB::bind_method(D_METHOD("get_rotation"), &Node2D::get_rotation);
+ ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Node2D::get_rotation_degrees);
ClassDB::bind_method(D_METHOD("get_skew"), &Node2D::get_skew);
ClassDB::bind_method(D_METHOD("get_scale"), &Node2D::get_scale);
@@ -390,7 +408,9 @@ void Node2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_global_position", "position"), &Node2D::set_global_position);
ClassDB::bind_method(D_METHOD("get_global_position"), &Node2D::get_global_position);
ClassDB::bind_method(D_METHOD("set_global_rotation", "radians"), &Node2D::set_global_rotation);
+ ClassDB::bind_method(D_METHOD("set_global_rotation_degrees", "degrees"), &Node2D::set_global_rotation_degrees);
ClassDB::bind_method(D_METHOD("get_global_rotation"), &Node2D::get_global_rotation);
+ ClassDB::bind_method(D_METHOD("get_global_rotation_degrees"), &Node2D::get_global_rotation_degrees);
ClassDB::bind_method(D_METHOD("set_global_skew", "radians"), &Node2D::set_global_skew);
ClassDB::bind_method(D_METHOD("get_global_skew"), &Node2D::get_global_skew);
ClassDB::bind_method(D_METHOD("set_global_scale", "scale"), &Node2D::set_global_scale);
@@ -410,12 +430,14 @@ void Node2D::_bind_methods() {
ADD_GROUP("Transform", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_less,or_greater,hide_slider,suffix:px"), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_rotation_degrees", "get_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_transform", "get_transform");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_global_position", "get_global_position");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_rotation", PROPERTY_HINT_NONE, "radians", PROPERTY_USAGE_NONE), "set_global_rotation", "get_global_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_rotation_degrees", "get_global_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_scale", "get_global_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_skew", PROPERTY_HINT_NONE, "radians", PROPERTY_USAGE_NONE), "set_global_skew", "get_global_skew");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform");
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index 76707dc422..b066332dcb 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -73,6 +73,7 @@ public:
void set_position(const Point2 &p_pos);
void set_rotation(real_t p_radians);
+ void set_rotation_degrees(real_t p_degrees);
void set_skew(real_t p_radians);
void set_scale(const Size2 &p_scale);
@@ -85,11 +86,13 @@ public:
Point2 get_position() const;
real_t get_rotation() const;
+ real_t get_rotation_degrees() const;
real_t get_skew() const;
Size2 get_scale() const;
Point2 get_global_position() const;
real_t get_global_rotation() const;
+ real_t get_global_rotation_degrees() const;
real_t get_global_skew() const;
Size2 get_global_scale() const;
@@ -97,6 +100,7 @@ public:
void set_global_transform(const Transform2D &p_transform);
void set_global_position(const Point2 &p_pos);
void set_global_rotation(const real_t p_radians);
+ void set_global_rotation_degrees(const real_t p_degrees);
void set_global_skew(const real_t p_radians);
void set_global_scale(const Size2 &p_scale);
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index e41664b006..5b00a3a2dc 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -664,6 +664,7 @@ Polygon2D::Polygon2D() {
Polygon2D::~Polygon2D() {
// This will free the internally-allocated mesh instance, if allocated.
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID());
RS::get_singleton()->free(mesh);
}
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 62787d4488..fa0358fabc 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -529,6 +529,7 @@ Bone2D::Bone2D() {
Bone2D::~Bone2D() {
#ifdef TOOLS_ENABLED
if (!editor_gizmo_rid.is_null()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(editor_gizmo_rid);
}
#endif // TOOLS_ENABLED
@@ -803,5 +804,6 @@ Skeleton2D::Skeleton2D() {
}
Skeleton2D::~Skeleton2D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(skeleton);
}
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 3ae7a0b34d..f52dbd1c53 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1092,7 +1092,7 @@ void TileMap::_rendering_update_layer(int p_layer) {
/*Transform2D xform;
xform.set_origin(Vector2(0, p_layer));
rs->canvas_item_set_transform(ci, xform);*/
- rs->canvas_item_set_draw_index(ci, p_layer);
+ rs->canvas_item_set_draw_index(ci, p_layer - (int64_t)0x80000000);
layers[p_layer].canvas_item = ci;
}
@@ -1108,6 +1108,7 @@ void TileMap::_rendering_update_layer(int p_layer) {
void TileMap::_rendering_cleanup_layer(int p_layer) {
ERR_FAIL_INDEX(p_layer, (int)layers.size());
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer *rs = RenderingServer::get_singleton();
if (layers[p_layer].canvas_item.is_valid()) {
rs->free(layers[p_layer].canvas_item);
@@ -1280,6 +1281,7 @@ void TileMap::_rendering_create_quadrant(TileMapQuadrant *p_quadrant) {
}
void TileMap::_rendering_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
// Free the canvas items.
for (const RID &ci : p_quadrant->canvas_items) {
RenderingServer::get_singleton()->free(ci);
@@ -1596,6 +1598,7 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
void TileMap::_physics_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
// Remove a quadrant.
+ ERR_FAIL_NULL(PhysicsServer2D::get_singleton());
for (RID body : p_quadrant->bodies) {
bodies_coords.erase(body);
PhysicsServer2D::get_singleton()->free(body);
@@ -1728,10 +1731,10 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
q.navigation_regions[E_cell].resize(tile_set->get_navigation_layers_count());
for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
- Ref<NavigationPolygon> navpoly;
- navpoly = tile_data->get_navigation_polygon(layer_index);
+ Ref<NavigationPolygon> navigation_polygon;
+ navigation_polygon = tile_data->get_navigation_polygon(layer_index);
- if (navpoly.is_valid()) {
+ if (navigation_polygon.is_valid()) {
Transform2D tile_transform;
tile_transform.set_origin(map_to_local(E_cell));
@@ -1739,7 +1742,8 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
NavigationServer2D::get_singleton()->region_set_owner_id(region, get_instance_id());
NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
- NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly);
+ NavigationServer2D::get_singleton()->region_set_navigation_layers(region, tile_set->get_navigation_layer_layers(layer_index));
+ NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, navigation_polygon);
q.navigation_regions[E_cell].write[layer_index] = region;
}
}
@@ -1753,6 +1757,7 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
void TileMap::_navigation_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
// Clear navigation shapes in the quadrant.
+ ERR_FAIL_NULL(NavigationServer2D::get_singleton());
for (const KeyValue<Vector2i, Vector<RID>> &E : p_quadrant->navigation_regions) {
for (int i = 0; i < E.value.size(); i++) {
RID region = E.value[i];
@@ -1996,7 +2001,6 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c
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)) {
- WARN_PRINT("Setting a cell as empty requires both source_id, atlas_coord and alternative_tile to be set to their respective \"invalid\" values. Values were thus changes accordingly.");
source_id = TileSet::INVALID_SOURCE;
atlas_coords = TileSetSource::INVALID_ATLAS_COORDS;
alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
@@ -3905,35 +3909,26 @@ void TileMap::draw_cells_outline(Control *p_control, const RBSet<Vector2i> &p_ce
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 2, 3);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 3, 0);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 0, 1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 2, 3);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 1, 2);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 3, 0);
} else {
if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0);
- } else {
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 1, 2);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 4, 5);
- }
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 1, 2);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 4, 5);
} else {
- if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3);
- } else {
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 4, 5);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 1, 2);
- DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3);
- }
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 4, 5);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 1, 2);
+ DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3);
}
}
}
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index 2a50575749..03c24e63ef 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -744,8 +744,10 @@ Camera3D::Camera3D() {
}
Camera3D::~Camera3D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(camera);
if (pyramid_shape.is_valid()) {
+ ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
PhysicsServer3D::get_singleton()->free(pyramid_shape);
}
}
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 66546092f2..1b94ff822c 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -352,6 +352,8 @@ void CollisionObject3D::_shape_changed(const Ref<Shape3D> &p_shape) {
}
void CollisionObject3D::_update_debug_shapes() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+
if (!is_inside_tree()) {
debug_shapes_to_update.clear();
return;
@@ -393,6 +395,8 @@ void CollisionObject3D::_update_debug_shapes() {
}
void CollisionObject3D::_clear_debug_shapes() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+
for (KeyValue<uint32_t, ShapeData> &E : shapes) {
ShapeData &shapedata = E.value;
ShapeData::ShapeBase *shape_bases = shapedata.shapes.ptrw();
@@ -627,6 +631,7 @@ int CollisionObject3D::shape_owner_get_shape_index(uint32_t p_owner, int p_shape
}
void CollisionObject3D::shape_owner_remove_shape(uint32_t p_owner, int p_shape) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
ERR_FAIL_COND(!shapes.has(p_owner));
ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size());
@@ -722,5 +727,6 @@ CollisionObject3D::CollisionObject3D() {
}
CollisionObject3D::~CollisionObject3D() {
+ ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
PhysicsServer3D::get_singleton()->free(rid);
}
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index ef381641ab..2729dfc369 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -34,6 +34,7 @@
#include "physics_body_3d.h"
#include "scene/resources/concave_polygon_shape_3d.h"
#include "scene/resources/convex_polygon_shape_3d.h"
+#include "scene/resources/world_boundary_shape_3d.h"
void CollisionShape3D::make_convex_from_siblings() {
Node *p = get_parent();
@@ -125,10 +126,12 @@ PackedStringArray CollisionShape3D::get_configuration_warnings() const {
warnings.push_back(RTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it."));
}
- if (shape.is_valid() &&
- Object::cast_to<RigidBody3D>(get_parent()) &&
- Object::cast_to<ConcavePolygonShape3D>(*shape)) {
- warnings.push_back(RTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."));
+ if (shape.is_valid() && Object::cast_to<RigidBody3D>(get_parent())) {
+ if (Object::cast_to<ConcavePolygonShape3D>(*shape)) {
+ warnings.push_back(RTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."));
+ } else if (Object::cast_to<WorldBoundaryShape3D>(*shape)) {
+ warnings.push_back(RTR("WorldBoundaryShape3D doesn't support RigidBody3D in another mode than static."));
+ }
}
return warnings;
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index 5ac8535bb6..6d47375589 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -1701,5 +1701,6 @@ CPUParticles3D::CPUParticles3D() {
}
CPUParticles3D::~CPUParticles3D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(multimesh);
}
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index fc442986a8..ee1086fb88 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -254,5 +254,6 @@ Decal::Decal() {
}
Decal::~Decal() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(decal);
}
diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp
index 4606e70310..d9912c47b1 100644
--- a/scene/3d/fog_volume.cpp
+++ b/scene/3d/fog_volume.cpp
@@ -118,5 +118,6 @@ FogVolume::FogVolume() {
}
FogVolume::~FogVolume() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(volume);
}
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index 17dfe2610e..6302a9e1b8 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -634,5 +634,6 @@ GPUParticles3D::GPUParticles3D() {
}
GPUParticles3D::~GPUParticles3D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(particles);
}
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index 476820b1c4..f6546b2d1f 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -58,6 +58,7 @@ GPUParticlesCollision3D::GPUParticlesCollision3D(RS::ParticlesCollisionType p_ty
}
GPUParticlesCollision3D::~GPUParticlesCollision3D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(collision);
}
@@ -819,6 +820,7 @@ GPUParticlesAttractor3D::GPUParticlesAttractor3D(RS::ParticlesCollisionType p_ty
set_base(collision);
}
GPUParticlesAttractor3D::~GPUParticlesAttractor3D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(collision);
}
diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp
index 1a18f43e7b..d86c156d99 100644
--- a/scene/3d/joint_3d.cpp
+++ b/scene/3d/joint_3d.cpp
@@ -234,6 +234,7 @@ Joint3D::Joint3D() {
}
Joint3D::~Joint3D() {
+ ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
PhysicsServer3D::get_singleton()->free(joint);
}
diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp
index 262dc0db37..d3020fc5b7 100644
--- a/scene/3d/label_3d.cpp
+++ b/scene/3d/label_3d.cpp
@@ -966,6 +966,7 @@ Label3D::~Label3D() {
TS->free_rid(text_rid);
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(mesh);
for (KeyValue<SurfaceKey, SurfaceData> E : surfaces) {
RenderingServer::get_singleton()->free(E.value.material);
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index 3f43e718b8..23a08f0292 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -476,6 +476,7 @@ Light3D::Light3D() {
}
Light3D::~Light3D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->instance_set_base(get_instance(), RID());
if (light.is_valid()) {
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 1b5427c80d..108bbe072e 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -313,6 +313,7 @@ LightmapGIData::LightmapGIData() {
}
LightmapGIData::~LightmapGIData() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(lightmap);
}
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index 10f3ab5c79..c4ec54fa8f 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -53,21 +53,11 @@ bool MeshInstance3D::_set(const StringName &p_name, const Variant &p_value) {
if (p_name.operator String().begins_with("surface_material_override/")) {
int idx = p_name.operator String().get_slicec('/', 1).to_int();
- // This is a bit of a hack to ensure compatibility with older material
- // overrides that start indexing at 0.
- // We assume that idx 0 is always read first, if its not, this won't work.
- if (idx == 0) {
- old_surface_index = true;
- }
- if (old_surface_index) {
- idx++;
- }
-
- if (idx > surface_override_materials.size() || idx < 0) {
+ if (idx >= surface_override_materials.size() || idx < 0) {
return false;
}
- set_surface_override_material(idx - 1, p_value);
+ set_surface_override_material(idx, p_value);
return true;
}
@@ -86,7 +76,7 @@ bool MeshInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
}
if (p_name.operator String().begins_with("surface_material_override/")) {
- int idx = p_name.operator String().get_slicec('/', 1).to_int() - 1;
+ int idx = p_name.operator String().get_slicec('/', 1).to_int();
if (idx >= surface_override_materials.size() || idx < 0) {
return false;
}
@@ -109,7 +99,7 @@ void MeshInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
}
if (mesh.is_valid()) {
- for (int i = 1; i <= mesh->get_surface_count(); i++) {
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("%s/%d", PNAME("surface_material_override"), i), PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE));
}
}
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index 9e6dbaf160..e1cc5272ea 100644
--- a/scene/3d/mesh_instance_3d.h
+++ b/scene/3d/mesh_instance_3d.h
@@ -57,7 +57,7 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- bool old_surface_index = false;
+ bool surface_index_0 = false;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index e907b9f66f..3acb33f42a 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -74,6 +74,9 @@ void NavigationAgent3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationAgent3D::set_navigation_layer_value);
ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationAgent3D::get_navigation_layer_value);
+ ClassDB::bind_method(D_METHOD("set_path_metadata_flags", "flags"), &NavigationAgent3D::set_path_metadata_flags);
+ ClassDB::bind_method(D_METHOD("get_path_metadata_flags"), &NavigationAgent3D::get_path_metadata_flags);
+
ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationAgent3D::set_navigation_map);
ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationAgent3D::get_navigation_map);
@@ -83,8 +86,9 @@ void NavigationAgent3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent3D::get_next_location);
ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent3D::distance_to_target);
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent3D::set_velocity);
- ClassDB::bind_method(D_METHOD("get_nav_path"), &NavigationAgent3D::get_nav_path);
- ClassDB::bind_method(D_METHOD("get_nav_path_index"), &NavigationAgent3D::get_nav_path_index);
+ ClassDB::bind_method(D_METHOD("get_current_navigation_result"), &NavigationAgent3D::get_current_navigation_result);
+ ClassDB::bind_method(D_METHOD("get_current_navigation_path"), &NavigationAgent3D::get_current_navigation_path);
+ ClassDB::bind_method(D_METHOD("get_current_navigation_path_index"), &NavigationAgent3D::get_current_navigation_path_index);
ClassDB::bind_method(D_METHOD("is_target_reached"), &NavigationAgent3D::is_target_reached);
ClassDB::bind_method(D_METHOD("is_target_reachable"), &NavigationAgent3D::is_target_reachable);
ClassDB::bind_method(D_METHOD("is_navigation_finished"), &NavigationAgent3D::is_navigation_finished);
@@ -99,6 +103,7 @@ void NavigationAgent3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01,suffix:m"), "set_agent_height_offset", "get_agent_height_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1,suffix:m"), "set_path_max_distance", "get_path_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "path_metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_path_metadata_flags", "get_path_metadata_flags");
ADD_GROUP("Avoidance", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled");
@@ -111,6 +116,8 @@ void NavigationAgent3D::_bind_methods() {
ADD_SIGNAL(MethodInfo("path_changed"));
ADD_SIGNAL(MethodInfo("target_reached"));
+ ADD_SIGNAL(MethodInfo("waypoint_reached", PropertyInfo(Variant::DICTIONARY, "details")));
+ ADD_SIGNAL(MethodInfo("link_reached", PropertyInfo(Variant::DICTIONARY, "details")));
ADD_SIGNAL(MethodInfo("navigation_finished"));
ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR3, "safe_velocity")));
}
@@ -167,7 +174,7 @@ void NavigationAgent3D::_notification(int p_what) {
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- if (agent_parent) {
+ if (agent_parent && target_position_submitted) {
if (avoidance_enabled) {
// agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding
// no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used
@@ -197,6 +204,7 @@ NavigationAgent3D::NavigationAgent3D() {
}
NavigationAgent3D::~NavigationAgent3D() {
+ ERR_FAIL_NULL(NavigationServer3D::get_singleton());
NavigationServer3D::get_singleton()->free(agent);
agent = RID(); // Pointless
}
@@ -263,6 +271,14 @@ bool NavigationAgent3D::get_navigation_layer_value(int p_layer_number) const {
return get_navigation_layers() & (1 << (p_layer_number - 1));
}
+void NavigationAgent3D::set_path_metadata_flags(BitField<NavigationPathQueryParameters3D::PathMetadataFlags> p_path_metadata_flags) {
+ if (path_metadata_flags == p_path_metadata_flags) {
+ return;
+ }
+
+ path_metadata_flags = p_path_metadata_flags;
+}
+
void NavigationAgent3D::set_navigation_map(RID p_navigation_map) {
map_override = p_navigation_map;
NavigationServer3D::get_singleton()->agent_set_map(agent, map_override);
@@ -330,6 +346,7 @@ real_t NavigationAgent3D::get_path_max_distance() {
void NavigationAgent3D::set_target_location(Vector3 p_location) {
target_location = p_location;
+ target_position_submitted = true;
_request_repath();
}
@@ -345,14 +362,10 @@ Vector3 NavigationAgent3D::get_next_location() {
ERR_FAIL_COND_V_MSG(agent_parent == nullptr, Vector3(), "The agent has no parent.");
return agent_parent->get_global_transform().origin;
} else {
- return navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0);
+ return navigation_path[navigation_path_index] - Vector3(0, navigation_height_offset, 0);
}
}
-const Vector<Vector3> &NavigationAgent3D::get_nav_path() const {
- return navigation_result->get_path();
-}
-
real_t NavigationAgent3D::distance_to_target() const {
ERR_FAIL_COND_V_MSG(agent_parent == nullptr, 0.0, "The agent has no parent.");
return agent_parent->get_global_transform().origin.distance_to(target_location);
@@ -417,6 +430,9 @@ void NavigationAgent3D::update_navigation() {
if (!agent_parent->is_inside_tree()) {
return;
}
+ if (!target_position_submitted) {
+ return;
+ }
if (update_frame_id == Engine::get_singleton()->get_physics_frames()) {
return;
}
@@ -433,12 +449,12 @@ void NavigationAgent3D::update_navigation() {
reload_path = true;
} else {
// Check if too far from the navigation path
- if (nav_path_index > 0) {
+ if (navigation_path_index > 0) {
const Vector<Vector3> &navigation_path = navigation_result->get_path();
Vector3 segment[2];
- segment[0] = navigation_path[nav_path_index - 1];
- segment[1] = navigation_path[nav_path_index];
+ segment[0] = navigation_path[navigation_path_index - 1];
+ segment[1] = navigation_path[navigation_path_index];
segment[0].y -= navigation_height_offset;
segment[1].y -= navigation_height_offset;
Vector3 p = Geometry3D::get_closest_point_to_segment(origin, segment);
@@ -453,6 +469,7 @@ void NavigationAgent3D::update_navigation() {
navigation_query->set_start_position(origin);
navigation_query->set_target_position(target_location);
navigation_query->set_navigation_layers(navigation_layers);
+ navigation_query->set_metadata_flags(path_metadata_flags);
if (map_override.is_valid()) {
navigation_query->set_map(map_override);
@@ -462,7 +479,7 @@ void NavigationAgent3D::update_navigation() {
NavigationServer3D::get_singleton()->query_path(navigation_query, navigation_result);
navigation_finished = false;
- nav_path_index = 0;
+ navigation_path_index = 0;
emit_signal(SNAME("path_changed"));
}
@@ -474,12 +491,57 @@ void NavigationAgent3D::update_navigation() {
if (navigation_finished == false) {
// Advances to the next far away location.
const Vector<Vector3> &navigation_path = navigation_result->get_path();
- while (origin.distance_to(navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0)) < path_desired_distance) {
- nav_path_index += 1;
- if (nav_path_index == navigation_path.size()) {
+ const Vector<int32_t> &navigation_path_types = navigation_result->get_path_types();
+ const TypedArray<RID> &navigation_path_rids = navigation_result->get_path_rids();
+ const Vector<int64_t> &navigation_path_owners = navigation_result->get_path_owner_ids();
+
+ while (origin.distance_to(navigation_path[navigation_path_index] - Vector3(0, navigation_height_offset, 0)) < path_desired_distance) {
+ Dictionary details;
+
+ const Vector3 waypoint = navigation_path[navigation_path_index];
+ details[SNAME("location")] = waypoint;
+
+ int waypoint_type = -1;
+ if (path_metadata_flags.has_flag(NavigationPathQueryParameters3D::PathMetadataFlags::PATH_METADATA_INCLUDE_TYPES)) {
+ const NavigationPathQueryResult3D::PathSegmentType type = NavigationPathQueryResult3D::PathSegmentType(navigation_path_types[navigation_path_index]);
+
+ details[SNAME("type")] = type;
+ waypoint_type = type;
+ }
+
+ if (path_metadata_flags.has_flag(NavigationPathQueryParameters3D::PathMetadataFlags::PATH_METADATA_INCLUDE_RIDS)) {
+ details[SNAME("rid")] = navigation_path_rids[navigation_path_index];
+ }
+
+ if (path_metadata_flags.has_flag(NavigationPathQueryParameters3D::PathMetadataFlags::PATH_METADATA_INCLUDE_OWNERS)) {
+ const ObjectID waypoint_owner_id = ObjectID(navigation_path_owners[navigation_path_index]);
+
+ // Get a reference to the owning object.
+ Object *owner = nullptr;
+ if (waypoint_owner_id.is_valid()) {
+ owner = ObjectDB::get_instance(waypoint_owner_id);
+ }
+
+ details[SNAME("owner")] = owner;
+ }
+
+ // Emit a signal for the waypoint
+ emit_signal(SNAME("waypoint_reached"), details);
+
+ // Emit a signal if we've reached a navigation link
+ if (waypoint_type == NavigationPathQueryResult3D::PATH_SEGMENT_TYPE_LINK) {
+ emit_signal(SNAME("link_reached"), details);
+ }
+
+ // Move to the next waypoint on the list
+ navigation_path_index += 1;
+
+ // Check to see if we've finished our route
+ if (navigation_path_index == navigation_path.size()) {
_check_distance_to_target();
- nav_path_index -= 1;
+ navigation_path_index -= 1;
navigation_finished = true;
+ target_position_submitted = false;
emit_signal(SNAME("navigation_finished"));
break;
}
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index 90ceab0242..cda218b538 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -32,10 +32,10 @@
#define NAVIGATION_AGENT_3D_H
#include "scene/main/node.h"
+#include "servers/navigation/navigation_path_query_parameters_3d.h"
+#include "servers/navigation/navigation_path_query_result_3d.h"
class Node3D;
-class NavigationPathQueryParameters3D;
-class NavigationPathQueryResult3D;
class NavigationAgent3D : public Node {
GDCLASS(NavigationAgent3D, Node);
@@ -48,6 +48,7 @@ class NavigationAgent3D : public Node {
bool avoidance_enabled = false;
uint32_t navigation_layers = 1;
+ BitField<NavigationPathQueryParameters3D::PathMetadataFlags> path_metadata_flags = NavigationPathQueryParameters3D::PathMetadataFlags::PATH_METADATA_INCLUDE_ALL;
real_t path_desired_distance = 1.0;
real_t target_desired_distance = 1.0;
@@ -62,9 +63,10 @@ class NavigationAgent3D : public Node {
real_t path_max_distance = 3.0;
Vector3 target_location;
+ bool target_position_submitted = false;
Ref<NavigationPathQueryParameters3D> navigation_query;
Ref<NavigationPathQueryResult3D> navigation_result;
- int nav_path_index = 0;
+ int navigation_path_index = 0;
bool velocity_submitted = false;
Vector3 prev_safe_velocity;
/// The submitted target velocity
@@ -97,6 +99,11 @@ public:
void set_navigation_layer_value(int p_layer_number, bool p_value);
bool get_navigation_layer_value(int p_layer_number) const;
+ void set_path_metadata_flags(BitField<NavigationPathQueryParameters3D::PathMetadataFlags> p_flags);
+ BitField<NavigationPathQueryParameters3D::PathMetadataFlags> get_path_metadata_flags() const {
+ return path_metadata_flags;
+ }
+
void set_navigation_map(RID p_navigation_map);
RID get_navigation_map() const;
@@ -153,10 +160,14 @@ public:
Vector3 get_next_location();
- const Vector<Vector3> &get_nav_path() const;
-
- int get_nav_path_index() const {
- return nav_path_index;
+ Ref<NavigationPathQueryResult3D> get_current_navigation_result() const {
+ return navigation_result;
+ }
+ const Vector<Vector3> &get_current_navigation_path() const {
+ return navigation_result->get_path();
+ }
+ int get_current_navigation_path_index() const {
+ return navigation_path_index;
}
real_t distance_to_target() const;
diff --git a/scene/3d/navigation_link_3d.cpp b/scene/3d/navigation_link_3d.cpp
index bee7c7f39b..009abfc8fd 100644
--- a/scene/3d/navigation_link_3d.cpp
+++ b/scene/3d/navigation_link_3d.cpp
@@ -227,10 +227,12 @@ NavigationLink3D::NavigationLink3D() {
}
NavigationLink3D::~NavigationLink3D() {
+ ERR_FAIL_NULL(NavigationServer3D::get_singleton());
NavigationServer3D::get_singleton()->free(link);
link = RID();
#ifdef DEBUG_ENABLED
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
if (debug_instance.is_valid()) {
RenderingServer::get_singleton()->free(debug_instance);
}
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index f241d65649..6431bd2b77 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -122,6 +122,7 @@ NavigationObstacle3D::NavigationObstacle3D() {
}
NavigationObstacle3D::~NavigationObstacle3D() {
+ ERR_FAIL_NULL(NavigationServer3D::get_singleton());
NavigationServer3D::get_singleton()->free(agent);
agent = RID(); // Pointless
}
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index bd96c55512..0e0233c0cd 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -192,26 +192,26 @@ void NavigationRegion3D::_notification(int p_what) {
}
}
-void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh) {
- if (p_navmesh == navmesh) {
+void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navigation_mesh) {
+ if (p_navigation_mesh == navigation_mesh) {
return;
}
- if (navmesh.is_valid()) {
- navmesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
+ if (navigation_mesh.is_valid()) {
+ navigation_mesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
}
- navmesh = p_navmesh;
+ navigation_mesh = p_navigation_mesh;
- if (navmesh.is_valid()) {
- navmesh->connect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
+ if (navigation_mesh.is_valid()) {
+ navigation_mesh->connect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
}
- NavigationServer3D::get_singleton()->region_set_navmesh(region, p_navmesh);
+ NavigationServer3D::get_singleton()->region_set_navigation_mesh(region, p_navigation_mesh);
#ifdef DEBUG_ENABLED
if (is_inside_tree() && NavigationServer3D::get_singleton()->get_debug_enabled()) {
- if (navmesh.is_valid()) {
+ if (navigation_mesh.is_valid()) {
_update_debug_mesh();
_update_debug_edge_connections_mesh();
} else {
@@ -232,7 +232,7 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes
}
Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const {
- return navmesh;
+ return navigation_mesh;
}
struct BakeThreadsArgs {
@@ -245,7 +245,7 @@ void _bake_navigation_mesh(void *p_user_data) {
if (args->nav_region->get_navigation_mesh().is_valid()) {
Ref<NavigationMesh> nav_mesh = args->nav_region->get_navigation_mesh()->duplicate();
- NavigationServer3D::get_singleton()->region_bake_navmesh(nav_mesh, args->nav_region);
+ NavigationServer3D::get_singleton()->region_bake_navigation_mesh(nav_mesh, args->nav_region);
args->nav_region->call_deferred(SNAME("_bake_finished"), nav_mesh);
memdelete(args);
} else {
@@ -278,7 +278,7 @@ PackedStringArray NavigationRegion3D::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings();
if (is_visible_in_tree() && is_inside_tree()) {
- if (!navmesh.is_valid()) {
+ if (!navigation_mesh.is_valid()) {
warnings.push_back(RTR("A NavigationMesh resource must be set or created for this node to work."));
}
}
@@ -287,7 +287,7 @@ PackedStringArray NavigationRegion3D::get_configuration_warnings() const {
}
void NavigationRegion3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navmesh"), &NavigationRegion3D::set_navigation_mesh);
+ ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navigation_mesh"), &NavigationRegion3D::set_navigation_mesh);
ClassDB::bind_method(D_METHOD("get_navigation_mesh"), &NavigationRegion3D::get_navigation_mesh);
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion3D::set_enabled);
@@ -308,9 +308,9 @@ 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", "nav_mesh"), &NavigationRegion3D::_bake_finished);
+ ClassDB::bind_method(D_METHOD("_bake_finished", "navigation_mesh"), &NavigationRegion3D::_bake_finished);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh");
+ 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");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost");
@@ -320,6 +320,25 @@ void NavigationRegion3D::_bind_methods() {
ADD_SIGNAL(MethodInfo("bake_finished"));
}
+#ifndef DISABLE_DEPRECATED
+// Compatibility with earlier 4.0 betas.
+bool NavigationRegion3D::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "navmesh") {
+ set_navigation_mesh(p_value);
+ return true;
+ }
+ return false;
+}
+
+bool NavigationRegion3D::_get(const StringName &p_name, Variant &r_ret) const {
+ if (p_name == "navmesh") {
+ r_ret = get_navigation_mesh();
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
void NavigationRegion3D::_navigation_changed() {
update_gizmos();
update_configuration_warnings();
@@ -353,15 +372,18 @@ NavigationRegion3D::NavigationRegion3D() {
}
NavigationRegion3D::~NavigationRegion3D() {
- if (navmesh.is_valid()) {
- navmesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
+ if (navigation_mesh.is_valid()) {
+ navigation_mesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
}
+ ERR_FAIL_NULL(NavigationServer3D::get_singleton());
NavigationServer3D::get_singleton()->free(region);
#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton_mut()->disconnect("map_changed", callable_mp(this, &NavigationRegion3D::_navigation_map_changed));
NavigationServer3D::get_singleton_mut()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_mesh));
NavigationServer3D::get_singleton_mut()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_edge_connections_mesh));
+
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
if (debug_instance.is_valid()) {
RenderingServer::get_singleton()->free(debug_instance);
}
@@ -392,7 +414,7 @@ void NavigationRegion3D::_update_debug_mesh() {
return;
}
- if (!navmesh.is_valid()) {
+ if (!navigation_mesh.is_valid()) {
if (debug_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(debug_instance, false);
}
@@ -412,12 +434,12 @@ void NavigationRegion3D::_update_debug_mesh() {
bool enabled_geometry_face_random_color = NavigationServer3D::get_singleton()->get_debug_navigation_enable_geometry_face_random_color();
bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines();
- Vector<Vector3> vertices = navmesh->get_vertices();
+ Vector<Vector3> vertices = navigation_mesh->get_vertices();
if (vertices.size() == 0) {
return;
}
- int polygon_count = navmesh->get_polygon_count();
+ int polygon_count = navigation_mesh->get_polygon_count();
if (polygon_count == 0) {
return;
}
@@ -450,7 +472,7 @@ void NavigationRegion3D::_update_debug_mesh() {
polygon_color.a = debug_navigation_geometry_face_color.a;
}
- Vector<int> polygon = navmesh->get_polygon(i);
+ Vector<int> polygon = navigation_mesh->get_polygon(i);
face_vertex_array.push_back(vertices[polygon[0]]);
face_vertex_array.push_back(vertices[polygon[1]]);
@@ -528,7 +550,7 @@ void NavigationRegion3D::_update_debug_edge_connections_mesh() {
return;
}
- if (!navmesh.is_valid()) {
+ if (!navigation_mesh.is_valid()) {
if (debug_edge_connections_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
}
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index 660538d314..811c0885a1 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -42,7 +42,7 @@ class NavigationRegion3D : public Node3D {
uint32_t navigation_layers = 1;
real_t enter_cost = 0.0;
real_t travel_cost = 1.0;
- Ref<NavigationMesh> navmesh;
+ Ref<NavigationMesh> navigation_mesh;
Thread bake_thread;
@@ -64,6 +64,11 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+#endif // DISABLE_DEPRECATED
+
public:
void set_enabled(bool p_enabled);
bool is_enabled() const;
@@ -82,13 +87,13 @@ public:
void set_travel_cost(real_t p_travel_cost);
real_t get_travel_cost() const;
- void set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh);
+ void set_navigation_mesh(const Ref<NavigationMesh> &p_navigation_mesh);
Ref<NavigationMesh> get_navigation_mesh() const;
/// Bakes the navigation mesh; once done, automatically
/// sets the new navigation mesh and emits a signal
void bake_navigation_mesh(bool p_on_thread);
- void _bake_finished(Ref<NavigationMesh> p_nav_mesh);
+ void _bake_finished(Ref<NavigationMesh> p_navigation_mesh);
PackedStringArray get_configuration_warnings() const override;
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index a60ccd2169..32bbea8ff3 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -251,12 +251,22 @@ Vector3 Node3D::get_global_rotation() const {
return get_global_transform().get_basis().get_euler();
}
+Vector3 Node3D::get_global_rotation_degrees() const {
+ Vector3 radians = get_global_rotation();
+ return Vector3(Math::rad_to_deg(radians.x), Math::rad_to_deg(radians.y), Math::rad_to_deg(radians.z));
+}
+
void Node3D::set_global_rotation(const Vector3 &p_euler_rad) {
Transform3D transform = get_global_transform();
transform.basis = Basis::from_euler(p_euler_rad);
set_global_transform(transform);
}
+void Node3D::set_global_rotation_degrees(const Vector3 &p_euler_degrees) {
+ Vector3 radians(Math::deg_to_rad(p_euler_degrees.x), Math::deg_to_rad(p_euler_degrees.y), Math::deg_to_rad(p_euler_degrees.z));
+ set_global_rotation(radians);
+}
+
void Node3D::set_transform(const Transform3D &p_transform) {
data.local_transform = p_transform;
data.dirty = DIRTY_EULER_ROTATION_AND_SCALE; // Make rot/scale dirty.
@@ -440,6 +450,11 @@ void Node3D::set_rotation(const Vector3 &p_euler_rad) {
}
}
+void Node3D::set_rotation_degrees(const Vector3 &p_euler_degrees) {
+ Vector3 radians(Math::deg_to_rad(p_euler_degrees.x), Math::deg_to_rad(p_euler_degrees.y), Math::deg_to_rad(p_euler_degrees.z));
+ set_rotation(radians);
+}
+
void Node3D::set_scale(const Vector3 &p_scale) {
if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) {
// Update rotation only if rotation and scale are dirty, as scale will be overridden.
@@ -467,6 +482,11 @@ Vector3 Node3D::get_rotation() const {
return data.euler_rotation;
}
+Vector3 Node3D::get_rotation_degrees() const {
+ Vector3 radians = get_rotation();
+ return Vector3(Math::rad_to_deg(radians.x), Math::rad_to_deg(radians.y), Math::rad_to_deg(radians.z));
+}
+
Vector3 Node3D::get_scale() const {
if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) {
_update_rotation_and_scale();
@@ -958,8 +978,10 @@ void Node3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_transform"), &Node3D::get_transform);
ClassDB::bind_method(D_METHOD("set_position", "position"), &Node3D::set_position);
ClassDB::bind_method(D_METHOD("get_position"), &Node3D::get_position);
- ClassDB::bind_method(D_METHOD("set_rotation", "euler"), &Node3D::set_rotation);
+ ClassDB::bind_method(D_METHOD("set_rotation", "euler_radians"), &Node3D::set_rotation);
ClassDB::bind_method(D_METHOD("get_rotation"), &Node3D::get_rotation);
+ ClassDB::bind_method(D_METHOD("set_rotation_degrees", "euler_degrees"), &Node3D::set_rotation_degrees);
+ ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Node3D::get_rotation_degrees);
ClassDB::bind_method(D_METHOD("set_rotation_order", "order"), &Node3D::set_rotation_order);
ClassDB::bind_method(D_METHOD("get_rotation_order"), &Node3D::get_rotation_order);
ClassDB::bind_method(D_METHOD("set_rotation_edit_mode", "edit_mode"), &Node3D::set_rotation_edit_mode);
@@ -975,8 +997,10 @@ void Node3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_global_transform"), &Node3D::get_global_transform);
ClassDB::bind_method(D_METHOD("set_global_position", "position"), &Node3D::set_global_position);
ClassDB::bind_method(D_METHOD("get_global_position"), &Node3D::get_global_position);
- ClassDB::bind_method(D_METHOD("set_global_rotation", "radians"), &Node3D::set_global_rotation);
+ ClassDB::bind_method(D_METHOD("set_global_rotation", "euler_radians"), &Node3D::set_global_rotation);
ClassDB::bind_method(D_METHOD("get_global_rotation"), &Node3D::get_global_rotation);
+ ClassDB::bind_method(D_METHOD("set_global_rotation_degrees", "euler_degrees"), &Node3D::set_global_rotation_degrees);
+ ClassDB::bind_method(D_METHOD("get_global_rotation_degrees"), &Node3D::get_global_rotation_degrees);
ClassDB::bind_method(D_METHOD("get_parent_node_3d"), &Node3D::get_parent_node_3d);
ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Node3D::set_ignore_transform_notification);
@@ -1045,6 +1069,7 @@ void Node3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_less,hide_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_rotation_degrees", "get_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_HIDE_QUATERNION_EDIT, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion");
ADD_PROPERTY(PropertyInfo(Variant::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_LINK, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
@@ -1054,6 +1079,7 @@ void Node3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_position", "get_global_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_rotation", "get_global_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_rotation_degrees", "get_global_rotation_degrees");
ADD_GROUP("Visibility", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "visibility_parent", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GeometryInstance3D"), "set_visibility_parent", "get_visibility_parent");
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index 76c1e3e22c..9558a978fd 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -172,19 +172,23 @@ public:
void set_rotation_order(EulerOrder p_order);
void set_rotation(const Vector3 &p_euler_rad);
+ void set_rotation_degrees(const Vector3 &p_euler_degrees);
void set_scale(const Vector3 &p_scale);
void set_global_position(const Vector3 &p_position);
void set_global_rotation(const Vector3 &p_euler_rad);
+ void set_global_rotation_degrees(const Vector3 &p_euler_degrees);
Vector3 get_position() const;
EulerOrder get_rotation_order() const;
Vector3 get_rotation() const;
+ Vector3 get_rotation_degrees() const;
Vector3 get_scale() const;
Vector3 get_global_position() const;
Vector3 get_global_rotation() const;
+ Vector3 get_global_rotation_degrees() const;
void set_transform(const Transform3D &p_transform);
void set_basis(const Basis &p_basis);
diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
index 4e1ed5654a..7166d99b92 100644
--- a/scene/3d/occluder_instance_3d.cpp
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/core_string_names.h"
+#include "core/io/marshalls.h"
#include "core/math/geometry_2d.h"
#include "core/math/triangulate.h"
#include "scene/3d/importer_mesh_instance_3d.h"
@@ -138,6 +139,7 @@ Occluder3D::Occluder3D() {
Occluder3D::~Occluder3D() {
if (occluder.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(occluder);
}
}
@@ -533,11 +535,20 @@ void OccluderInstance3D::_bake_surface(const Transform3D &p_transform, Array p_s
}
if (!Math::is_zero_approx(p_simplification_dist) && SurfaceTool::simplify_func) {
- float error_scale = SurfaceTool::simplify_scale_func((float *)vertices.ptr(), vertices.size(), sizeof(Vector3));
+ Vector<float> vertices_f32 = vector3_to_float32_array(vertices.ptr(), vertices.size());
+
+ float error_scale = SurfaceTool::simplify_scale_func(vertices_f32.ptr(), vertices.size(), sizeof(float) * 3);
float target_error = p_simplification_dist / error_scale;
float error = -1.0f;
int target_index_count = MIN(indices.size(), 36);
- uint32_t index_count = SurfaceTool::simplify_func((unsigned int *)indices.ptrw(), (unsigned int *)indices.ptr(), indices.size(), (float *)vertices.ptr(), vertices.size(), sizeof(Vector3), target_index_count, target_error, &error);
+
+ uint32_t index_count = SurfaceTool::simplify_func(
+ (unsigned int *)indices.ptrw(),
+ (unsigned int *)indices.ptr(),
+ indices.size(),
+ vertices_f32.ptr(), vertices.size(), sizeof(float) * 3,
+ target_index_count, target_error, &error);
+
indices.resize(index_count);
}
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 02ab297d8e..ea0cfce987 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -40,6 +40,7 @@ Path3D::Path3D() {
}
Path3D::~Path3D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
if (debug_instance.is_valid()) {
RS::get_singleton()->free(debug_instance);
}
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index d29f337fc8..fd0b7912ae 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -1246,6 +1246,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
platform_rid = RID();
platform_object_id = ObjectID();
platform_velocity = Vector3();
+ platform_angular_velocity = Vector3();
platform_ceiling_velocity = Vector3();
floor_normal = Vector3();
wall_normal = Vector3();
@@ -1506,6 +1507,7 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) {
platform_object_id = ObjectID();
floor_normal = Vector3();
platform_velocity = Vector3();
+ platform_angular_velocity = Vector3();
bool first_slide = true;
for (int iteration = 0; iteration < max_slides; ++iteration) {
@@ -1708,6 +1710,7 @@ void CharacterBody3D::_set_platform_data(const PhysicsServer3D::MotionCollision
platform_rid = p_collision.collider;
platform_object_id = p_collision.collider_id;
platform_velocity = p_collision.collider_velocity;
+ platform_angular_velocity = p_collision.collider_angular_velocity;
platform_layer = PhysicsServer3D::get_singleton()->body_get_collision_layer(platform_rid);
}
@@ -1780,6 +1783,10 @@ const Vector3 &CharacterBody3D::get_platform_velocity() const {
return platform_velocity;
}
+const Vector3 &CharacterBody3D::get_platform_angular_velocity() const {
+ return platform_angular_velocity;
+}
+
Vector3 CharacterBody3D::get_linear_velocity() const {
return get_real_velocity();
}
@@ -1932,6 +1939,7 @@ void CharacterBody3D::_notification(int p_what) {
platform_object_id = ObjectID();
motion_results.clear();
platform_velocity = Vector3();
+ platform_angular_velocity = Vector3();
} break;
}
}
@@ -1986,6 +1994,7 @@ void CharacterBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_real_velocity"), &CharacterBody3D::get_real_velocity);
ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &CharacterBody3D::get_floor_angle, DEFVAL(Vector3(0.0, 1.0, 0.0)));
ClassDB::bind_method(D_METHOD("get_platform_velocity"), &CharacterBody3D::get_platform_velocity);
+ ClassDB::bind_method(D_METHOD("get_platform_angular_velocity"), &CharacterBody3D::get_platform_angular_velocity);
ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody3D::get_slide_collision_count);
ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody3D::_get_slide_collision);
ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody3D::_get_last_slide_collision);
@@ -3358,6 +3367,7 @@ PhysicalBone3D::~PhysicalBone3D() {
if (joint_data) {
memdelete(joint_data);
}
+ ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
PhysicsServer3D::get_singleton()->free(joint);
}
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 36b7ce774c..9c5cb48762 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -371,6 +371,7 @@ public:
const Vector3 &get_real_velocity() const;
real_t get_floor_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
const Vector3 &get_platform_velocity() const;
+ const Vector3 &get_platform_angular_velocity() const;
virtual Vector3 get_linear_velocity() const override;
@@ -423,6 +424,7 @@ private:
Vector3 ceiling_normal;
Vector3 last_motion;
Vector3 platform_velocity;
+ Vector3 platform_angular_velocity;
Vector3 platform_ceiling_velocity;
Vector3 previous_position;
Vector3 real_velocity;
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index bc3cc31963..f8164ee1aa 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -257,5 +257,6 @@ ReflectionProbe::ReflectionProbe() {
}
ReflectionProbe::~ReflectionProbe() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(probe);
}
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index b205c2cde0..27310e7cee 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -58,10 +58,10 @@ Ref<Skin> SkinReference::get_skin() const {
}
SkinReference::~SkinReference() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
if (skeleton_node) {
skeleton_node->skin_bindings.erase(this);
}
-
RS::get_singleton()->free(skeleton);
}
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 1814baa9e9..31d3f1aeb7 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -704,6 +704,7 @@ SoftBody3D::SoftBody3D() :
SoftBody3D::~SoftBody3D() {
memdelete(rendering_server_handler);
+ ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
PhysicsServer3D::get_singleton()->free(physics_rid);
}
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index d69953fee5..3629464cd1 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -191,9 +191,7 @@ void SpriteBase3D::draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect,
uint32_t v_normal;
{
- Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
- Vector2 res = n.octahedron_encode();
+ Vector2 res = normal.octahedron_encode();
uint32_t value = 0;
value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
@@ -613,6 +611,7 @@ SpriteBase3D::SpriteBase3D() {
}
SpriteBase3D::~SpriteBase3D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(mesh);
RenderingServer::get_singleton()->free(material);
}
diff --git a/scene/3d/visible_on_screen_notifier_3d.cpp b/scene/3d/visible_on_screen_notifier_3d.cpp
index 6d4c18a69e..70c9321338 100644
--- a/scene/3d/visible_on_screen_notifier_3d.cpp
+++ b/scene/3d/visible_on_screen_notifier_3d.cpp
@@ -99,6 +99,7 @@ VisibleOnScreenNotifier3D::VisibleOnScreenNotifier3D() {
VisibleOnScreenNotifier3D::~VisibleOnScreenNotifier3D() {
RID base_old = get_base();
set_base(RID());
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(base_old);
}
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index b5b37bf837..07ca63dcd6 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -30,6 +30,7 @@
#include "visual_instance_3d.h"
+#include "core/core_string_names.h"
#include "scene/scene_string_names.h"
AABB VisualInstance3D::get_aabb() const {
@@ -101,6 +102,24 @@ bool VisualInstance3D::get_layer_mask_value(int p_layer_number) const {
return layers & (1 << (p_layer_number - 1));
}
+void VisualInstance3D::set_sorting_offset(float p_offset) {
+ sorting_offset = p_offset;
+ RenderingServer::get_singleton()->instance_set_pivot_data(instance, sorting_offset, sorting_use_aabb_center);
+}
+
+float VisualInstance3D::get_sorting_offset() const {
+ return sorting_offset;
+}
+
+void VisualInstance3D::set_sorting_use_aabb_center(bool p_enabled) {
+ sorting_use_aabb_center = p_enabled;
+ RenderingServer::get_singleton()->instance_set_pivot_data(instance, sorting_offset, sorting_use_aabb_center);
+}
+
+bool VisualInstance3D::is_sorting_use_aabb_center() const {
+ return sorting_use_aabb_center;
+}
+
void VisualInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance3D::set_base);
ClassDB::bind_method(D_METHOD("get_base"), &VisualInstance3D::get_base);
@@ -109,9 +128,17 @@ void VisualInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_layer_mask"), &VisualInstance3D::get_layer_mask);
ClassDB::bind_method(D_METHOD("set_layer_mask_value", "layer_number", "value"), &VisualInstance3D::set_layer_mask_value);
ClassDB::bind_method(D_METHOD("get_layer_mask_value", "layer_number"), &VisualInstance3D::get_layer_mask_value);
+ ClassDB::bind_method(D_METHOD("set_sorting_offset", "offset"), &VisualInstance3D::set_sorting_offset);
+ ClassDB::bind_method(D_METHOD("get_sorting_offset"), &VisualInstance3D::get_sorting_offset);
+ ClassDB::bind_method(D_METHOD("set_sorting_use_aabb_center", "enabled"), &VisualInstance3D::set_sorting_use_aabb_center);
+ ClassDB::bind_method(D_METHOD("is_sorting_use_aabb_center"), &VisualInstance3D::is_sorting_use_aabb_center);
GDVIRTUAL_BIND(_get_aabb);
ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_RENDER), "set_layer_mask", "get_layer_mask");
+
+ ADD_GROUP("Sorting", "sorting_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sorting_offset"), "set_sorting_offset", "get_sorting_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sorting_use_aabb_center"), "set_sorting_use_aabb_center", "is_sorting_use_aabb_center");
}
void VisualInstance3D::set_base(const RID &p_base) {
@@ -130,11 +157,18 @@ VisualInstance3D::VisualInstance3D() {
}
VisualInstance3D::~VisualInstance3D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(instance);
}
void GeometryInstance3D::set_material_override(const Ref<Material> &p_material) {
+ if (material_override.is_valid()) {
+ material_override->disconnect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
+ }
material_override = p_material;
+ if (material_override.is_valid()) {
+ material_override->connect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
+ }
RS::get_singleton()->instance_geometry_set_material_override(get_instance(), p_material.is_valid() ? p_material->get_rid() : RID());
}
@@ -331,8 +365,16 @@ Variant GeometryInstance3D::get_instance_shader_parameter(const StringName &p_na
return RS::get_singleton()->instance_geometry_get_shader_parameter(get_instance(), p_name);
}
-void GeometryInstance3D::set_custom_aabb(AABB aabb) {
- RS::get_singleton()->instance_set_custom_aabb(get_instance(), aabb);
+void GeometryInstance3D::set_custom_aabb(AABB p_aabb) {
+ if (p_aabb == custom_aabb) {
+ return;
+ }
+ custom_aabb = p_aabb;
+ RS::get_singleton()->instance_set_custom_aabb(get_instance(), custom_aabb);
+}
+
+AABB GeometryInstance3D::get_custom_aabb() const {
+ return custom_aabb;
}
void GeometryInstance3D::set_lightmap_scale(LightmapScale p_scale) {
@@ -442,6 +484,7 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_ignoring_occlusion_culling"), &GeometryInstance3D::is_ignoring_occlusion_culling);
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance3D::set_custom_aabb);
+ ClassDB::bind_method(D_METHOD("get_custom_aabb"), &GeometryInstance3D::get_custom_aabb);
ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance3D::get_aabb);
@@ -451,6 +494,7 @@ void GeometryInstance3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "transparency", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_transparency", "get_transparency");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01,suffix:m"), "set_extra_cull_margin", "get_extra_cull_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, "suffix:m"), "set_custom_aabb", "get_custom_aabb");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_bias", PROPERTY_HINT_RANGE, "0.001,128,0.001"), "set_lod_bias", "get_lod_bias");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_occlusion_culling"), "set_ignore_occlusion_culling", "is_ignoring_occlusion_culling");
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index f18bff2ddc..2d107f61d2 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -39,6 +39,8 @@ class VisualInstance3D : public Node3D {
RID base;
RID instance;
uint32_t layers = 1;
+ float sorting_offset = 0.0;
+ bool sorting_use_aabb_center = true;
protected:
void _update_visibility();
@@ -67,6 +69,12 @@ public:
void set_layer_mask_value(int p_layer_number, bool p_enable);
bool get_layer_mask_value(int p_layer_number) const;
+ void set_sorting_offset(float p_offset);
+ float get_sorting_offset() const;
+
+ void set_sorting_use_aabb_center(bool p_enabled);
+ bool is_sorting_use_aabb_center() const;
+
VisualInstance3D();
~VisualInstance3D();
};
@@ -121,6 +129,7 @@ private:
mutable HashMap<StringName, StringName> instance_shader_parameter_property_remap;
float extra_cull_margin = 0.0;
+ AABB custom_aabb;
LightmapScale lightmap_scale = LIGHTMAP_SCALE_1X;
GIMode gi_mode = GI_MODE_STATIC;
bool ignore_occlusion_culling = false;
@@ -177,7 +186,8 @@ public:
void set_instance_shader_parameter(const StringName &p_name, const Variant &p_value);
Variant get_instance_shader_parameter(const StringName &p_name) const;
- void set_custom_aabb(AABB aabb);
+ void set_custom_aabb(AABB p_aabb);
+ AABB get_custom_aabb() const;
void set_ignore_occlusion_culling(bool p_enabled);
bool is_ignoring_occlusion_culling();
diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp
index 7caf2f4874..2cb15715c6 100644
--- a/scene/3d/voxel_gi.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -242,6 +242,7 @@ VoxelGIData::VoxelGIData() {
}
VoxelGIData::~VoxelGIData() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(probe);
}
@@ -516,5 +517,6 @@ VoxelGI::VoxelGI() {
}
VoxelGI::~VoxelGI() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(voxel_gi);
}
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 6200062f60..26261d6da5 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -144,6 +144,19 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_is_ext
}
}
}
+
+ // Emit start & finish signal. Internally, the detections are the same for backward.
+ // We should use call_deferred since the track keys are still being prosessed.
+ if (state->tree) {
+ // AnimationTree uses seek to 0 "internally" to process the first key of the animation, which is used as the start detection.
+ if (p_seek && !p_is_external_seeking && cur_time == 0) {
+ state->tree->call_deferred(SNAME("emit_signal"), "animation_started", animation);
+ }
+ // Finished.
+ if (prev_time < anim_size && cur_time >= anim_size) {
+ state->tree->call_deferred(SNAME("emit_signal"), "animation_finished", animation);
+ }
+ }
}
if (play_mode == PLAY_MODE_FORWARD) {
@@ -351,7 +364,7 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_exter
} else {
main_rem = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - blend, FILTER_BLEND, sync); // Unlike below, processing this edge is a corner case.
}
- double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_is_external_seeking, MAX(CMP_EPSILON, blend), FILTER_PASS, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
+ double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_PASS, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
if (do_start) {
cur_remaining = os_rem;
@@ -769,17 +782,18 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
}
// Blend values must be more than CMP_EPSILON to process discrete keys in edge.
+ real_t blend_inv = 1.0 - blend;
if (from_start && !p_seek && switched) { //just switched, seek to start of current
- rem = blend_input(cur_current, 0, true, p_is_external_seeking, MAX(CMP_EPSILON, 1.0 - blend), FILTER_IGNORE, true);
+ rem = blend_input(cur_current, 0, true, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
} else {
- rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, MAX(CMP_EPSILON, 1.0 - blend), FILTER_IGNORE, true);
+ rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
}
if (p_seek) {
- blend_input(cur_prev, p_time, true, p_is_external_seeking, MAX(CMP_EPSILON, blend), FILTER_IGNORE, true);
+ blend_input(cur_prev, p_time, true, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
cur_time = p_time;
} else {
- blend_input(cur_prev, p_time, false, p_is_external_seeking, MAX(CMP_EPSILON, blend), FILTER_IGNORE, true);
+ blend_input(cur_prev, p_time, false, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
cur_time += p_time;
cur_prev_xfading -= p_time;
if (cur_prev_xfading < 0) {
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index d3746c1144..4c677b6a9f 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -41,12 +41,12 @@ AnimationNodeStateMachineTransition::SwitchMode AnimationNodeStateMachineTransit
return switch_mode;
}
-void AnimationNodeStateMachineTransition::set_auto_advance(bool p_enable) {
- auto_advance = p_enable;
+void AnimationNodeStateMachineTransition::set_advance_mode(AdvanceMode p_mode) {
+ advance_mode = p_mode;
}
-bool AnimationNodeStateMachineTransition::has_auto_advance() const {
- return auto_advance;
+AnimationNodeStateMachineTransition::AdvanceMode AnimationNodeStateMachineTransition::get_advance_mode() const {
+ return advance_mode;
}
void AnimationNodeStateMachineTransition::set_advance_condition(const StringName &p_condition) {
@@ -107,15 +107,6 @@ Ref<Curve> AnimationNodeStateMachineTransition::get_xfade_curve() const {
return xfade_curve;
}
-void AnimationNodeStateMachineTransition::set_disabled(bool p_disabled) {
- disabled = p_disabled;
- emit_changed();
-}
-
-bool AnimationNodeStateMachineTransition::is_disabled() const {
- return disabled;
-}
-
void AnimationNodeStateMachineTransition::set_priority(int p_priority) {
priority = p_priority;
emit_changed();
@@ -129,8 +120,8 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_switch_mode", "mode"), &AnimationNodeStateMachineTransition::set_switch_mode);
ClassDB::bind_method(D_METHOD("get_switch_mode"), &AnimationNodeStateMachineTransition::get_switch_mode);
- ClassDB::bind_method(D_METHOD("set_auto_advance", "auto_advance"), &AnimationNodeStateMachineTransition::set_auto_advance);
- ClassDB::bind_method(D_METHOD("has_auto_advance"), &AnimationNodeStateMachineTransition::has_auto_advance);
+ ClassDB::bind_method(D_METHOD("set_advance_mode", "mode"), &AnimationNodeStateMachineTransition::set_advance_mode);
+ ClassDB::bind_method(D_METHOD("get_advance_mode"), &AnimationNodeStateMachineTransition::get_advance_mode);
ClassDB::bind_method(D_METHOD("set_advance_condition", "name"), &AnimationNodeStateMachineTransition::set_advance_condition);
ClassDB::bind_method(D_METHOD("get_advance_condition"), &AnimationNodeStateMachineTransition::get_advance_condition);
@@ -141,9 +132,6 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeStateMachineTransition::set_xfade_curve);
ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeStateMachineTransition::get_xfade_curve);
- ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &AnimationNodeStateMachineTransition::set_disabled);
- ClassDB::bind_method(D_METHOD("is_disabled"), &AnimationNodeStateMachineTransition::is_disabled);
-
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &AnimationNodeStateMachineTransition::set_priority);
ClassDB::bind_method(D_METHOD("get_priority"), &AnimationNodeStateMachineTransition::get_priority);
@@ -155,17 +143,19 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority");
ADD_GROUP("Switch", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,At End"), "set_switch_mode", "get_switch_mode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_advance"), "set_auto_advance", "has_auto_advance");
ADD_GROUP("Advance", "advance_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "advance_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Auto"), "set_advance_mode", "get_advance_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "advance_condition"), "set_advance_condition", "get_advance_condition");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "advance_expression", PROPERTY_HINT_EXPRESSION, ""), "set_advance_expression", "get_advance_expression");
- ADD_GROUP("Disabling", "");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
BIND_ENUM_CONSTANT(SWITCH_MODE_IMMEDIATE);
BIND_ENUM_CONSTANT(SWITCH_MODE_SYNC);
BIND_ENUM_CONSTANT(SWITCH_MODE_AT_END);
+ BIND_ENUM_CONSTANT(ADVANCE_MODE_DISABLED);
+ BIND_ENUM_CONSTANT(ADVANCE_MODE_ENABLED);
+ BIND_ENUM_CONSTANT(ADVANCE_MODE_AUTO);
+
ADD_SIGNAL(MethodInfo("advance_condition_changed"));
}
@@ -234,7 +224,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
//build open list
for (int i = 0; i < p_state_machine->transitions.size(); i++) {
- if (p_state_machine->transitions[i].transition->is_disabled()) {
+ if (p_state_machine->transitions[i].transition->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED) {
continue;
}
@@ -279,7 +269,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
StringName transition = p_state_machine->transitions[least_cost_transition->get()].local_to;
for (int i = 0; i < p_state_machine->transitions.size(); i++) {
- if (p_state_machine->transitions[i].transition->is_disabled()) {
+ if (p_state_machine->transitions[i].transition->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED) {
continue;
}
@@ -379,6 +369,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
// can't travel, then teleport
path.clear();
current = start_request;
+ play_start = true;
}
start_request = StringName(); //clear start request
}
@@ -424,19 +415,20 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
fading_pos += p_time;
}
fade_blend = MIN(1.0, fading_pos / fading_time);
- if (fade_blend >= 1.0) {
- fading_from = StringName();
- }
}
}
if (current_curve.is_valid()) {
fade_blend = current_curve->sample(fade_blend);
}
- float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, MAX(CMP_EPSILON, fade_blend), AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
+ double rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
if (fading_from != StringName()) {
- p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, MAX(CMP_EPSILON, 1.0 - fade_blend), AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
+ double fade_blend_inv = 1.0 - fade_blend;
+ p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend_inv) ? CMP_EPSILON : fade_blend_inv, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
+ if (fade_blend >= 1.0) {
+ fading_from = StringName();
+ }
}
//guess playback position
@@ -445,19 +437,19 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
}
{ //advance and loop check
- float next_pos = len_current - rem;
+ double next_pos = len_current - rem;
end_loop = next_pos < pos_current;
pos_current = next_pos; //looped
}
//find next
StringName next;
- float next_xfade = 0.0;
+ double next_xfade = 0.0;
AnimationNodeStateMachineTransition::SwitchMode switch_mode = AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE;
if (path.size()) {
for (int i = 0; i < p_state_machine->transitions.size(); i++) {
- if (p_state_machine->transitions[i].transition->is_disabled()) {
+ if (p_state_machine->transitions[i].transition->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED) {
continue;
}
@@ -473,7 +465,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
int auto_advance_to = -1;
for (int i = 0; i < p_state_machine->transitions.size(); i++) {
- if (p_state_machine->transitions[i].transition->is_disabled()) {
+ if (p_state_machine->transitions[i].transition->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED) {
continue;
}
@@ -541,7 +533,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
int auto_advance_to = -1;
for (int i = 0; i < prev_state_machine->transitions.size(); i++) {
- if (prev_state_machine->transitions[i].transition->is_disabled()) {
+ if (prev_state_machine->transitions[i].transition->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED) {
continue;
}
@@ -628,14 +620,14 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
}
bool AnimationNodeStateMachinePlayback::_check_advance_condition(const Ref<AnimationNodeStateMachine> state_machine, const Ref<AnimationNodeStateMachineTransition> transition) const {
- if (transition->has_auto_advance()) {
- return true;
+ if (transition->get_advance_mode() != AnimationNodeStateMachineTransition::ADVANCE_MODE_AUTO) {
+ return false;
}
StringName advance_condition_name = transition->get_advance_condition_name();
- if (advance_condition_name != StringName() && bool(state_machine->get_parameter(advance_condition_name))) {
- return true;
+ if (advance_condition_name != StringName() && !bool(state_machine->get_parameter(advance_condition_name))) {
+ return false;
}
if (transition->expression.is_valid()) {
@@ -645,20 +637,18 @@ bool AnimationNodeStateMachinePlayback::_check_advance_condition(const Ref<Anima
NodePath advance_expression_base_node_path = tree_base->get_advance_expression_base_node();
Node *expression_base = tree_base->get_node_or_null(advance_expression_base_node_path);
- WARN_PRINT_ONCE("Animation transition has a valid expression, but no expression base node was set on its AnimationTree.");
-
if (expression_base) {
Ref<Expression> exp = transition->expression;
bool ret = exp->execute(Array(), expression_base, false, Engine::get_singleton()->is_editor_hint()); // Avoids allowing the user to crash the system with an expression by only allowing const calls.
- if (!exp->has_execute_failed()) {
- if (ret) {
- return true;
- }
+ if (exp->has_execute_failed() || !ret) {
+ return false;
}
+ } else {
+ WARN_PRINT_ONCE("Animation transition has a valid expression, but no expression base node was set on its AnimationTree.");
}
}
- return false;
+ return true;
}
void AnimationNodeStateMachinePlayback::_bind_methods() {
@@ -834,7 +824,8 @@ void AnimationNodeStateMachine::rename_node(const StringName &p_name, const Stri
_rename_transitions(p_name, p_new_name);
- emit_signal("tree_changed");
+ emit_changed();
+ emit_signal(SNAME("tree_changed"));
}
void AnimationNodeStateMachine::_rename_transitions(const StringName &p_name, const StringName &p_new_name) {
@@ -877,9 +868,8 @@ void AnimationNodeStateMachine::_rename_transitions(const StringName &p_name, co
transitions.write[i].to = p_new_name;
}
-
- updating_transitions = false;
}
+ updating_transitions = false;
}
void AnimationNodeStateMachine::get_node_list(List<StringName> *r_nodes) const {
@@ -1291,6 +1281,7 @@ Vector2 AnimationNodeStateMachine::get_node_position(const StringName &p_name) c
}
void AnimationNodeStateMachine::_tree_changed() {
+ emit_changed();
emit_signal(SNAME("tree_changed"));
}
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index 0dfe5a3a43..83b5e66491 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -44,14 +44,19 @@ public:
SWITCH_MODE_AT_END,
};
+ enum AdvanceMode {
+ ADVANCE_MODE_DISABLED,
+ ADVANCE_MODE_ENABLED,
+ ADVANCE_MODE_AUTO,
+ };
+
private:
SwitchMode switch_mode = SWITCH_MODE_IMMEDIATE;
- bool auto_advance = false;
+ AdvanceMode advance_mode = ADVANCE_MODE_ENABLED;
StringName advance_condition;
StringName advance_condition_name;
float xfade_time = 0.0;
Ref<Curve> xfade_curve;
- bool disabled = false;
int priority = 1;
String advance_expression;
@@ -65,8 +70,8 @@ public:
void set_switch_mode(SwitchMode p_mode);
SwitchMode get_switch_mode() const;
- void set_auto_advance(bool p_enable);
- bool has_auto_advance() const;
+ void set_advance_mode(AdvanceMode p_mode);
+ AdvanceMode get_advance_mode() const;
void set_advance_condition(const StringName &p_condition);
StringName get_advance_condition() const;
@@ -82,9 +87,6 @@ public:
void set_xfade_curve(const Ref<Curve> &p_curve);
Ref<Curve> get_xfade_curve() const;
- void set_disabled(bool p_disabled);
- bool is_disabled() const;
-
void set_priority(int p_priority);
int get_priority() const;
@@ -92,6 +94,7 @@ public:
};
VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::SwitchMode)
+VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::AdvanceMode)
class AnimationNodeStateMachine;
@@ -111,8 +114,8 @@ class AnimationNodeStateMachinePlayback : public Resource {
StringName next;
};
- float len_current = 0.0;
- float pos_current = 0.0;
+ double len_current = 0.0;
+ double pos_current = 0.0;
bool end_loop = false;
StringName current;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index cc6fadd9b2..ff20724f89 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -691,7 +691,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
}
} else {
if (p_started) {
- int first_key = a->track_find_key(i, p_prev_time, true);
+ int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
if (first_key >= 0) {
indices.push_back(first_key);
}
@@ -761,7 +761,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
}
} else {
if (p_started) {
- int first_key = a->track_find_key(i, p_prev_time, true);
+ int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
if (first_key >= 0) {
indices.push_back(first_key);
}
@@ -855,7 +855,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
//find stuff to play
List<int> to_play;
if (p_started) {
- int first_key = a->track_find_key(i, p_prev_time, true);
+ int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
if (first_key >= 0) {
to_play.push_back(first_key);
}
@@ -968,7 +968,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
//find stuff to play
List<int> to_play;
if (p_started) {
- int first_key = a->track_find_key(i, p_prev_time, true);
+ int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
if (first_key >= 0) {
to_play.push_back(first_key);
}
@@ -1072,25 +1072,34 @@ void AnimationPlayer::_animation_process2(double p_delta, bool p_started) {
accum_pass++;
bool seeked = c.seeked; // The animation may be changed during process, so it is safer that the state is changed before process.
+
if (p_delta != 0) {
c.seeked = false;
}
- _animation_process_data(c.current, p_delta, 1.0f, seeked, p_started);
+ float blend = 1.0; // First animation we play at 100% blend
- List<Blend>::Element *prev = nullptr;
- for (List<Blend>::Element *E = c.blend.back(); E; E = prev) {
+ List<Blend>::Element *next = NULL;
+ for (List<Blend>::Element *E = c.blend.front(); E; E = next) {
Blend &b = E->get();
- float blend = b.blend_left / b.blend_time;
+ // Note: There may be issues if an animation event triggers an animation change while this blend is active,
+ // so it is best to use "deferred" calls instead of "immediate" for animation events that can trigger new animations.
+ _animation_process_data(b.data, p_delta, blend, false, false);
+ blend = 1.0 - b.blend_left / b.blend_time; // This is how much to blend the NEXT animation
b.blend_left -= Math::absf(speed_scale * p_delta);
- prev = E->prev();
+ next = E->next();
if (b.blend_left < 0) {
- c.blend.erase(E);
+ // If the blend of this has finished, we need to remove ALL the previous blends
+ List<Blend>::Element *prev;
+ while (E) {
+ prev = E->prev();
+ c.blend.erase(E);
+ E = prev;
+ }
}
- // The effect of animation changes during blending is unknown...
- // In that case, we recommends to use method call mode "deferred", not "immediate".
- _animation_process_data(b.data, p_delta, blend, false, false);
}
+
+ _animation_process_data(c.current, p_delta, blend, seeked, p_started);
}
void AnimationPlayer::_animation_update_transforms() {
@@ -1643,6 +1652,8 @@ void AnimationPlayer::play(const StringName &p_name, double p_custom_blend, floa
b.data = c.current;
b.blend_time = b.blend_left = blend_time;
c.blend.push_back(b);
+ } else {
+ c.blend.clear();
}
}
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index b06a21dea9..b3408c1509 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -432,7 +432,6 @@ void AnimationNode::_bind_methods() {
GDVIRTUAL_BIND(_has_filter);
ADD_SIGNAL(MethodInfo("removed_from_graph"));
-
ADD_SIGNAL(MethodInfo("tree_changed"));
BIND_ENUM_CONSTANT(FILTER_IGNORE);
@@ -1383,7 +1382,7 @@ void AnimationTree::_process_graph(double p_delta) {
}
} else {
if (seeked) {
- int idx = a->track_find_key(i, time, !is_external_seeking);
+ int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT);
if (idx < 0) {
continue;
}
@@ -1406,7 +1405,7 @@ void AnimationTree::_process_graph(double p_delta) {
TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track);
if (seeked) {
- int idx = a->track_find_key(i, time, !is_external_seeking);
+ int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT);
if (idx < 0) {
continue;
}
@@ -1440,7 +1439,7 @@ void AnimationTree::_process_graph(double p_delta) {
if (seeked) {
//find whatever should be playing
- int idx = a->track_find_key(i, time, !is_external_seeking);
+ int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT);
if (idx < 0) {
continue;
}
@@ -1553,7 +1552,7 @@ void AnimationTree::_process_graph(double p_delta) {
if (seeked) {
//seek
- int idx = a->track_find_key(i, time, !is_external_seeking);
+ int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT);
if (idx < 0) {
continue;
}
@@ -2037,6 +2036,10 @@ void AnimationTree::_bind_methods() {
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL);
ADD_SIGNAL(MethodInfo("animation_player_changed"));
+
+ // Signals from AnimationNodes.
+ ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING_NAME, "anim_name")));
+ ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING_NAME, "anim_name")));
}
AnimationTree::AnimationTree() {
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index ac9034c6fd..9da1fbda1b 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -300,6 +300,7 @@ void BaseButton::set_toggle_mode(bool p_on) {
}
toggle_mode = p_on;
+ update_configuration_warnings();
}
bool BaseButton::is_toggle_mode() const {
@@ -381,6 +382,7 @@ void BaseButton::set_button_group(const Ref<ButtonGroup> &p_group) {
}
queue_redraw(); //checkbox changes to radio if set a buttongroup
+ update_configuration_warnings();
}
Ref<ButtonGroup> BaseButton::get_button_group() const {
@@ -399,6 +401,16 @@ bool BaseButton::is_shortcut_feedback() const {
return shortcut_feedback;
}
+PackedStringArray BaseButton::get_configuration_warnings() const {
+ PackedStringArray warnings = Control::get_configuration_warnings();
+
+ if (get_button_group().is_valid() && !is_toggle_mode()) {
+ warnings.push_back(RTR("ButtonGroup is intended to be used only with buttons that have toggle_mode set to true."));
+ }
+
+ return warnings;
+}
+
void BaseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &BaseButton::set_pressed);
ClassDB::bind_method(D_METHOD("is_pressed"), &BaseButton::is_pressed);
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index 3acf535f54..5018aea120 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -136,6 +136,8 @@ public:
void set_shortcut_feedback(bool p_feedback);
bool is_shortcut_feedback() const;
+ PackedStringArray get_configuration_warnings() const override;
+
BaseButton();
~BaseButton();
};
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index f46daef127..c84438ed5e 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -115,7 +115,9 @@ void CodeEdit::_notification(int p_what) {
const Point2 caret_pos = get_caret_draw_pos();
const int total_height = csb->get_minimum_size().y + code_completion_rect.size.height;
- if (caret_pos.y + row_height + total_height > get_size().height) {
+ const bool can_fit_completion_above = (caret_pos.y - row_height > total_height);
+ const bool can_fit_completion_below = (caret_pos.y + row_height + total_height <= get_size().height);
+ if (!can_fit_completion_below && can_fit_completion_above) {
code_completion_rect.position.y = (caret_pos.y - total_height - row_height) + line_spacing;
} else {
code_completion_rect.position.y = caret_pos.y + (line_spacing / 2.0f);
@@ -2079,20 +2081,22 @@ void CodeEdit::confirm_code_completion(bool p_replace) {
}
char32_t last_completion_char_display = display_text[display_text.length() - 1];
+ bool last_char_matches = (last_completion_char == next_char || last_completion_char_display == next_char);
int pre_brace_pair = get_caret_column(i) > 0 ? _get_auto_brace_pair_open_at_pos(caret_line, get_caret_column(i)) : -1;
int post_brace_pair = get_caret_column(i) < get_line(caret_line).length() ? _get_auto_brace_pair_close_at_pos(caret_line, get_caret_column(i)) : -1;
- if (post_brace_pair != -1 && (last_completion_char == next_char || last_completion_char_display == next_char)) {
+ // Strings do not nest like brackets, so ensure we don't add an additional closing pair.
+ if (has_string_delimiter(String::chr(last_completion_char)) && post_brace_pair != -1 && last_char_matches) {
remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
- }
-
- if (pre_brace_pair != -1 && pre_brace_pair != post_brace_pair && (last_completion_char == next_char || last_completion_char_display == next_char)) {
- remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
- adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
- } else if (auto_brace_completion_enabled && pre_brace_pair != -1 && post_brace_pair == -1) {
- insert_text_at_caret(auto_brace_completion_pairs[pre_brace_pair].close_key, i);
- set_caret_column(get_caret_column(i) - auto_brace_completion_pairs[pre_brace_pair].close_key.length(), i == 0, i);
+ } else {
+ if (pre_brace_pair != -1 && pre_brace_pair != post_brace_pair && last_char_matches) {
+ remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
+ adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
+ } else if (auto_brace_completion_enabled && pre_brace_pair != -1) {
+ insert_text_at_caret(auto_brace_completion_pairs[pre_brace_pair].close_key, i);
+ set_caret_column(get_caret_column(i) - auto_brace_completion_pairs[pre_brace_pair].close_key.length(), i == 0, i);
+ }
}
if (pre_brace_pair == -1 && post_brace_pair == -1 && get_caret_column(i) > 0 && get_caret_column(i) < get_line(caret_line).length()) {
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index eb9f9039b7..fa4b57d7a7 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -1577,8 +1577,7 @@ void ColorPicker::_bind_methods() {
BIND_ENUM_CONSTANT(SHAPE_NONE);
}
-ColorPicker::ColorPicker() :
- BoxContainer(true) {
+ColorPicker::ColorPicker() {
HBoxContainer *hb_edit = memnew(HBoxContainer);
add_child(hb_edit, false, INTERNAL_MODE_FRONT);
hb_edit->set_v_size_flags(SIZE_SHRINK_BEGIN);
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 3208676539..799ca2d202 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -68,8 +68,8 @@ public:
~ColorPresetButton();
};
-class ColorPicker : public BoxContainer {
- GDCLASS(ColorPicker, BoxContainer);
+class ColorPicker : public VBoxContainer {
+ GDCLASS(ColorPicker, VBoxContainer);
public:
enum ColorModeType {
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 68af7af5d4..21c7c4ddb4 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -1475,10 +1475,18 @@ void Control::set_rotation(real_t p_radians) {
_notify_transform();
}
+void Control::set_rotation_degrees(real_t p_degrees) {
+ set_rotation(Math::deg_to_rad(p_degrees));
+}
+
real_t Control::get_rotation() const {
return data.rotation;
}
+real_t Control::get_rotation_degrees() const {
+ return Math::rad_to_deg(get_rotation());
+}
+
void Control::set_pivot_offset(const Vector2 &p_pivot) {
if (data.pivot_offset == p_pivot) {
return;
@@ -3042,6 +3050,7 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_global_position", "position", "keep_offsets"), &Control::set_global_position, DEFVAL(false));
ClassDB::bind_method(D_METHOD("_set_global_position", "position"), &Control::_set_global_position);
ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Control::set_rotation);
+ ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &Control::set_rotation_degrees);
ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Control::set_scale);
ClassDB::bind_method(D_METHOD("set_pivot_offset", "pivot_offset"), &Control::set_pivot_offset);
ClassDB::bind_method(D_METHOD("get_begin"), &Control::get_begin);
@@ -3049,6 +3058,7 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_position"), &Control::get_position);
ClassDB::bind_method(D_METHOD("get_size"), &Control::get_size);
ClassDB::bind_method(D_METHOD("get_rotation"), &Control::get_rotation);
+ ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Control::get_rotation_degrees);
ClassDB::bind_method(D_METHOD("get_scale"), &Control::get_scale);
ClassDB::bind_method(D_METHOD("get_pivot_offset"), &Control::get_pivot_offset);
ClassDB::bind_method(D_METHOD("get_custom_minimum_size"), &Control::get_custom_minimum_size);
@@ -3217,6 +3227,7 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "_set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "_set_global_position", "get_global_position");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_rotation_degrees", "get_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "pivot_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_pivot_offset", "get_pivot_offset");
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 12710f3a93..f82fba3b1b 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -451,7 +451,9 @@ public:
void set_scale(const Vector2 &p_scale);
Vector2 get_scale() const;
void set_rotation(real_t p_radians);
+ void set_rotation_degrees(real_t p_degrees);
real_t get_rotation() const;
+ real_t get_rotation_degrees() const;
void set_pivot_offset(const Vector2 &p_pivot);
Vector2 get_pivot_offset() const;
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 11a3803b35..a846ab9485 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -411,7 +411,7 @@ void FileDialog::_go_back() {
}
void FileDialog::_go_forward() {
- if (local_history_pos == local_history.size() - 1) {
+ if (local_history_pos >= local_history.size() - 1) {
return;
}
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index bd39ee3bb3..b8e2c76413 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -822,7 +822,7 @@ void LineEdit::_notification(int p_what) {
case HORIZONTAL_ALIGNMENT_FILL:
case HORIZONTAL_ALIGNMENT_LEFT: {
if (rtl) {
- x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - style->get_margin(SIDE_RIGHT) - (text_width)));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - Math::ceil(style->get_margin(SIDE_RIGHT) + (text_width))));
} else {
x_ofs = style->get_offset().x;
}
@@ -838,7 +838,7 @@ void LineEdit::_notification(int p_what) {
if (rtl) {
x_ofs = style->get_offset().x;
} else {
- x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - style->get_margin(SIDE_RIGHT) - (text_width)));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - Math::ceil(style->get_margin(SIDE_RIGHT) + (text_width))));
}
} break;
}
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index 7219e86f52..2c43ca7143 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -108,6 +108,14 @@ String LinkButton::get_language() const {
return language;
}
+void LinkButton::set_uri(const String &p_uri) {
+ uri = p_uri;
+}
+
+String LinkButton::get_uri() const {
+ return uri;
+}
+
void LinkButton::set_underline_mode(UnderlineMode p_underline_mode) {
if (underline_mode == p_underline_mode) {
return;
@@ -121,6 +129,14 @@ LinkButton::UnderlineMode LinkButton::get_underline_mode() const {
return underline_mode;
}
+void LinkButton::pressed() {
+ if (uri.is_empty()) {
+ return;
+ }
+
+ OS::get_singleton()->shell_open(uri);
+}
+
Size2 LinkButton::get_minimum_size() const {
return text_buf->get_size();
}
@@ -245,6 +261,8 @@ void LinkButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_text_direction"), &LinkButton::get_text_direction);
ClassDB::bind_method(D_METHOD("set_language", "language"), &LinkButton::set_language);
ClassDB::bind_method(D_METHOD("get_language"), &LinkButton::get_language);
+ ClassDB::bind_method(D_METHOD("set_uri", "uri"), &LinkButton::set_uri);
+ ClassDB::bind_method(D_METHOD("get_uri"), &LinkButton::get_uri);
ClassDB::bind_method(D_METHOD("set_underline_mode", "underline_mode"), &LinkButton::set_underline_mode);
ClassDB::bind_method(D_METHOD("get_underline_mode"), &LinkButton::get_underline_mode);
ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override", "parser"), &LinkButton::set_structured_text_bidi_override);
@@ -258,6 +276,7 @@ void LinkButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
ADD_PROPERTY(PropertyInfo(Variant::INT, "underline", PROPERTY_HINT_ENUM, "Always,On Hover,Never"), "set_underline_mode", "get_underline_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "uri"), "set_uri", "get_uri");
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h
index accd848163..c71872fc86 100644
--- a/scene/gui/link_button.h
+++ b/scene/gui/link_button.h
@@ -49,6 +49,7 @@ private:
String xl_text;
Ref<TextLine> text_buf;
UnderlineMode underline_mode = UNDERLINE_MODE_ALWAYS;
+ String uri;
String language;
TextDirection text_direction = TEXT_DIRECTION_AUTO;
@@ -76,6 +77,7 @@ private:
void _shape();
protected:
+ virtual void pressed() override;
virtual Size2 get_minimum_size() const override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
@@ -84,6 +86,8 @@ protected:
public:
void set_text(const String &p_text);
String get_text() const;
+ void set_uri(const String &p_uri);
+ String get_uri() const;
void set_structured_text_bidi_override(TextServer::StructuredTextParser p_parser);
TextServer::StructuredTextParser get_structured_text_bidi_override() const;
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index 82ef53e317..3c404c65b5 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -345,6 +345,7 @@ void MenuBar::_notification(int p_what) {
} break;
case NOTIFICATION_MOUSE_EXIT: {
focused_menu = -1;
+ selected_menu = -1;
queue_redraw();
} break;
case NOTIFICATION_TRANSLATION_CHANGED:
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index d9f76a6fa6..d5c4fd3f07 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -330,7 +330,11 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
if (table->columns[i].expand && total_ratio > 0 && remaining_width > 0) {
table->columns[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
}
- table->total_width += table->columns[i].width + theme_cache.table_h_separation;
+ if (i != col_count - 1) {
+ table->total_width += table->columns[i].width + theme_cache.table_h_separation;
+ } else {
+ table->total_width += table->columns[i].width;
+ }
}
// Resize to max_width if needed and distribute the remaining space.
@@ -371,6 +375,7 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
idx = 0;
table->total_height = 0;
table->rows.clear();
+ table->rows_baseline.clear();
Vector2 offset;
float row_height = 0.0;
@@ -384,13 +389,13 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
offset.x += frame->padding.position.x;
float yofs = frame->padding.position.y;
float prev_h = 0;
+ float row_baseline = 0.0;
for (int i = 0; i < (int)frame->lines.size(); i++) {
MutexLock sub_lock(frame->lines[i].text_buf->get_mutex());
frame->lines[i].text_buf->set_width(table->columns[column].width);
table->columns[column].width = MAX(table->columns[column].width, ceil(frame->lines[i].text_buf->get_size().x));
frame->lines[i].offset.y = prev_h;
- frame->lines[i].offset += offset;
float h = frame->lines[i].text_buf->get_size().y + (frame->lines[i].text_buf->get_line_count() - 1) * theme_cache.line_separation;
if (i > 0) {
@@ -404,6 +409,9 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
}
yofs += h;
prev_h = frame->lines[i].offset.y + frame->lines[i].text_buf->get_size().y + frame->lines[i].text_buf->get_line_count() * theme_cache.line_separation;
+
+ frame->lines[i].offset += offset;
+ row_baseline = MAX(row_baseline, frame->lines[i].text_buf->get_line_ascent(frame->lines[i].text_buf->get_line_count() - 1));
}
yofs += frame->padding.size.y;
offset.x += table->columns[column].width + theme_cache.table_h_separation + frame->padding.size.x;
@@ -415,11 +423,17 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
table->total_height += row_height;
offset.y += row_height;
table->rows.push_back(row_height);
+ table->rows_baseline.push_back(table->total_height - row_height + row_baseline);
row_height = 0;
}
idx++;
}
- l.text_buf->resize_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align);
+ int row_idx = (table->align_to_row < 0) ? table->rows_baseline.size() - 1 : table->align_to_row;
+ if (table->rows_baseline.size() != 0 && row_idx < (int)table->rows_baseline.size() - 1) {
+ l.text_buf->resize_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align, Math::round(table->rows_baseline[row_idx]));
+ } else {
+ l.text_buf->resize_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align);
+ }
} break;
default:
break;
@@ -605,7 +619,11 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
if (table->columns[i].expand && total_ratio > 0 && remaining_width > 0) {
table->columns[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
}
- table->total_width += table->columns[i].width + theme_cache.table_h_separation;
+ if (i != col_count - 1) {
+ table->total_width += table->columns[i].width + theme_cache.table_h_separation;
+ } else {
+ table->total_width += table->columns[i].width;
+ }
}
// Resize to max_width if needed and distribute the remaining space.
@@ -646,6 +664,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
idx = 0;
table->total_height = 0;
table->rows.clear();
+ table->rows_baseline.clear();
Vector2 offset;
float row_height = 0.0;
@@ -659,6 +678,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
offset.x += frame->padding.position.x;
float yofs = frame->padding.position.y;
float prev_h = 0;
+ float row_baseline = 0.0;
for (int i = 0; i < (int)frame->lines.size(); i++) {
MutexLock sub_lock(frame->lines[i].text_buf->get_mutex());
@@ -666,7 +686,6 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
table->columns[column].width = MAX(table->columns[column].width, ceil(frame->lines[i].text_buf->get_size().x));
frame->lines[i].offset.y = prev_h;
- frame->lines[i].offset += offset;
float h = frame->lines[i].text_buf->get_size().y + (frame->lines[i].text_buf->get_line_count() - 1) * theme_cache.line_separation;
if (i > 0) {
@@ -680,6 +699,9 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
}
yofs += h;
prev_h = frame->lines[i].offset.y + frame->lines[i].text_buf->get_size().y + frame->lines[i].text_buf->get_line_count() * theme_cache.line_separation;
+
+ frame->lines[i].offset += offset;
+ row_baseline = MAX(row_baseline, frame->lines[i].text_buf->get_line_ascent(frame->lines[i].text_buf->get_line_count() - 1));
}
yofs += frame->padding.size.y;
offset.x += table->columns[column].width + theme_cache.table_h_separation + frame->padding.size.x;
@@ -692,12 +714,17 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
table->total_height += row_height;
offset.y += row_height;
table->rows.push_back(row_height);
+ table->rows_baseline.push_back(table->total_height - row_height + row_baseline);
row_height = 0;
}
idx++;
}
-
- l.text_buf->add_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align, t_char_count);
+ int row_idx = (table->align_to_row < 0) ? table->rows_baseline.size() - 1 : table->align_to_row;
+ if (table->rows_baseline.size() != 0 && row_idx < (int)table->rows_baseline.size() - 1) {
+ l.text_buf->add_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align, t_char_count, Math::round(table->rows_baseline[row_idx]));
+ } else {
+ l.text_buf->add_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align, t_char_count);
+ }
txt += String::chr(0xfffc).repeat(t_char_count);
} break;
default:
@@ -3044,18 +3071,18 @@ void RichTextLabel::add_newline() {
queue_redraw();
}
-bool RichTextLabel::remove_line(const int p_line) {
+bool RichTextLabel::remove_paragraph(const int p_paragraph) {
_stop_thread();
MutexLock data_lock(data_mutex);
- if (p_line >= (int)current_frame->lines.size() || p_line < 0) {
+ if (p_paragraph >= (int)current_frame->lines.size() || p_paragraph < 0) {
return false;
}
// Remove all subitems with the same line as that provided.
Vector<int> subitem_indices_to_remove;
for (int i = 0; i < current->subitems.size(); i++) {
- if (current->subitems[i]->line == p_line) {
+ if (current->subitems[i]->line == p_paragraph) {
subitem_indices_to_remove.push_back(i);
}
}
@@ -3065,17 +3092,17 @@ bool RichTextLabel::remove_line(const int p_line) {
for (int i = subitem_indices_to_remove.size() - 1; i >= 0; i--) {
int subitem_idx = subitem_indices_to_remove[i];
had_newline = had_newline || current->subitems[subitem_idx]->type == ITEM_NEWLINE;
- _remove_item(current->subitems[subitem_idx], current->subitems[subitem_idx]->line, p_line);
+ _remove_item(current->subitems[subitem_idx], current->subitems[subitem_idx]->line, p_paragraph);
}
if (!had_newline) {
- current_frame->lines.remove_at(p_line);
+ current_frame->lines.remove_at(p_paragraph);
if (current_frame->lines.size() == 0) {
current_frame->lines.resize(1);
}
}
- if (p_line == 0 && current->subitems.size() > 0) {
+ if (p_paragraph == 0 && current->subitems.size() > 0) {
main->lines[0].from = main;
}
@@ -3155,7 +3182,8 @@ void RichTextLabel::push_normal() {
void RichTextLabel::push_bold() {
ERR_FAIL_COND(theme_cache.bold_font.is_null());
- _push_def_font(BOLD_FONT);
+ ItemFont *item_font = _find_font(current);
+ _push_def_font((item_font && item_font->def_font == ITALICS_FONT) ? BOLD_ITALICS_FONT : BOLD_FONT);
}
void RichTextLabel::push_bold_italics() {
@@ -3167,7 +3195,8 @@ void RichTextLabel::push_bold_italics() {
void RichTextLabel::push_italics() {
ERR_FAIL_COND(theme_cache.italics_font.is_null());
- _push_def_font(ITALICS_FONT);
+ ItemFont *item_font = _find_font(current);
+ _push_def_font((item_font && item_font->def_font == BOLD_FONT) ? BOLD_ITALICS_FONT : ITALICS_FONT);
}
void RichTextLabel::push_mono() {
@@ -3303,7 +3332,7 @@ void RichTextLabel::push_hint(const String &p_string) {
_add_item(item, true);
}
-void RichTextLabel::push_table(int p_columns, InlineAlignment p_alignment) {
+void RichTextLabel::push_table(int p_columns, InlineAlignment p_alignment, int p_align_to_row) {
_stop_thread();
MutexLock data_lock(data_mutex);
@@ -3313,6 +3342,7 @@ void RichTextLabel::push_table(int p_columns, InlineAlignment p_alignment) {
item->columns.resize(p_columns);
item->total_width = 0;
item->inline_align = p_alignment;
+ item->align_to_row = p_align_to_row;
for (int i = 0; i < (int)item->columns.size(); i++) {
item->columns[i].expand = false;
item->columns[i].expand_ratio = 1;
@@ -3793,6 +3823,8 @@ void RichTextLabel::append_text(const String &p_bbcode) {
alignment = INLINE_ALIGNMENT_TOP_TO;
} else if (subtag[1] == "center" || subtag[1] == "c") {
alignment = INLINE_ALIGNMENT_CENTER_TO;
+ } else if (subtag[1] == "baseline" || subtag[1] == "l") {
+ alignment = INLINE_ALIGNMENT_BASELINE_TO;
} else if (subtag[1] == "bottom" || subtag[1] == "b") {
alignment = INLINE_ALIGNMENT_BOTTOM_TO;
}
@@ -3814,8 +3846,12 @@ void RichTextLabel::append_text(const String &p_bbcode) {
alignment = INLINE_ALIGNMENT_BOTTOM;
}
}
+ int row = -1;
+ if (subtag.size() > 3) {
+ row = subtag[3].to_int();
+ }
- push_table(columns, (InlineAlignment)alignment);
+ push_table(columns, (InlineAlignment)alignment, row);
pos = brk_end + 1;
tag_stack.push_front("table");
} else if (tag == "cell") {
@@ -3867,6 +3903,11 @@ void RichTextLabel::append_text(const String &p_bbcode) {
Color color1 = Color::from_string(subtag_a[1], fallback_color);
set_cell_row_background_color(color1, color1);
}
+ } else if (subtag_a[0] == "padding") {
+ Vector<String> subtag_b = subtag_a[1].split(",");
+ if (subtag_b.size() == 4) {
+ set_cell_padding(Rect2(subtag_b[0].to_float(), subtag_b[1].to_float(), subtag_b[2].to_float(), subtag_b[3].to_float()));
+ }
}
}
}
@@ -5274,7 +5315,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text);
ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align", "region"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(Rect2(0, 0, 0, 0)));
ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline);
- ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line);
+ ClassDB::bind_method(D_METHOD("remove_paragraph", "paragraph"), &RichTextLabel::remove_paragraph);
ClassDB::bind_method(D_METHOD("push_font", "font", "font_size"), &RichTextLabel::push_font);
ClassDB::bind_method(D_METHOD("push_font_size", "font_size"), &RichTextLabel::push_font_size);
ClassDB::bind_method(D_METHOD("push_normal"), &RichTextLabel::push_normal);
@@ -5292,7 +5333,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("push_hint", "description"), &RichTextLabel::push_hint);
ClassDB::bind_method(D_METHOD("push_underline"), &RichTextLabel::push_underline);
ClassDB::bind_method(D_METHOD("push_strikethrough"), &RichTextLabel::push_strikethrough);
- ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align"), &RichTextLabel::push_table, DEFVAL(INLINE_ALIGNMENT_TOP));
+ ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align", "align_to_row"), &RichTextLabel::push_table, DEFVAL(INLINE_ALIGNMENT_TOP), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("push_dropcap", "string", "font", "size", "dropcap_margins", "color", "outline_size", "outline_color"), &RichTextLabel::push_dropcap, DEFVAL(Rect2()), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(0, 0, 0, 0)));
ClassDB::bind_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand);
ClassDB::bind_method(D_METHOD("set_cell_row_background_color", "odd_row_bg", "even_row_bg"), &RichTextLabel::set_cell_row_background_color);
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index b00cc3d055..a4bc1c8e03 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -268,7 +268,9 @@ private:
LocalVector<Column> columns;
LocalVector<float> rows;
+ LocalVector<float> rows_baseline;
+ int align_to_row = -1;
int total_width = 0;
int total_height = 0;
InlineAlignment inline_align = INLINE_ALIGNMENT_TOP;
@@ -571,7 +573,7 @@ public:
void add_text(const String &p_text);
void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), InlineAlignment p_alignment = INLINE_ALIGNMENT_CENTER, const Rect2 &p_region = Rect2(0, 0, 0, 0));
void add_newline();
- bool remove_line(const int p_line);
+ bool remove_paragraph(const int p_paragraph);
void push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0));
void _push_def_font(DefaultFont p_def_font);
void _push_def_font_var(DefaultFont p_def_font, const Ref<Font> &p_font, int p_size = -1);
@@ -592,7 +594,7 @@ public:
void push_list(int p_level, ListType p_list, bool p_capitalize);
void push_meta(const Variant &p_meta);
void push_hint(const String &p_string);
- void push_table(int p_columns, InlineAlignment p_alignment = INLINE_ALIGNMENT_TOP);
+ void push_table(int p_columns, InlineAlignment p_alignment = INLINE_ALIGNMENT_TOP, int p_align_to_row = -1);
void push_fade(int p_start_index, int p_length);
void push_shake(int p_strength, float p_rate, bool p_connected);
void push_wave(float p_frequency, float p_amplitude, bool p_connected);
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index f87829cf71..beaffc14b0 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -154,7 +154,9 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
queue_redraw();
}
- _update_hover();
+ if (!tabs.is_empty()) {
+ _update_hover();
+ }
return;
}
@@ -362,12 +364,19 @@ void TabBar::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
+ bool rtl = is_layout_rtl();
+ Vector2 size = get_size();
+
if (tabs.is_empty()) {
+ // Draw the drop indicator where the first tab would be if there are no tabs.
+ if (dragging_valid_tab) {
+ int x = rtl ? size.x : 0;
+ theme_cache.drop_mark_icon->draw(get_canvas_item(), Point2(x - (theme_cache.drop_mark_icon->get_width() / 2), (size.height - theme_cache.drop_mark_icon->get_height()) / 2), theme_cache.drop_mark_color);
+ }
+
return;
}
- bool rtl = is_layout_rtl();
- Vector2 size = get_size();
int limit_minus_buttons = size.width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
int ofs = tabs[offset].ofs_cache;
@@ -1092,7 +1101,8 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
hover_now += 1;
}
} else {
- hover_now = is_layout_rtl() ^ (p_point.x < get_tab_rect(0).position.x) ? 0 : get_tab_count() - 1;
+ int x = tabs.is_empty() ? 0 : get_tab_rect(0).position.x;
+ hover_now = is_layout_rtl() ^ (p_point.x < x) ? 0 : get_tab_count() - 1;
}
move_tab(tab_from_id, hover_now);
@@ -1118,7 +1128,7 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
hover_now += 1;
}
} else {
- hover_now = is_layout_rtl() ^ (p_point.x < get_tab_rect(0).position.x) ? 0 : get_tab_count();
+ hover_now = tabs.is_empty() || (is_layout_rtl() ^ (p_point.x < get_tab_rect(0).position.x)) ? 0 : get_tab_count();
}
Tab moving_tab = from_tabs->tabs[tab_from_id];
@@ -1154,10 +1164,13 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
int TabBar::get_tab_idx_at_point(const Point2 &p_point) const {
int hover_now = -1;
- for (int i = offset; i <= max_drawn_tab; i++) {
- Rect2 rect = get_tab_rect(i);
- if (rect.has_point(p_point)) {
- hover_now = i;
+
+ if (!tabs.is_empty()) {
+ for (int i = offset; i <= max_drawn_tab; i++) {
+ Rect2 rect = get_tab_rect(i);
+ if (rect.has_point(p_point)) {
+ hover_now = i;
+ }
}
}
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 35cc29d080..b105ad5165 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -2580,8 +2580,8 @@ void Tree::_range_click_timeout() {
mb.instantiate();
int x_limit = get_size().width - theme_cache.panel_style->get_minimum_size().width;
- if (h_scroll->is_visible()) {
- x_limit -= h_scroll->get_minimum_size().width;
+ if (v_scroll->is_visible()) {
+ x_limit -= v_scroll->get_minimum_size().width;
}
cache.rtl = is_layout_rtl();
@@ -3640,8 +3640,8 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
propagate_mouse_activated = false;
int x_limit = get_size().width - theme_cache.panel_style->get_minimum_size().width;
- if (h_scroll->is_visible()) {
- x_limit -= h_scroll->get_minimum_size().width;
+ if (v_scroll->is_visible()) {
+ x_limit -= v_scroll->get_minimum_size().width;
}
cache.rtl = is_layout_rtl();
@@ -3785,7 +3785,9 @@ bool Tree::edit_selected() {
} else if (c.mode == TreeItem::CELL_MODE_STRING || c.mode == TreeItem::CELL_MODE_RANGE) {
Rect2 popup_rect;
- Vector2 ofs(0, Math::floor((text_editor->get_size().height - rect.size.height) / 2)); // "floor()" centers vertically.
+ int value_editor_height = c.mode == TreeItem::CELL_MODE_RANGE ? value_editor->get_minimum_size().height : 0;
+ // "floor()" centers vertically.
+ Vector2 ofs(0, Math::floor((MAX(text_editor->get_minimum_size().height, rect.size.height - value_editor_height) - rect.size.height) / 2));
Point2i textedpos = get_screen_position() + rect.position - ofs;
cache.text_editor_position = textedpos;
@@ -3801,7 +3803,7 @@ bool Tree::edit_selected() {
text_editor->select_all();
if (c.mode == TreeItem::CELL_MODE_RANGE) {
- popup_rect.size.y += value_editor->get_minimum_size().height;
+ popup_rect.size.y += value_editor_height;
value_editor->show();
updating_value_editor = true;
@@ -3845,41 +3847,38 @@ Size2 Tree::get_internal_min_size() const {
}
void Tree::update_scrollbars() {
- Size2 size = get_size();
- int tbh;
- if (show_column_titles) {
- tbh = _get_title_button_height();
- } else {
- tbh = 0;
- }
-
- Size2 hmin = h_scroll->get_combined_minimum_size();
- Size2 vmin = v_scroll->get_combined_minimum_size();
-
- v_scroll->set_begin(Point2(size.width - vmin.width, theme_cache.panel_style->get_margin(SIDE_TOP)));
- v_scroll->set_end(Point2(size.width, size.height - theme_cache.panel_style->get_margin(SIDE_TOP) - theme_cache.panel_style->get_margin(SIDE_BOTTOM)));
-
- h_scroll->set_begin(Point2(0, size.height - hmin.height));
- h_scroll->set_end(Point2(size.width - vmin.width, size.height));
-
- Size2 internal_min_size = get_internal_min_size();
-
- bool display_vscroll = internal_min_size.height + theme_cache.panel_style->get_margin(SIDE_TOP) > size.height;
- bool display_hscroll = internal_min_size.width + theme_cache.panel_style->get_margin(SIDE_LEFT) > size.width;
+ const Size2 size = get_size();
+ const Size2 hmin = h_scroll->get_combined_minimum_size();
+ const Size2 vmin = v_scroll->get_combined_minimum_size();
+
+ const Rect2 content_rect = Rect2(theme_cache.panel_style->get_offset(), size - theme_cache.panel_style->get_minimum_size());
+ v_scroll->set_begin(content_rect.get_position() + Vector2(content_rect.get_size().x - vmin.width, 0));
+ v_scroll->set_end(content_rect.get_end() - Vector2(0, hmin.height));
+ h_scroll->set_begin(content_rect.get_position() + Vector2(0, content_rect.get_size().y - hmin.height));
+ h_scroll->set_end(content_rect.get_end() - Vector2(vmin.width, 0));
+
+ const Size2 internal_min_size = get_internal_min_size();
+ const int title_button_height = _get_title_button_height();
+
+ Size2 tree_content_size = content_rect.get_size() - Vector2(0, title_button_height);
+ bool display_vscroll = internal_min_size.height > tree_content_size.height;
+ bool display_hscroll = internal_min_size.width > tree_content_size.width;
for (int i = 0; i < 2; i++) {
// Check twice, as both values are dependent on each other.
if (display_hscroll) {
- display_vscroll = internal_min_size.height + theme_cache.panel_style->get_margin(SIDE_TOP) + hmin.height > size.height;
+ tree_content_size.height = content_rect.get_size().height - title_button_height - hmin.height;
+ display_vscroll = internal_min_size.height > tree_content_size.height;
}
if (display_vscroll) {
- display_hscroll = internal_min_size.width + theme_cache.panel_style->get_margin(SIDE_LEFT) + vmin.width > size.width;
+ tree_content_size.width = content_rect.get_size().width - vmin.width;
+ display_hscroll = internal_min_size.width > tree_content_size.width;
}
}
if (display_vscroll) {
v_scroll->show();
v_scroll->set_max(internal_min_size.height);
- v_scroll->set_page(size.height - hmin.height - tbh);
+ v_scroll->set_page(tree_content_size.height);
theme_cache.offset.y = v_scroll->get_value();
} else {
v_scroll->hide();
@@ -3889,7 +3888,7 @@ void Tree::update_scrollbars() {
if (display_hscroll) {
h_scroll->show();
h_scroll->set_max(internal_min_size.width);
- h_scroll->set_page(size.width - vmin.width);
+ h_scroll->set_page(tree_content_size.width);
theme_cache.offset.x = h_scroll->get_value();
} else {
h_scroll->hide();
@@ -4013,8 +4012,8 @@ void Tree::_notification(int p_what) {
Point2 draw_ofs;
draw_ofs += bg->get_offset();
Size2 draw_size = get_size() - bg->get_minimum_size();
- if (h_scroll->is_visible()) {
- draw_size.width -= h_scroll->get_minimum_size().width;
+ if (v_scroll->is_visible()) {
+ draw_size.width -= v_scroll->get_minimum_size().width;
}
bg->draw(ci, Rect2(Point2(), get_size()));
@@ -5281,7 +5280,6 @@ Tree::Tree() {
add_child(popup_menu, false, INTERNAL_MODE_FRONT);
popup_editor = memnew(Popup);
- popup_editor->set_wrap_controls(true);
add_child(popup_editor, false, INTERNAL_MODE_FRONT);
popup_editor_vb = memnew(VBoxContainer);
popup_editor->add_child(popup_editor_vb);
@@ -5290,11 +5288,9 @@ Tree::Tree() {
text_editor = memnew(LineEdit);
popup_editor_vb->add_child(text_editor);
text_editor->set_v_size_flags(SIZE_EXPAND_FILL);
- text_editor->set_h_size_flags(SIZE_EXPAND_FILL);
value_editor = memnew(HSlider);
- value_editor->set_v_size_flags(SIZE_EXPAND_FILL);
- value_editor->set_h_size_flags(SIZE_EXPAND_FILL);
popup_editor_vb->add_child(value_editor);
+ value_editor->set_v_size_flags(SIZE_EXPAND_FILL);
value_editor->hide();
h_scroll = memnew(HScrollBar);
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 2563fa5914..404c289a6a 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -144,7 +144,7 @@ void CanvasItem::_redraw_callback() {
Transform2D CanvasItem::get_global_transform_with_canvas() const {
if (canvas_layer) {
- return canvas_layer->get_transform() * get_global_transform();
+ return canvas_layer->get_final_transform() * get_global_transform();
} else if (is_inside_tree()) {
return get_viewport()->get_canvas_transform() * get_global_transform();
} else {
@@ -621,10 +621,10 @@ void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const
p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_clip_uv);
}
-void CanvasItem::draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, double p_outline, double p_pixel_range) {
+void CanvasItem::draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, double p_outline, double p_pixel_range, double p_scale) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND(p_texture.is_null());
- RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate, p_outline, p_pixel_range);
+ RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate, p_outline, p_pixel_range, p_scale);
}
void CanvasItem::draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate) {
@@ -950,14 +950,14 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_self_modulate", "self_modulate"), &CanvasItem::set_self_modulate);
ClassDB::bind_method(D_METHOD("get_self_modulate"), &CanvasItem::get_self_modulate);
- ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &Node2D::set_z_index);
- ClassDB::bind_method(D_METHOD("get_z_index"), &Node2D::get_z_index);
+ ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &CanvasItem::set_z_index);
+ ClassDB::bind_method(D_METHOD("get_z_index"), &CanvasItem::get_z_index);
- ClassDB::bind_method(D_METHOD("set_z_as_relative", "enable"), &Node2D::set_z_as_relative);
- ClassDB::bind_method(D_METHOD("is_z_relative"), &Node2D::is_z_relative);
+ ClassDB::bind_method(D_METHOD("set_z_as_relative", "enable"), &CanvasItem::set_z_as_relative);
+ ClassDB::bind_method(D_METHOD("is_z_relative"), &CanvasItem::is_z_relative);
- ClassDB::bind_method(D_METHOD("set_y_sort_enabled", "enabled"), &Node2D::set_y_sort_enabled);
- ClassDB::bind_method(D_METHOD("is_y_sort_enabled"), &Node2D::is_y_sort_enabled);
+ ClassDB::bind_method(D_METHOD("set_y_sort_enabled", "enabled"), &CanvasItem::set_y_sort_enabled);
+ ClassDB::bind_method(D_METHOD("is_y_sort_enabled"), &CanvasItem::is_y_sort_enabled);
ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent);
ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled);
@@ -974,7 +974,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)));
ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("draw_msdf_texture_rect_region", "texture", "rect", "src_rect", "modulate", "outline", "pixel_range"), &CanvasItem::draw_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0.0), DEFVAL(4.0));
+ ClassDB::bind_method(D_METHOD("draw_msdf_texture_rect_region", "texture", "rect", "src_rect", "modulate", "outline", "pixel_range", "scale"), &CanvasItem::draw_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0.0), DEFVAL(4.0), DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("draw_lcd_texture_rect_region", "texture", "rect", "src_rect", "modulate"), &CanvasItem::draw_lcd_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)));
ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box);
ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0));
@@ -1099,7 +1099,7 @@ Transform2D CanvasItem::get_canvas_transform() const {
ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
if (canvas_layer) {
- return canvas_layer->get_transform();
+ return canvas_layer->get_final_transform();
} else if (Object::cast_to<CanvasItem>(get_parent())) {
return Object::cast_to<CanvasItem>(get_parent())->get_canvas_transform();
} else {
@@ -1111,7 +1111,7 @@ Transform2D CanvasItem::get_viewport_transform() const {
ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
if (canvas_layer) {
- return get_viewport()->get_final_transform() * canvas_layer->get_transform();
+ return get_viewport()->get_final_transform() * canvas_layer->get_final_transform();
} else {
return get_viewport()->get_final_transform() * get_viewport()->get_canvas_transform();
}
@@ -1305,6 +1305,7 @@ CanvasItem::CanvasItem() :
}
CanvasItem::~CanvasItem() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(canvas_item);
}
@@ -1459,5 +1460,6 @@ CanvasTexture::CanvasTexture() {
canvas_texture = RS::get_singleton()->canvas_texture_create();
}
CanvasTexture::~CanvasTexture() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(canvas_texture);
}
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 4ace982825..bae03d706a 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -259,7 +259,7 @@ public:
void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1));
void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false);
- void draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), double p_outline = 0.0, double p_pixel_range = 4.0);
+ void draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), double p_outline = 0.0, double p_pixel_range = 4.0, double p_scale = 1.0);
void draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1));
void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect);
void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), real_t p_width = 1);
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 5fde18721a..2aa8df10ab 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -88,6 +88,18 @@ Transform2D CanvasLayer::get_transform() const {
return transform;
}
+Transform2D CanvasLayer::get_final_transform() const {
+ if (is_following_viewport()) {
+ Transform2D follow;
+ follow.scale(Vector2(get_follow_viewport_scale(), get_follow_viewport_scale()));
+ if (vp) {
+ follow = vp->get_canvas_transform() * follow;
+ }
+ return follow * transform;
+ }
+ return transform;
+}
+
void CanvasLayer::_update_xform() {
transform.set_rotation_and_scale(rot, scale);
transform.set_origin(ofs);
@@ -304,6 +316,7 @@ void CanvasLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transform", "transform"), &CanvasLayer::set_transform);
ClassDB::bind_method(D_METHOD("get_transform"), &CanvasLayer::get_transform);
+ ClassDB::bind_method(D_METHOD("get_final_transform"), &CanvasLayer::get_final_transform);
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &CanvasLayer::set_offset);
ClassDB::bind_method(D_METHOD("get_offset"), &CanvasLayer::get_offset);
@@ -347,5 +360,6 @@ CanvasLayer::CanvasLayer() {
}
CanvasLayer::~CanvasLayer() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(canvas);
}
diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h
index 74b5ebd453..2afc842a50 100644
--- a/scene/main/canvas_layer.h
+++ b/scene/main/canvas_layer.h
@@ -77,6 +77,7 @@ public:
void set_transform(const Transform2D &p_xform);
Transform2D get_transform() const;
+ Transform2D get_final_transform() const;
void set_offset(const Vector2 &p_offset);
Vector2 get_offset() const;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index ceb5b76ff2..e61cca0a0f 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -594,6 +594,12 @@ void SceneTree::finalize() {
timer->release_connections();
}
timers.clear();
+
+ // Cleanup tweens.
+ for (Ref<Tween> &tween : tweens) {
+ tween->clear();
+ }
+ tweens.clear();
}
void SceneTree::quit(int p_exit_code) {
@@ -942,6 +948,9 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
}
for (const ObjectID &id : no_context_node_ids) {
+ if (p_viewport->is_input_handled()) {
+ break;
+ }
Node *n = Object::cast_to<Node>(ObjectDB::get_instance(id));
if (n) {
n->_call_shortcut_input(p_input);
@@ -1413,7 +1422,7 @@ SceneTree::SceneTree() {
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa_3d", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")));
root->set_msaa_3d(Viewport::MSAA(msaa_mode_3d));
- const bool transparent_background = GLOBAL_DEF("rendering/transparent_background", false);
+ const bool transparent_background = GLOBAL_DEF("rendering/viewport/transparent_background", false);
root->set_transparent_background(transparent_background);
const int ssaa_mode = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/screen_space_aa", 0);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index fdbcb20d30..c0b81c9b9a 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -80,6 +80,7 @@ void ViewportTexture::setup_local_to_scene() {
vp->viewport_textures.insert(this);
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
if (proxy_ph.is_valid()) {
RS::get_singleton()->texture_proxy_update(proxy, vp->texture_rid);
RS::get_singleton()->free(proxy_ph);
@@ -153,6 +154,8 @@ ViewportTexture::~ViewportTexture() {
vp->viewport_textures.erase(this);
}
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+
if (proxy_ph.is_valid()) {
RS::get_singleton()->free(proxy_ph);
}
@@ -301,6 +304,8 @@ void Viewport::_sub_window_remove(Window *p_window) {
int index = _sub_window_find(p_window);
ERR_FAIL_COND(index == -1);
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+
RS::get_singleton()->free(gui.sub_windows[index].canvas_item);
gui.sub_windows.remove_at(index);
@@ -642,7 +647,7 @@ void Viewport::_process_picking() {
ObjectID canvas_layer_id;
if (E) {
// A descendant CanvasLayer.
- canvas_layer_transform = E->get_transform();
+ canvas_layer_transform = E->get_final_transform();
canvas_layer_id = E->get_instance_id();
} else {
// This Viewport's builtin canvas.
@@ -4117,6 +4122,7 @@ Viewport::~Viewport() {
for (ViewportTexture *E : viewport_textures) {
E->vp = nullptr;
}
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(viewport);
}
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index c71c3e195b..f18b712153 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -462,9 +462,8 @@ void Window::_make_window() {
}
DisplayServer::VSyncMode vsync_mode = DisplayServer::get_singleton()->window_get_vsync_mode(DisplayServer::MAIN_WINDOW_ID);
- window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, Rect2i(position, size));
+ window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, Rect2i(position, size), current_screen);
ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
- DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id);
DisplayServer::get_singleton()->window_set_max_size(Size2i(), window_id);
DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id);
String tr_title = atr(title);
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 043895b591..4f300cb5d6 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -56,6 +56,7 @@
#include "scene/2d/navigation_agent_2d.h"
#include "scene/2d/navigation_link_2d.h"
#include "scene/2d/navigation_obstacle_2d.h"
+#include "scene/2d/navigation_region_2d.h"
#include "scene/2d/parallax_background.h"
#include "scene/2d/parallax_layer.h"
#include "scene/2d/path_2d.h"
@@ -163,6 +164,7 @@
#include "scene/resources/mesh_data_tool.h"
#include "scene/resources/multimesh.h"
#include "scene/resources/navigation_mesh.h"
+#include "scene/resources/navigation_polygon.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/particle_process_material.h"
#include "scene/resources/physics_material.h"
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 077a53464e..37407edc33 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -1319,7 +1319,7 @@ Error Animation::blend_shape_track_interpolate(int p_track, double p_time, float
}
void Animation::track_remove_key_at_time(int p_track, double p_time) {
- int idx = track_find_key(p_track, p_time, true);
+ int idx = track_find_key(p_track, p_time, FIND_MODE_APPROX);
ERR_FAIL_COND(idx < 0);
track_remove_key(p_track, idx);
}
@@ -1400,7 +1400,7 @@ void Animation::track_remove_key(int p_track, int p_idx) {
emit_changed();
}
-int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
+int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode) const {
ERR_FAIL_INDEX_V(p_track, tracks.size(), -1);
Track *t = tracks[p_track];
@@ -1416,7 +1416,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
uint32_t key_index;
bool fetch_compressed_success = _fetch_compressed<3>(tt->compressed_track, p_time, key, time, key_next, time_next, &key_index);
ERR_FAIL_COND_V(!fetch_compressed_success, -1);
- if (p_exact && time != p_time) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(time, p_time)) || (p_find_mode == FIND_MODE_EXACT && time != p_time)) {
return -1;
}
return key_index;
@@ -1426,7 +1426,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= tt->positions.size()) {
return -1;
}
- if (tt->positions[k].time != p_time && p_exact) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(tt->positions[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && tt->positions[k].time != p_time)) {
return -1;
}
return k;
@@ -1443,7 +1443,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
uint32_t key_index;
bool fetch_compressed_success = _fetch_compressed<3>(rt->compressed_track, p_time, key, time, key_next, time_next, &key_index);
ERR_FAIL_COND_V(!fetch_compressed_success, -1);
- if (p_exact && time != p_time) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(time, p_time)) || (p_find_mode == FIND_MODE_EXACT && time != p_time)) {
return -1;
}
return key_index;
@@ -1453,7 +1453,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= rt->rotations.size()) {
return -1;
}
- if (rt->rotations[k].time != p_time && p_exact) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(rt->rotations[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && rt->rotations[k].time != p_time)) {
return -1;
}
return k;
@@ -1470,7 +1470,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
uint32_t key_index;
bool fetch_compressed_success = _fetch_compressed<3>(st->compressed_track, p_time, key, time, key_next, time_next, &key_index);
ERR_FAIL_COND_V(!fetch_compressed_success, -1);
- if (p_exact && time != p_time) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(time, p_time)) || (p_find_mode == FIND_MODE_EXACT && time != p_time)) {
return -1;
}
return key_index;
@@ -1480,7 +1480,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= st->scales.size()) {
return -1;
}
- if (st->scales[k].time != p_time && p_exact) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(st->scales[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && st->scales[k].time != p_time)) {
return -1;
}
return k;
@@ -1497,7 +1497,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
uint32_t key_index;
bool fetch_compressed_success = _fetch_compressed<1>(bst->compressed_track, p_time, key, time, key_next, time_next, &key_index);
ERR_FAIL_COND_V(!fetch_compressed_success, -1);
- if (p_exact && time != p_time) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(time, p_time)) || (p_find_mode == FIND_MODE_EXACT && time != p_time)) {
return -1;
}
return key_index;
@@ -1507,7 +1507,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= bst->blend_shapes.size()) {
return -1;
}
- if (bst->blend_shapes[k].time != p_time && p_exact) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(bst->blend_shapes[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && bst->blend_shapes[k].time != p_time)) {
return -1;
}
return k;
@@ -1519,7 +1519,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= vt->values.size()) {
return -1;
}
- if (vt->values[k].time != p_time && p_exact) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(vt->values[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && vt->values[k].time != p_time)) {
return -1;
}
return k;
@@ -1531,7 +1531,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= mt->methods.size()) {
return -1;
}
- if (mt->methods[k].time != p_time && p_exact) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(mt->methods[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && mt->methods[k].time != p_time)) {
return -1;
}
return k;
@@ -1543,7 +1543,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= bt->values.size()) {
return -1;
}
- if (bt->values[k].time != p_time && p_exact) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(bt->values[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && bt->values[k].time != p_time)) {
return -1;
}
return k;
@@ -1555,7 +1555,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= at->values.size()) {
return -1;
}
- if (at->values[k].time != p_time && p_exact) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(at->values[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && at->values[k].time != p_time)) {
return -1;
}
return k;
@@ -1567,7 +1567,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= at->values.size()) {
return -1;
}
- if (at->values[k].time != p_time && p_exact) {
+ if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(at->values[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && at->values[k].time != p_time)) {
return -1;
}
return k;
@@ -2944,12 +2944,12 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
// Not from_time > to_time but most recent of looping...
if (p_looped_flag != Animation::LOOPED_FLAG_NONE) {
if (!is_backward && Math::is_equal_approx(from_time, 0)) {
- int edge = track_find_key(p_track, 0, true);
+ int edge = track_find_key(p_track, 0, FIND_MODE_EXACT);
if (edge >= 0) {
p_indices->push_back(edge);
}
} else if (is_backward && Math::is_equal_approx(to_time, length)) {
- int edge = track_find_key(p_track, length, true);
+ int edge = track_find_key(p_track, length, FIND_MODE_EXACT);
if (edge >= 0) {
p_indices->push_back(edge);
}
@@ -2971,7 +2971,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
if (tt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, from_time, p_indices);
- _get_compressed_key_indices_in_range<3>(tt->compressed_track, CMP_EPSILON, to_time, p_indices);
+ _get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, to_time, p_indices);
} else {
_track_get_key_indices_in_range(tt->positions, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(tt->positions, 0, to_time, p_indices, false);
@@ -2981,7 +2981,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
const RotationTrack *rt = static_cast<const RotationTrack *>(t);
if (rt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, from_time, p_indices);
- _get_compressed_key_indices_in_range<3>(rt->compressed_track, CMP_EPSILON, to_time, p_indices);
+ _get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, to_time, p_indices);
} else {
_track_get_key_indices_in_range(rt->rotations, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(rt->rotations, 0, to_time, p_indices, false);
@@ -3072,7 +3072,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t);
if (bst->compressed_track >= 0) {
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, length, p_indices);
- _get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length - CMP_EPSILON, p_indices);
+ _get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length, p_indices);
} else {
_track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices, false);
_track_get_key_indices_in_range(bst->blend_shapes, to_time, length, p_indices, true);
@@ -3109,9 +3109,9 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
// The edge will be pingponged in the next frame and processed there, so let's ignore it now...
if (!is_backward && Math::is_equal_approx(to_time, length)) {
- to_time = length - CMP_EPSILON;
+ to_time -= CMP_EPSILON;
} else if (is_backward && Math::is_equal_approx(from_time, 0)) {
- from_time = CMP_EPSILON;
+ from_time += CMP_EPSILON;
}
} break;
}
@@ -3818,7 +3818,7 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("track_get_key_count", "track_idx"), &Animation::track_get_key_count);
ClassDB::bind_method(D_METHOD("track_get_key_value", "track_idx", "key_idx"), &Animation::track_get_key_value);
ClassDB::bind_method(D_METHOD("track_get_key_time", "track_idx", "key_idx"), &Animation::track_get_key_time);
- ClassDB::bind_method(D_METHOD("track_find_key", "track_idx", "time", "exact"), &Animation::track_find_key, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("track_find_key", "track_idx", "time", "find_mode"), &Animation::track_find_key, DEFVAL(FIND_MODE_NEAREST));
ClassDB::bind_method(D_METHOD("track_set_interpolation_type", "track_idx", "interpolation"), &Animation::track_set_interpolation_type);
ClassDB::bind_method(D_METHOD("track_get_interpolation_type", "track_idx"), &Animation::track_get_interpolation_type);
@@ -3905,6 +3905,10 @@ void Animation::_bind_methods() {
BIND_ENUM_CONSTANT(LOOPED_FLAG_NONE);
BIND_ENUM_CONSTANT(LOOPED_FLAG_END);
BIND_ENUM_CONSTANT(LOOPED_FLAG_START);
+
+ BIND_ENUM_CONSTANT(FIND_MODE_NEAREST);
+ BIND_ENUM_CONSTANT(FIND_MODE_APPROX);
+ BIND_ENUM_CONSTANT(FIND_MODE_EXACT);
}
void Animation::clear() {
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 0ac1279063..b7d5a683db 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -79,6 +79,12 @@ public:
LOOPED_FLAG_START,
};
+ enum FindMode {
+ FIND_MODE_NEAREST,
+ FIND_MODE_APPROX,
+ FIND_MODE_EXACT,
+ };
+
#ifdef TOOLS_ENABLED
enum HandleMode {
HANDLE_MODE_FREE,
@@ -392,7 +398,7 @@ public:
void track_set_key_transition(int p_track, int p_key_idx, real_t p_transition);
void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value);
void track_set_key_time(int p_track, int p_key_idx, double p_time);
- int track_find_key(int p_track, double p_time, bool p_exact = false) const;
+ int track_find_key(int p_track, double p_time, FindMode p_find_mode = FIND_MODE_NEAREST) const;
void track_remove_key(int p_track, int p_idx);
void track_remove_key_at_time(int p_track, double p_time);
int track_get_key_count(int p_track) const;
@@ -489,6 +495,7 @@ VARIANT_ENUM_CAST(Animation::InterpolationType);
VARIANT_ENUM_CAST(Animation::UpdateMode);
VARIANT_ENUM_CAST(Animation::LoopMode);
VARIANT_ENUM_CAST(Animation::LoopedFlag);
+VARIANT_ENUM_CAST(Animation::FindMode);
#ifdef TOOLS_ENABLED
VARIANT_ENUM_CAST(Animation::HandleMode);
VARIANT_ENUM_CAST(Animation::HandleSetMode);
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index 0df61871d8..86b806bc4f 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -317,7 +317,7 @@ Vector<Vector<Vector2>> BitMap::_march_square(const Rect2i &p_rect, const Point2
if (sv == 6 || sv == 9) {
const Point2i cur_pos(curx, cury);
- // Find if this point has occured before.
+ // Find if this point has occurred before.
if (HashMap<Point2i, int>::Iterator found = cross_map.find(cur_pos)) {
// Add points after the previous crossing to the result.
ret.push_back(_points.slice(found->value + 1, points_size));
diff --git a/scene/resources/camera_attributes.cpp b/scene/resources/camera_attributes.cpp
index 8e4876e01f..292accddc1 100644
--- a/scene/resources/camera_attributes.cpp
+++ b/scene/resources/camera_attributes.cpp
@@ -135,6 +135,7 @@ CameraAttributes::CameraAttributes() {
}
CameraAttributes::~CameraAttributes() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(camera_attributes);
}
diff --git a/scene/resources/canvas_item_material.cpp b/scene/resources/canvas_item_material.cpp
index b16059c218..0cc5faffb1 100644
--- a/scene/resources/canvas_item_material.cpp
+++ b/scene/resources/canvas_item_material.cpp
@@ -294,6 +294,8 @@ CanvasItemMaterial::CanvasItemMaterial() :
CanvasItemMaterial::~CanvasItemMaterial() {
MutexLock lock(material_mutex);
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+
if (shader_map.has(current_key)) {
shader_map[current_key].users--;
if (shader_map[current_key].users == 0) {
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index b0a63bb7fa..be9c0dc725 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -829,7 +829,7 @@ void Curve2D::_bake() const {
return;
}
- // Tesselate curve to (almost) even length segments
+ // Tessellate curve to (almost) even length segments
{
Vector<RBMap<real_t, Vector2>> midpoints = _tessellate_even_length(10, bake_interval);
@@ -1546,7 +1546,7 @@ void Curve3D::_bake() const {
return;
}
- // Step 1: Tesselate curve to (almost) even length segments
+ // Step 1: Tessellate curve to (almost) even length segments
{
Vector<RBMap<real_t, Vector3>> midpoints = _tessellate_even_length(10, bake_interval);
@@ -1649,7 +1649,7 @@ void Curve3D::_bake() const {
}
real_t dot = forward_ptr[0].dot(forward_ptr[point_count - 1]);
- if (dot < 1.0 - UNIT_EPSILON) { // Alignment should not be too tight, or it dosen't work for coarse bake interval.
+ if (dot < 1.0 - UNIT_EPSILON) { // Alignment should not be too tight, or it doesn't work for coarse bake interval.
is_loop = false;
}
}
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index f179b4b818..a2638c39ca 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -100,6 +100,11 @@ static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margi
void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &bold_font, const Ref<Font> &bold_italics_font, const Ref<Font> &italics_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale) {
scale = p_scale;
+ // Default theme properties.
+ theme->set_default_font(default_font);
+ theme->set_default_font_size(default_font_size * scale);
+ theme->set_default_base_scale(scale);
+
// Font colors
const Color control_font_color = Color(0.875, 0.875, 0.875);
const Color control_font_low_color = Color(0.7, 0.7, 0.7);
@@ -504,14 +509,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
Ref<Texture2D> empty_icon = memnew(ImageTexture);
- const Ref<StyleBoxFlat> style_scrollbar = make_flat_stylebox(style_normal_color, 4, 4, 4, 4, 10);
+ const Ref<StyleBoxFlat> style_h_scrollbar = make_flat_stylebox(style_normal_color, 0, 4, 0, 4, 10);
+ const Ref<StyleBoxFlat> style_v_scrollbar = make_flat_stylebox(style_normal_color, 4, 0, 4, 0, 10);
Ref<StyleBoxFlat> style_scrollbar_grabber = make_flat_stylebox(style_progress_color, 4, 4, 4, 4, 10);
Ref<StyleBoxFlat> style_scrollbar_grabber_highlight = make_flat_stylebox(style_focus_color, 4, 4, 4, 4, 10);
Ref<StyleBoxFlat> style_scrollbar_grabber_pressed = make_flat_stylebox(style_focus_color * Color(0.75, 0.75, 0.75), 4, 4, 4, 4, 10);
// HScrollBar
- theme->set_stylebox("scroll", "HScrollBar", style_scrollbar);
+ theme->set_stylebox("scroll", "HScrollBar", style_h_scrollbar);
theme->set_stylebox("scroll_focus", "HScrollBar", focus);
theme->set_stylebox("grabber", "HScrollBar", style_scrollbar_grabber);
theme->set_stylebox("grabber_highlight", "HScrollBar", style_scrollbar_grabber_highlight);
@@ -526,7 +532,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// VScrollBar
- theme->set_stylebox("scroll", "VScrollBar", style_scrollbar);
+ theme->set_stylebox("scroll", "VScrollBar", style_v_scrollbar);
theme->set_stylebox("scroll_focus", "VScrollBar", focus);
theme->set_stylebox("grabber", "VScrollBar", style_scrollbar_grabber);
theme->set_stylebox("grabber_highlight", "VScrollBar", style_scrollbar_grabber_highlight);
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 23bd8a4be4..f97cffc3fc 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -1550,5 +1550,6 @@ Environment::Environment() {
}
Environment::~Environment() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(environment);
}
diff --git a/scene/resources/fog_material.cpp b/scene/resources/fog_material.cpp
index 46b44d681f..2aca552716 100644
--- a/scene/resources/fog_material.cpp
+++ b/scene/resources/fog_material.cpp
@@ -132,6 +132,7 @@ void FogMaterial::_bind_methods() {
void FogMaterial::cleanup_shader() {
if (shader.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(shader);
}
}
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 584a7e7eac..78b4edfcf7 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -270,24 +270,18 @@ void Font::set_cache_capacity(int p_single_line, int p_multi_line) {
}
Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
- uint64_t hash = p_text.hash64();
- hash = hash_djb2_one_64(p_font_size, hash);
- if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
- hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
- }
- hash = hash_djb2_one_64(p_direction, hash);
- hash = hash_djb2_one_64(p_orientation, hash);
+ bool fill = (p_alignment == HORIZONTAL_ALIGNMENT_FILL);
+ ShapedTextKey key = ShapedTextKey(p_text, p_font_size, fill ? p_width : 0.0, fill ? p_jst_flags : TextServer::JUSTIFICATION_NONE, TextServer::BREAK_NONE, p_direction, p_orientation);
Ref<TextLine> buffer;
- if (cache.has(hash)) {
- buffer = cache.get(hash);
+ if (cache.has(key)) {
+ buffer = cache.get(key);
} else {
buffer.instantiate();
buffer->set_direction(p_direction);
buffer->set_orientation(p_orientation);
buffer->add_string(p_text, Ref<Font>(this), p_font_size);
- cache.insert(hash, buffer);
+ cache.insert(key, buffer);
}
buffer->set_width(p_width);
@@ -300,17 +294,11 @@ Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignmen
}
Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
- uint64_t hash = p_text.hash64();
- hash = hash_djb2_one_64(p_font_size, hash);
- hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
- hash = hash_djb2_one_64(p_brk_flags.operator int64_t(), hash);
- hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
- hash = hash_djb2_one_64(p_direction, hash);
- hash = hash_djb2_one_64(p_orientation, hash);
+ ShapedTextKey key = ShapedTextKey(p_text, p_font_size, p_width, p_jst_flags, p_brk_flags, p_direction, p_orientation);
Ref<TextParagraph> lines_buffer;
- if (cache_wrap.has(hash)) {
- lines_buffer = cache_wrap.get(hash);
+ if (cache_wrap.has(key)) {
+ lines_buffer = cache_wrap.get(key);
} else {
lines_buffer.instantiate();
lines_buffer->set_direction(p_direction);
@@ -319,7 +307,7 @@ Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment
lines_buffer->set_width(p_width);
lines_buffer->set_break_flags(p_brk_flags);
lines_buffer->set_justification_flags(p_jst_flags);
- cache_wrap.insert(hash, lines_buffer);
+ cache_wrap.insert(key, lines_buffer);
}
lines_buffer->set_alignment(p_alignment);
@@ -329,24 +317,18 @@ Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment
}
void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
- uint64_t hash = p_text.hash64();
- hash = hash_djb2_one_64(p_font_size, hash);
- if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
- hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
- }
- hash = hash_djb2_one_64(p_direction, hash);
- hash = hash_djb2_one_64(p_orientation, hash);
+ bool fill = (p_alignment == HORIZONTAL_ALIGNMENT_FILL);
+ ShapedTextKey key = ShapedTextKey(p_text, p_font_size, fill ? p_width : 0.0, fill ? p_jst_flags : TextServer::JUSTIFICATION_NONE, TextServer::BREAK_NONE, p_direction, p_orientation);
Ref<TextLine> buffer;
- if (cache.has(hash)) {
- buffer = cache.get(hash);
+ if (cache.has(key)) {
+ buffer = cache.get(key);
} else {
buffer.instantiate();
buffer->set_direction(p_direction);
buffer->set_orientation(p_orientation);
buffer->add_string(p_text, Ref<Font>(this), p_font_size);
- cache.insert(hash, buffer);
+ cache.insert(key, buffer);
}
Vector2 ofs = p_pos;
@@ -366,17 +348,11 @@ void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_t
}
void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
- uint64_t hash = p_text.hash64();
- hash = hash_djb2_one_64(p_font_size, hash);
- hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
- hash = hash_djb2_one_64(p_brk_flags.operator int64_t(), hash);
- hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
- hash = hash_djb2_one_64(p_direction, hash);
- hash = hash_djb2_one_64(p_orientation, hash);
+ ShapedTextKey key = ShapedTextKey(p_text, p_font_size, p_width, p_jst_flags, p_brk_flags, p_direction, p_orientation);
Ref<TextParagraph> lines_buffer;
- if (cache_wrap.has(hash)) {
- lines_buffer = cache_wrap.get(hash);
+ if (cache_wrap.has(key)) {
+ lines_buffer = cache_wrap.get(key);
} else {
lines_buffer.instantiate();
lines_buffer->set_direction(p_direction);
@@ -385,7 +361,7 @@ void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const S
lines_buffer->set_width(p_width);
lines_buffer->set_break_flags(p_brk_flags);
lines_buffer->set_justification_flags(p_jst_flags);
- cache_wrap.insert(hash, lines_buffer);
+ cache_wrap.insert(key, lines_buffer);
}
Vector2 ofs = p_pos;
@@ -402,24 +378,18 @@ void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const S
}
void Font::draw_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
- uint64_t hash = p_text.hash64();
- hash = hash_djb2_one_64(p_font_size, hash);
- if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
- hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
- }
- hash = hash_djb2_one_64(p_direction, hash);
- hash = hash_djb2_one_64(p_orientation, hash);
+ bool fill = (p_alignment == HORIZONTAL_ALIGNMENT_FILL);
+ ShapedTextKey key = ShapedTextKey(p_text, p_font_size, fill ? p_width : 0.0, fill ? p_jst_flags : TextServer::JUSTIFICATION_NONE, TextServer::BREAK_NONE, p_direction, p_orientation);
Ref<TextLine> buffer;
- if (cache.has(hash)) {
- buffer = cache.get(hash);
+ if (cache.has(key)) {
+ buffer = cache.get(key);
} else {
buffer.instantiate();
buffer->set_direction(p_direction);
buffer->set_orientation(p_orientation);
buffer->add_string(p_text, Ref<Font>(this), p_font_size);
- cache.insert(hash, buffer);
+ cache.insert(key, buffer);
}
Vector2 ofs = p_pos;
@@ -439,17 +409,11 @@ void Font::draw_string_outline(RID p_canvas_item, const Point2 &p_pos, const Str
}
void Font::draw_multiline_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, int p_size, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
- uint64_t hash = p_text.hash64();
- hash = hash_djb2_one_64(p_font_size, hash);
- hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
- hash = hash_djb2_one_64(p_brk_flags.operator int64_t(), hash);
- hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
- hash = hash_djb2_one_64(p_direction, hash);
- hash = hash_djb2_one_64(p_orientation, hash);
+ ShapedTextKey key = ShapedTextKey(p_text, p_font_size, p_width, p_jst_flags, p_brk_flags, p_direction, p_orientation);
Ref<TextParagraph> lines_buffer;
- if (cache_wrap.has(hash)) {
- lines_buffer = cache_wrap.get(hash);
+ if (cache_wrap.has(key)) {
+ lines_buffer = cache_wrap.get(key);
} else {
lines_buffer.instantiate();
lines_buffer->set_direction(p_direction);
@@ -458,7 +422,7 @@ void Font::draw_multiline_string_outline(RID p_canvas_item, const Point2 &p_pos,
lines_buffer->set_width(p_width);
lines_buffer->set_break_flags(p_brk_flags);
lines_buffer->set_justification_flags(p_jst_flags);
- cache_wrap.insert(hash, lines_buffer);
+ cache_wrap.insert(key, lines_buffer);
}
Vector2 ofs = p_pos;
diff --git a/scene/resources/font.h b/scene/resources/font.h
index e9f7507652..44198a3111 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -47,9 +47,44 @@ class TextParagraph;
class Font : public Resource {
GDCLASS(Font, Resource);
+ struct ShapedTextKey {
+ String text;
+ int font_size = 14;
+ float width = 0.f;
+ BitField<TextServer::JustificationFlag> jst_flags = TextServer::JUSTIFICATION_NONE;
+ BitField<TextServer::LineBreakFlag> brk_flags = TextServer::BREAK_MANDATORY;
+ TextServer::Direction direction = TextServer::DIRECTION_AUTO;
+ TextServer::Orientation orientation = TextServer::ORIENTATION_HORIZONTAL;
+
+ bool operator==(const ShapedTextKey &p_b) const {
+ return (font_size == p_b.font_size) && (width == p_b.width) && (jst_flags == p_b.jst_flags) && (brk_flags == p_b.brk_flags) && (direction == p_b.direction) && (orientation == p_b.orientation) && (text == p_b.text);
+ }
+
+ ShapedTextKey() {}
+ ShapedTextKey(const String &p_text, int p_font_size, float p_width, BitField<TextServer::JustificationFlag> p_jst_flags, BitField<TextServer::LineBreakFlag> p_brk_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
+ text = p_text;
+ font_size = p_font_size;
+ width = p_width;
+ jst_flags = p_jst_flags;
+ brk_flags = p_brk_flags;
+ direction = p_direction;
+ orientation = p_orientation;
+ }
+ };
+
+ struct ShapedTextKeyHasher {
+ _FORCE_INLINE_ static uint32_t hash(const ShapedTextKey &p_a) {
+ uint32_t hash = p_a.text.hash();
+ hash = hash_murmur3_one_32(p_a.font_size, hash);
+ hash = hash_murmur3_one_float(p_a.width, hash);
+ hash = hash_murmur3_one_32(p_a.brk_flags | (p_a.jst_flags << 6) | (p_a.direction << 12) | (p_a.orientation << 15), hash);
+ return hash_fmix32(hash);
+ }
+ };
+
// Shaped string cache.
- mutable LRUCache<uint64_t, Ref<TextLine>> cache;
- mutable LRUCache<uint64_t, Ref<TextParagraph>> cache_wrap;
+ mutable LRUCache<ShapedTextKey, Ref<TextLine>, ShapedTextKeyHasher> cache;
+ mutable LRUCache<ShapedTextKey, Ref<TextParagraph>, ShapedTextKeyHasher> cache_wrap;
protected:
// Output.
diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp
index f04eb75d86..4890bb32c4 100644
--- a/scene/resources/gradient.cpp
+++ b/scene/resources/gradient.cpp
@@ -58,7 +58,7 @@ void Gradient::_bind_methods() {
ClassDB::bind_method(D_METHOD("sample", "offset"), &Gradient::get_color_at_offset);
- ClassDB::bind_method(D_METHOD("get_point_count"), &Gradient::get_points_count);
+ ClassDB::bind_method(D_METHOD("get_point_count"), &Gradient::get_point_count);
ClassDB::bind_method(D_METHOD("set_offsets", "offsets"), &Gradient::set_offsets);
ClassDB::bind_method(D_METHOD("get_offsets"), &Gradient::get_offsets);
@@ -190,6 +190,6 @@ Color Gradient::get_color(int pos) {
return points[pos].color;
}
-int Gradient::get_points_count() const {
+int Gradient::get_point_count() const {
return points.size();
}
diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h
index 2b91331ab0..16ddf5df2a 100644
--- a/scene/resources/gradient.h
+++ b/scene/resources/gradient.h
@@ -171,7 +171,7 @@ public:
}
}
- int get_points_count() const;
+ int get_point_count() const;
};
VARIANT_ENUM_CAST(Gradient::InterpolationMode);
diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp
index 90cc3ea5f4..2defe729cc 100644
--- a/scene/resources/immediate_mesh.cpp
+++ b/scene/resources/immediate_mesh.cpp
@@ -410,5 +410,6 @@ ImmediateMesh::ImmediateMesh() {
mesh = RS::get_singleton()->mesh_create();
}
ImmediateMesh::~ImmediateMesh() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(mesh);
}
diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index d1278f9340..b5e02b2f76 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -30,6 +30,7 @@
#include "importer_mesh.h"
+#include "core/io/marshalls.h"
#include "core/math/random_pcg.h"
#include "core/math/static_raycaster.h"
#include "scene/resources/surface_tool.h"
@@ -424,9 +425,8 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
normal_weights[j] = 2.0; // Give some weight to normal preservation, may be worth exposing as an import setting
}
- const float max_mesh_error = FLT_MAX; // We don't want to limit by error, just by index target
- float scale = SurfaceTool::simplify_scale_func((const float *)merged_vertices_ptr, merged_vertex_count, sizeof(Vector3));
- float mesh_error = 0.0f;
+ Vector<float> merged_vertices_f32 = vector3_to_float32_array(merged_vertices_ptr, merged_vertex_count);
+ float scale = SurfaceTool::simplify_scale_func(merged_vertices_f32.ptr(), merged_vertex_count, sizeof(float) * 3);
unsigned int index_target = 12; // Start with the smallest target, 4 triangles
unsigned int last_index_count = 0;
@@ -446,11 +446,25 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
raycaster->commit();
}
+ const float max_mesh_error = FLT_MAX; // We don't want to limit by error, just by index target
+ float mesh_error = 0.0f;
+
while (index_target < index_count) {
PackedInt32Array new_indices;
new_indices.resize(index_count);
- size_t new_index_count = SurfaceTool::simplify_with_attrib_func((unsigned int *)new_indices.ptrw(), (const uint32_t *)merged_indices_ptr, index_count, (const float *)merged_vertices_ptr, merged_vertex_count, sizeof(Vector3), index_target, max_mesh_error, &mesh_error, (float *)merged_normals.ptr(), normal_weights.ptr(), 3);
+ Vector<float> merged_normals_f32 = vector3_to_float32_array(merged_normals.ptr(), merged_normals.size());
+
+ size_t new_index_count = SurfaceTool::simplify_with_attrib_func(
+ (unsigned int *)new_indices.ptrw(),
+ (const uint32_t *)merged_indices_ptr, index_count,
+ merged_vertices_f32.ptr(), merged_vertex_count,
+ sizeof(float) * 3, // Vertex stride
+ index_target,
+ max_mesh_error,
+ &mesh_error,
+ merged_normals_f32.ptr(),
+ normal_weights.ptr(), 3);
if (new_index_count < last_index_count * 1.5f) {
index_target = index_target * 1.5f;
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index a16d2c2072..44ce90cc4a 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -141,6 +141,7 @@ Material::Material() {
}
Material::~Material() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(material);
}
@@ -3005,6 +3006,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
}
BaseMaterial3D::~BaseMaterial3D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
MutexLock lock(material_mutex);
if (shader_map.has(current_key)) {
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index a5e7602c8b..a610290a11 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -1118,7 +1118,19 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
if (sl == -1) {
return false;
}
- int idx = sname.substr(8, sl - 8).to_int() - 1;
+ int idx = sname.substr(8, sl - 8).to_int();
+
+ // This is a bit of a hack to ensure compatibility with older material
+ // overrides that start indexing at 1.
+ // We assume that idx 0 is always read first, if its not, this won't work.
+ if (idx == 0) {
+ surface_index_0 = true;
+ }
+ if (!surface_index_0) {
+ // This means the file was created when the indexing started at 1, so decrease by one.
+ idx--;
+ }
+
String what = sname.get_slicec('/', 1);
if (what == "material") {
surface_set_material(idx, p_value);
@@ -1491,7 +1503,7 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const {
if (sl == -1) {
return false;
}
- int idx = sname.substr(8, sl - 8).to_int() - 1;
+ int idx = sname.substr(8, sl - 8).to_int();
String what = sname.get_slicec('/', 1);
if (what == "material") {
r_ret = surface_get_material(idx);
@@ -1519,11 +1531,11 @@ void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const {
}
for (int i = 0; i < surfaces.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::STRING, "surface_" + itos(i + 1) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::STRING, "surface_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
if (surfaces[i].is_2d) {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial", PROPERTY_USAGE_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial", PROPERTY_USAGE_EDITOR));
} else {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_EDITOR));
}
}
}
@@ -2105,6 +2117,7 @@ ArrayMesh::ArrayMesh() {
ArrayMesh::~ArrayMesh() {
if (mesh.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(mesh);
}
}
@@ -2120,5 +2133,6 @@ PlaceholderMesh::PlaceholderMesh() {
}
PlaceholderMesh::~PlaceholderMesh() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(rid);
}
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 6f995280e8..fabc09a42c 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -262,6 +262,7 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ bool surface_index_0 = false;
virtual void reset_state() override;
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index 7c78b757c7..858146da96 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -57,10 +57,18 @@ bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) {
_set_item_shapes(idx, p_value);
} else if (what == "preview") {
set_item_preview(idx, p_value);
- } else if (what == "navmesh") {
- set_item_navmesh(idx, p_value);
- } else if (what == "navmesh_transform") {
- set_item_navmesh_transform(idx, p_value);
+ } else if (what == "navigation_mesh") {
+ set_item_navigation_mesh(idx, p_value);
+ } else if (what == "navigation_mesh_transform") {
+ set_item_navigation_mesh_transform(idx, p_value);
+#ifndef DISABLE_DEPRECATED
+ } else if (what == "navmesh") { // Renamed in 4.0 beta 9.
+ set_item_navigation_mesh(idx, p_value);
+ } else if (what == "navmesh_transform") { // Renamed in 4.0 beta 9.
+ set_item_navigation_mesh_transform(idx, p_value);
+#endif // DISABLE_DEPRECATED
+ } else if (what == "navigation_layers") {
+ set_item_navigation_layers(idx, p_value);
} else {
return false;
}
@@ -85,10 +93,18 @@ bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = get_item_mesh_transform(idx);
} else if (what == "shapes") {
r_ret = _get_item_shapes(idx);
- } else if (what == "navmesh") {
- r_ret = get_item_navmesh(idx);
- } else if (what == "navmesh_transform") {
- r_ret = get_item_navmesh_transform(idx);
+ } else if (what == "navigation_mesh") {
+ r_ret = get_item_navigation_mesh(idx);
+ } else if (what == "navigation_mesh_transform") {
+ r_ret = get_item_navigation_mesh_transform(idx);
+#ifndef DISABLE_DEPRECATED
+ } else if (what == "navmesh") { // Renamed in 4.0 beta 9.
+ r_ret = get_item_navigation_mesh(idx);
+ } else if (what == "navmesh_transform") { // Renamed in 4.0 beta 9.
+ r_ret = get_item_navigation_mesh_transform(idx);
+#endif // DISABLE_DEPRECATED
+ } else if (what == "navigation_layers") {
+ r_ret = get_item_navigation_layers(idx);
} else if (what == "preview") {
r_ret = get_item_preview(idx);
} else {
@@ -105,8 +121,9 @@ void MeshLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("mesh"), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prop_name + PNAME("mesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
p_list->push_back(PropertyInfo(Variant::ARRAY, prop_name + PNAME("shapes")));
- p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("navmesh"), PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prop_name + PNAME("navmesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("navigation_mesh"), PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prop_name + PNAME("navigation_mesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
+ p_list->push_back(PropertyInfo(Variant::INT, prop_name + PNAME("navigation_layers"), PROPERTY_HINT_LAYERS_3D_NAVIGATION));
p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("preview"), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT));
}
}
@@ -150,18 +167,27 @@ void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes)
notify_property_list_changed();
}
-void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh) {
+void MeshLibrary::set_item_navigation_mesh(int p_item, const Ref<NavigationMesh> &p_navigation_mesh) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
- item_map[p_item].navmesh = p_navmesh;
+ item_map[p_item].navigation_mesh = p_navigation_mesh;
notify_property_list_changed();
notify_change_to_owners();
emit_changed();
notify_property_list_changed();
}
-void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform3D &p_transform) {
+void MeshLibrary::set_item_navigation_mesh_transform(int p_item, const Transform3D &p_transform) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
- item_map[p_item].navmesh_transform = p_transform;
+ item_map[p_item].navigation_mesh_transform = p_transform;
+ notify_change_to_owners();
+ emit_changed();
+ notify_property_list_changed();
+}
+
+void MeshLibrary::set_item_navigation_layers(int p_item, uint32_t p_navigation_layers) {
+ ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
+ item_map[p_item].navigation_layers = p_navigation_layers;
+ notify_property_list_changed();
notify_change_to_owners();
emit_changed();
notify_property_list_changed();
@@ -194,14 +220,19 @@ Vector<MeshLibrary::ShapeData> MeshLibrary::get_item_shapes(int p_item) const {
return item_map[p_item].shapes;
}
-Ref<NavigationMesh> MeshLibrary::get_item_navmesh(int p_item) const {
+Ref<NavigationMesh> MeshLibrary::get_item_navigation_mesh(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Ref<NavigationMesh>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
- return item_map[p_item].navmesh;
+ return item_map[p_item].navigation_mesh;
}
-Transform3D MeshLibrary::get_item_navmesh_transform(int p_item) const {
+Transform3D MeshLibrary::get_item_navigation_mesh_transform(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform3D(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
- return item_map[p_item].navmesh_transform;
+ return item_map[p_item].navigation_mesh_transform;
+}
+
+uint32_t MeshLibrary::get_item_navigation_layers(int p_item) const {
+ ERR_FAIL_COND_V_MSG(!item_map.has(p_item), 0, "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
+ return item_map[p_item].navigation_layers;
}
Ref<Texture2D> MeshLibrary::get_item_preview(int p_item) const {
@@ -314,15 +345,17 @@ void MeshLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_name", "id", "name"), &MeshLibrary::set_item_name);
ClassDB::bind_method(D_METHOD("set_item_mesh", "id", "mesh"), &MeshLibrary::set_item_mesh);
ClassDB::bind_method(D_METHOD("set_item_mesh_transform", "id", "mesh_transform"), &MeshLibrary::set_item_mesh_transform);
- ClassDB::bind_method(D_METHOD("set_item_navmesh", "id", "navmesh"), &MeshLibrary::set_item_navmesh);
- ClassDB::bind_method(D_METHOD("set_item_navmesh_transform", "id", "navmesh"), &MeshLibrary::set_item_navmesh_transform);
+ ClassDB::bind_method(D_METHOD("set_item_navigation_mesh", "id", "navigation_mesh"), &MeshLibrary::set_item_navigation_mesh);
+ ClassDB::bind_method(D_METHOD("set_item_navigation_mesh_transform", "id", "navigation_mesh"), &MeshLibrary::set_item_navigation_mesh_transform);
+ ClassDB::bind_method(D_METHOD("set_item_navigation_layers", "id", "navigation_layers"), &MeshLibrary::set_item_navigation_layers);
ClassDB::bind_method(D_METHOD("set_item_shapes", "id", "shapes"), &MeshLibrary::_set_item_shapes);
ClassDB::bind_method(D_METHOD("set_item_preview", "id", "texture"), &MeshLibrary::set_item_preview);
ClassDB::bind_method(D_METHOD("get_item_name", "id"), &MeshLibrary::get_item_name);
ClassDB::bind_method(D_METHOD("get_item_mesh", "id"), &MeshLibrary::get_item_mesh);
ClassDB::bind_method(D_METHOD("get_item_mesh_transform", "id"), &MeshLibrary::get_item_mesh_transform);
- ClassDB::bind_method(D_METHOD("get_item_navmesh", "id"), &MeshLibrary::get_item_navmesh);
- ClassDB::bind_method(D_METHOD("get_item_navmesh_transform", "id"), &MeshLibrary::get_item_navmesh_transform);
+ ClassDB::bind_method(D_METHOD("get_item_navigation_mesh", "id"), &MeshLibrary::get_item_navigation_mesh);
+ ClassDB::bind_method(D_METHOD("get_item_navigation_mesh_transform", "id"), &MeshLibrary::get_item_navigation_mesh_transform);
+ ClassDB::bind_method(D_METHOD("get_item_navigation_layers", "id"), &MeshLibrary::get_item_navigation_layers);
ClassDB::bind_method(D_METHOD("get_item_shapes", "id"), &MeshLibrary::_get_item_shapes);
ClassDB::bind_method(D_METHOD("get_item_preview", "id"), &MeshLibrary::get_item_preview);
ClassDB::bind_method(D_METHOD("remove_item", "id"), &MeshLibrary::remove_item);
diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h
index 79acb41c4e..1d5af9e176 100644
--- a/scene/resources/mesh_library.h
+++ b/scene/resources/mesh_library.h
@@ -49,11 +49,12 @@ public:
struct Item {
String name;
Ref<Mesh> mesh;
+ Transform3D mesh_transform;
Vector<ShapeData> shapes;
Ref<Texture2D> preview;
- Transform3D navmesh_transform;
- Transform3D mesh_transform;
- Ref<NavigationMesh> navmesh;
+ Ref<NavigationMesh> navigation_mesh;
+ Transform3D navigation_mesh_transform;
+ uint32_t navigation_layers = 1;
};
RBMap<int, Item> item_map;
@@ -74,15 +75,17 @@ public:
void set_item_name(int p_item, const String &p_name);
void set_item_mesh(int p_item, const Ref<Mesh> &p_mesh);
void set_item_mesh_transform(int p_item, const Transform3D &p_transform);
- void set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh);
- void set_item_navmesh_transform(int p_item, const Transform3D &p_transform);
+ void set_item_navigation_mesh(int p_item, const Ref<NavigationMesh> &p_navigation_mesh);
+ void set_item_navigation_mesh_transform(int p_item, const Transform3D &p_transform);
+ void set_item_navigation_layers(int p_item, uint32_t p_navigation_layers);
void set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes);
void set_item_preview(int p_item, const Ref<Texture2D> &p_preview);
String get_item_name(int p_item) const;
Ref<Mesh> get_item_mesh(int p_item) const;
Transform3D get_item_mesh_transform(int p_item) const;
- Ref<NavigationMesh> get_item_navmesh(int p_item) const;
- Transform3D get_item_navmesh_transform(int p_item) const;
+ Ref<NavigationMesh> get_item_navigation_mesh(int p_item) const;
+ Transform3D get_item_navigation_mesh_transform(int p_item) const;
+ uint32_t get_item_navigation_layers(int p_item) const;
Vector<ShapeData> get_item_shapes(int p_item) const;
Ref<Texture2D> get_item_preview(int p_item) const;
diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp
index ff4a7a4560..2ea357d814 100644
--- a/scene/resources/multimesh.cpp
+++ b/scene/resources/multimesh.cpp
@@ -242,6 +242,7 @@ void MultiMesh::set_instance_transform(int p_instance, const Transform3D &p_tran
void MultiMesh::set_instance_transform_2d(int p_instance, const Transform2D &p_transform) {
RenderingServer::get_singleton()->multimesh_instance_set_transform_2d(multimesh, p_instance, p_transform);
+ emit_changed();
}
Transform3D MultiMesh::get_instance_transform(int p_instance) const {
@@ -364,5 +365,6 @@ MultiMesh::MultiMesh() {
}
MultiMesh::~MultiMesh() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(multimesh);
}
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index de97498674..bf4291869f 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -225,13 +225,13 @@ float NavigationMesh::get_edge_max_error() const {
return edge_max_error;
}
-void NavigationMesh::set_verts_per_poly(float p_value) {
+void NavigationMesh::set_vertices_per_polygon(float p_value) {
ERR_FAIL_COND(p_value < 3);
- verts_per_poly = p_value;
+ vertices_per_polygon = p_value;
}
-float NavigationMesh::get_verts_per_poly() const {
- return verts_per_poly;
+float NavigationMesh::get_vertices_per_polygon() const {
+ return vertices_per_polygon;
}
void NavigationMesh::set_detail_sample_distance(float p_value) {
@@ -483,8 +483,8 @@ void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_edge_max_error", "edge_max_error"), &NavigationMesh::set_edge_max_error);
ClassDB::bind_method(D_METHOD("get_edge_max_error"), &NavigationMesh::get_edge_max_error);
- ClassDB::bind_method(D_METHOD("set_verts_per_poly", "verts_per_poly"), &NavigationMesh::set_verts_per_poly);
- ClassDB::bind_method(D_METHOD("get_verts_per_poly"), &NavigationMesh::get_verts_per_poly);
+ ClassDB::bind_method(D_METHOD("set_vertices_per_polygon", "vertices_per_polygon"), &NavigationMesh::set_vertices_per_polygon);
+ ClassDB::bind_method(D_METHOD("get_vertices_per_polygon"), &NavigationMesh::get_vertices_per_polygon);
ClassDB::bind_method(D_METHOD("set_detail_sample_distance", "detail_sample_dist"), &NavigationMesh::set_detail_sample_distance);
ClassDB::bind_method(D_METHOD("get_detail_sample_distance"), &NavigationMesh::get_detail_sample_distance);
@@ -527,9 +527,9 @@ void NavigationMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_PROPERTY_DEFAULT("geometry_collision_mask", 0xFFFFFFFF);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "NavMesh Children,Group With Children,Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "Root Node Children,Group With Children,Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry_source_group_name"), "set_source_group_name", "get_source_group_name");
- ADD_PROPERTY_DEFAULT("geometry_source_group_name", StringName("navmesh"));
+ ADD_PROPERTY_DEFAULT("geometry_source_group_name", StringName("navigation_mesh_source_group"));
ADD_GROUP("Cells", "cell_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_height", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_height", "get_cell_height");
@@ -544,8 +544,8 @@ void NavigationMesh::_bind_methods() {
ADD_GROUP("Edges", "edge_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01,or_greater,suffix:m"), "set_edge_max_length", "get_edge_max_length");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01,or_greater,suffix:m"), "set_edge_max_error", "get_edge_max_error");
- ADD_GROUP("Polygons", "polygon_");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "polygon_verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_verts_per_poly", "get_verts_per_poly");
+ ADD_GROUP("Polygons", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vertices_per_polygon", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_vertices_per_polygon", "get_vertices_per_polygon");
ADD_GROUP("Details", "detail_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_sample_distance", PROPERTY_HINT_RANGE, "0.1,16.0,0.01,or_greater,suffix:m"), "set_detail_sample_distance", "get_detail_sample_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater,suffix:m"), "set_detail_sample_max_error", "get_detail_sample_max_error");
@@ -566,7 +566,7 @@ void NavigationMesh::_bind_methods() {
BIND_ENUM_CONSTANT(PARSED_GEOMETRY_BOTH);
BIND_ENUM_CONSTANT(PARSED_GEOMETRY_MAX);
- BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_NAVMESH_CHILDREN);
+ BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_ROOT_NODE_CHILDREN);
BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN);
BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_GROUPS_EXPLICIT);
BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_MAX);
@@ -581,7 +581,7 @@ void NavigationMesh::_validate_property(PropertyInfo &p_property) const {
}
if (p_property.name == "geometry_source_group_name") {
- if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) {
+ if (source_geometry_mode == SOURCE_GEOMETRY_ROOT_NODE_CHILDREN) {
p_property.usage = PROPERTY_USAGE_NONE;
return;
}
@@ -590,35 +590,16 @@ void NavigationMesh::_validate_property(PropertyInfo &p_property) const {
#ifndef DISABLE_DEPRECATED
bool NavigationMesh::_set(const StringName &p_name, const Variant &p_value) {
- String prop_name = p_name;
- if (prop_name.find("/") != -1) {
- // Compatibility with pre-3.5 "category/path" property names.
- prop_name = prop_name.replace("/", "_");
- if (prop_name == "sample_partition_type_sample_partition_type") {
- set("sample_partition_type", p_value);
- } else if (prop_name == "filter_filter_walkable_low_height_spans") {
- set("filter_walkable_low_height_spans", p_value);
- } else {
- set(prop_name, p_value);
- }
-
+ if (p_name == "polygon_verts_per_poly") { // Renamed in 4.0 beta 9.
+ set_vertices_per_polygon(p_value);
return true;
}
return false;
}
bool NavigationMesh::_get(const StringName &p_name, Variant &r_ret) const {
- String prop_name = p_name;
- if (prop_name.find("/") != -1) {
- // Compatibility with pre-3.5 "category/path" property names.
- prop_name = prop_name.replace("/", "_");
- if (prop_name == "sample_partition_type_sample_partition_type") {
- r_ret = get("sample_partition_type");
- } else if (prop_name == "filter_filter_walkable_low_height_spans") {
- r_ret = get("filter_walkable_low_height_spans");
- } else {
- r_ret = get(prop_name);
- }
+ if (p_name == "polygon_verts_per_poly") { // Renamed in 4.0 beta 9.
+ r_ret = get_vertices_per_polygon();
return true;
}
return false;
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index 5ddbd75dcb..3d072423db 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -84,7 +84,7 @@ public:
};
enum SourceGeometryMode {
- SOURCE_GEOMETRY_NAVMESH_CHILDREN = 0,
+ SOURCE_GEOMETRY_ROOT_NODE_CHILDREN = 0,
SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN,
SOURCE_GEOMETRY_GROUPS_EXPLICIT,
SOURCE_GEOMETRY_MAX
@@ -101,7 +101,7 @@ protected:
float region_merge_size = 20.0f;
float edge_max_length = 12.0f;
float edge_max_error = 1.3f;
- float verts_per_poly = 6.0f;
+ float vertices_per_polygon = 6.0f;
float detail_sample_distance = 6.0f;
float detail_sample_max_error = 1.0f;
@@ -109,8 +109,8 @@ protected:
ParsedGeometryType parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES;
uint32_t collision_mask = 0xFFFFFFFF;
- SourceGeometryMode source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN;
- StringName source_group_name = "navmesh";
+ SourceGeometryMode source_geometry_mode = SOURCE_GEOMETRY_ROOT_NODE_CHILDREN;
+ StringName source_group_name = "navigation_mesh_source_group";
bool filter_low_hanging_obstacles = false;
bool filter_ledge_spans = false;
@@ -168,8 +168,8 @@ public:
void set_edge_max_error(float p_value);
float get_edge_max_error() const;
- void set_verts_per_poly(float p_value);
- float get_verts_per_poly() const;
+ void set_vertices_per_polygon(float p_value);
+ float get_vertices_per_polygon() const;
void set_detail_sample_distance(float p_value);
float get_detail_sample_distance() const;
diff --git a/scene/resources/navigation_polygon.cpp b/scene/resources/navigation_polygon.cpp
new file mode 100644
index 0000000000..04077e95a7
--- /dev/null
+++ b/scene/resources/navigation_polygon.cpp
@@ -0,0 +1,354 @@
+/*************************************************************************/
+/* navigation_polygon.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "navigation_polygon.h"
+
+#include "core/core_string_names.h"
+#include "core/math/geometry_2d.h"
+#include "core/os/mutex.h"
+
+#include "thirdparty/misc/polypartition.h"
+
+#ifdef TOOLS_ENABLED
+Rect2 NavigationPolygon::_edit_get_rect() const {
+ if (rect_cache_dirty) {
+ item_rect = Rect2();
+ bool first = true;
+
+ for (int i = 0; i < outlines.size(); i++) {
+ const Vector<Vector2> &outline = outlines[i];
+ const int outline_size = outline.size();
+ if (outline_size < 3) {
+ continue;
+ }
+ const Vector2 *p = outline.ptr();
+ for (int j = 0; j < outline_size; j++) {
+ if (first) {
+ item_rect = Rect2(p[j], Vector2(0, 0));
+ first = false;
+ } else {
+ item_rect.expand_to(p[j]);
+ }
+ }
+ }
+
+ rect_cache_dirty = false;
+ }
+ return item_rect;
+}
+
+bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+ for (int i = 0; i < outlines.size(); i++) {
+ const Vector<Vector2> &outline = outlines[i];
+ const int outline_size = outline.size();
+ if (outline_size < 3) {
+ continue;
+ }
+ if (Geometry2D::is_point_in_polygon(p_point, Variant(outline))) {
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
+void NavigationPolygon::set_vertices(const Vector<Vector2> &p_vertices) {
+ {
+ MutexLock lock(navigation_mesh_generation);
+ navigation_mesh.unref();
+ }
+ vertices = p_vertices;
+ rect_cache_dirty = true;
+}
+
+Vector<Vector2> NavigationPolygon::get_vertices() const {
+ return vertices;
+}
+
+void NavigationPolygon::_set_polygons(const TypedArray<Vector<int32_t>> &p_array) {
+ {
+ MutexLock lock(navigation_mesh_generation);
+ navigation_mesh.unref();
+ }
+ polygons.resize(p_array.size());
+ for (int i = 0; i < p_array.size(); i++) {
+ polygons.write[i].indices = p_array[i];
+ }
+}
+
+TypedArray<Vector<int32_t>> NavigationPolygon::_get_polygons() const {
+ TypedArray<Vector<int32_t>> ret;
+ ret.resize(polygons.size());
+ for (int i = 0; i < ret.size(); i++) {
+ ret[i] = polygons[i].indices;
+ }
+
+ return ret;
+}
+
+void NavigationPolygon::_set_outlines(const TypedArray<Vector<Vector2>> &p_array) {
+ outlines.resize(p_array.size());
+ for (int i = 0; i < p_array.size(); i++) {
+ outlines.write[i] = p_array[i];
+ }
+ rect_cache_dirty = true;
+}
+
+TypedArray<Vector<Vector2>> NavigationPolygon::_get_outlines() const {
+ TypedArray<Vector<Vector2>> ret;
+ ret.resize(outlines.size());
+ for (int i = 0; i < ret.size(); i++) {
+ ret[i] = outlines[i];
+ }
+
+ return ret;
+}
+
+void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) {
+ Polygon polygon;
+ polygon.indices = p_polygon;
+ polygons.push_back(polygon);
+ {
+ MutexLock lock(navigation_mesh_generation);
+ navigation_mesh.unref();
+ }
+}
+
+void NavigationPolygon::add_outline_at_index(const Vector<Vector2> &p_outline, int p_index) {
+ outlines.insert(p_index, p_outline);
+ rect_cache_dirty = true;
+}
+
+int NavigationPolygon::get_polygon_count() const {
+ return polygons.size();
+}
+
+Vector<int> NavigationPolygon::get_polygon(int p_idx) {
+ ERR_FAIL_INDEX_V(p_idx, polygons.size(), Vector<int>());
+ return polygons[p_idx].indices;
+}
+
+void NavigationPolygon::clear_polygons() {
+ polygons.clear();
+ {
+ MutexLock lock(navigation_mesh_generation);
+ navigation_mesh.unref();
+ }
+}
+
+Ref<NavigationMesh> NavigationPolygon::get_navigation_mesh() {
+ MutexLock lock(navigation_mesh_generation);
+
+ if (navigation_mesh.is_null()) {
+ navigation_mesh.instantiate();
+ Vector<Vector3> verts;
+ {
+ verts.resize(get_vertices().size());
+ Vector3 *w = verts.ptrw();
+
+ const Vector2 *r = get_vertices().ptr();
+
+ for (int i(0); i < get_vertices().size(); i++) {
+ w[i] = Vector3(r[i].x, 0.0, r[i].y);
+ }
+ }
+ navigation_mesh->set_vertices(verts);
+
+ for (int i(0); i < get_polygon_count(); i++) {
+ navigation_mesh->add_polygon(get_polygon(i));
+ }
+ }
+
+ return navigation_mesh;
+}
+
+void NavigationPolygon::add_outline(const Vector<Vector2> &p_outline) {
+ outlines.push_back(p_outline);
+ rect_cache_dirty = true;
+}
+
+int NavigationPolygon::get_outline_count() const {
+ return outlines.size();
+}
+
+void NavigationPolygon::set_outline(int p_idx, const Vector<Vector2> &p_outline) {
+ ERR_FAIL_INDEX(p_idx, outlines.size());
+ outlines.write[p_idx] = p_outline;
+ rect_cache_dirty = true;
+}
+
+void NavigationPolygon::remove_outline(int p_idx) {
+ ERR_FAIL_INDEX(p_idx, outlines.size());
+ outlines.remove_at(p_idx);
+ rect_cache_dirty = true;
+}
+
+Vector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, outlines.size(), Vector<Vector2>());
+ return outlines[p_idx];
+}
+
+void NavigationPolygon::clear_outlines() {
+ outlines.clear();
+ rect_cache_dirty = true;
+}
+
+void NavigationPolygon::make_polygons_from_outlines() {
+ {
+ MutexLock lock(navigation_mesh_generation);
+ navigation_mesh.unref();
+ }
+ List<TPPLPoly> in_poly, out_poly;
+
+ Vector2 outside_point(-1e10, -1e10);
+
+ for (int i = 0; i < outlines.size(); i++) {
+ Vector<Vector2> ol = outlines[i];
+ int olsize = ol.size();
+ if (olsize < 3) {
+ continue;
+ }
+ const Vector2 *r = ol.ptr();
+ for (int j = 0; j < olsize; j++) {
+ outside_point.x = MAX(r[j].x, outside_point.x);
+ outside_point.y = MAX(r[j].y, outside_point.y);
+ }
+ }
+
+ outside_point += Vector2(0.7239784, 0.819238); //avoid precision issues
+
+ for (int i = 0; i < outlines.size(); i++) {
+ Vector<Vector2> ol = outlines[i];
+ int olsize = ol.size();
+ if (olsize < 3) {
+ continue;
+ }
+ const Vector2 *r = ol.ptr();
+
+ int interscount = 0;
+ //test if this is an outer outline
+ for (int k = 0; k < outlines.size(); k++) {
+ if (i == k) {
+ continue; //no self intersect
+ }
+
+ Vector<Vector2> ol2 = outlines[k];
+ int olsize2 = ol2.size();
+ if (olsize2 < 3) {
+ continue;
+ }
+ const Vector2 *r2 = ol2.ptr();
+
+ for (int l = 0; l < olsize2; l++) {
+ if (Geometry2D::segment_intersects_segment(r[0], outside_point, r2[l], r2[(l + 1) % olsize2], nullptr)) {
+ interscount++;
+ }
+ }
+ }
+
+ bool outer = (interscount % 2) == 0;
+
+ TPPLPoly tp;
+ tp.Init(olsize);
+ for (int j = 0; j < olsize; j++) {
+ tp[j] = r[j];
+ }
+
+ if (outer) {
+ tp.SetOrientation(TPPL_ORIENTATION_CCW);
+ } else {
+ tp.SetOrientation(TPPL_ORIENTATION_CW);
+ tp.SetHole(true);
+ }
+
+ in_poly.push_back(tp);
+ }
+
+ TPPLPartition tpart;
+ if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
+ ERR_PRINT("NavigationPolygon: Convex partition failed! Failed to convert outlines to a valid NavigationMesh."
+ "\nNavigationPolygon outlines can not overlap vertices or edges inside same outline or with other outlines or have any intersections."
+ "\nAdd the outmost and largest outline first. To add holes inside this outline add the smaller outlines with opposite winding order.");
+ return;
+ }
+
+ polygons.clear();
+ vertices.clear();
+
+ HashMap<Vector2, int> points;
+ for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) {
+ TPPLPoly &tp = I->get();
+
+ struct Polygon p;
+
+ for (int64_t i = 0; i < tp.GetNumPoints(); i++) {
+ HashMap<Vector2, int>::Iterator E = points.find(tp[i]);
+ if (!E) {
+ E = points.insert(tp[i], vertices.size());
+ vertices.push_back(tp[i]);
+ }
+ p.indices.push_back(E->value);
+ }
+
+ polygons.push_back(p);
+ }
+
+ emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+void NavigationPolygon::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices);
+ ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices);
+
+ ClassDB::bind_method(D_METHOD("add_polygon", "polygon"), &NavigationPolygon::add_polygon);
+ ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationPolygon::get_polygon_count);
+ ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationPolygon::get_polygon);
+ ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationPolygon::clear_polygons);
+ ClassDB::bind_method(D_METHOD("get_navigation_mesh"), &NavigationPolygon::get_navigation_mesh);
+
+ ClassDB::bind_method(D_METHOD("add_outline", "outline"), &NavigationPolygon::add_outline);
+ ClassDB::bind_method(D_METHOD("add_outline_at_index", "outline", "index"), &NavigationPolygon::add_outline_at_index);
+ ClassDB::bind_method(D_METHOD("get_outline_count"), &NavigationPolygon::get_outline_count);
+ ClassDB::bind_method(D_METHOD("set_outline", "idx", "outline"), &NavigationPolygon::set_outline);
+ ClassDB::bind_method(D_METHOD("get_outline", "idx"), &NavigationPolygon::get_outline);
+ ClassDB::bind_method(D_METHOD("remove_outline", "idx"), &NavigationPolygon::remove_outline);
+ ClassDB::bind_method(D_METHOD("clear_outlines"), &NavigationPolygon::clear_outlines);
+ ClassDB::bind_method(D_METHOD("make_polygons_from_outlines"), &NavigationPolygon::make_polygons_from_outlines);
+
+ ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationPolygon::_set_polygons);
+ ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationPolygon::_get_polygons);
+
+ ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines);
+ ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines");
+}
diff --git a/scene/resources/navigation_polygon.h b/scene/resources/navigation_polygon.h
new file mode 100644
index 0000000000..e943cff04e
--- /dev/null
+++ b/scene/resources/navigation_polygon.h
@@ -0,0 +1,94 @@
+/*************************************************************************/
+/* navigation_polygon.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef NAVIGATION_POLYGON_H
+#define NAVIGATION_POLYGON_H
+
+#include "scene/2d/node_2d.h"
+#include "scene/resources/navigation_mesh.h"
+
+class NavigationPolygon : public Resource {
+ GDCLASS(NavigationPolygon, Resource);
+
+ Vector<Vector2> vertices;
+ struct Polygon {
+ Vector<int> indices;
+ };
+ Vector<Polygon> polygons;
+ Vector<Vector<Vector2>> outlines;
+
+ mutable Rect2 item_rect;
+ mutable bool rect_cache_dirty = true;
+
+ Mutex navigation_mesh_generation;
+ // Navigation mesh
+ Ref<NavigationMesh> navigation_mesh;
+
+protected:
+ static void _bind_methods();
+
+ void _set_polygons(const TypedArray<Vector<int32_t>> &p_array);
+ TypedArray<Vector<int32_t>> _get_polygons() const;
+
+ void _set_outlines(const TypedArray<Vector<Vector2>> &p_array);
+ TypedArray<Vector<Vector2>> _get_outlines() const;
+
+public:
+#ifdef TOOLS_ENABLED
+ Rect2 _edit_get_rect() const;
+ bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+#endif
+
+ void set_vertices(const Vector<Vector2> &p_vertices);
+ Vector<Vector2> get_vertices() const;
+
+ void add_polygon(const Vector<int> &p_polygon);
+ int get_polygon_count() const;
+
+ void add_outline(const Vector<Vector2> &p_outline);
+ void add_outline_at_index(const Vector<Vector2> &p_outline, int p_index);
+ void set_outline(int p_idx, const Vector<Vector2> &p_outline);
+ Vector<Vector2> get_outline(int p_idx) const;
+ void remove_outline(int p_idx);
+ int get_outline_count() const;
+
+ void clear_outlines();
+ void make_polygons_from_outlines();
+
+ Vector<int> get_polygon(int p_idx);
+ void clear_polygons();
+
+ Ref<NavigationMesh> get_navigation_mesh();
+
+ NavigationPolygon() {}
+ ~NavigationPolygon() {}
+};
+
+#endif // NAVIGATION_POLYGON_H
diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp
index b77430c154..a07a8ac7cd 100644
--- a/scene/resources/particle_process_material.cpp
+++ b/scene/resources/particle_process_material.cpp
@@ -1894,6 +1894,7 @@ ParticleProcessMaterial::ParticleProcessMaterial() :
}
ParticleProcessMaterial::~ParticleProcessMaterial() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
MutexLock lock(material_mutex);
if (shader_map.has(current_key)) {
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 2e8fcb3717..aeb62d6709 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -340,6 +340,7 @@ PrimitiveMesh::PrimitiveMesh() {
}
PrimitiveMesh::~PrimitiveMesh() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(mesh);
}
@@ -2171,6 +2172,24 @@ int TubeTrailMesh::get_section_rings() const {
return section_rings;
}
+void TubeTrailMesh::set_cap_top(bool p_cap_top) {
+ cap_top = p_cap_top;
+ _request_update();
+}
+
+bool TubeTrailMesh::is_cap_top() const {
+ return cap_top;
+}
+
+void TubeTrailMesh::set_cap_bottom(bool p_cap_bottom) {
+ cap_bottom = p_cap_bottom;
+ _request_update();
+}
+
+bool TubeTrailMesh::is_cap_bottom() const {
+ return cap_bottom;
+}
+
void TubeTrailMesh::set_curve(const Ref<Curve> &p_curve) {
if (curve == p_curve) {
return;
@@ -2284,49 +2303,21 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
thisrow = point;
}
- // add top
- float scale_pos = 1.0;
- if (curve.is_valid() && curve->get_point_count() > 0) {
- scale_pos = curve->sample_baked(0);
- }
-
- if (scale_pos > CMP_EPSILON) {
- float y = depth * 0.5;
-
- thisrow = point;
- points.push_back(Vector3(0.0, y, 0));
- normals.push_back(Vector3(0.0, 1.0, 0.0));
- ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
- uvs.push_back(Vector2(0.25, 0.75));
- point++;
-
- bone_indices.push_back(0);
- bone_indices.push_back(0);
- bone_indices.push_back(0);
- bone_indices.push_back(0);
-
- bone_weights.push_back(1.0);
- bone_weights.push_back(0);
- bone_weights.push_back(0);
- bone_weights.push_back(0);
-
- float rm = radius * scale_pos;
-
- for (int i = 0; i <= radial_steps; i++) {
- float r = i;
- r /= radial_steps;
-
- float x = sin(r * Math_TAU);
- float z = cos(r * Math_TAU);
+ if (cap_top) {
+ // add top
+ float scale_pos = 1.0;
+ if (curve.is_valid() && curve->get_point_count() > 0) {
+ scale_pos = curve->sample_baked(0);
+ }
- float u = ((x + 1.0) * 0.25);
- float v = 0.5 + ((z + 1.0) * 0.25);
+ if (scale_pos > CMP_EPSILON) {
+ float y = depth * 0.5;
- Vector3 p = Vector3(x * rm, y, z * rm);
- points.push_back(p);
+ thisrow = point;
+ points.push_back(Vector3(0.0, y, 0));
normals.push_back(Vector3(0.0, 1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
- uvs.push_back(Vector2(u, v));
+ uvs.push_back(Vector2(0.25, 0.75));
point++;
bone_indices.push_back(0);
@@ -2339,57 +2330,59 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
bone_weights.push_back(0);
bone_weights.push_back(0);
- if (i > 0) {
- indices.push_back(thisrow);
- indices.push_back(point - 1);
- indices.push_back(point - 2);
- }
- }
- }
+ float rm = radius * scale_pos;
- float scale_neg = 1.0;
- if (curve.is_valid() && curve->get_point_count() > 0) {
- scale_neg = curve->sample_baked(1.0);
- }
+ for (int i = 0; i <= radial_steps; i++) {
+ float r = i;
+ r /= radial_steps;
- // add bottom
- if (scale_neg > CMP_EPSILON) {
- float y = depth * -0.5;
+ float x = sin(r * Math_TAU);
+ float z = cos(r * Math_TAU);
- thisrow = point;
- points.push_back(Vector3(0.0, y, 0.0));
- normals.push_back(Vector3(0.0, -1.0, 0.0));
- ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
- uvs.push_back(Vector2(0.75, 0.75));
- point++;
+ float u = ((x + 1.0) * 0.25);
+ float v = 0.5 + ((z + 1.0) * 0.25);
- bone_indices.push_back(sections);
- bone_indices.push_back(0);
- bone_indices.push_back(0);
- bone_indices.push_back(0);
+ Vector3 p = Vector3(x * rm, y, z * rm);
+ points.push_back(p);
+ normals.push_back(Vector3(0.0, 1.0, 0.0));
+ ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
+ uvs.push_back(Vector2(u, v));
+ point++;
- bone_weights.push_back(1.0);
- bone_weights.push_back(0);
- bone_weights.push_back(0);
- bone_weights.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
- float rm = radius * scale_neg;
+ bone_weights.push_back(1.0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
- for (int i = 0; i <= radial_steps; i++) {
- float r = i;
- r /= radial_steps;
+ if (i > 0) {
+ indices.push_back(thisrow);
+ indices.push_back(point - 1);
+ indices.push_back(point - 2);
+ }
+ }
+ }
+ }
- float x = sin(r * Math_TAU);
- float z = cos(r * Math_TAU);
+ if (cap_bottom) {
+ float scale_neg = 1.0;
+ if (curve.is_valid() && curve->get_point_count() > 0) {
+ scale_neg = curve->sample_baked(1.0);
+ }
- float u = 0.5 + ((x + 1.0) * 0.25);
- float v = 1.0 - ((z + 1.0) * 0.25);
+ if (scale_neg > CMP_EPSILON) {
+ // add bottom
+ float y = depth * -0.5;
- Vector3 p = Vector3(x * rm, y, z * rm);
- points.push_back(p);
+ thisrow = point;
+ points.push_back(Vector3(0.0, y, 0.0));
normals.push_back(Vector3(0.0, -1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
- uvs.push_back(Vector2(u, v));
+ uvs.push_back(Vector2(0.75, 0.75));
point++;
bone_indices.push_back(sections);
@@ -2402,10 +2395,40 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
bone_weights.push_back(0);
bone_weights.push_back(0);
- if (i > 0) {
- indices.push_back(thisrow);
- indices.push_back(point - 2);
- indices.push_back(point - 1);
+ float rm = radius * scale_neg;
+
+ for (int i = 0; i <= radial_steps; i++) {
+ float r = i;
+ r /= radial_steps;
+
+ float x = sin(r * Math_TAU);
+ float z = cos(r * Math_TAU);
+
+ float u = 0.5 + ((x + 1.0) * 0.25);
+ float v = 1.0 - ((z + 1.0) * 0.25);
+
+ Vector3 p = Vector3(x * rm, y, z * rm);
+ points.push_back(p);
+ normals.push_back(Vector3(0.0, -1.0, 0.0));
+ ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
+ uvs.push_back(Vector2(u, v));
+ point++;
+
+ bone_indices.push_back(sections);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(1.0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+
+ if (i > 0) {
+ indices.push_back(thisrow);
+ indices.push_back(point - 2);
+ indices.push_back(point - 1);
+ }
}
}
}
@@ -2435,6 +2458,12 @@ void TubeTrailMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_section_rings", "section_rings"), &TubeTrailMesh::set_section_rings);
ClassDB::bind_method(D_METHOD("get_section_rings"), &TubeTrailMesh::get_section_rings);
+ ClassDB::bind_method(D_METHOD("set_cap_top", "cap_top"), &TubeTrailMesh::set_cap_top);
+ ClassDB::bind_method(D_METHOD("is_cap_top"), &TubeTrailMesh::is_cap_top);
+
+ ClassDB::bind_method(D_METHOD("set_cap_bottom", "cap_bottom"), &TubeTrailMesh::set_cap_bottom);
+ ClassDB::bind_method(D_METHOD("is_cap_bottom"), &TubeTrailMesh::is_cap_bottom);
+
ClassDB::bind_method(D_METHOD("set_curve", "curve"), &TubeTrailMesh::set_curve);
ClassDB::bind_method(D_METHOD("get_curve"), &TubeTrailMesh::get_curve);
@@ -2447,13 +2476,16 @@ void TubeTrailMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "section_rings", PROPERTY_HINT_RANGE, "1,128,1"), "set_section_rings", "get_section_rings");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cap_top"), "set_cap_top", "is_cap_top");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cap_bottom"), "set_cap_bottom", "is_cap_bottom");
+
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
}
TubeTrailMesh::TubeTrailMesh() {
}
-// TUBE TRAIL
+// RIBBON TRAIL
void RibbonTrailMesh::set_shape(Shape p_shape) {
shape = p_shape;
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 06f9781b84..5cef042a18 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -431,6 +431,8 @@ private:
int sections = 5;
float section_length = 0.2;
int section_rings = 3;
+ bool cap_top = true;
+ bool cap_bottom = true;
Ref<Curve> curve;
@@ -456,6 +458,12 @@ public:
void set_section_rings(const int p_section_rings);
int get_section_rings() const;
+ void set_cap_top(bool p_cap_top);
+ bool is_cap_top() const;
+
+ void set_cap_bottom(bool p_cap_bottom);
+ bool is_cap_bottom() const;
+
void set_curve(const Ref<Curve> &p_curve);
Ref<Curve> get_curve() const;
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 48ec084b02..c6621ce482 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -208,6 +208,7 @@ Shader::Shader() {
}
Shader::~Shader() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(shader);
}
diff --git a/scene/resources/sky.cpp b/scene/resources/sky.cpp
index 735134e27b..32ce0abf7a 100644
--- a/scene/resources/sky.cpp
+++ b/scene/resources/sky.cpp
@@ -106,5 +106,6 @@ Sky::Sky() {
}
Sky::~Sky() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(sky);
}
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 94967352c8..185cbdc6bf 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -46,7 +46,7 @@ void SurfaceTool::strip_mesh_arrays(PackedVector3Array &r_vertices, PackedInt32A
Vector<uint32_t> remap;
remap.resize(r_vertices.size());
- uint32_t new_vertex_count = generate_remap_func(remap.ptrw(), (unsigned int *)r_indices.ptr(), r_indices.size(), (float *)r_vertices.ptr(), r_vertices.size(), sizeof(Vector3));
+ uint32_t new_vertex_count = generate_remap_func(remap.ptrw(), (unsigned int *)r_indices.ptr(), r_indices.size(), r_vertices.ptr(), r_vertices.size(), sizeof(Vector3));
remap_vertex_func(r_vertices.ptrw(), r_vertices.ptr(), r_vertices.size(), sizeof(Vector3), remap.ptr());
r_vertices.resize(new_vertex_count);
remap_index_func((unsigned int *)r_indices.ptrw(), (unsigned int *)r_indices.ptr(), r_indices.size(), remap.ptr());
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index afab44834d..d094563e6a 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -56,8 +56,8 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextLine::set_bidi_override);
ClassDB::bind_method(D_METHOD("add_string", "text", "font", "font_size", "language", "meta"), &TextLine::add_string, DEFVAL(""), DEFVAL(Variant()));
- ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextLine::add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1));
- ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextLine::resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER));
+ ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length", "baseline"), &TextLine::add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align", "baseline"), &TextLine::resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("set_width", "width"), &TextLine::set_width);
ClassDB::bind_method(D_METHOD("get_width"), &TextLine::get_width);
@@ -202,15 +202,15 @@ bool TextLine::add_string(const String &p_text, const Ref<Font> &p_font, int p_f
return res;
}
-bool TextLine::add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length) {
- bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length);
+bool TextLine::add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length, float p_baseline) {
+ bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length, p_baseline);
dirty = true;
return res;
}
-bool TextLine::resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
+bool TextLine::resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, float p_baseline) {
const_cast<TextLine *>(this)->_shape();
- return TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align);
+ return TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align, p_baseline);
}
Array TextLine::get_objects() const {
diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h
index e70e82cf2b..801a8a8c11 100644
--- a/scene/resources/text_line.h
+++ b/scene/resources/text_line.h
@@ -76,8 +76,8 @@ public:
bool get_preserve_control() const;
bool add_string(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", const Variant &p_meta = Variant());
- bool add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1);
- bool resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER);
+ bool add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1, float p_baseline = 0.0);
+ bool resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, float p_baseline = 0.0);
void set_horizontal_alignment(HorizontalAlignment p_alignment);
HorizontalAlignment get_horizontal_alignment() const;
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 59bb24c8b8..d2e85d28e6 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -64,8 +64,8 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_dropcap"), &TextParagraph::clear_dropcap);
ClassDB::bind_method(D_METHOD("add_string", "text", "font", "font_size", "language", "meta"), &TextParagraph::add_string, DEFVAL(""), DEFVAL(Variant()));
- ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextParagraph::add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1));
- ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextParagraph::resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER));
+ ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length", "baseline"), &TextParagraph::add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align", "baseline"), &TextParagraph::resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("set_alignment", "alignment"), &TextParagraph::set_alignment);
ClassDB::bind_method(D_METHOD("get_alignment"), &TextParagraph::get_alignment);
@@ -385,18 +385,18 @@ void TextParagraph::set_bidi_override(const Array &p_override) {
lines_dirty = true;
}
-bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length) {
+bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length, float p_baseline) {
_THREAD_SAFE_METHOD_
- bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length);
+ bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length, p_baseline);
lines_dirty = true;
return res;
}
-bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
+bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, float p_baseline) {
_THREAD_SAFE_METHOD_
- bool res = TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align);
+ bool res = TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align, p_baseline);
lines_dirty = true;
return res;
}
diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h
index 0fe82b4364..dced278db4 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -95,8 +95,8 @@ public:
void clear_dropcap();
bool add_string(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", const Variant &p_meta = Variant());
- bool add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1);
- bool resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER);
+ bool add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1, float p_baseline = 0.0);
+ bool resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, float p_baseline = 0.0);
void set_alignment(HorizontalAlignment p_alignment);
HorizontalAlignment get_alignment() const;
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 2106619a6b..6193c62788 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -324,6 +324,7 @@ ImageTexture::ImageTexture() {}
ImageTexture::~ImageTexture() {
if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(texture);
}
}
@@ -630,6 +631,7 @@ PortableCompressedTexture2D::PortableCompressedTexture2D() {}
PortableCompressedTexture2D::~PortableCompressedTexture2D() {
if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(texture);
}
}
@@ -1041,6 +1043,7 @@ CompressedTexture2D::CompressedTexture2D() {}
CompressedTexture2D::~CompressedTexture2D() {
if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(texture);
}
}
@@ -1225,6 +1228,7 @@ ImageTexture3D::ImageTexture3D() {
ImageTexture3D::~ImageTexture3D() {
if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(texture);
}
}
@@ -1386,6 +1390,7 @@ CompressedTexture3D::CompressedTexture3D() {}
CompressedTexture3D::~CompressedTexture3D() {
if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(texture);
}
}
@@ -1591,35 +1596,28 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect,
return false;
}
- Rect2 rc = region;
-
Rect2 src = p_src_rect;
if (src.size == Size2()) {
- src.size = rc.size;
+ src.size = region.size;
}
Vector2 scale = p_rect.size / src.size;
- src.position += (rc.position - margin.position);
- Rect2 src_c = rc.intersection(src);
- if (src_c.size == Size2()) {
+ src.position += (region.position - margin.position);
+ Rect2 src_clipped = region.intersection(src);
+ if (src_clipped.size == Size2()) {
return false;
}
- Vector2 ofs = (src_c.position - src.position);
+ Vector2 ofs = (src_clipped.position - src.position);
if (scale.x < 0) {
- float mx = (margin.size.width - margin.position.x);
- mx -= margin.position.x;
- ofs.x = -(ofs.x + mx);
+ ofs.x += (src_clipped.size.x - src.size.x);
}
if (scale.y < 0) {
- float my = margin.size.height - margin.position.y;
- my -= margin.position.y;
- ofs.y = -(ofs.y + my);
+ ofs.y += (src_clipped.size.y - src.size.y);
}
- Rect2 dr(p_rect.position + ofs * scale, src_c.size * scale);
- r_rect = dr;
- r_src_rect = src_c;
+ r_rect = Rect2(p_rect.position + ofs * scale, src_clipped.size * scale);
+ r_src_rect = src_clipped;
return true;
}
@@ -1918,6 +1916,7 @@ CurveTexture::CurveTexture() {}
CurveTexture::~CurveTexture() {
if (_texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(_texture);
}
}
@@ -2116,6 +2115,7 @@ CurveXYZTexture::CurveXYZTexture() {}
CurveXYZTexture::~CurveXYZTexture() {
if (_texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(_texture);
}
}
@@ -2128,6 +2128,7 @@ GradientTexture1D::GradientTexture1D() {
GradientTexture1D::~GradientTexture1D() {
if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(texture);
}
}
@@ -2270,6 +2271,7 @@ GradientTexture2D::GradientTexture2D() {
GradientTexture2D::~GradientTexture2D() {
if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(texture);
}
}
@@ -2310,9 +2312,9 @@ void GradientTexture2D::_update() {
Ref<Image> image;
image.instantiate();
- if (gradient->get_points_count() <= 1) { // No need to interpolate.
+ if (gradient->get_point_count() <= 1) { // No need to interpolate.
image->initialize_data(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8);
- image->fill((gradient->get_points_count() == 1) ? gradient->get_color(0) : Color(0, 0, 0, 1));
+ image->fill((gradient->get_point_count() == 1) ? gradient->get_color(0) : Color(0, 0, 0, 1));
} else {
if (use_hdr) {
image->initialize_data(width, height, false, Image::FORMAT_RGBAF);
@@ -2528,6 +2530,7 @@ void ProxyTexture::set_base(const Ref<Texture2D> &p_texture) {
base = p_texture;
if (base.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
if (proxy_ph.is_valid()) {
RS::get_singleton()->texture_proxy_update(proxy, base->get_rid());
RS::get_singleton()->free(proxy_ph);
@@ -2578,6 +2581,7 @@ ProxyTexture::ProxyTexture() {
}
ProxyTexture::~ProxyTexture() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
if (proxy_ph.is_valid()) {
RS::get_singleton()->free(proxy_ph);
}
@@ -2835,6 +2839,7 @@ AnimatedTexture::AnimatedTexture() {
}
AnimatedTexture::~AnimatedTexture() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(proxy);
RS::get_singleton()->free(proxy_ph);
}
@@ -3038,6 +3043,7 @@ ImageTextureLayered::ImageTextureLayered(LayeredType p_layered_type) {
ImageTextureLayered::~ImageTextureLayered() {
if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(texture);
}
}
@@ -3205,6 +3211,7 @@ CompressedTextureLayered::CompressedTextureLayered(LayeredType p_type) {
CompressedTextureLayered::~CompressedTextureLayered() {
if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(texture);
}
}
@@ -3360,6 +3367,7 @@ CameraTexture::CameraTexture() {}
CameraTexture::~CameraTexture() {
if (_texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(_texture);
}
}
@@ -3393,7 +3401,7 @@ RID PlaceholderTexture2D::get_rid() const {
void PlaceholderTexture2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTexture2D::set_size);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
}
PlaceholderTexture2D::PlaceholderTexture2D() {
@@ -3401,6 +3409,7 @@ PlaceholderTexture2D::PlaceholderTexture2D() {
}
PlaceholderTexture2D::~PlaceholderTexture2D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(rid);
}
@@ -3448,6 +3457,7 @@ PlaceholderTexture3D::PlaceholderTexture3D() {
rid = RS::get_singleton()->texture_3d_placeholder_create();
}
PlaceholderTexture3D::~PlaceholderTexture3D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(rid);
}
@@ -3506,5 +3516,6 @@ PlaceholderTextureLayered::PlaceholderTextureLayered(LayeredType p_type) {
rid = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type));
}
PlaceholderTextureLayered::~PlaceholderTextureLayered() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(rid);
}
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 9d2537bb4d..0b0461432b 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -35,7 +35,6 @@
#include "core/math/geometry_2d.h"
#include "core/templates/local_vector.h"
#include "core/templates/rb_set.h"
-#include "scene/2d/navigation_region_2d.h"
#include "scene/gui/control.h"
#include "scene/resources/convex_polygon_shape_2d.h"
#include "servers/navigation_server_2d.h"
@@ -477,7 +476,7 @@ int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source
int new_source_id = p_atlas_source_id_override >= 0 ? p_atlas_source_id_override : next_source_id;
sources[new_source_id] = p_tile_set_source;
- source_ids.append(new_source_id);
+ source_ids.push_back(new_source_id);
source_ids.sort();
p_tile_set_source->set_tile_set(this);
_compute_next_source_id();
@@ -517,7 +516,7 @@ void TileSet::set_source_id(int p_source_id, int p_new_source_id) {
sources.erase(p_source_id);
source_ids.erase(p_source_id);
- source_ids.append(p_new_source_id);
+ source_ids.push_back(p_new_source_id);
source_ids.sort();
_compute_next_source_id();
@@ -1297,7 +1296,7 @@ void TileSet::cleanup_invalid_tile_proxies() {
Vector<int> source_to_remove;
for (const KeyValue<int, int> &E : source_level_proxies) {
if (has_source(E.key)) {
- source_to_remove.append(E.key);
+ source_to_remove.push_back(E.key);
}
}
for (int i = 0; i < source_to_remove.size(); i++) {
@@ -1309,7 +1308,7 @@ void TileSet::cleanup_invalid_tile_proxies() {
for (const KeyValue<Array, Array> &E : coords_level_proxies) {
Array a = E.key;
if (has_source(a[0]) && get_source(a[0])->has_tile(a[1])) {
- coords_to_remove.append(a);
+ coords_to_remove.push_back(a);
}
}
for (int i = 0; i < coords_to_remove.size(); i++) {
@@ -1322,7 +1321,7 @@ void TileSet::cleanup_invalid_tile_proxies() {
for (const KeyValue<Array, Array> &E : alternative_level_proxies) {
Array a = E.key;
if (has_source(a[0]) && get_source(a[0])->has_tile(a[1]) && get_source(a[0])->has_alternative_tile(a[1], a[2])) {
- alternative_to_remove.append(a);
+ alternative_to_remove.push_back(a);
}
}
for (int i = 0; i < alternative_to_remove.size(); i++) {
@@ -1439,16 +1438,18 @@ TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, Ti
Vector<Vector2> TileSet::get_tile_shape_polygon() {
Vector<Vector2> points;
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
- points.append(Vector2(-0.5, -0.5));
- points.append(Vector2(0.5, -0.5));
- points.append(Vector2(0.5, 0.5));
- points.append(Vector2(-0.5, 0.5));
+ points.push_back(Vector2(-0.5, -0.5));
+ points.push_back(Vector2(0.5, -0.5));
+ points.push_back(Vector2(0.5, 0.5));
+ points.push_back(Vector2(-0.5, 0.5));
+ } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ points.push_back(Vector2(0.0, -0.5));
+ points.push_back(Vector2(-0.5, 0.0));
+ points.push_back(Vector2(0.0, 0.5));
+ points.push_back(Vector2(0.5, 0.0));
} else {
float overlap = 0.0;
switch (tile_shape) {
- case TileSet::TILE_SHAPE_ISOMETRIC:
- overlap = 0.5;
- break;
case TileSet::TILE_SHAPE_HEXAGON:
overlap = 0.25;
break;
@@ -1459,12 +1460,13 @@ Vector<Vector2> TileSet::get_tile_shape_polygon() {
break;
}
- points.append(Vector2(0.0, -0.5));
- points.append(Vector2(-0.5, overlap - 0.5));
- points.append(Vector2(-0.5, 0.5 - overlap));
- points.append(Vector2(0.0, 0.5));
- points.append(Vector2(0.5, 0.5 - overlap));
- points.append(Vector2(0.5, overlap - 0.5));
+ points.push_back(Vector2(0.0, -0.5));
+ points.push_back(Vector2(-0.5, overlap - 0.5));
+ points.push_back(Vector2(-0.5, 0.5 - overlap));
+ points.push_back(Vector2(0.0, 0.5));
+ points.push_back(Vector2(0.5, 0.5 - overlap));
+ points.push_back(Vector2(0.5, overlap - 0.5));
+
if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
for (int i = 0; i < points.size(); i++) {
points.write[i] = Vector2(points[i].y, points[i].x);
@@ -3854,7 +3856,7 @@ bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value)
tiles[coords].alternatives[alternative_id] = memnew(TileData);
tiles[coords].alternatives[alternative_id]->set_tile_set(tile_set);
tiles[coords].alternatives[alternative_id]->set_allow_transform(alternative_id > 0);
- tiles[coords].alternatives_ids.append(alternative_id);
+ tiles[coords].alternatives_ids.push_back(alternative_id);
}
if (components.size() >= 3) {
bool valid;
@@ -4028,11 +4030,11 @@ void TileSetAtlasSource::create_tile(const Vector2i p_atlas_coords, const Vector
tad.alternatives[0]->set_allow_transform(false);
tad.alternatives[0]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed));
tad.alternatives[0]->notify_property_list_changed();
- tad.alternatives_ids.append(0);
+ tad.alternatives_ids.push_back(0);
// Create and resize the tile.
tiles.insert(p_atlas_coords, tad);
- tiles_ids.append(p_atlas_coords);
+ tiles_ids.push_back(p_atlas_coords);
tiles_ids.sort();
_create_coords_mapping_cache(p_atlas_coords);
@@ -4343,7 +4345,7 @@ void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_
tiles.erase(p_atlas_coords);
tiles_ids.erase(p_atlas_coords);
- tiles_ids.append(new_atlas_coords);
+ tiles_ids.push_back(new_atlas_coords);
tiles_ids.sort();
}
tiles[new_atlas_coords].size_in_atlas = new_size;
@@ -4365,7 +4367,7 @@ int TileSetAtlasSource::create_alternative_tile(const Vector2i p_atlas_coords, i
tiles[p_atlas_coords].alternatives[new_alternative_id]->set_allow_transform(true);
tiles[p_atlas_coords].alternatives[new_alternative_id]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed));
tiles[p_atlas_coords].alternatives[new_alternative_id]->notify_property_list_changed();
- tiles[p_atlas_coords].alternatives_ids.append(new_alternative_id);
+ tiles[p_atlas_coords].alternatives_ids.push_back(new_alternative_id);
tiles[p_atlas_coords].alternatives_ids.sort();
_compute_next_alternative_id(p_atlas_coords);
@@ -4395,7 +4397,7 @@ void TileSetAtlasSource::set_alternative_tile_id(const Vector2i p_atlas_coords,
ERR_FAIL_COND_MSG(tiles[p_atlas_coords].alternatives.has(p_new_id), vformat("TileSetAtlasSource has already an alternative with id %d at %s.", p_new_id, String(p_atlas_coords)));
tiles[p_atlas_coords].alternatives[p_new_id] = tiles[p_atlas_coords].alternatives[p_alternative_tile];
- tiles[p_atlas_coords].alternatives_ids.append(p_new_id);
+ tiles[p_atlas_coords].alternatives_ids.push_back(p_new_id);
tiles[p_atlas_coords].alternatives.erase(p_alternative_tile);
tiles[p_atlas_coords].alternatives_ids.erase(p_alternative_tile);
@@ -4683,7 +4685,7 @@ int TileSetScenesCollectionSource::create_scene_tile(Ref<PackedScene> p_packed_s
int new_scene_id = p_id_override >= 0 ? p_id_override : next_scene_id;
scenes[new_scene_id] = SceneData();
- scenes_ids.append(new_scene_id);
+ scenes_ids.push_back(new_scene_id);
scenes_ids.sort();
set_scene_tile_scene(new_scene_id, p_packed_scene);
_compute_next_alternative_id();
@@ -4700,7 +4702,7 @@ void TileSetScenesCollectionSource::set_scene_tile_id(int p_id, int p_new_id) {
scenes[p_new_id] = SceneData();
scenes[p_new_id] = scenes[p_id];
- scenes_ids.append(p_new_id);
+ scenes_ids.push_back(p_new_id);
scenes_ids.sort();
_compute_next_alternative_id();
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 9f465a17e9..88bbbd157a 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -36,10 +36,10 @@
#include "core/templates/local_vector.h"
#include "core/templates/rb_set.h"
#include "scene/2d/light_occluder_2d.h"
-#include "scene/2d/navigation_region_2d.h"
#include "scene/main/canvas_item.h"
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
+#include "scene/resources/navigation_polygon.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/physics_material.h"
#include "scene/resources/shape_2d.h"
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 6b8f8097a8..fc2366a78c 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -2650,6 +2650,10 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "camera_visible_layers", "CAMERA_VISIBLE_LAYERS" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_view", "NODE_POSITION_VIEW" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom0", "CUSTOM0" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom1", "CUSTOM1" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom2", "CUSTOM2" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom3", "CUSTOM3" },
// Node3D, Fragment
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index 75deb1e60b..85ce47f06c 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -89,6 +89,9 @@ World2D::World2D() {
}
World2D::~World2D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ ERR_FAIL_NULL(PhysicsServer2D::get_singleton());
+ ERR_FAIL_NULL(NavigationServer2D::get_singleton());
RenderingServer::get_singleton()->free(canvas);
PhysicsServer2D::get_singleton()->free(space);
NavigationServer2D::get_singleton()->free(navigation_map);
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index ae8c9a182f..8808da95d7 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -157,6 +157,9 @@ World3D::World3D() {
}
World3D::~World3D() {
+ ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ ERR_FAIL_NULL(NavigationServer3D::get_singleton());
PhysicsServer3D::get_singleton()->free(space);
RenderingServer::get_singleton()->free(scenario);
NavigationServer3D::get_singleton()->free(navigation_map);
diff --git a/scene/theme/theme_db.cpp b/scene/theme/theme_db.cpp
index 0268a685fe..ae64313741 100644
--- a/scene/theme/theme_db.cpp
+++ b/scene/theme/theme_db.cpp
@@ -70,7 +70,9 @@ void ThemeDB::initialize_theme() {
Ref<Font> font;
if (!font_path.is_empty()) {
font = ResourceLoader::load(font_path);
- if (!font.is_valid()) {
+ if (font.is_valid()) {
+ set_fallback_font(font);
+ } else {
ERR_PRINT("Error loading custom font '" + font_path + "'");
}
}
@@ -84,9 +86,6 @@ void ThemeDB::initialize_theme() {
Ref<Theme> theme = ResourceLoader::load(theme_path);
if (theme.is_valid()) {
set_project_theme(theme);
- if (font.is_valid()) {
- set_fallback_font(font);
- }
} else {
ERR_PRINT("Error loading custom theme '" + theme_path + "'");
}
diff --git a/scene/theme/theme_owner.cpp b/scene/theme/theme_owner.cpp
index e89aa1b28d..44e0c5d0c8 100644
--- a/scene/theme/theme_owner.cpp
+++ b/scene/theme/theme_owner.cpp
@@ -205,16 +205,7 @@ Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const S
while (owner_node) {
// For each theme resource check the theme types provided and see if p_name exists with any of them.
for (const StringName &E : p_theme_types) {
- Ref<Theme> owner_theme;
-
- Control *owner_c = Object::cast_to<Control>(owner_node);
- if (owner_c) {
- owner_theme = owner_c->get_theme();
- }
- Window *owner_w = Object::cast_to<Window>(owner_node);
- if (owner_w) {
- owner_theme = owner_w->get_theme();
- }
+ Ref<Theme> owner_theme = _get_owner_node_theme(owner_node);
if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) {
return owner_theme->get_theme_item(p_data_type, p_name, E);
@@ -254,16 +245,7 @@ bool ThemeOwner::has_theme_item_in_types(Theme::DataType p_data_type, const Stri
while (owner_node) {
// For each theme resource check the theme types provided and see if p_name exists with any of them.
for (const StringName &E : p_theme_types) {
- Ref<Theme> owner_theme;
-
- Control *owner_c = Object::cast_to<Control>(owner_node);
- if (owner_c) {
- owner_theme = owner_c->get_theme();
- }
- Window *owner_w = Object::cast_to<Window>(owner_node);
- if (owner_w) {
- owner_theme = owner_w->get_theme();
- }
+ Ref<Theme> owner_theme = _get_owner_node_theme(owner_node);
if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) {
return true;
@@ -299,16 +281,7 @@ float ThemeOwner::get_theme_default_base_scale() {
Node *owner_node = get_owner_node();
while (owner_node) {
- Ref<Theme> owner_theme;
-
- Control *owner_c = Object::cast_to<Control>(owner_node);
- if (owner_c) {
- owner_theme = owner_c->get_theme();
- }
- Window *owner_w = Object::cast_to<Window>(owner_node);
- if (owner_w) {
- owner_theme = owner_w->get_theme();
- }
+ Ref<Theme> owner_theme = _get_owner_node_theme(owner_node);
if (owner_theme.is_valid() && owner_theme->has_default_base_scale()) {
return owner_theme->get_default_base_scale();
@@ -338,16 +311,7 @@ Ref<Font> ThemeOwner::get_theme_default_font() {
Node *owner_node = get_owner_node();
while (owner_node) {
- Ref<Theme> owner_theme;
-
- Control *owner_c = Object::cast_to<Control>(owner_node);
- if (owner_c) {
- owner_theme = owner_c->get_theme();
- }
- Window *owner_w = Object::cast_to<Window>(owner_node);
- if (owner_w) {
- owner_theme = owner_w->get_theme();
- }
+ Ref<Theme> owner_theme = _get_owner_node_theme(owner_node);
if (owner_theme.is_valid() && owner_theme->has_default_font()) {
return owner_theme->get_default_font();
@@ -377,16 +341,7 @@ int ThemeOwner::get_theme_default_font_size() {
Node *owner_node = get_owner_node();
while (owner_node) {
- Ref<Theme> owner_theme;
-
- Control *owner_c = Object::cast_to<Control>(owner_node);
- if (owner_c) {
- owner_theme = owner_c->get_theme();
- }
- Window *owner_w = Object::cast_to<Window>(owner_node);
- if (owner_w) {
- owner_theme = owner_w->get_theme();
- }
+ Ref<Theme> owner_theme = _get_owner_node_theme(owner_node);
if (owner_theme.is_valid() && owner_theme->has_default_font_size()) {
return owner_theme->get_default_font_size();
@@ -408,3 +363,17 @@ int ThemeOwner::get_theme_default_font_size() {
}
return ThemeDB::get_singleton()->get_fallback_font_size();
}
+
+Ref<Theme> ThemeOwner::_get_owner_node_theme(Node *p_owner_node) const {
+ const Control *owner_c = Object::cast_to<Control>(p_owner_node);
+ if (owner_c) {
+ return owner_c->get_theme();
+ }
+
+ const Window *owner_w = Object::cast_to<Window>(p_owner_node);
+ if (owner_w) {
+ return owner_w->get_theme();
+ }
+
+ return Ref<Theme>();
+}
diff --git a/scene/theme/theme_owner.h b/scene/theme/theme_owner.h
index 59b72c1627..60d60f525c 100644
--- a/scene/theme/theme_owner.h
+++ b/scene/theme/theme_owner.h
@@ -43,6 +43,7 @@ class ThemeOwner : public Object {
Window *owner_window = nullptr;
Node *_get_next_owner_node(Node *p_from_node) const;
+ Ref<Theme> _get_owner_node_theme(Node *p_owner_node) const;
public:
// Theme owner node.
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
index 113e728106..84c21f7cd6 100644
--- a/servers/audio/audio_stream.cpp
+++ b/servers/audio/audio_stream.cpp
@@ -410,12 +410,12 @@ AudioStreamPlaybackMicrophone::AudioStreamPlaybackMicrophone() {
////////////////////////////////
-void AudioStreamRandomizer::add_stream(int p_index) {
+void AudioStreamRandomizer::add_stream(int p_index, Ref<AudioStream> p_stream, float p_weight) {
if (p_index < 0) {
p_index = audio_stream_pool.size();
}
ERR_FAIL_COND(p_index > audio_stream_pool.size());
- PoolEntry entry{ nullptr, 1.0f };
+ PoolEntry entry{ p_stream, p_weight };
audio_stream_pool.insert(p_index, entry);
emit_signal(SNAME("changed"));
notify_property_list_changed();
@@ -709,7 +709,7 @@ void AudioStreamRandomizer::_get_property_list(List<PropertyInfo> *p_list) const
}
void AudioStreamRandomizer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_stream", "index"), &AudioStreamRandomizer::add_stream);
+ ClassDB::bind_method(D_METHOD("add_stream", "index", "stream", "weight"), &AudioStreamRandomizer::add_stream, DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("move_stream", "index_from", "index_to"), &AudioStreamRandomizer::move_stream);
ClassDB::bind_method(D_METHOD("remove_stream", "index"), &AudioStreamRandomizer::remove_stream);
diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h
index c6ae6817e7..0d3f7bca04 100644
--- a/servers/audio/audio_stream.h
+++ b/servers/audio/audio_stream.h
@@ -241,7 +241,7 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const;
public:
- void add_stream(int p_index);
+ void add_stream(int p_index, Ref<AudioStream> p_stream, float p_weight = 1.0);
void move_stream(int p_index_from, int p_index_to);
void remove_stream(int p_index);
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index e657570f9b..c7d626c159 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -449,12 +449,8 @@ void AudioServer::_mix_step() {
case AudioStreamPlaybackListNode::AWAITING_DELETION:
case AudioStreamPlaybackListNode::FADE_OUT_TO_DELETION:
playback_list.erase(playback, [](AudioStreamPlaybackListNode *p) {
- if (p->prev_bus_details) {
- delete p->prev_bus_details;
- }
- if (p->bus_details) {
- delete p->bus_details;
- }
+ delete p->prev_bus_details;
+ delete p->bus_details;
p->stream_playback.unref();
delete p;
});
diff --git a/servers/camera/camera_feed.cpp b/servers/camera/camera_feed.cpp
index 624c06ecf1..e5b160ae27 100644
--- a/servers/camera/camera_feed.cpp
+++ b/servers/camera/camera_feed.cpp
@@ -165,6 +165,7 @@ CameraFeed::CameraFeed(String p_name, FeedPosition p_position) {
CameraFeed::~CameraFeed() {
// Free our textures
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(texture[CameraServer::FEED_Y_IMAGE]);
RenderingServer::get_singleton()->free(texture[CameraServer::FEED_CBCR_IMAGE]);
}
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 523cc714f0..68d625b083 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -379,7 +379,7 @@ bool DisplayServer::screen_is_kept_on() const {
return false;
}
-DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
+DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) {
ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server.");
}
diff --git a/servers/display_server.h b/servers/display_server.h
index 4c36b0acb9..67e7a82e25 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -312,7 +312,7 @@ public:
WINDOW_FLAG_EXTEND_TO_TITLE_BIT = (1 << WINDOW_FLAG_EXTEND_TO_TITLE),
};
- virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
+ virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0);
virtual void show_window(WindowID p_id);
virtual void delete_sub_window(WindowID p_id);
diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h
index 94b5f3c1e9..c4f6c7f165 100644
--- a/servers/display_server_headless.h
+++ b/servers/display_server_headless.h
@@ -66,7 +66,7 @@ public:
Vector<DisplayServer::WindowID> get_window_list() const override { return Vector<DisplayServer::WindowID>(); }
- WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override { return 0; }
+ WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0) override { return 0; }
void show_window(WindowID p_id) override {}
void delete_sub_window(WindowID p_id) override {}
diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp
index 811ff231fc..4ed2bb49d4 100644
--- a/servers/extensions/physics_server_3d_extension.cpp
+++ b/servers/extensions/physics_server_3d_extension.cpp
@@ -400,6 +400,9 @@ void PhysicsServer3DExtension::_bind_methods() {
GDVIRTUAL_BIND(_joint_set_solver_priority, "joint", "priority");
GDVIRTUAL_BIND(_joint_get_solver_priority, "joint");
+ GDVIRTUAL_BIND(_joint_disable_collisions_between_bodies, "joint", "disable");
+ GDVIRTUAL_BIND(_joint_is_disabled_collisions_between_bodies, "joint");
+
GDVIRTUAL_BIND(_free_rid, "rid");
GDVIRTUAL_BIND(_set_active, "active");
diff --git a/servers/navigation/navigation_path_query_parameters_2d.cpp b/servers/navigation/navigation_path_query_parameters_2d.cpp
index 574af90be1..717ada3834 100644
--- a/servers/navigation/navigation_path_query_parameters_2d.cpp
+++ b/servers/navigation/navigation_path_query_parameters_2d.cpp
@@ -105,11 +105,19 @@ Vector2 NavigationPathQueryParameters2D::get_target_position() const {
void NavigationPathQueryParameters2D::set_navigation_layers(uint32_t p_navigation_layers) {
parameters.navigation_layers = p_navigation_layers;
-};
+}
uint32_t NavigationPathQueryParameters2D::get_navigation_layers() const {
return parameters.navigation_layers;
-};
+}
+
+void NavigationPathQueryParameters2D::set_metadata_flags(BitField<NavigationPathQueryParameters2D::PathMetadataFlags> p_flags) {
+ parameters.metadata_flags = (int64_t)p_flags;
+}
+
+BitField<NavigationPathQueryParameters2D::PathMetadataFlags> NavigationPathQueryParameters2D::get_metadata_flags() const {
+ return (int64_t)parameters.metadata_flags;
+}
void NavigationPathQueryParameters2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pathfinding_algorithm", "pathfinding_algorithm"), &NavigationPathQueryParameters2D::set_pathfinding_algorithm);
@@ -130,15 +138,25 @@ void NavigationPathQueryParameters2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationPathQueryParameters2D::set_navigation_layers);
ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationPathQueryParameters2D::get_navigation_layers);
+ ClassDB::bind_method(D_METHOD("set_metadata_flags", "flags"), &NavigationPathQueryParameters2D::set_metadata_flags);
+ ClassDB::bind_method(D_METHOD("get_metadata_flags"), &NavigationPathQueryParameters2D::get_metadata_flags);
+
ADD_PROPERTY(PropertyInfo(Variant::RID, "map"), "set_map", "get_map");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "start_position"), "set_start_position", "get_start_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_position"), "set_target_position", "get_target_position");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered"), "set_path_postprocessing", "get_path_postprocessing");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_metadata_flags", "get_metadata_flags");
BIND_ENUM_CONSTANT(PATHFINDING_ALGORITHM_ASTAR);
BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_CORRIDORFUNNEL);
BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_EDGECENTERED);
+
+ BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_NONE);
+ BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_TYPES);
+ BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_RIDS);
+ BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_OWNERS);
+ BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_ALL);
}
diff --git a/servers/navigation/navigation_path_query_parameters_2d.h b/servers/navigation/navigation_path_query_parameters_2d.h
index c0ef337a27..aeabe1f690 100644
--- a/servers/navigation/navigation_path_query_parameters_2d.h
+++ b/servers/navigation/navigation_path_query_parameters_2d.h
@@ -52,6 +52,14 @@ public:
PATH_POSTPROCESSING_EDGECENTERED,
};
+ enum PathMetadataFlags {
+ PATH_METADATA_INCLUDE_NONE = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_NONE,
+ PATH_METADATA_INCLUDE_TYPES = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_TYPES,
+ PATH_METADATA_INCLUDE_RIDS = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_RIDS,
+ PATH_METADATA_INCLUDE_OWNERS = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_OWNERS,
+ PATH_METADATA_INCLUDE_ALL = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_ALL
+ };
+
const NavigationUtilities::PathQueryParameters &get_parameters() const { return parameters; }
void set_pathfinding_algorithm(const PathfindingAlgorithm p_pathfinding_algorithm);
@@ -71,9 +79,13 @@ public:
void set_navigation_layers(uint32_t p_navigation_layers);
uint32_t get_navigation_layers() const;
+
+ void set_metadata_flags(BitField<NavigationPathQueryParameters2D::PathMetadataFlags> p_flags);
+ BitField<NavigationPathQueryParameters2D::PathMetadataFlags> get_metadata_flags() const;
};
VARIANT_ENUM_CAST(NavigationPathQueryParameters2D::PathfindingAlgorithm);
VARIANT_ENUM_CAST(NavigationPathQueryParameters2D::PathPostProcessing);
+VARIANT_BITFIELD_CAST(NavigationPathQueryParameters2D::PathMetadataFlags);
#endif // NAVIGATION_PATH_QUERY_PARAMETERS_2D_H
diff --git a/servers/navigation/navigation_path_query_parameters_3d.cpp b/servers/navigation/navigation_path_query_parameters_3d.cpp
index b09448e82e..180af57af5 100644
--- a/servers/navigation/navigation_path_query_parameters_3d.cpp
+++ b/servers/navigation/navigation_path_query_parameters_3d.cpp
@@ -111,6 +111,14 @@ uint32_t NavigationPathQueryParameters3D::get_navigation_layers() const {
return parameters.navigation_layers;
}
+void NavigationPathQueryParameters3D::set_metadata_flags(BitField<NavigationPathQueryParameters3D::PathMetadataFlags> p_flags) {
+ parameters.metadata_flags = (int64_t)p_flags;
+}
+
+BitField<NavigationPathQueryParameters3D::PathMetadataFlags> NavigationPathQueryParameters3D::get_metadata_flags() const {
+ return (int64_t)parameters.metadata_flags;
+}
+
void NavigationPathQueryParameters3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pathfinding_algorithm", "pathfinding_algorithm"), &NavigationPathQueryParameters3D::set_pathfinding_algorithm);
ClassDB::bind_method(D_METHOD("get_pathfinding_algorithm"), &NavigationPathQueryParameters3D::get_pathfinding_algorithm);
@@ -130,15 +138,25 @@ void NavigationPathQueryParameters3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationPathQueryParameters3D::set_navigation_layers);
ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationPathQueryParameters3D::get_navigation_layers);
+ ClassDB::bind_method(D_METHOD("set_metadata_flags", "flags"), &NavigationPathQueryParameters3D::set_metadata_flags);
+ ClassDB::bind_method(D_METHOD("get_metadata_flags"), &NavigationPathQueryParameters3D::get_metadata_flags);
+
ADD_PROPERTY(PropertyInfo(Variant::RID, "map"), "set_map", "get_map");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "start_position"), "set_start_position", "get_start_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position"), "set_target_position", "get_target_position");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered"), "set_path_postprocessing", "get_path_postprocessing");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_metadata_flags", "get_metadata_flags");
BIND_ENUM_CONSTANT(PATHFINDING_ALGORITHM_ASTAR);
BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_CORRIDORFUNNEL);
BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_EDGECENTERED);
+
+ BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_NONE);
+ BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_TYPES);
+ BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_RIDS);
+ BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_OWNERS);
+ BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_ALL);
}
diff --git a/servers/navigation/navigation_path_query_parameters_3d.h b/servers/navigation/navigation_path_query_parameters_3d.h
index b4cf02fc79..386c83dece 100644
--- a/servers/navigation/navigation_path_query_parameters_3d.h
+++ b/servers/navigation/navigation_path_query_parameters_3d.h
@@ -52,6 +52,14 @@ public:
PATH_POSTPROCESSING_EDGECENTERED,
};
+ enum PathMetadataFlags {
+ PATH_METADATA_INCLUDE_NONE = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_NONE,
+ PATH_METADATA_INCLUDE_TYPES = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_TYPES,
+ PATH_METADATA_INCLUDE_RIDS = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_RIDS,
+ PATH_METADATA_INCLUDE_OWNERS = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_OWNERS,
+ PATH_METADATA_INCLUDE_ALL = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_ALL
+ };
+
const NavigationUtilities::PathQueryParameters &get_parameters() const { return parameters; }
void set_pathfinding_algorithm(const PathfindingAlgorithm p_pathfinding_algorithm);
@@ -71,9 +79,13 @@ public:
void set_navigation_layers(uint32_t p_navigation_layers);
uint32_t get_navigation_layers() const;
+
+ void set_metadata_flags(BitField<NavigationPathQueryParameters3D::PathMetadataFlags> p_flags);
+ BitField<NavigationPathQueryParameters3D::PathMetadataFlags> get_metadata_flags() const;
};
VARIANT_ENUM_CAST(NavigationPathQueryParameters3D::PathfindingAlgorithm);
VARIANT_ENUM_CAST(NavigationPathQueryParameters3D::PathPostProcessing);
+VARIANT_BITFIELD_CAST(NavigationPathQueryParameters3D::PathMetadataFlags);
#endif // NAVIGATION_PATH_QUERY_PARAMETERS_3D_H
diff --git a/servers/navigation/navigation_path_query_result_2d.cpp b/servers/navigation/navigation_path_query_result_2d.cpp
index 8a55451e40..e2764daa9a 100644
--- a/servers/navigation/navigation_path_query_result_2d.cpp
+++ b/servers/navigation/navigation_path_query_result_2d.cpp
@@ -38,15 +38,57 @@ const Vector<Vector2> &NavigationPathQueryResult2D::get_path() const {
return path;
}
+void NavigationPathQueryResult2D::set_path_types(const Vector<int32_t> &p_path_types) {
+ path_types = p_path_types;
+}
+
+const Vector<int32_t> &NavigationPathQueryResult2D::get_path_types() const {
+ return path_types;
+}
+
+void NavigationPathQueryResult2D::set_path_rids(const TypedArray<RID> &p_path_rids) {
+ path_rids = p_path_rids;
+}
+
+TypedArray<RID> NavigationPathQueryResult2D::get_path_rids() const {
+ return path_rids;
+}
+
+void NavigationPathQueryResult2D::set_path_owner_ids(const Vector<int64_t> &p_path_owner_ids) {
+ path_owner_ids = p_path_owner_ids;
+}
+
+const Vector<int64_t> &NavigationPathQueryResult2D::get_path_owner_ids() const {
+ return path_owner_ids;
+}
+
void NavigationPathQueryResult2D::reset() {
path.clear();
+ path_types.clear();
+ path_rids.clear();
+ path_owner_ids.clear();
}
void NavigationPathQueryResult2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_path", "path"), &NavigationPathQueryResult2D::set_path);
ClassDB::bind_method(D_METHOD("get_path"), &NavigationPathQueryResult2D::get_path);
+ ClassDB::bind_method(D_METHOD("set_path_types", "path_types"), &NavigationPathQueryResult2D::set_path_types);
+ ClassDB::bind_method(D_METHOD("get_path_types"), &NavigationPathQueryResult2D::get_path_types);
+
+ ClassDB::bind_method(D_METHOD("set_path_rids", "path_rids"), &NavigationPathQueryResult2D::set_path_rids);
+ ClassDB::bind_method(D_METHOD("get_path_rids"), &NavigationPathQueryResult2D::get_path_rids);
+
+ ClassDB::bind_method(D_METHOD("set_path_owner_ids", "path_owner_ids"), &NavigationPathQueryResult2D::set_path_owner_ids);
+ ClassDB::bind_method(D_METHOD("get_path_owner_ids"), &NavigationPathQueryResult2D::get_path_owner_ids);
+
ClassDB::bind_method(D_METHOD("reset"), &NavigationPathQueryResult2D::reset);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "path"), "set_path", "get_path");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "path_types"), "set_path_types", "get_path_types");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "path_rids", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_path_rids", "get_path_rids");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT64_ARRAY, "path_owner_ids"), "set_path_owner_ids", "get_path_owner_ids");
+
+ BIND_ENUM_CONSTANT(PATH_SEGMENT_TYPE_REGION);
+ BIND_ENUM_CONSTANT(PATH_SEGMENT_TYPE_LINK);
}
diff --git a/servers/navigation/navigation_path_query_result_2d.h b/servers/navigation/navigation_path_query_result_2d.h
index da251ef32d..852a9780ef 100644
--- a/servers/navigation/navigation_path_query_result_2d.h
+++ b/servers/navigation/navigation_path_query_result_2d.h
@@ -38,15 +38,34 @@ class NavigationPathQueryResult2D : public RefCounted {
GDCLASS(NavigationPathQueryResult2D, RefCounted);
Vector<Vector2> path;
+ Vector<int32_t> path_types;
+ TypedArray<RID> path_rids;
+ Vector<int64_t> path_owner_ids;
protected:
static void _bind_methods();
public:
+ enum PathSegmentType {
+ PATH_SEGMENT_TYPE_REGION = 0,
+ PATH_SEGMENT_TYPE_LINK = 1,
+ };
+
void set_path(const Vector<Vector2> &p_path);
const Vector<Vector2> &get_path() const;
+ void set_path_types(const Vector<int32_t> &p_path_types);
+ const Vector<int32_t> &get_path_types() const;
+
+ void set_path_rids(const TypedArray<RID> &p_path_rids);
+ TypedArray<RID> get_path_rids() const;
+
+ void set_path_owner_ids(const Vector<int64_t> &p_path_owner_ids);
+ const Vector<int64_t> &get_path_owner_ids() const;
+
void reset();
};
+VARIANT_ENUM_CAST(NavigationPathQueryResult2D::PathSegmentType);
+
#endif // NAVIGATION_PATH_QUERY_RESULT_2D_H
diff --git a/servers/navigation/navigation_path_query_result_3d.cpp b/servers/navigation/navigation_path_query_result_3d.cpp
index 1e28352995..8218adec18 100644
--- a/servers/navigation/navigation_path_query_result_3d.cpp
+++ b/servers/navigation/navigation_path_query_result_3d.cpp
@@ -38,15 +38,57 @@ const Vector<Vector3> &NavigationPathQueryResult3D::get_path() const {
return path;
}
+void NavigationPathQueryResult3D::set_path_types(const Vector<int32_t> &p_path_types) {
+ path_types = p_path_types;
+}
+
+const Vector<int32_t> &NavigationPathQueryResult3D::get_path_types() const {
+ return path_types;
+}
+
+void NavigationPathQueryResult3D::set_path_rids(const TypedArray<RID> &p_path_rids) {
+ path_rids = p_path_rids;
+}
+
+TypedArray<RID> NavigationPathQueryResult3D::get_path_rids() const {
+ return path_rids;
+}
+
+void NavigationPathQueryResult3D::set_path_owner_ids(const Vector<int64_t> &p_path_owner_ids) {
+ path_owner_ids = p_path_owner_ids;
+}
+
+const Vector<int64_t> &NavigationPathQueryResult3D::get_path_owner_ids() const {
+ return path_owner_ids;
+}
+
void NavigationPathQueryResult3D::reset() {
path.clear();
+ path_types.clear();
+ path_rids.clear();
+ path_owner_ids.clear();
}
void NavigationPathQueryResult3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_path", "path"), &NavigationPathQueryResult3D::set_path);
ClassDB::bind_method(D_METHOD("get_path"), &NavigationPathQueryResult3D::get_path);
+ ClassDB::bind_method(D_METHOD("set_path_types", "path_types"), &NavigationPathQueryResult3D::set_path_types);
+ ClassDB::bind_method(D_METHOD("get_path_types"), &NavigationPathQueryResult3D::get_path_types);
+
+ ClassDB::bind_method(D_METHOD("set_path_rids", "path_rids"), &NavigationPathQueryResult3D::set_path_rids);
+ ClassDB::bind_method(D_METHOD("get_path_rids"), &NavigationPathQueryResult3D::get_path_rids);
+
+ ClassDB::bind_method(D_METHOD("set_path_owner_ids", "path_owner_ids"), &NavigationPathQueryResult3D::set_path_owner_ids);
+ ClassDB::bind_method(D_METHOD("get_path_owner_ids"), &NavigationPathQueryResult3D::get_path_owner_ids);
+
ClassDB::bind_method(D_METHOD("reset"), &NavigationPathQueryResult3D::reset);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "path"), "set_path", "get_path");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "path_types"), "set_path_types", "get_path_types");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "path_rids", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_path_rids", "get_path_rids");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT64_ARRAY, "path_owner_ids"), "set_path_owner_ids", "get_path_owner_ids");
+
+ BIND_ENUM_CONSTANT(PATH_SEGMENT_TYPE_REGION);
+ BIND_ENUM_CONSTANT(PATH_SEGMENT_TYPE_LINK);
}
diff --git a/servers/navigation/navigation_path_query_result_3d.h b/servers/navigation/navigation_path_query_result_3d.h
index fc143ac389..ce34e18dc1 100644
--- a/servers/navigation/navigation_path_query_result_3d.h
+++ b/servers/navigation/navigation_path_query_result_3d.h
@@ -32,21 +32,41 @@
#define NAVIGATION_PATH_QUERY_RESULT_3D_H
#include "core/object/ref_counted.h"
+#include "core/variant/typed_array.h"
#include "servers/navigation/navigation_utilities.h"
class NavigationPathQueryResult3D : public RefCounted {
GDCLASS(NavigationPathQueryResult3D, RefCounted);
Vector<Vector3> path;
+ Vector<int32_t> path_types;
+ TypedArray<RID> path_rids;
+ Vector<int64_t> path_owner_ids;
protected:
static void _bind_methods();
public:
+ enum PathSegmentType {
+ PATH_SEGMENT_TYPE_REGION = 0,
+ PATH_SEGMENT_TYPE_LINK = 1,
+ };
+
void set_path(const Vector<Vector3> &p_path);
const Vector<Vector3> &get_path() const;
+ void set_path_types(const Vector<int32_t> &p_path_types);
+ const Vector<int32_t> &get_path_types() const;
+
+ void set_path_rids(const TypedArray<RID> &p_path_rids);
+ TypedArray<RID> get_path_rids() const;
+
+ void set_path_owner_ids(const Vector<int64_t> &p_path_owner_ids);
+ const Vector<int64_t> &get_path_owner_ids() const;
+
void reset();
};
+VARIANT_ENUM_CAST(NavigationPathQueryResult3D::PathSegmentType);
+
#endif // NAVIGATION_PATH_QUERY_RESULT_3D_H
diff --git a/servers/navigation/navigation_utilities.h b/servers/navigation/navigation_utilities.h
index e99c139528..c22a2ed952 100644
--- a/servers/navigation/navigation_utilities.h
+++ b/servers/navigation/navigation_utilities.h
@@ -32,6 +32,7 @@
#define NAVIGATION_UTILITIES_H
#include "core/math/vector3.h"
+#include "core/variant/typed_array.h"
namespace NavigationUtilities {
@@ -44,6 +45,19 @@ enum PathPostProcessing {
PATH_POSTPROCESSING_EDGECENTERED,
};
+enum PathSegmentType {
+ PATH_SEGMENT_TYPE_REGION = 0,
+ PATH_SEGMENT_TYPE_LINK
+};
+
+enum PathMetadataFlags {
+ PATH_INCLUDE_NONE = 0,
+ PATH_INCLUDE_TYPES = 1,
+ PATH_INCLUDE_RIDS = 2,
+ PATH_INCLUDE_OWNERS = 4,
+ PATH_INCLUDE_ALL = PATH_INCLUDE_TYPES | PATH_INCLUDE_RIDS | PATH_INCLUDE_OWNERS
+};
+
struct PathQueryParameters {
PathfindingAlgorithm pathfinding_algorithm = PATHFINDING_ALGORITHM_ASTAR;
PathPostProcessing path_postprocessing = PATH_POSTPROCESSING_CORRIDORFUNNEL;
@@ -51,10 +65,14 @@ struct PathQueryParameters {
Vector3 start_position;
Vector3 target_position;
uint32_t navigation_layers = 1;
+ BitField<PathMetadataFlags> metadata_flags = PATH_INCLUDE_ALL;
};
struct PathQueryResult {
Vector<Vector3> path;
+ Vector<int32_t> path_types;
+ TypedArray<RID> path_rids;
+ Vector<int64_t> path_owner_ids;
};
} //namespace NavigationUtilities
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index 4ed998a77e..6fd5f222cf 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -154,7 +154,7 @@ static ObjectID id_to_id(const ObjectID &id) {
static Ref<NavigationMesh> poly_to_mesh(Ref<NavigationPolygon> d) {
if (d.is_valid()) {
- return d->get_mesh();
+ return d->get_navigation_mesh();
} else {
return Ref<NavigationMesh>();
}
@@ -258,7 +258,7 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("region_set_navigation_layers", "region", "navigation_layers"), &NavigationServer2D::region_set_navigation_layers);
ClassDB::bind_method(D_METHOD("region_get_navigation_layers", "region"), &NavigationServer2D::region_get_navigation_layers);
ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer2D::region_set_transform);
- ClassDB::bind_method(D_METHOD("region_set_navpoly", "region", "nav_poly"), &NavigationServer2D::region_set_navpoly);
+ ClassDB::bind_method(D_METHOD("region_set_navigation_polygon", "region", "navigation_polygon"), &NavigationServer2D::region_set_navigation_polygon);
ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer2D::region_get_connections_count);
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_start);
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_end);
@@ -361,8 +361,8 @@ void FORWARD_2_C(region_set_navigation_layers, RID, p_region, uint32_t, p_naviga
uint32_t FORWARD_1_C(region_get_navigation_layers, RID, p_region, rid_to_rid);
void FORWARD_2_C(region_set_transform, RID, p_region, Transform2D, p_transform, rid_to_rid, trf2_to_trf3);
-void NavigationServer2D::region_set_navpoly(RID p_region, Ref<NavigationPolygon> p_nav_mesh) const {
- NavigationServer3D::get_singleton()->region_set_navmesh(p_region, poly_to_mesh(p_nav_mesh));
+void NavigationServer2D::region_set_navigation_polygon(RID p_region, Ref<NavigationPolygon> p_navigation_polygon) const {
+ NavigationServer3D::get_singleton()->region_set_navigation_mesh(p_region, poly_to_mesh(p_navigation_polygon));
}
int FORWARD_1_C(region_get_connections_count, RID, p_region, rid_to_rid);
@@ -427,4 +427,7 @@ void NavigationServer2D::query_path(const Ref<NavigationPathQueryParameters2D> &
const NavigationUtilities::PathQueryResult _query_result = NavigationServer3D::get_singleton()->_query_path(p_query_parameters->get_parameters());
p_query_result->set_path(vector_v3_to_v2(_query_result.path));
+ p_query_result->set_path_types(_query_result.path_types);
+ p_query_result->set_path_rids(_query_result.path_rids);
+ p_query_result->set_path_owner_ids(_query_result.path_owner_ids);
}
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index cf6011a0f9..9b921969c0 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -34,7 +34,7 @@
#include "core/object/class_db.h"
#include "core/templates/rid.h"
-#include "scene/2d/navigation_region_2d.h"
+#include "scene/resources/navigation_polygon.h"
#include "servers/navigation/navigation_path_query_parameters_2d.h"
#include "servers/navigation/navigation_path_query_result_2d.h"
@@ -126,7 +126,7 @@ public:
virtual void region_set_transform(RID p_region, Transform2D p_transform) const;
/// Set the navigation poly of this region.
- virtual void region_set_navpoly(RID p_region, Ref<NavigationPolygon> p_nav_mesh) const;
+ virtual void region_set_navigation_polygon(RID p_region, Ref<NavigationPolygon> p_navigation_polygon) const;
/// Get a list of a region's connection to other regions.
virtual int region_get_connections_count(RID p_region) const;
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index 940dd61f67..6ad07d3053 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -77,8 +77,8 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("region_set_navigation_layers", "region", "navigation_layers"), &NavigationServer3D::region_set_navigation_layers);
ClassDB::bind_method(D_METHOD("region_get_navigation_layers", "region"), &NavigationServer3D::region_get_navigation_layers);
ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer3D::region_set_transform);
- ClassDB::bind_method(D_METHOD("region_set_navmesh", "region", "nav_mesh"), &NavigationServer3D::region_set_navmesh);
- ClassDB::bind_method(D_METHOD("region_bake_navmesh", "mesh", "node"), &NavigationServer3D::region_bake_navmesh);
+ ClassDB::bind_method(D_METHOD("region_set_navigation_mesh", "region", "navigation_mesh"), &NavigationServer3D::region_set_navigation_mesh);
+ ClassDB::bind_method(D_METHOD("region_bake_navigation_mesh", "navigation_mesh", "root_node"), &NavigationServer3D::region_bake_navigation_mesh);
ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer3D::region_get_connections_count);
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_start);
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_end);
@@ -155,7 +155,7 @@ NavigationServer3D::NavigationServer3D() {
debug_navigation_enable_link_connections_xray = GLOBAL_DEF("debug/shapes/navigation/enable_link_connections_xray", true);
if (Engine::get_singleton()->is_editor_hint()) {
- // enable NavigationServer3D when in Editor or else navmesh edge connections are invisible
+ // enable NavigationServer3D when in Editor or else navigation mesh edge connections are invisible
// on runtime tests SceneTree has "Visible Navigation" set and main iteration takes care of this
set_debug_enabled(true);
}
@@ -491,4 +491,7 @@ void NavigationServer3D::query_path(const Ref<NavigationPathQueryParameters3D> &
const NavigationUtilities::PathQueryResult _query_result = _query_path(p_query_parameters->get_parameters());
p_query_result->set_path(_query_result.path);
+ p_query_result->set_path_types(_query_result.path_types);
+ p_query_result->set_path_rids(_query_result.path_rids);
+ p_query_result->set_path_owner_ids(_query_result.path_owner_ids);
}
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index bf4c22be8a..65d6d19073 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -138,10 +138,10 @@ public:
virtual void region_set_transform(RID p_region, Transform3D p_transform) const = 0;
/// Set the navigation mesh of this region.
- virtual void region_set_navmesh(RID p_region, Ref<NavigationMesh> p_nav_mesh) const = 0;
+ virtual void region_set_navigation_mesh(RID p_region, Ref<NavigationMesh> p_navigation_mesh) const = 0;
/// Bake the navigation mesh.
- virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const = 0;
+ virtual void region_bake_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) const = 0;
/// Get a list of a region's connection to other regions.
virtual int region_get_connections_count(RID p_region) const = 0;
diff --git a/servers/physics_2d/godot_body_pair_2d.cpp b/servers/physics_2d/godot_body_pair_2d.cpp
index 79e084e90e..1684835e76 100644
--- a/servers/physics_2d/godot_body_pair_2d.cpp
+++ b/servers/physics_2d/godot_body_pair_2d.cpp
@@ -198,13 +198,13 @@ bool GodotBodyPair2D::_test_ccd(real_t p_step, GodotBody2D *p_A, int p_shape_A,
Vector2 from = p_xform_A.xform(s[0]);
// Back up 10% of the per-frame motion behind the support point and use that as the beginning of our cast.
// This should ensure the calculated new velocity will really cause a bit of overlap instead of just getting us very close.
- from -= motion * 0.1;
Vector2 to = from + motion;
Transform2D from_inv = p_xform_B.affine_inverse();
- // Start from a little inside the bounding box.
- Vector2 local_from = from_inv.xform(from);
+ // Back up 10% of the per-frame motion behind the support point and use that as the beginning of our cast.
+ // At high speeds, this may mean we're actually casting from well behind the body instead of inside it, which is odd. But it still works out.
+ Vector2 local_from = from_inv.xform(from - motion * 0.1);
Vector2 local_to = from_inv.xform(to);
Vector2 rpos, rnorm;
@@ -228,7 +228,7 @@ bool GodotBodyPair2D::_test_ccd(real_t p_step, GodotBody2D *p_A, int p_shape_A,
// next frame will hit softly or soft enough.
Vector2 hitpos = p_xform_B.xform(rpos);
- real_t newlen = hitpos.distance_to(from);
+ real_t newlen = hitpos.distance_to(from) + (max - min) * 0.01; // adding 1% of body length to the distance between collision and support point should cause body A's support point to arrive just within B's collider next frame.
p_A->set_linear_velocity(mnormal * (newlen / p_step));
return true;
diff --git a/servers/physics_3d/godot_body_pair_3d.cpp b/servers/physics_3d/godot_body_pair_3d.cpp
index 981a7c502f..00b7941292 100644
--- a/servers/physics_3d/godot_body_pair_3d.cpp
+++ b/servers/physics_3d/godot_body_pair_3d.cpp
@@ -194,14 +194,13 @@ bool GodotBodyPair3D::_test_ccd(real_t p_step, GodotBody3D *p_A, int p_shape_A,
// convert mnormal into body A's local xform because get_support requires (and returns) local coordinates.
Vector3 s = p_A->get_shape(p_shape_A)->get_support(p_xform_A.basis.xform_inv(mnormal).normalized());
Vector3 from = p_xform_A.xform(s);
- // Back up 10% of the per-frame motion behind the support point and use that as the beginning of our cast.
- // This should ensure the calculated new velocity will really cause a bit of overlap instead of just getting us very close.
- from -= motion * 0.1;
Vector3 to = from + motion;
Transform3D from_inv = p_xform_B.affine_inverse();
- Vector3 local_from = from_inv.xform(from);
+ // Back up 10% of the per-frame motion behind the support point and use that as the beginning of our cast.
+ // At high speeds, this may mean we're actually casting from well behind the body instead of inside it, which is odd. But it still works out.
+ Vector3 local_from = from_inv.xform(from - motion * 0.1);
Vector3 local_to = from_inv.xform(to);
Vector3 rpos, rnorm;
@@ -214,7 +213,8 @@ bool GodotBodyPair3D::_test_ccd(real_t p_step, GodotBody3D *p_A, int p_shape_A,
// Shorten the linear velocity so it will collide next frame.
Vector3 hitpos = p_xform_B.xform(rpos);
- real_t newlen = hitpos.distance_to(from); // this length (speed) should cause the point we chose slightly behind A's support point to arrive right at B's collider next frame.
+ real_t newlen = hitpos.distance_to(from) + (max - min) * 0.01; // adding 1% of body length to the distance between collision and support point should cause body A's support point to arrive just within B's collider next frame.
+
p_A->set_linear_velocity((mnormal * newlen) / p_step);
return true;
diff --git a/servers/physics_3d/godot_collision_solver_3d.cpp b/servers/physics_3d/godot_collision_solver_3d.cpp
index ca76a819ec..47f767425b 100644
--- a/servers/physics_3d/godot_collision_solver_3d.cpp
+++ b/servers/physics_3d/godot_collision_solver_3d.cpp
@@ -513,10 +513,6 @@ bool GodotCollisionSolver3D::solve_distance_world_boundary(const GodotShape3D *p
}
bool GodotCollisionSolver3D::solve_distance(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis) {
- if (p_shape_A->is_concave()) {
- return false;
- }
-
if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) {
Vector3 a, b;
bool col = solve_distance_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, a, b);
diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp
index c98409e2c4..813970848a 100644
--- a/servers/physics_3d/godot_space_3d.cpp
+++ b/servers/physics_3d/godot_space_3d.cpp
@@ -992,6 +992,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
Vector3 rel_vec = result.contact - (body->get_transform().origin + body->get_center_of_mass());
collision.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
+ collision.collider_angular_velocity = body->get_angular_velocity();
}
r_result->travel = safe * p_parameters.motion;
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index c5a93cc390..bd4512a3d5 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -765,10 +765,16 @@ void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("joint_set_param", "joint", "param", "value"), &PhysicsServer2D::joint_set_param);
ClassDB::bind_method(D_METHOD("joint_get_param", "joint", "param"), &PhysicsServer2D::joint_get_param);
+ ClassDB::bind_method(D_METHOD("joint_disable_collisions_between_bodies", "joint", "disable"), &PhysicsServer2D::joint_disable_collisions_between_bodies);
+ ClassDB::bind_method(D_METHOD("joint_is_disabled_collisions_between_bodies", "joint"), &PhysicsServer2D::joint_is_disabled_collisions_between_bodies);
+
ClassDB::bind_method(D_METHOD("joint_make_pin", "joint", "anchor", "body_a", "body_b"), &PhysicsServer2D::joint_make_pin, DEFVAL(RID()));
ClassDB::bind_method(D_METHOD("joint_make_groove", "joint", "groove1_a", "groove2_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::joint_make_groove, DEFVAL(RID()), DEFVAL(RID()));
ClassDB::bind_method(D_METHOD("joint_make_damped_spring", "joint", "anchor_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::joint_make_damped_spring, DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("pin_joint_set_param", "joint", "param", "value"), &PhysicsServer2D::pin_joint_set_param);
+ ClassDB::bind_method(D_METHOD("pin_joint_get_param", "joint", "param"), &PhysicsServer2D::pin_joint_get_param);
+
ClassDB::bind_method(D_METHOD("damped_spring_joint_set_param", "joint", "param", "value"), &PhysicsServer2D::damped_spring_joint_set_param);
ClassDB::bind_method(D_METHOD("damped_spring_joint_get_param", "joint", "param"), &PhysicsServer2D::damped_spring_joint_get_param);
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index aecb687d5f..25912e9aca 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -943,6 +943,9 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("joint_set_solver_priority", "joint", "priority"), &PhysicsServer3D::joint_set_solver_priority);
ClassDB::bind_method(D_METHOD("joint_get_solver_priority", "joint"), &PhysicsServer3D::joint_get_solver_priority);
+ ClassDB::bind_method(D_METHOD("joint_disable_collisions_between_bodies", "joint", "disable"), &PhysicsServer3D::joint_disable_collisions_between_bodies);
+ ClassDB::bind_method(D_METHOD("joint_is_disabled_collisions_between_bodies", "joint"), &PhysicsServer3D::joint_is_disabled_collisions_between_bodies);
+
ClassDB::bind_method(D_METHOD("joint_make_generic_6dof", "joint", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_make_generic_6dof);
ClassDB::bind_method(D_METHOD("generic_6dof_joint_set_param", "joint", "axis", "param", "value"), &PhysicsServer3D::generic_6dof_joint_set_param);
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index ca1ff57c99..922baad663 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -541,6 +541,7 @@ public:
Vector3 position;
Vector3 normal;
Vector3 collider_velocity;
+ Vector3 collider_angular_velocity;
real_t depth = 0.0;
int local_shape = 0;
ObjectID collider_id;
diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h
index 3937362920..918f5c1fb7 100644
--- a/servers/rendering/dummy/rasterizer_scene_dummy.h
+++ b/servers/rendering/dummy/rasterizer_scene_dummy.h
@@ -49,6 +49,7 @@ public:
virtual void set_surface_materials(const Vector<RID> &p_materials) override {}
virtual void set_mesh_instance(RID p_mesh_instance) override {}
virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override {}
+ virtual void set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) override {}
virtual void set_lod_bias(float p_lod_bias) override {}
virtual void set_layer_mask(uint32_t p_layer_mask) override {}
virtual void set_fade_range(bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override {}
diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h
index 13c342d823..960f5a867a 100644
--- a/servers/rendering/dummy/storage/light_storage.h
+++ b/servers/rendering/dummy/storage/light_storage.h
@@ -135,6 +135,7 @@ public:
virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; }
virtual bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; }
virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override { return false; }
+ virtual Ref<RenderSceneBuffers> reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) override { return Ref<RenderSceneBuffers>(); }
virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override { return true; }
/* LIGHTMAP CAPTURE */
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 33f1f38bf5..6be0419d98 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -1185,7 +1185,7 @@ void RendererCanvasCull::canvas_item_add_texture_rect(RID p_item, const Rect2 &p
rect->texture = p_texture;
}
-void RendererCanvasCull::canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, int p_outline_size, float p_px_range) {
+void RendererCanvasCull::canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, int p_outline_size, float p_px_range, float p_scale) {
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
@@ -1215,7 +1215,7 @@ void RendererCanvasCull::canvas_item_add_msdf_texture_rect_region(RID p_item, co
rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V;
rect->source.size.y = -rect->source.size.y;
}
- rect->outline = p_outline_size;
+ rect->outline = (float)p_outline_size / p_scale / 4.0;
rect->px_range = p_px_range;
}
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index 198e1020f0..808c0acc35 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -228,7 +228,7 @@ public:
void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color);
void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false);
- void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0);
+ void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0, float p_scale = 1.0);
void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1));
void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode = RS::NINE_PATCH_STRETCH, RS::NinePatchAxisMode p_y_axis_mode = RS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1));
void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0);
diff --git a/servers/rendering/renderer_geometry_instance.cpp b/servers/rendering/renderer_geometry_instance.cpp
index 675659f4c8..f4681916f4 100644
--- a/servers/rendering/renderer_geometry_instance.cpp
+++ b/servers/rendering/renderer_geometry_instance.cpp
@@ -80,6 +80,11 @@ void RenderGeometryInstanceBase::set_transform(const Transform3D &p_transform, c
lod_model_scale = max_scale;
}
+void RenderGeometryInstanceBase::set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) {
+ sorting_offset = p_sorting_offset;
+ use_aabb_center = p_use_aabb_center;
+}
+
void RenderGeometryInstanceBase::set_lod_bias(float p_lod_bias) {
lod_bias = p_lod_bias;
}
diff --git a/servers/rendering/renderer_geometry_instance.h b/servers/rendering/renderer_geometry_instance.h
index fecb9878c2..37fde9e1f6 100644
--- a/servers/rendering/renderer_geometry_instance.h
+++ b/servers/rendering/renderer_geometry_instance.h
@@ -50,6 +50,7 @@ public:
virtual void set_surface_materials(const Vector<RID> &p_materials) = 0;
virtual void set_mesh_instance(RID p_mesh_instance) = 0;
virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) = 0;
+ virtual void set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) = 0;
virtual void set_lod_bias(float p_lod_bias) = 0;
virtual void set_layer_mask(uint32_t p_layer_mask) = 0;
virtual void set_fade_range(bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) = 0;
@@ -86,11 +87,13 @@ public:
RID mesh_instance;
Transform3D transform;
- bool mirror = false; // move into data?
- AABB transformed_aabb; //needed for LOD
+ bool mirror = false;
+ AABB transformed_aabb;
bool non_uniform_scale = false;
float lod_model_scale = 1.0;
float lod_bias = 0.0;
+ float sorting_offset = 0.0;
+ bool use_aabb_center = true;
uint32_t layer_mask = 1;
@@ -133,6 +136,7 @@ public:
virtual void set_surface_materials(const Vector<RID> &p_materials) override;
virtual void set_mesh_instance(RID p_mesh_instance) override;
virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override;
+ virtual void set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) override;
virtual void set_lod_bias(float p_lod_bias) override;
virtual void set_layer_mask(uint32_t p_layer_mask) override;
virtual void set_fade_range(bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override;
diff --git a/servers/rendering/renderer_rd/SCsub b/servers/rendering/renderer_rd/SCsub
index 10b83dca11..a27439e931 100644
--- a/servers/rendering/renderer_rd/SCsub
+++ b/servers/rendering/renderer_rd/SCsub
@@ -9,4 +9,5 @@ SConscript("environment/SCsub")
SConscript("forward_clustered/SCsub")
SConscript("forward_mobile/SCsub")
SConscript("shaders/SCsub")
+SConscript("spirv-reflect/SCsub")
SConscript("storage_rd/SCsub")
diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index eece195946..38066b6613 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -319,10 +319,6 @@ void Fog::free_fog_shader() {
material_storage->material_free(volumetric_fog.default_material);
}
-void Fog::FogShaderData::set_path_hint(const String &p_path) {
- path = p_path;
-}
-
void Fog::FogShaderData::set_code(const String &p_code) {
//compile
@@ -366,83 +362,6 @@ void Fog::FogShaderData::set_code(const String &p_code) {
valid = true;
}
-void Fog::FogShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
- if (!p_texture.is_valid()) {
- if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
- default_texture_params[p_name].erase(p_index);
-
- if (default_texture_params[p_name].is_empty()) {
- default_texture_params.erase(p_name);
- }
- }
- } else {
- if (!default_texture_params.has(p_name)) {
- default_texture_params[p_name] = HashMap<int, RID>();
- }
- default_texture_params[p_name][p_index] = p_texture;
- }
-}
-
-void Fog::FogShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
- RBMap<int, StringName> order;
-
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- if (E.value.texture_order >= 0) {
- order[E.value.texture_order + 100000] = E.key;
- } else {
- order[E.value.order] = E.key;
- }
- }
-
- String last_group;
- for (const KeyValue<int, StringName> &E : order) {
- String group = uniforms[E.value].group;
- if (!uniforms[E.value].subgroup.is_empty()) {
- group += "::" + uniforms[E.value].subgroup;
- }
-
- if (group != last_group) {
- PropertyInfo pi;
- pi.usage = PROPERTY_USAGE_GROUP;
- pi.name = group;
- p_param_list->push_back(pi);
-
- last_group = group;
- }
-
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
- pi.name = E.value;
- p_param_list->push_back(pi);
- }
-}
-
-void Fog::FogShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererMaterialStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E.value);
- p.info.name = E.key; //supply name
- p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
- p_param_list->push_back(p);
- }
-}
-
-bool Fog::FogShaderData::is_parameter_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
bool Fog::FogShaderData::is_animated() const {
return false;
}
@@ -451,15 +370,6 @@ bool Fog::FogShaderData::casts_shadows() const {
return false;
}
-Variant Fog::FogShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
- }
- return Variant();
-}
-
RS::ShaderNativeSourceCode Fog::FogShaderData::get_native_source_code() const {
Fog *fog_singleton = Fog::get_singleton();
@@ -789,6 +699,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, volumetric_fog.base_uniform_set, VolumetricFogShader::FogSet::FOG_SET_BASE);
if (material->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material->uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, material->uniform_set, VolumetricFogShader::FogSet::FOG_SET_MATERIAL);
+ material->set_as_used();
}
RD::get_singleton()->compute_list_dispatch_threads(compute_list, kernel_size.x, kernel_size.y, kernel_size.z);
diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h
index 0ade995758..a5f06a129d 100644
--- a/servers/rendering/renderer_rd/environment/fog.h
+++ b/servers/rendering/renderer_rd/environment/fog.h
@@ -188,27 +188,18 @@ private:
RID version;
RID pipeline;
- HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
- String path;
String code;
- HashMap<StringName, HashMap<int, RID>> default_texture_params;
bool uses_time = false;
- virtual void set_path_hint(const String &p_hint);
virtual void set_code(const String &p_Code);
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
- virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
- virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
FogShaderData() {}
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index 550fe27e4c..61b7dd4504 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -3496,6 +3496,10 @@ void GI::init(SkyRD *p_sky) {
{
//calculate tables
String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
+ if (RendererSceneRenderRD::get_singleton()->is_vrs_supported()) {
+ defines += "\n#define USE_VRS\n";
+ }
+
Vector<String> gi_modes;
gi_modes.push_back("\n#define USE_VOXEL_GI_INSTANCES\n"); // MODE_VOXEL_GI
@@ -4011,7 +4015,7 @@ void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_nor
u.append_id(rbgi->scene_data_ubo);
uniforms.push_back(u);
}
- {
+ if (RendererSceneRenderRD::get_singleton()->is_vrs_supported()) {
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 19;
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index 36d26ad783..19546968cd 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -32,23 +32,25 @@
#include "core/config/project_settings.h"
#include "core/math/math_defs.h"
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
+#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
+#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
#include "servers/rendering/rendering_server_default.h"
#include "servers/rendering/rendering_server_globals.h"
using namespace RendererRD;
+#define RB_SCOPE_SKY SNAME("sky_buffers")
+#define RB_HALF_TEXTURE SNAME("half_texture")
+#define RB_QUARTER_TEXTURE SNAME("quarter_texture")
+
////////////////////////////////////////////////////////////////////////////////
// SKY SHADER
-void SkyRD::SkyShaderData::set_path_hint(const String &p_path) {
- path = p_path;
-}
-
void SkyRD::SkyShaderData::set_code(const String &p_code) {
//compile
@@ -152,82 +154,6 @@ void SkyRD::SkyShaderData::set_code(const String &p_code) {
valid = true;
}
-void SkyRD::SkyShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
- if (!p_texture.is_valid()) {
- if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
- default_texture_params[p_name].erase(p_index);
-
- if (default_texture_params[p_name].is_empty()) {
- default_texture_params.erase(p_name);
- }
- }
- } else {
- if (!default_texture_params.has(p_name)) {
- default_texture_params[p_name] = HashMap<int, RID>();
- }
- default_texture_params[p_name][p_index] = p_texture;
- }
-}
-
-void SkyRD::SkyShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
- HashMap<int, StringName> order;
-
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- if (E.value.texture_order >= 0) {
- order[E.value.texture_order + 100000] = E.key;
- } else {
- order[E.value.order] = E.key;
- }
- }
- String last_group;
- for (const KeyValue<int, StringName> &E : order) {
- String group = uniforms[E.value].group;
- if (!uniforms[E.value].subgroup.is_empty()) {
- group += "::" + uniforms[E.value].subgroup;
- }
-
- if (group != last_group) {
- PropertyInfo pi;
- pi.usage = PROPERTY_USAGE_GROUP;
- pi.name = group;
- p_param_list->push_back(pi);
-
- last_group = group;
- }
-
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
- pi.name = E.value;
- p_param_list->push_back(pi);
- }
-}
-
-void SkyRD::SkyShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererMaterialStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E.value);
- p.info.name = E.key; //supply name
- p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
- p_param_list->push_back(p);
- }
-}
-
-bool SkyRD::SkyShaderData::is_parameter_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
bool SkyRD::SkyShaderData::is_animated() const {
return false;
}
@@ -236,15 +162,6 @@ bool SkyRD::SkyShaderData::casts_shadows() const {
return false;
}
-Variant SkyRD::SkyShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
- }
- return Variant();
-}
-
RS::ShaderNativeSourceCode SkyRD::SkyShaderData::get_native_source_code() const {
RendererSceneRenderRD *scene_singleton = static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton);
@@ -293,18 +210,17 @@ static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_ar
p_array[11] = 0;
}
-void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const Projection *p_projections, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier) {
+void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const Projection &p_projection, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier) {
SkyPushConstant sky_push_constant;
memset(&sky_push_constant, 0, sizeof(SkyPushConstant));
- for (uint32_t v = 0; v < p_view_count; v++) {
- // We only need key components of our projection matrix
- sky_push_constant.projections[v][0] = p_projections[v].columns[2][0];
- sky_push_constant.projections[v][1] = p_projections[v].columns[0][0];
- sky_push_constant.projections[v][2] = p_projections[v].columns[2][1];
- sky_push_constant.projections[v][3] = p_projections[v].columns[1][1];
- }
+ // We only need key components of our projection matrix
+ sky_push_constant.projection[0] = p_projection.columns[2][0];
+ sky_push_constant.projection[1] = p_projection.columns[0][0];
+ sky_push_constant.projection[2] = p_projection.columns[2][1];
+ sky_push_constant.projection[3] = p_projection.columns[1][1];
+
sky_push_constant.position[0] = p_position.x;
sky_push_constant.position[1] = p_position.y;
sky_push_constant.position[2] = p_position.z;
@@ -629,28 +545,15 @@ void SkyRD::Sky::free() {
uniform_buffer = RID();
}
- if (half_res_pass.is_valid()) {
- RD::get_singleton()->free(half_res_pass);
- half_res_pass = RID();
- }
-
- if (quarter_res_pass.is_valid()) {
- RD::get_singleton()->free(quarter_res_pass);
- quarter_res_pass = RID();
- }
-
if (material.is_valid()) {
RSG::material_storage->material_free(material);
material = RID();
}
}
-RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd) {
+RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd, Ref<RenderSceneBuffersRD> p_render_buffers) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
- if (texture_uniform_sets[p_version].is_valid() && RD::get_singleton()->uniform_set_is_valid(texture_uniform_sets[p_version])) {
- return texture_uniform_sets[p_version];
- }
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
@@ -667,17 +570,18 @@ RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shade
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1; // half res
- if (half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) {
- if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
+ if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
+ if (reflection.layers[0].views[1].is_valid() && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) {
u.append_id(reflection.layers[0].views[1]);
} else {
- u.append_id(half_res_pass);
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
}
} else {
- if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE));
+ RID half_texture = p_render_buffers->has_texture(RB_SCOPE_SKY, RB_HALF_TEXTURE) ? p_render_buffers->get_texture(RB_SCOPE_SKY, RB_HALF_TEXTURE) : RID();
+ if (half_texture.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES) {
+ u.append_id(half_texture);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE));
}
}
uniforms.push_back(u);
@@ -686,24 +590,24 @@ RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shade
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 2; // quarter res
- if (quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) {
- if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
+ if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
+ if (reflection.layers[0].views[2].is_valid() && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) {
u.append_id(reflection.layers[0].views[2]);
} else {
- u.append_id(quarter_res_pass);
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
}
} else {
- if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE));
+ RID quarter_texture = p_render_buffers->has_texture(RB_SCOPE_SKY, RB_QUARTER_TEXTURE) ? p_render_buffers->get_texture(RB_SCOPE_SKY, RB_QUARTER_TEXTURE) : RID();
+ if (quarter_texture.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES) {
+ u.append_id(quarter_texture);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE));
}
}
uniforms.push_back(u);
}
- texture_uniform_sets[p_version] = RD::get_singleton()->uniform_set_create(uniforms, p_default_shader_rd, SKY_SET_TEXTURES);
- return texture_uniform_sets[p_version];
+ return UniformSetCacheRD::get_singleton()->get_cache_vec(p_default_shader_rd, SKY_SET_TEXTURES, uniforms);
}
bool SkyRD::Sky::set_radiance_size(int p_radiance_size) {
@@ -1109,11 +1013,17 @@ SkyRD::~SkyRD() {
RD::get_singleton()->free(index_buffer); //array gets freed as dependency
}
-void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
+void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, uint32_t p_view_count, const Projection *p_view_projections, const Vector3 *p_view_eye_offsets, const Transform3D &p_cam_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ // make sure we support our view count
+ ERR_FAIL_COND(p_view_count == 0);
+ ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
+
SkyMaterialData *material = nullptr;
Sky *sky = get_sky(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
@@ -1142,31 +1052,14 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P
ERR_FAIL_COND(!shader_data);
- // Invalidate supbass buffers if screen size changes
- if (sky->screen_size != p_screen_size) {
- sky->screen_size = p_screen_size;
- sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x;
- sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y;
- if (shader_data->uses_half_res) {
- if (sky->half_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->half_res_pass);
- sky->half_res_pass = RID();
- }
- invalidate_sky(sky);
- }
- if (shader_data->uses_quarter_res) {
- if (sky->quarter_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->quarter_res_pass);
- sky->quarter_res_pass = RID();
- }
- invalidate_sky(sky);
- }
- }
+ material->set_as_used();
+
+ // Save our screen size, our buffers will already have been cleared
+ sky->screen_size.x = p_screen_size.x < 4 ? 4 : p_screen_size.x;
+ sky->screen_size.y = p_screen_size.y < 4 ? 4 : p_screen_size.y;
- // Create new subpass buffers if necessary
- if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) ||
- (shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) ||
- sky->radiance.is_null()) {
+ // Trigger updating radiance buffers
+ if (sky->radiance.is_null()) {
invalidate_sky(sky);
update_dirty_skys();
}
@@ -1187,8 +1080,8 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P
sky->reflection.dirty = true;
}
- if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
- sky->prev_position = p_transform.origin;
+ if (!p_cam_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
+ sky->prev_position = p_cam_transform.origin;
sky->reflection.dirty = true;
}
@@ -1316,7 +1209,20 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P
}
}
- sky_scene_state.ubo.z_far = p_projection.get_z_far();
+ sky_scene_state.view_count = p_view_count;
+ sky_scene_state.cam_transform = p_cam_transform;
+ sky_scene_state.cam_projection = p_view_projections[0]; // We only use this when rendering a single view
+
+ // Our info in our UBO is only used if we're rendering stereo
+ for (uint32_t i = 0; i < p_view_count; i++) {
+ RendererRD::MaterialStorage::store_camera(p_view_projections[i].inverse(), sky_scene_state.ubo.view_inv_projections[i]);
+ sky_scene_state.ubo.view_eye_offsets[i][0] = p_view_eye_offsets[i].x;
+ sky_scene_state.ubo.view_eye_offsets[i][1] = p_view_eye_offsets[i].y;
+ sky_scene_state.ubo.view_eye_offsets[i][2] = p_view_eye_offsets[i].z;
+ sky_scene_state.ubo.view_eye_offsets[i][3] = 0.0;
+ }
+
+ sky_scene_state.ubo.z_far = p_view_projections[0].get_z_far(); // Should be the same for all projection
sky_scene_state.ubo.fog_enabled = RendererSceneRenderRD::get_singleton()->environment_get_fog_enabled(p_env);
sky_scene_state.ubo.fog_density = RendererSceneRenderRD::get_singleton()->environment_get_fog_density(p_env);
sky_scene_state.ubo.fog_aerial_perspective = RendererSceneRenderRD::get_singleton()->environment_get_fog_aerial_perspective(p_env);
@@ -1333,7 +1239,8 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P
RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo);
}
-void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) {
+void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, const Vector3 &p_global_pos, double p_time, float p_luminance_multiplier) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
@@ -1411,6 +1318,8 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
correction.set_depth_correction(true);
cm = correction * cm;
+ // Note, we ignore environment_get_sky_orientation here as this is applied when we do our lookup in our scene shader.
+
if (shader_data->uses_quarter_res) {
RD::get_singleton()->draw_command_begin_label("Render Sky to Quarter Res Cubemap");
PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES];
@@ -1421,10 +1330,10 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
for (int i = 0; i < 6; i++) {
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);
+ 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);
- _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, p_transform.origin, p_luminance_multiplier);
+ _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();
}
RD::get_singleton()->draw_command_end_label();
@@ -1440,10 +1349,10 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
for (int i = 0; i < 6; i++) {
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);
+ 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);
- _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, p_transform.origin, p_luminance_multiplier);
+ _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();
}
RD::get_singleton()->draw_command_end_label();
@@ -1455,10 +1364,10 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
RD::get_singleton()->draw_command_begin_label("Render Sky Cubemap");
for (int i = 0; i < 6; i++) {
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);
+ 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);
- _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, p_transform.origin, p_luminance_multiplier);
+ _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();
}
RD::get_singleton()->draw_command_end_label();
@@ -1500,13 +1409,11 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
}
}
-void SkyRD::draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) {
+void SkyRD::update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, double p_time, float p_luminance_multiplier) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
- ERR_FAIL_COND(p_view_count == 0);
- ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
-
Sky *sky = get_sky(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
SkyMaterialData *material = nullptr;
@@ -1539,105 +1446,16 @@ void SkyRD::draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth
ERR_FAIL_COND(!material);
SkyShaderData *shader_data = material->shader_data;
-
ERR_FAIL_COND(!shader_data);
- Basis sky_transform = RendererSceneRenderRD::get_singleton()->environment_get_sky_orientation(p_env);
- sky_transform.invert();
-
- float custom_fov = RendererSceneRenderRD::get_singleton()->environment_get_sky_custom_fov(p_env);
-
- // Camera
- Projection camera;
- uint32_t view_count = p_view_count;
- const Projection *projections = p_projections;
-
- if (custom_fov) {
- // With custom fov we don't support stereo...
- float near_plane = p_projections[0].get_z_near();
- float far_plane = p_projections[0].get_z_far();
- float aspect = p_projections[0].get_aspect();
-
- camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
-
- view_count = 1;
- projections = &camera;
- }
-
- sky_transform = sky_transform * p_transform.basis;
-
- if (shader_data->uses_quarter_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES];
-
- RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd);
-
- 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(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
- RD::get_singleton()->draw_list_end();
- }
-
- if (shader_data->uses_half_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES];
-
- RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd);
-
- 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(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
- RD::get_singleton()->draw_list_end();
- }
-
- PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND];
-
- RID texture_uniform_set;
- if (sky) {
- texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd);
- } else {
- texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
- }
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
- _render_sky(draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
- RD::get_singleton()->draw_list_end();
-}
-
-void SkyRD::update_res_buffers(RID p_env, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) {
- RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
- ERR_FAIL_COND(p_env.is_null());
-
- ERR_FAIL_COND(p_view_count == 0);
- ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
-
- Sky *sky = get_sky(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
- ERR_FAIL_COND(!sky);
-
- SkyMaterialData *material = nullptr;
- RID sky_material;
-
- sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
-
- if (sky_material.is_valid()) {
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
- if (!material || !material->shader_data->valid) {
- material = nullptr;
- }
- }
-
- if (!material) {
- sky_material = sky_shader.default_material;
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
+ if (!shader_data->uses_quarter_res && !shader_data->uses_half_res) {
+ return;
}
- ERR_FAIL_COND(!material);
+ material->set_as_used();
- SkyShaderData *shader_data = material->shader_data;
-
- ERR_FAIL_COND(!shader_data);
+ RENDER_TIMESTAMP("Setup Sky Resolution Buffers");
+ RD::get_singleton()->draw_command_begin_label("Setup Sky Resolution Buffers");
Basis sky_transform = RendererSceneRenderRD::get_singleton()->environment_get_sky_orientation(p_env);
sky_transform.invert();
@@ -1645,58 +1463,65 @@ void SkyRD::update_res_buffers(RID p_env, uint32_t p_view_count, const Projectio
float custom_fov = RendererSceneRenderRD::get_singleton()->environment_get_sky_custom_fov(p_env);
// Camera
- Projection camera;
- uint32_t view_count = p_view_count;
- const Projection *projections = p_projections;
+ Projection projection = sky_scene_state.cam_projection;
- if (custom_fov) {
+ if (custom_fov && sky_scene_state.view_count == 1) {
// With custom fov we don't support stereo...
- float near_plane = p_projections[0].get_z_near();
- float far_plane = p_projections[0].get_z_far();
- float aspect = p_projections[0].get_aspect();
-
- camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
+ float near_plane = projection.get_z_near();
+ float far_plane = projection.get_z_far();
+ float aspect = projection.get_aspect();
- view_count = 1;
- projections = &camera;
+ projection.set_perspective(custom_fov, aspect, near_plane, far_plane);
}
- sky_transform = sky_transform * p_transform.basis;
+ sky_transform = sky_transform * sky_scene_state.cam_transform.basis;
if (shader_data->uses_quarter_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES];
+ PipelineCacheRD *pipeline = &shader_data->pipelines[sky_scene_state.view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES];
+
+ // Grab texture and framebuffer from cache, create if needed...
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ Size2i quarter_size = sky->screen_size / 4;
+ RID texture = p_render_buffers->create_texture(RB_SCOPE_SKY, RB_QUARTER_TEXTURE, texture_format, usage_bits, RD::TEXTURE_SAMPLES_1, quarter_size);
+ RID framebuffer = FramebufferCacheRD::get_singleton()->get_cache_multiview(sky_scene_state.view_count, texture);
- RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd);
+ RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd, p_render_buffers);
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(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
+ 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);
+ _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();
}
if (shader_data->uses_half_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES];
+ PipelineCacheRD *pipeline = &shader_data->pipelines[sky_scene_state.view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES];
- RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd);
+ // Grab texture and framebuffer from cache, create if needed...
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ Size2i half_size = sky->screen_size / 2;
+ RID texture = p_render_buffers->create_texture(RB_SCOPE_SKY, RB_HALF_TEXTURE, texture_format, usage_bits, RD::TEXTURE_SAMPLES_1, half_size);
+ RID framebuffer = FramebufferCacheRD::get_singleton()->get_cache_multiview(sky_scene_state.view_count, texture);
+
+ RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd, p_render_buffers);
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(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
+ 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);
+ _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();
}
+
+ RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
}
-void SkyRD::draw(RD::DrawListID p_draw_list, RID p_env, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) {
+void SkyRD::draw_sky(RD::DrawListID p_draw_list, Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, RID p_fb, double p_time, float p_luminance_multiplier) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
- ERR_FAIL_COND(p_view_count == 0);
- ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
-
Sky *sky = get_sky(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
SkyMaterialData *material = nullptr;
@@ -1729,43 +1554,39 @@ void SkyRD::draw(RD::DrawListID p_draw_list, RID p_env, RID p_fb, uint32_t p_vie
ERR_FAIL_COND(!material);
SkyShaderData *shader_data = material->shader_data;
-
ERR_FAIL_COND(!shader_data);
+ material->set_as_used();
+
Basis sky_transform = RendererSceneRenderRD::get_singleton()->environment_get_sky_orientation(p_env);
sky_transform.invert();
float custom_fov = RendererSceneRenderRD::get_singleton()->environment_get_sky_custom_fov(p_env);
// Camera
- Projection camera;
- uint32_t view_count = p_view_count;
- const Projection *projections = p_projections;
+ Projection projection = sky_scene_state.cam_projection;
- if (custom_fov) {
+ if (custom_fov && sky_scene_state.view_count == 1) {
// With custom fov we don't support stereo...
- float near_plane = p_projections[0].get_z_near();
- float far_plane = p_projections[0].get_z_far();
- float aspect = p_projections[0].get_aspect();
+ float near_plane = projection.get_z_near();
+ float far_plane = projection.get_z_far();
+ float aspect = projection.get_aspect();
- camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
-
- view_count = 1;
- projections = &camera;
+ projection.set_perspective(custom_fov, aspect, near_plane, far_plane);
}
- sky_transform = sky_transform * p_transform.basis;
+ sky_transform = sky_transform * sky_scene_state.cam_transform.basis;
- PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND];
+ PipelineCacheRD *pipeline = &shader_data->pipelines[sky_scene_state.view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND];
RID texture_uniform_set;
if (sky) {
- texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd);
+ texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd, p_render_buffers);
} else {
texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
}
- _render_sky(p_draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
+ _render_sky(p_draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, projection, sky_transform, sky_scene_state.cam_transform.origin, p_luminance_multiplier);
}
void SkyRD::invalidate_sky(Sky *p_sky) {
@@ -1780,9 +1601,11 @@ void SkyRD::update_dirty_skys() {
Sky *sky = dirty_sky_list;
while (sky) {
- bool texture_set_dirty = false;
//update sky configuration if texture is missing
+ // TODO See if we can move this into `update_radiance_buffers` and remove our dirty_sky logic.
+ // As this is basically a duplicate of the logic in reflection probes we could move this logic
+ // into RenderSceneBuffersRD and use that from both places.
if (sky->radiance.is_null()) {
int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1;
@@ -1825,47 +1648,6 @@ void SkyRD::update_dirty_skys() {
sky->reflection.update_reflection_data(sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format);
}
- texture_set_dirty = true;
- }
-
- // Create subpass buffers if they haven't been created already
- if (sky->half_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->half_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
- RD::TextureFormat tformat;
- tformat.format = texture_format;
- tformat.width = sky->screen_size.x / 2;
- tformat.height = sky->screen_size.y / 2;
- tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- tformat.texture_type = RD::TEXTURE_TYPE_2D;
-
- sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView());
- Vector<RID> texs;
- texs.push_back(sky->half_res_pass);
- sky->half_res_framebuffer = RD::get_singleton()->framebuffer_create(texs);
- texture_set_dirty = true;
- }
-
- if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
- RD::TextureFormat tformat;
- tformat.format = texture_format;
- tformat.width = sky->screen_size.x / 4;
- tformat.height = sky->screen_size.y / 4;
- tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- tformat.texture_type = RD::TEXTURE_TYPE_2D;
-
- sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView());
- Vector<RID> texs;
- texs.push_back(sky->quarter_res_pass);
- sky->quarter_res_framebuffer = RD::get_singleton()->framebuffer_create(texs);
- texture_set_dirty = true;
- }
-
- if (texture_set_dirty) {
- for (int i = 0; i < SKY_TEXTURE_SET_MAX; i++) {
- if (sky->texture_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(sky->texture_uniform_sets[i])) {
- RD::get_singleton()->free(sky->texture_uniform_sets[i]);
- sky->texture_uniform_sets[i] = RID();
- }
- }
}
sky->reflection.dirty = true;
diff --git a/servers/rendering/renderer_rd/environment/sky.h b/servers/rendering/renderer_rd/environment/sky.h
index 45c4f9bda7..6e0ebb5f8e 100644
--- a/servers/rendering/renderer_rd/environment/sky.h
+++ b/servers/rendering/renderer_rd/environment/sky.h
@@ -99,11 +99,11 @@ private:
struct SkyPushConstant {
float orientation[12]; // 48 - 48
- float projections[RendererSceneRender::MAX_RENDER_VIEWS][4]; // 2 x 16 - 80
- float position[3]; // 12 - 92
- float time; // 4 - 96
- float pad[3]; // 12 - 108
- float luminance_multiplier; // 4 - 112
+ float projection[4]; // 16 - 64
+ float position[3]; // 12 - 76
+ float time; // 4 - 80
+ float pad[3]; // 12 - 92
+ float luminance_multiplier; // 4 - 96
// 128 is the max size of a push constant. We can replace "pad" but we can't add any more.
};
@@ -112,15 +112,12 @@ private:
RID version;
PipelineCacheRD pipelines[SKY_VERSION_MAX];
- HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
- String path;
String code;
- HashMap<StringName, HashMap<int, RID>> default_texture_params;
bool uses_time = false;
bool uses_position = false;
@@ -129,46 +126,47 @@ private:
bool uses_light = false;
virtual void set_code(const String &p_Code);
- virtual void set_path_hint(const String &p_hint);
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
- virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
- virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
SkyShaderData() {}
virtual ~SkyShaderData();
};
- void _render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const Projection *p_projections, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier);
+ void _render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const Projection &p_projection, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier);
public:
struct SkySceneState {
struct UBO {
- uint32_t volumetric_fog_enabled; // 4 - 4
- float volumetric_fog_inv_length; // 4 - 8
- float volumetric_fog_detail_spread; // 4 - 12
- float volumetric_fog_sky_affect; // 4 - 16
-
- uint32_t fog_enabled; // 4 - 20
- float fog_sky_affect; // 4 - 24
- float fog_density; // 4 - 28
- float fog_sun_scatter; // 4 - 32
-
- float fog_light_color[3]; // 12 - 44
- float fog_aerial_perspective; // 4 - 48
-
- float z_far; // 4 - 52
- uint32_t directional_light_count; // 4 - 56
- uint32_t pad1; // 4 - 60
- uint32_t pad2; // 4 - 64
+ float view_inv_projections[RendererSceneRender::MAX_RENDER_VIEWS][16]; // 2 x 64 - 128
+ float view_eye_offsets[RendererSceneRender::MAX_RENDER_VIEWS][4]; // 2 x 16 - 160
+
+ uint32_t volumetric_fog_enabled; // 4 - 164
+ float volumetric_fog_inv_length; // 4 - 168
+ float volumetric_fog_detail_spread; // 4 - 172
+ float volumetric_fog_sky_affect; // 4 - 176
+
+ uint32_t fog_enabled; // 4 - 180
+ float fog_sky_affect; // 4 - 184
+ float fog_density; // 4 - 188
+ float fog_sun_scatter; // 4 - 192
+
+ float fog_light_color[3]; // 12 - 204
+ float fog_aerial_perspective; // 4 - 208
+
+ float z_far; // 4 - 212
+ uint32_t directional_light_count; // 4 - 216
+ uint32_t pad1; // 4 - 220
+ uint32_t pad2; // 4 - 224
};
UBO ubo;
+ uint32_t view_count = 1;
+ Transform3D cam_transform;
+ Projection cam_projection;
+
SkyDirectionalLightData *directional_lights = nullptr;
SkyDirectionalLightData *last_frame_directional_lights = nullptr;
uint32_t max_directional_lights;
@@ -247,13 +245,10 @@ public:
struct Sky {
RID radiance;
- RID half_res_pass;
- RID half_res_framebuffer;
RID quarter_res_pass;
RID quarter_res_framebuffer;
Size2i screen_size;
- RID texture_uniform_sets[SKY_TEXTURE_SET_MAX];
RID uniform_set;
RID material;
@@ -276,7 +271,7 @@ public:
void free();
- RID get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd);
+ RID get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd, Ref<RenderSceneBuffersRD> p_render_buffers);
bool set_radiance_size(int p_radiance_size);
bool set_mode(RS::SkyMode p_mode);
bool set_material(RID p_material);
@@ -300,11 +295,10 @@ public:
void set_texture_format(RD::DataFormat p_texture_format);
~SkyRD();
- void setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
- void update(RID p_env, const Projection &p_projection, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0);
- void draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0); // only called by clustered renderer
- void update_res_buffers(RID p_env, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0);
- void draw(RD::DrawListID p_draw_list, RID p_env, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0);
+ void setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, uint32_t p_view_count, const Projection *p_view_projections, const Vector3 *p_view_eye_offsets, const Transform3D &p_cam_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
+ void update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, const Vector3 &p_global_pos, double p_time, float p_luminance_multiplier = 1.0);
+ void update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, double p_time, float p_luminance_multiplier = 1.0);
+ void draw_sky(RD::DrawListID p_draw_list, Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, RID p_fb, double p_time, float p_luminance_multiplier = 1.0);
void invalidate_sky(Sky *p_sky);
void update_dirty_skys();
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 3d1e04fe99..5b465fb45c 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -348,6 +348,7 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
#endif
material_uniform_set = surf->material_uniform_set;
shader = surf->shader;
+ surf->material->set_as_used();
#ifdef DEBUG_ENABLED
}
#endif
@@ -830,8 +831,18 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
for (int i = 0; i < (int)p_render_data->instances->size(); i++) {
GeometryInstanceForwardClustered *inst = static_cast<GeometryInstanceForwardClustered *>((*p_render_data->instances)[i]);
- Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal);
- inst->depth = near_plane.distance_to(support_min);
+ Vector3 center = inst->transform.origin;
+ if (p_render_data->scene_data->cam_orthogonal) {
+ if (inst->use_aabb_center) {
+ center = inst->transformed_aabb.get_support(-near_plane.normal);
+ }
+ inst->depth = near_plane.distance_to(center) - inst->sorting_offset;
+ } else {
+ if (inst->use_aabb_center) {
+ center = inst->transformed_aabb.position + (inst->transformed_aabb.size * 0.5);
+ }
+ inst->depth = p_render_data->scene_data->cam_transform.origin.distance_to(center) - inst->sorting_offset;
+ }
uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15);
uint32_t flags = inst->base_flags; //fill flags if appropriate
@@ -1151,6 +1162,7 @@ void RenderForwardClustered::_update_volumetric_fog(Ref<RenderSceneBuffersRD> p_
ERR_FAIL_COND(p_render_buffers.is_null());
Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ ERR_FAIL_COND(rb_data.is_null());
ERR_FAIL_COND(!p_render_buffers->has_custom_data(RB_SCOPE_GI));
Ref<RendererRD::GI::RenderBuffersGI> rbgi = p_render_buffers->get_custom_data(RB_SCOPE_GI);
@@ -1321,7 +1333,9 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
Ref<RenderBufferDataForwardClustered> rb_data;
- if (rb.is_valid()) {
+ if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_FORWARD_CLUSTERED)) {
+ // Our forward clustered custom data buffer will only be available when we're rendering our normal view.
+ // This will not be available when rendering reflection probes.
rb_data = rb->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
}
@@ -1474,7 +1488,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
current_cluster_builder->bake_cluster();
}
- if (rb.is_valid()) {
+ if (rb_data.is_valid()) {
bool directional_shadows = RendererRD::LightStorage::get_singleton()->has_directional_shadows(directional_light_count);
_update_volumetric_fog(rb, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, p_render_data->voxel_gi_count, *p_render_data->fog_volumes);
}
@@ -1540,7 +1554,11 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
Ref<RenderBufferDataForwardClustered> rb_data;
if (p_render_data && p_render_data->render_buffers.is_valid()) {
rb = p_render_data->render_buffers;
- rb_data = rb->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ if (rb->has_custom_data(RB_SCOPE_FORWARD_CLUSTERED)) {
+ // Our forward clustered custom data buffer will only be available when we're rendering our normal view.
+ // This will not be available when rendering reflection probes.
+ rb_data = rb->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ }
}
static const int texture_multisamples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8 };
@@ -1559,32 +1577,32 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
// obtain cluster builder
- if (rb_data.is_valid()) {
- current_cluster_builder = rb_data->cluster_builder;
- } else if (light_storage->owns_reflection_probe_instance(p_render_data->reflection_probe)) {
+ if (light_storage->owns_reflection_probe_instance(p_render_data->reflection_probe)) {
current_cluster_builder = light_storage->reflection_probe_instance_get_cluster_builder(p_render_data->reflection_probe, &cluster_builder_shared);
if (p_render_data->camera_attributes.is_valid()) {
light_storage->reflection_probe_set_baked_exposure(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe), RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes));
}
- } else {
- ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash
- current_cluster_builder = nullptr;
- }
+ } else if (rb_data.is_valid()) {
+ current_cluster_builder = rb_data->cluster_builder;
- p_render_data->voxel_gi_count = 0;
+ p_render_data->voxel_gi_count = 0;
- if (rb.is_valid()) {
- if (rb->has_custom_data(RB_SCOPE_SDFGI)) {
- Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
- if (sdfgi.is_valid()) {
- sdfgi->update_cascades();
- sdfgi->pre_process_gi(p_render_data->scene_data->cam_transform, p_render_data);
- sdfgi->update_light();
+ if (rb.is_valid()) {
+ if (rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ if (sdfgi.is_valid()) {
+ sdfgi->update_cascades();
+ sdfgi->pre_process_gi(p_render_data->scene_data->cam_transform, p_render_data);
+ sdfgi->update_light();
+ }
}
- }
- gi.setup_voxel_gi_instances(p_render_data, p_render_data->render_buffers, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances, p_render_data->voxel_gi_count);
+ gi.setup_voxel_gi_instances(p_render_data, p_render_data->render_buffers, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances, p_render_data->voxel_gi_count);
+ }
+ } else {
+ ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash
+ current_cluster_builder = nullptr;
}
if (current_cluster_builder != nullptr) {
@@ -1622,10 +1640,24 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
bool using_ssr = false;
bool using_sdfgi = false;
bool using_voxelgi = false;
- bool reverse_cull = false;
+ bool reverse_cull = p_render_data->scene_data->cam_transform.basis.determinant() < 0;
bool using_ssil = p_render_data->environment.is_valid() && environment_get_ssil_enabled(p_render_data->environment);
- if (rb.is_valid()) {
+ if (p_render_data->reflection_probe.is_valid()) {
+ uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
+ screen_size.x = resolution;
+ screen_size.y = resolution;
+
+ color_framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+ color_only_framebuffer = color_framebuffer;
+ depth_framebuffer = light_storage->reflection_probe_instance_get_depth_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+
+ if (light_storage->reflection_probe_is_interior(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+ p_render_data->environment = RID(); //no environment on interiors
+ }
+
+ reverse_cull = true; // for some reason our views are inverted
+ } else if (rb.is_valid()) {
screen_size = rb->get_internal_size();
if (rb->get_use_taa() || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
@@ -1677,20 +1709,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
color_framebuffer = rb_data->get_color_pass_fb(color_pass_flags);
color_only_framebuffer = rb_data->get_color_only_fb();
- } else if (p_render_data->reflection_probe.is_valid()) {
- uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
- screen_size.x = resolution;
- screen_size.y = resolution;
-
- color_framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
- color_only_framebuffer = color_framebuffer;
- depth_framebuffer = light_storage->reflection_probe_instance_get_depth_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
-
- if (light_storage->reflection_probe_is_interior(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
- p_render_data->environment = RID(); //no environment on interiors
- }
-
- reverse_cull = true; // for some reason our views are inverted
} else {
ERR_FAIL(); //bug?
}
@@ -1779,29 +1797,40 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
default: {
}
}
+
// setup sky if used for ambient, reflections, or background
if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
RENDER_TIMESTAMP("Setup Sky");
RD::get_singleton()->draw_command_begin_label("Setup Sky");
- Projection projection = p_render_data->scene_data->cam_projection;
+
+ // Setup our sky render information for this frame/viewport
if (p_render_data->reflection_probe.is_valid()) {
+ Vector3 eye_offset;
Projection correction;
correction.set_depth_correction(true);
- projection = correction * p_render_data->scene_data->cam_projection;
- }
+ Projection projection = correction * p_render_data->scene_data->cam_projection;
- sky.setup(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->scene_data->cam_transform, screen_size, this);
+ sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, screen_size, this);
+ } else {
+ sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, 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, screen_size, this);
+ }
sky_energy_multiplier *= bg_energy_multiplier;
RID sky_rid = environment_get_sky(p_render_data->environment);
if (sky_rid.is_valid()) {
- sky.update(p_render_data->environment, projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
+ sky.update_radiance_buffers(rb, p_render_data->environment, p_render_data->scene_data->cam_transform.origin, time, sky_energy_multiplier);
radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
} else {
// do not try to draw sky if invalid
draw_sky = false;
}
+
+ if (draw_sky || draw_sky_fog_only) {
+ // update sky half/quarter res buffers (if required)
+ sky.update_res_buffers(rb, p_render_data->environment, time, sky_energy_multiplier);
+ }
+
RD::get_singleton()->draw_command_end_label();
}
} else {
@@ -1951,15 +1980,11 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
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);
- if (p_render_data->reflection_probe.is_valid()) {
- Projection correction;
- correction.set_depth_correction(true);
- Projection projection = correction * p_render_data->scene_data->cam_projection;
- sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
- } else {
- sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
- }
+ sky.draw_sky(draw_list, rb, p_render_data->environment, color_only_framebuffer, time, sky_energy_multiplier);
+
+ RD::get_singleton()->draw_list_end();
RD::get_singleton()->draw_command_end_label();
}
@@ -2036,7 +2061,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_begin_label("Resolve");
- if (rb.is_valid() && rb->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
+ if (rb_data.is_valid() && rb->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
RD::get_singleton()->texture_resolve_multisample(rb_data->get_color_msaa(v), rb->get_internal_texture(v));
resolve_effects->resolve_depth(rb_data->get_depth_msaa(v), rb->get_depth_texture(v), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
@@ -2055,12 +2080,12 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
RD::get_singleton()->draw_command_end_label();
- if (rb.is_valid() && taa && rb->get_use_taa()) {
+ if (rb_data.is_valid() && taa && rb->get_use_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);
}
- if (rb.is_valid()) {
+ if (rb_data.is_valid()) {
_debug_draw_cluster(rb);
RENDER_TIMESTAMP("Tonemap");
@@ -2068,7 +2093,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
_render_buffers_post_process_and_tonemap(p_render_data);
}
- if (rb.is_valid()) {
+ if (rb_data.is_valid()) {
_render_buffers_debug_draw(rb, p_render_data->shadow_atlas, p_render_data->occluder_debug_tex);
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb->has_custom_data(RB_SCOPE_SDFGI)) {
@@ -2858,7 +2883,11 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
Ref<RenderBufferDataForwardClustered> rb_data;
if (p_render_data && p_render_data->render_buffers.is_valid()) {
rb = p_render_data->render_buffers;
- rb_data = rb->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ if (rb->has_custom_data(RB_SCOPE_FORWARD_CLUSTERED)) {
+ // Our forward clustered custom data buffer will only be available when we're rendering our normal view.
+ // This will not be available when rendering reflection probes.
+ rb_data = rb->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ }
}
//default render buffer and scene state uniform set
@@ -3291,6 +3320,99 @@ void RenderForwardClustered::sub_surface_scattering_set_scale(float p_scale, flo
RenderForwardClustered *RenderForwardClustered::singleton = nullptr;
+void RenderForwardClustered::sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) {
+ Ref<RenderSceneBuffersRD> rb = p_render_buffers;
+ ERR_FAIL_COND(rb.is_null());
+ Ref<RendererRD::GI::SDFGI> sdfgi;
+ if (rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ }
+
+ bool needs_sdfgi = p_environment.is_valid() && environment_get_sdfgi_enabled(p_environment);
+
+ if (!needs_sdfgi) {
+ if (sdfgi.is_valid()) {
+ // delete it
+ sdfgi.unref();
+ rb->set_custom_data(RB_SCOPE_SDFGI, sdfgi);
+ }
+ return;
+ }
+
+ static const uint32_t history_frames_to_converge[RS::ENV_SDFGI_CONVERGE_MAX] = { 5, 10, 15, 20, 25, 30 };
+ uint32_t requested_history_size = history_frames_to_converge[gi.sdfgi_frames_to_converge];
+
+ if (sdfgi.is_valid() && (sdfgi->num_cascades != environment_get_sdfgi_cascades(p_environment) || sdfgi->min_cell_size != environment_get_sdfgi_min_cell_size(p_environment) || requested_history_size != sdfgi->history_size || sdfgi->uses_occlusion != environment_get_sdfgi_use_occlusion(p_environment) || sdfgi->y_scale_mode != environment_get_sdfgi_y_scale(p_environment))) {
+ //configuration changed, erase
+ sdfgi.unref();
+ rb->set_custom_data(RB_SCOPE_SDFGI, sdfgi);
+ }
+
+ if (sdfgi.is_null()) {
+ // re-create
+ sdfgi = gi.create_sdfgi(p_environment, p_world_position, requested_history_size);
+ rb->set_custom_data(RB_SCOPE_SDFGI, sdfgi);
+ } else {
+ //check for updates
+ sdfgi->update(p_environment, p_world_position);
+ }
+}
+
+int RenderForwardClustered::sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const {
+ Ref<RenderSceneBuffersRD> rb = p_render_buffers;
+ ERR_FAIL_COND_V(rb.is_null(), 0);
+
+ if (!rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ return 0;
+ }
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+
+ int dirty_count = 0;
+ for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) {
+ const RendererRD::GI::SDFGI::Cascade &c = sdfgi->cascades[i];
+
+ if (c.dirty_regions == RendererRD::GI::SDFGI::Cascade::DIRTY_ALL) {
+ dirty_count++;
+ } else {
+ for (int j = 0; j < 3; j++) {
+ if (c.dirty_regions[j] != 0) {
+ dirty_count++;
+ }
+ }
+ }
+ }
+
+ return dirty_count;
+}
+
+AABB RenderForwardClustered::sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const {
+ AABB bounds;
+ Vector3i from;
+ Vector3i size;
+
+ Ref<RenderSceneBuffersRD> rb = p_render_buffers;
+ ERR_FAIL_COND_V(rb.is_null(), AABB());
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ ERR_FAIL_COND_V(sdfgi.is_null(), AABB());
+
+ int c = sdfgi->get_pending_region_data(p_region, from, size, bounds);
+ ERR_FAIL_COND_V(c == -1, AABB());
+ return bounds;
+}
+
+uint32_t RenderForwardClustered::sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const {
+ AABB bounds;
+ Vector3i from;
+ Vector3i size;
+
+ Ref<RenderSceneBuffersRD> rb = p_render_buffers;
+ ERR_FAIL_COND_V(rb.is_null(), -1);
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ ERR_FAIL_COND_V(sdfgi.is_null(), -1);
+
+ return sdfgi->get_pending_region_data(p_region, from, size, bounds);
+}
+
void RenderForwardClustered::GeometryInstanceForwardClustered::_mark_dirty() {
if (dirty_list_element.in_list()) {
return;
@@ -3378,6 +3500,7 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
sdcache->flags = flags;
sdcache->shader = p_material->shader_data;
+ sdcache->material = p_material;
sdcache->material_uniform_set = p_material->uniform_set;
sdcache->surface = mesh_storage->mesh_get_surface(p_mesh, p_surface);
sdcache->primitive = mesh_storage->mesh_surface_get_primitive(sdcache->surface);
@@ -3596,6 +3719,10 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p
}
ginstance->transforms_uniform_set = particles_storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ if (particles_storage->particles_get_frame_counter(ginstance->data->base) == 0) {
+ // Particles haven't been cleared or updated, update once now to ensure they are ready to render.
+ particles_storage->update_particles();
+ }
} else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
if (mesh_storage->skeleton_is_valid(ginstance->data->skeleton)) {
ginstance->transforms_uniform_set = mesh_storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
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 d9145b5818..3399382b56 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -441,6 +441,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
void *surface = nullptr;
RID material_uniform_set;
SceneShaderForwardClustered::ShaderData *shader = nullptr;
+ SceneShaderForwardClustered::MaterialData *material = nullptr;
void *surface_shadow = nullptr;
RID material_uniform_set_shadow;
@@ -649,6 +650,16 @@ public:
_update_render_base_uniform_set();
}
+ /* SDFGI UPDATE */
+
+ virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override;
+ virtual int sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const override;
+ virtual AABB sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override;
+ virtual uint32_t sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override;
+ RID sdfgi_get_ubo() const { return gi.sdfgi_ubo; }
+
+ /* GEOMETRY INSTANCE */
+
virtual RenderGeometryInstance *geometry_instance_create(RID p_base) override;
virtual void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override;
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 b5d4098e65..914ca25899 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
@@ -37,10 +37,6 @@
using namespace RendererSceneRenderImplementation;
-void SceneShaderForwardClustered::ShaderData::set_path_hint(const String &p_path) {
- path = p_path;
-}
-
void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
//compile
@@ -260,6 +256,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
}
+ bool depth_pre_pass_enabled = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
for (int i = 0; i < CULL_VARIANT_MAX; i++) {
RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
@@ -311,8 +308,16 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
continue;
}
- RD::PipelineColorBlendState blend_state;
RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
+ if (depth_pre_pass_enabled && casts_shadows()) {
+ // We already have a depth from the depth pre-pass, there is no need to write it again.
+ // In addition we can use COMPARE_OP_EQUAL instead of COMPARE_OP_LESS_OR_EQUAL.
+ // This way we can use the early depth test to discard transparent fragments before the fragment shader even starts.
+ depth_stencil.depth_compare_operator = RD::COMPARE_OP_EQUAL;
+ depth_stencil.enable_depth_write = false;
+ }
+
+ RD::PipelineColorBlendState blend_state;
RD::PipelineMultisampleState multisample_state;
int shader_flags = 0;
@@ -380,87 +385,6 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
valid = true;
}
-void SceneShaderForwardClustered::ShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
- if (!p_texture.is_valid()) {
- if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
- default_texture_params[p_name].erase(p_index);
-
- if (default_texture_params[p_name].is_empty()) {
- default_texture_params.erase(p_name);
- }
- }
- } else {
- if (!default_texture_params.has(p_name)) {
- default_texture_params[p_name] = HashMap<int, RID>();
- }
- default_texture_params[p_name][p_index] = p_texture;
- }
-}
-
-void SceneShaderForwardClustered::ShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
- HashMap<int, StringName> order;
-
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
- // Don't expose any of these.
- continue;
- }
-
- if (E.value.texture_order >= 0) {
- order[E.value.texture_order + 100000] = E.key;
- } else {
- order[E.value.order] = E.key;
- }
- }
-
- String last_group;
- for (const KeyValue<int, StringName> &E : order) {
- String group = uniforms[E.value].group;
- if (!uniforms[E.value].subgroup.is_empty()) {
- group += "::" + uniforms[E.value].subgroup;
- }
-
- if (group != last_group) {
- PropertyInfo pi;
- pi.usage = PROPERTY_USAGE_GROUP;
- pi.name = group;
- p_param_list->push_back(pi);
-
- last_group = group;
- }
-
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
- pi.name = E.value;
- p_param_list->push_back(pi);
- }
-}
-
-void SceneShaderForwardClustered::ShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererMaterialStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E.value);
- p.info.name = E.key; //supply name
- p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
- p_param_list->push_back(p);
- }
-}
-
-bool SceneShaderForwardClustered::ShaderData::is_parameter_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
bool SceneShaderForwardClustered::ShaderData::is_animated() const {
return (uses_fragment_time && uses_discard) || (uses_vertex_time && uses_vertex);
}
@@ -473,15 +397,6 @@ bool SceneShaderForwardClustered::ShaderData::casts_shadows() const {
return !has_alpha || (uses_depth_pre_pass && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
}
-Variant SceneShaderForwardClustered::ShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
- }
- return Variant();
-}
-
RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_source_code() const {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
index 194edf2dcb..51e4dd44d5 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -139,16 +139,12 @@ public:
PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_VERSION_MAX];
PipelineCacheRD color_pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_COLOR_PASS_FLAG_COUNT];
- String path;
-
- HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
String code;
- HashMap<StringName, HashMap<int, RID>> default_texture_params;
DepthDraw depth_draw = DEPTH_DRAW_OPAQUE;
DepthTest depth_test = DEPTH_TEST_ENABLED;
@@ -183,15 +179,9 @@ public:
uint32_t index = 0;
virtual void set_code(const String &p_Code);
- virtual void set_path_hint(const String &p_path);
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
- void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
- virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
SelfList<ShaderData> shader_list_element;
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 f860bab15e..53bcb1c038 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -70,17 +70,17 @@ void RenderForwardMobile::ForwardIDStorageMobile::map_forward_id(RendererRD::For
void RenderForwardMobile::ForwardIDStorageMobile::fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) {
// first zero out our indices
- p_push_constant->omni_lights[0] = 0xFFFF;
- p_push_constant->omni_lights[1] = 0xFFFF;
+ p_push_constant->omni_lights[0] = 0xFFFFFFFF;
+ p_push_constant->omni_lights[1] = 0xFFFFFFFF;
- p_push_constant->spot_lights[0] = 0xFFFF;
- p_push_constant->spot_lights[1] = 0xFFFF;
+ p_push_constant->spot_lights[0] = 0xFFFFFFFF;
+ p_push_constant->spot_lights[1] = 0xFFFFFFFF;
- p_push_constant->decals[0] = 0xFFFF;
- p_push_constant->decals[1] = 0xFFFF;
+ p_push_constant->decals[0] = 0xFFFFFFFF;
+ p_push_constant->decals[1] = 0xFFFFFFFF;
- p_push_constant->reflection_probes[0] = 0xFFFF;
- p_push_constant->reflection_probes[1] = 0xFFFF;
+ p_push_constant->reflection_probes[0] = 0xFFFFFFFF;
+ p_push_constant->reflection_probes[1] = 0xFFFFFFFF;
if (p_instance->omni_light_count == 0) {
spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
@@ -154,8 +154,8 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RenderSceneBu
render_buffers->create_texture(RB_SCOPE_MOBILE, RB_TEX_COLOR_MSAA, format, usage_bits, texture_samples);
- format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
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;
render_buffers->create_texture(RB_SCOPE_MOBILE, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples);
}
@@ -361,7 +361,11 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
Ref<RenderSceneBuffersRD> rb;
if (p_render_data && p_render_data->render_buffers.is_valid()) {
rb = p_render_data->render_buffers;
- rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
+ if (rb->has_custom_data(RB_SCOPE_MOBILE)) {
+ // Our forward mobile custom data buffer will only be available when we're rendering our normal view.
+ // This will not be available when rendering reflection probes.
+ rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
+ }
}
// default render buffer and scene state uniform set
@@ -640,7 +644,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
Ref<RenderBufferDataForwardMobile> rb_data;
if (p_render_data->render_buffers.is_valid()) {
rb = p_render_data->render_buffers;
- rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
+ if (rb->has_custom_data(RB_SCOPE_MOBILE)) {
+ // Our forward mobile custom data buffer will only be available when we're rendering our normal view.
+ // This will not be available when rendering reflection probes.
+ rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
+ }
}
RENDER_TIMESTAMP("Prepare 3D Scene");
@@ -673,7 +681,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
Size2i screen_size;
RID framebuffer;
- bool reverse_cull = false;
+ bool reverse_cull = p_render_data->scene_data->cam_transform.basis.determinant() < 0;
bool using_subpass_transparent = true;
bool using_subpass_post_process = true;
@@ -689,7 +697,21 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = p_render_data->instances->size();
}
- if (rb_data.is_valid()) {
+ if (p_render_data->reflection_probe.is_valid()) {
+ uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
+ screen_size.x = resolution;
+ screen_size.y = resolution;
+
+ framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+
+ if (light_storage->reflection_probe_is_interior(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+ p_render_data->environment = RID(); //no environment on interiors
+ }
+
+ reverse_cull = true;
+ using_subpass_transparent = true; // we ignore our screen/depth texture here
+ using_subpass_post_process = false; // not applicable at all for reflection probes.
+ } else if (rb_data.is_valid()) {
// setup rendering to render buffer
screen_size = p_render_data->render_buffers->get_internal_size();
@@ -717,20 +739,6 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// only opaque and sky as subpasses
framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_TWO_SUBPASSES);
}
- } else if (p_render_data->reflection_probe.is_valid()) {
- uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
- screen_size.x = resolution;
- screen_size.y = resolution;
-
- framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
-
- if (light_storage->reflection_probe_is_interior(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
- p_render_data->environment = RID(); //no environment on interiors
- }
-
- reverse_cull = true;
- using_subpass_transparent = true; // we ignore our screen/depth texture here
- using_subpass_post_process = false; // not applicable at all for reflection probes.
} else {
ERR_FAIL(); //bug?
}
@@ -796,7 +804,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
draw_sky = true;
} break;
case RS::ENV_BG_CANVAS: {
- if (rb.is_valid()) {
+ if (rb_data.is_valid()) {
RID dest_framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS);
RID texture = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(rb->get_render_target());
copy_effects->copy_to_fb_rect(texture, dest_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, true);
@@ -811,55 +819,45 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
default: {
}
}
+
// setup sky if used for ambient, reflections, or background
if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
RENDER_TIMESTAMP("Setup Sky");
RD::get_singleton()->draw_command_begin_label("Setup Sky");
- Projection projection = p_render_data->scene_data->cam_projection;
+
+ // Setup our sky render information for this frame/viewport
if (p_render_data->reflection_probe.is_valid()) {
+ Vector3 eye_offset;
Projection correction;
correction.set_depth_correction(true);
- projection = correction * p_render_data->scene_data->cam_projection;
- }
+ Projection projection = correction * p_render_data->scene_data->cam_projection;
- sky.setup(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->scene_data->cam_transform, screen_size, this);
+ sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, screen_size, this);
+ } else {
+ sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, 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, screen_size, this);
+ }
sky_energy_multiplier *= bg_energy_multiplier;
RID sky_rid = environment_get_sky(p_render_data->environment);
if (sky_rid.is_valid()) {
- sky.update(p_render_data->environment, projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
+ sky.update_radiance_buffers(rb, p_render_data->environment, p_render_data->scene_data->cam_transform.origin, time, sky_energy_multiplier);
radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
} else {
// do not try to draw sky if invalid
draw_sky = false;
}
+
+ if (draw_sky || draw_sky_fog_only) {
+ // update sky half/quarter res buffers (if required)
+ sky.update_res_buffers(rb, p_render_data->environment, time, sky_energy_multiplier);
+ }
RD::get_singleton()->draw_command_end_label(); // Setup Sky
}
} else {
clear_color = p_default_bg_color;
}
- // update sky buffers (if required)
- if (draw_sky || draw_sky_fog_only) {
- // !BAS! @TODO See if we can limit doing some things double and maybe even move this into _pre_opaque_render
- // and change Forward Clustered in the same way as we have here (but without using subpasses)
- RENDER_TIMESTAMP("Setup Sky Resolution Buffers");
-
- RD::get_singleton()->draw_command_begin_label("Setup Sky Resolution Buffers");
-
- if (p_render_data->reflection_probe.is_valid()) {
- Projection correction;
- correction.set_depth_correction(true);
- Projection projection = correction * p_render_data->scene_data->cam_projection;
- sky.update_res_buffers(p_render_data->environment, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
- } else {
- sky.update_res_buffers(p_render_data->environment, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
- }
-
- RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
- }
-
_pre_opaque_render(p_render_data);
uint32_t spec_constant_base_flags = 0;
@@ -944,16 +942,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (draw_sky || draw_sky_fog_only) {
RD::get_singleton()->draw_command_begin_label("Draw Sky Subpass");
+ // Note, sky.setup should have been called up above and setup stuff we need.
+
RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
- if (p_render_data->reflection_probe.is_valid()) {
- Projection correction;
- correction.set_depth_correction(true);
- Projection projection = correction * p_render_data->scene_data->cam_projection;
- sky.draw(draw_list, p_render_data->environment, framebuffer, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
- } else {
- sky.draw(draw_list, p_render_data->environment, framebuffer, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
- }
+ sky.draw_sky(draw_list, rb, p_render_data->environment, framebuffer, time, sky_energy_multiplier);
RD::get_singleton()->draw_command_end_label(); // Draw Sky Subpass
@@ -1021,7 +1014,9 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
} else {
RENDER_TIMESTAMP("Render Transparent");
- framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS);
+ if (rb_data.is_valid()) {
+ framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS);
+ }
// this may be needed if we re-introduced steps that change info, not sure which do so in the previous implementation
// _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
@@ -1757,8 +1752,18 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
for (int i = 0; i < (int)p_render_data->instances->size(); i++) {
GeometryInstanceForwardMobile *inst = static_cast<GeometryInstanceForwardMobile *>((*p_render_data->instances)[i]);
- Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal);
- inst->depth = near_plane.distance_to(support_min);
+ Vector3 center = inst->transform.origin;
+ if (p_render_data->scene_data->cam_orthogonal) {
+ if (inst->use_aabb_center) {
+ center = inst->transformed_aabb.get_support(-near_plane.normal);
+ }
+ inst->depth = near_plane.distance_to(center) - inst->sorting_offset;
+ } else {
+ if (inst->use_aabb_center) {
+ center = inst->transformed_aabb.position + (inst->transformed_aabb.size * 0.5);
+ }
+ inst->depth = p_render_data->scene_data->cam_transform.origin.distance_to(center) - inst->sorting_offset;
+ }
uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15);
uint32_t flags = inst->base_flags; //fill flags if appropriate
@@ -2092,6 +2097,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
#endif
material_uniform_set = surf->material_uniform_set;
shader = surf->shader;
+ surf->material->set_as_used();
#ifdef DEBUG_ENABLED
}
#endif
@@ -2407,6 +2413,7 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
sdcache->flags = flags;
sdcache->shader = p_material->shader_data;
+ sdcache->material = p_material;
sdcache->material_uniform_set = p_material->uniform_set;
sdcache->surface = mesh_storage->mesh_get_surface(p_mesh, p_surface);
sdcache->primitive = mesh_storage->mesh_surface_get_primitive(sdcache->surface);
@@ -2624,6 +2631,10 @@ void RenderForwardMobile::_geometry_instance_update(RenderGeometryInstance *p_ge
}
ginstance->transforms_uniform_set = particles_storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ if (particles_storage->particles_get_frame_counter(ginstance->data->base) == 0) {
+ // Particles haven't been cleared or updated, update once now to ensure they are ready to render.
+ particles_storage->update_particles();
+ }
} else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
if (mesh_storage->skeleton_is_valid(ginstance->data->skeleton)) {
ginstance->transforms_uniform_set = mesh_storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
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 6c85e1cffc..7ed6061def 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -440,6 +440,7 @@ protected:
void *surface = nullptr;
RID material_uniform_set;
SceneShaderForwardMobile::ShaderData *shader = nullptr;
+ SceneShaderForwardMobile::MaterialData *material = nullptr;
void *surface_shadow = nullptr;
RID material_uniform_set_shadow;
@@ -554,6 +555,15 @@ public:
virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth) override;
+ /* SDFGI UPDATE */
+
+ virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
+ virtual int sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const override { return 0; }
+ virtual AABB sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override { return AABB(); }
+ virtual uint32_t sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override { return 0; }
+
+ /* GEOMETRY INSTANCE */
+
static void _geometry_instance_dependency_changed(Dependency::DependencyChangedNotification p_notification, DependencyTracker *p_tracker);
static void _geometry_instance_dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker);
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 2d80cffdad..224bb34189 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
@@ -39,10 +39,6 @@ using namespace RendererSceneRenderImplementation;
/* ShaderData */
-void SceneShaderForwardMobile::ShaderData::set_path_hint(const String &p_path) {
- path = p_path;
-}
-
void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
//compile
@@ -336,86 +332,6 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
valid = true;
}
-void SceneShaderForwardMobile::ShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
- if (!p_texture.is_valid()) {
- if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
- default_texture_params[p_name].erase(p_index);
-
- if (default_texture_params[p_name].is_empty()) {
- default_texture_params.erase(p_name);
- }
- }
- } else {
- if (!default_texture_params.has(p_name)) {
- default_texture_params[p_name] = HashMap<int, RID>();
- }
- default_texture_params[p_name][p_index] = p_texture;
- }
-}
-
-void SceneShaderForwardMobile::ShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
- HashMap<int, StringName> order;
-
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
- continue;
- }
-
- if (E.value.texture_order >= 0) {
- order[E.value.texture_order + 100000] = E.key;
- } else {
- order[E.value.order] = E.key;
- }
- }
-
- String last_group;
- for (const KeyValue<int, StringName> &E : order) {
- String group = uniforms[E.value].group;
- if (!uniforms[E.value].subgroup.is_empty()) {
- group += "::" + uniforms[E.value].subgroup;
- }
-
- if (group != last_group) {
- PropertyInfo pi;
- pi.usage = PROPERTY_USAGE_GROUP;
- pi.name = group;
- p_param_list->push_back(pi);
-
- last_group = group;
- }
-
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
- pi.name = E.value;
- p_param_list->push_back(pi);
- }
-}
-
-void SceneShaderForwardMobile::ShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererMaterialStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E.value);
- p.info.name = E.key; //supply name
- p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
- p_param_list->push_back(p);
- }
-}
-
-bool SceneShaderForwardMobile::ShaderData::is_parameter_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
bool SceneShaderForwardMobile::ShaderData::is_animated() const {
return (uses_fragment_time && uses_discard) || (uses_vertex_time && uses_vertex);
}
@@ -428,15 +344,6 @@ bool SceneShaderForwardMobile::ShaderData::casts_shadows() const {
return !has_alpha || (uses_depth_pre_pass && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
}
-Variant SceneShaderForwardMobile::ShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
- }
- return Variant();
-}
-
RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_source_code() const {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index 5b51cfc8c3..18a897a9e9 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -100,16 +100,12 @@ public:
uint32_t vertex_input_mask = 0;
PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
- String path;
-
- HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
String code;
- HashMap<StringName, HashMap<int, RID>> default_texture_params;
DepthDraw depth_draw;
DepthTest depth_test;
@@ -141,16 +137,8 @@ public:
uint32_t index = 0;
virtual void set_code(const String &p_Code);
- virtual void set_path_hint(const String &p_path);
-
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
- void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
-
- virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
SelfList<ShaderData> shader_list_element;
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index d41daa18b4..96690ceac1 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -790,7 +790,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
ERR_BREAK(particles_storage->particles_get_mode(pt->particles) != RS::PARTICLES_MODE_2D);
particles_storage->particles_request_process(pt->particles);
- if (particles_storage->particles_is_inactive(pt->particles)) {
+ if (particles_storage->particles_is_inactive(pt->particles) || particles_storage->particles_get_frame_counter(pt->particles) == 0) {
break;
}
@@ -1136,6 +1136,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
// Update uniform set.
if (material_data->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_data->uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, MATERIAL_UNIFORM_SET);
+ material_data->set_as_used();
}
} else {
pipeline_variants = &shader.pipeline_variants;
@@ -2001,10 +2002,6 @@ void RendererCanvasRenderRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::
oc->cull_mode = p_mode;
}
-void RendererCanvasRenderRD::CanvasShaderData::set_path_hint(const String &p_path) {
- path = p_path;
-}
-
void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
//compile
@@ -2216,86 +2213,6 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
valid = true;
}
-void RendererCanvasRenderRD::CanvasShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
- if (!p_texture.is_valid()) {
- if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
- default_texture_params[p_name].erase(p_index);
-
- if (default_texture_params[p_name].is_empty()) {
- default_texture_params.erase(p_name);
- }
- }
- } else {
- if (!default_texture_params.has(p_name)) {
- default_texture_params[p_name] = HashMap<int, RID>();
- }
- default_texture_params[p_name][p_index] = p_texture;
- }
-}
-
-void RendererCanvasRenderRD::CanvasShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
- HashMap<int, StringName> order;
-
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
- // Don't expose any of these.
- continue;
- }
- if (E.value.texture_order >= 0) {
- order[E.value.texture_order + 100000] = E.key;
- } else {
- order[E.value.order] = E.key;
- }
- }
-
- String last_group;
- for (const KeyValue<int, StringName> &E : order) {
- String group = uniforms[E.value].group;
- if (!uniforms[E.value].subgroup.is_empty()) {
- group += "::" + uniforms[E.value].subgroup;
- }
-
- if (group != last_group) {
- PropertyInfo pi;
- pi.usage = PROPERTY_USAGE_GROUP;
- pi.name = group;
- p_param_list->push_back(pi);
-
- last_group = group;
- }
-
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
- pi.name = E.value;
- p_param_list->push_back(pi);
- }
-}
-
-void RendererCanvasRenderRD::CanvasShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererMaterialStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E.value);
- p.info.name = E.key; //supply name
- p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
- p_param_list->push_back(p);
- }
-}
-
-bool RendererCanvasRenderRD::CanvasShaderData::is_parameter_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
bool RendererCanvasRenderRD::CanvasShaderData::is_animated() const {
return false;
}
@@ -2304,15 +2221,6 @@ bool RendererCanvasRenderRD::CanvasShaderData::casts_shadows() const {
return false;
}
-Variant RendererCanvasRenderRD::CanvasShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
- }
- return Variant();
-}
-
RS::ShaderNativeSourceCode RendererCanvasRenderRD::CanvasShaderData::get_native_source_code() const {
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
return canvas_singleton->shader.canvas_shader.version_get_native_source_code(version);
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 6e876b1297..f809c7f046 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -160,16 +160,13 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
bool valid = false;
RID version;
PipelineVariants pipeline_variants;
- String path;
- HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
String code;
- HashMap<StringName, HashMap<int, RID>> default_texture_params;
bool uses_screen_texture = false;
bool uses_screen_texture_mipmaps = false;
@@ -177,15 +174,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
bool uses_time = false;
virtual void set_code(const String &p_Code);
- virtual void set_path_hint(const String &p_path);
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
- virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
-
- virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
CanvasShaderData() {}
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index 3289bfb0ea..f488fd63fe 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -174,13 +174,19 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color
texture_storage->texture_2d_initialize(texture, p_image);
RID rd_texture = texture_storage->texture_get_rd_texture(texture);
+ RD::SamplerState sampler_state;
+ sampler_state.min_filter = p_use_filter ? RD::SAMPLER_FILTER_LINEAR : RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.mag_filter = p_use_filter ? RD::SAMPLER_FILTER_LINEAR : RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.max_lod = 0;
+ RID sampler = RD::get_singleton()->sampler_create(sampler_state);
+
RID uset;
{
Vector<RD::Uniform> uniforms;
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u.binding = 0;
- u.append_id(blit.sampler);
+ u.append_id(sampler);
u.append_id(rd_texture);
uniforms.push_back(u);
uset = RD::get_singleton()->uniform_set_create(uniforms, blit.shader.version_get_shader(blit.shader_version, BLIT_MODE_NORMAL), 0);
@@ -241,6 +247,7 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color
RD::get_singleton()->swap_buffers();
texture_storage->texture_free(texture);
+ RD::get_singleton()->free(sampler);
}
RendererCompositorRD *RendererCompositorRD::singleton = nullptr;
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 3d84d47333..1242c11bea 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -51,99 +51,6 @@ void get_vogel_disk(float *r_kernel, int p_sample_count) {
}
}
-void RendererSceneRenderRD::sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) {
- Ref<RenderSceneBuffersRD> rb = p_render_buffers;
- ERR_FAIL_COND(rb.is_null());
- Ref<RendererRD::GI::SDFGI> sdfgi;
- if (rb->has_custom_data(RB_SCOPE_SDFGI)) {
- sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
- }
-
- bool needs_sdfgi = p_environment.is_valid() && environment_get_sdfgi_enabled(p_environment);
-
- if (!needs_sdfgi) {
- if (sdfgi.is_valid()) {
- // delete it
- sdfgi.unref();
- rb->set_custom_data(RB_SCOPE_SDFGI, sdfgi);
- }
- return;
- }
-
- static const uint32_t history_frames_to_converge[RS::ENV_SDFGI_CONVERGE_MAX] = { 5, 10, 15, 20, 25, 30 };
- uint32_t requested_history_size = history_frames_to_converge[gi.sdfgi_frames_to_converge];
-
- if (sdfgi.is_valid() && (sdfgi->num_cascades != environment_get_sdfgi_cascades(p_environment) || sdfgi->min_cell_size != environment_get_sdfgi_min_cell_size(p_environment) || requested_history_size != sdfgi->history_size || sdfgi->uses_occlusion != environment_get_sdfgi_use_occlusion(p_environment) || sdfgi->y_scale_mode != environment_get_sdfgi_y_scale(p_environment))) {
- //configuration changed, erase
- sdfgi.unref();
- rb->set_custom_data(RB_SCOPE_SDFGI, sdfgi);
- }
-
- if (sdfgi.is_null()) {
- // re-create
- sdfgi = gi.create_sdfgi(p_environment, p_world_position, requested_history_size);
- rb->set_custom_data(RB_SCOPE_SDFGI, sdfgi);
- } else {
- //check for updates
- sdfgi->update(p_environment, p_world_position);
- }
-}
-
-int RendererSceneRenderRD::sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const {
- Ref<RenderSceneBuffersRD> rb = p_render_buffers;
- ERR_FAIL_COND_V(rb.is_null(), 0);
-
- if (!rb->has_custom_data(RB_SCOPE_SDFGI)) {
- return 0;
- }
- Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
-
- int dirty_count = 0;
- for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) {
- const RendererRD::GI::SDFGI::Cascade &c = sdfgi->cascades[i];
-
- if (c.dirty_regions == RendererRD::GI::SDFGI::Cascade::DIRTY_ALL) {
- dirty_count++;
- } else {
- for (int j = 0; j < 3; j++) {
- if (c.dirty_regions[j] != 0) {
- dirty_count++;
- }
- }
- }
- }
-
- return dirty_count;
-}
-
-AABB RendererSceneRenderRD::sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const {
- AABB bounds;
- Vector3i from;
- Vector3i size;
-
- Ref<RenderSceneBuffersRD> rb = p_render_buffers;
- ERR_FAIL_COND_V(rb.is_null(), AABB());
- Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
- ERR_FAIL_COND_V(sdfgi.is_null(), AABB());
-
- int c = sdfgi->get_pending_region_data(p_region, from, size, bounds);
- ERR_FAIL_COND_V(c == -1, AABB());
- return bounds;
-}
-
-uint32_t RendererSceneRenderRD::sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const {
- AABB bounds;
- Vector3i from;
- Vector3i size;
-
- Ref<RenderSceneBuffersRD> rb = p_render_buffers;
- ERR_FAIL_COND_V(rb.is_null(), -1);
- Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
- ERR_FAIL_COND_V(sdfgi.is_null(), -1);
-
- return sdfgi->get_pending_region_data(p_region, from, size, bounds);
-}
-
RID RendererSceneRenderRD::sky_allocate() {
return sky.allocate_sky_rid();
}
@@ -1002,10 +909,20 @@ bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const {
}
void RendererSceneRenderRD::_update_vrs(Ref<RenderSceneBuffersRD> p_render_buffers) {
- if (p_render_buffers.is_valid() && vrs) {
+ if (p_render_buffers.is_null()) {
+ return;
+ }
+
+ RID render_target = p_render_buffers->get_render_target();
+ if (render_target.is_null()) {
+ // must be rendering reflection probes
+ return;
+ }
+
+ if (vrs) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
- RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(p_render_buffers->get_render_target());
+ RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(render_target);
if (vrs_mode != RS::VIEWPORT_VRS_DISABLED) {
RID vrs_texture = p_render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE);
@@ -1157,7 +1074,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
}
Color clear_color;
- if (p_render_buffers.is_valid()) {
+ if (p_render_buffers.is_valid() && p_reflection_probe.is_null()) {
clear_color = texture_storage->render_target_get_clear_request_color(rb->get_render_target());
} else {
clear_color = RSG::texture_storage->get_default_clear_color();
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index d813d96f77..704cb37c91 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -217,14 +217,6 @@ public:
RendererRD::SkyRD *get_sky() { return &sky; }
- /* SDFGI UPDATE */
-
- virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override;
- virtual int sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const override;
- virtual AABB sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override;
- virtual uint32_t sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override;
- RID sdfgi_get_ubo() const { return gi.sdfgi_ubo; }
-
/* SKY API */
virtual RID sky_allocate() override;
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
index a8b2d77718..631d1968b0 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
@@ -66,6 +66,19 @@ void main() {
vec4 normal_roughness = imageLoad(source_normal_roughness, ssC);
vec3 normal = normal_roughness.xyz * 2.0 - 1.0;
+ float roughness = normal_roughness.w;
+
+ // The roughness cutoff of 0.6 is chosen to match the roughness fadeout from GH-69828.
+ if (roughness > 0.6) {
+ // Do not compute SSR for rough materials to improve performance at the cost of
+ // subtle artifacting.
+#ifdef MODE_ROUGH
+ imageStore(blur_radius_image, ssC, vec4(0.0));
+#endif
+ imageStore(ssr_image, ssC, vec4(0.0));
+ return;
+ }
+
normal = normalize(normal);
normal.y = -normal.y; //because this code reads flipped
@@ -81,8 +94,6 @@ void main() {
imageStore(ssr_image, ssC, vec4(0.0));
return;
}
- //ray_dir = normalize(view_dir - normal * dot(normal,view_dir) * 2.0);
- //ray_dir = normalize(vec3(1.0, 1.0, -1.0));
////////////////
@@ -223,7 +234,6 @@ void main() {
// if roughness is enabled, do screen space cone tracing
float blur_radius = 0.0;
- float roughness = normal_roughness.w;
if (roughness > 0.001) {
float cone_angle = min(roughness, 0.999) * M_PI * 0.5;
diff --git a/servers/rendering/renderer_rd/shaders/environment/gi.glsl b/servers/rendering/renderer_rd/shaders/environment/gi.glsl
index ab927df678..459c4dcb1d 100644
--- a/servers/rendering/renderer_rd/shaders/environment/gi.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/gi.glsl
@@ -108,7 +108,9 @@ layout(set = 0, binding = 18, std140) uniform SceneData {
}
scene_data;
+#ifdef USE_VRS
layout(r8ui, set = 0, binding = 19) uniform restrict readonly uimage2D vrs_buffer;
+#endif
layout(push_constant, std430) uniform Params {
uint max_voxel_gi_instances;
@@ -661,6 +663,7 @@ void main() {
ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
uint vrs_x, vrs_y;
+#ifdef USE_VRS
if (sc_use_vrs) {
ivec2 vrs_pos;
@@ -684,6 +687,7 @@ void main() {
return;
}
}
+#endif
if (sc_half_res) {
pos <<= 1;
@@ -708,6 +712,7 @@ void main() {
imageStore(ambient_buffer, pos, ambient_light);
imageStore(reflection_buffer, pos, reflection_light);
+#ifdef USE_VRS
if (sc_use_vrs) {
if (vrs_x > 1) {
imageStore(ambient_buffer, pos + ivec2(1, 0), ambient_light);
@@ -766,4 +771,5 @@ void main() {
imageStore(reflection_buffer, pos + ivec2(3, 3), reflection_light);
}
}
+#endif
}
diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
index d523461600..bf974a3fd5 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sky.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
@@ -14,7 +14,7 @@ layout(location = 0) out vec2 uv_interp;
layout(push_constant, std430) uniform Params {
mat3 orientation;
- vec4 projections[MAX_VIEWS];
+ vec4 projection; // only applicable if not multiview
vec3 position;
float time;
vec3 pad;
@@ -54,7 +54,7 @@ layout(location = 0) in vec2 uv_interp;
layout(push_constant, std430) uniform Params {
mat3 orientation;
- vec4 projections[MAX_VIEWS];
+ vec4 projection; // only applicable if not multiview
vec3 position;
float time;
vec3 pad;
@@ -82,7 +82,10 @@ layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalShaderUnifor
}
global_shader_uniforms;
-layout(set = 0, binding = 2, std140) uniform SceneData {
+layout(set = 0, binding = 2, std140) uniform SkySceneData {
+ mat4 view_inv_projections[2];
+ vec4 view_eye_offsets[2];
+
bool volumetric_fog_enabled; // 4 - 4
float volumetric_fog_inv_length; // 4 - 8
float volumetric_fog_detail_spread; // 4 - 12
@@ -101,7 +104,7 @@ layout(set = 0, binding = 2, std140) uniform SceneData {
uint pad1; // 4 - 60
uint pad2; // 4 - 64
}
-scene_data;
+sky_scene_data;
struct DirectionalLightData {
vec4 direction_energy;
@@ -124,6 +127,9 @@ layout(set = 2, binding = 0) uniform textureCube radiance;
#ifdef USE_CUBEMAP_PASS
layout(set = 2, binding = 1) uniform textureCube half_res;
layout(set = 2, binding = 2) uniform textureCube quarter_res;
+#elif defined(USE_MULTIVIEW)
+layout(set = 2, binding = 1) uniform texture2DArray half_res;
+layout(set = 2, binding = 2) uniform texture2DArray quarter_res;
#else
layout(set = 2, binding = 1) uniform texture2D half_res;
layout(set = 2, binding = 2) uniform texture2D quarter_res;
@@ -169,15 +175,15 @@ vec4 volumetric_fog_process(vec2 screen_uv) {
}
vec4 fog_process(vec3 view, vec3 sky_color) {
- vec3 fog_color = mix(scene_data.fog_light_color, sky_color, scene_data.fog_aerial_perspective);
+ vec3 fog_color = mix(sky_scene_data.fog_light_color, sky_color, sky_scene_data.fog_aerial_perspective);
- if (scene_data.fog_sun_scatter > 0.001) {
+ if (sky_scene_data.fog_sun_scatter > 0.001) {
vec4 sun_scatter = vec4(0.0);
float sun_total = 0.0;
- for (uint i = 0; i < scene_data.directional_light_count; i++) {
+ for (uint i = 0; i < sky_scene_data.directional_light_count; i++) {
vec3 light_color = directional_lights.data[i].color_size.xyz * directional_lights.data[i].direction_energy.w;
float light_amount = pow(max(dot(view, directional_lights.data[i].direction_energy.xyz), 0.0), 8.0);
- fog_color += light_color * light_amount * scene_data.fog_sun_scatter;
+ fog_color += light_color * light_amount * sky_scene_data.fog_sun_scatter;
}
}
@@ -186,9 +192,17 @@ vec4 fog_process(vec3 view, vec3 sky_color) {
void main() {
vec3 cube_normal;
+#ifdef USE_MULTIVIEW
+ // In multiview our projection matrices will contain positional and rotational offsets that we need to properly unproject.
+ vec4 unproject = vec4(uv_interp.x, -uv_interp.y, 1.0, 1.0);
+ vec4 unprojected = sky_scene_data.view_inv_projections[ViewIndex] * unproject;
+ cube_normal = unprojected.xyz / unprojected.w;
+ cube_normal += sky_scene_data.view_eye_offsets[ViewIndex].xyz;
+#else
cube_normal.z = -1.0;
- cube_normal.x = (cube_normal.z * (-uv_interp.x - params.projections[ViewIndex].x)) / params.projections[ViewIndex].y;
- cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.projections[ViewIndex].z)) / params.projections[ViewIndex].w;
+ cube_normal.x = (cube_normal.z * (-uv_interp.x - params.projection.x)) / params.projection.y;
+ cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.projection.z)) / params.projection.w;
+#endif
cube_normal = mat3(params.orientation) * cube_normal;
cube_normal = normalize(cube_normal);
@@ -209,20 +223,33 @@ void main() {
vec4 custom_fog = vec4(0.0);
#ifdef USE_CUBEMAP_PASS
+
#ifdef USES_HALF_RES_COLOR
half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) / params.luminance_multiplier;
#endif
#ifdef USES_QUARTER_RES_COLOR
quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) / params.luminance_multiplier;
#endif
+
#else
+
#ifdef USES_HALF_RES_COLOR
+#ifdef USE_MULTIVIEW
+ half_res_color = textureLod(sampler2DArray(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(uv, ViewIndex), 0.0) / params.luminance_multiplier;
+#else
half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) / params.luminance_multiplier;
-#endif
+#endif // USE_MULTIVIEW
+#endif // USES_HALF_RES_COLOR
+
#ifdef USES_QUARTER_RES_COLOR
+#ifdef USE_MULTIVIEW
+ quarter_res_color = textureLod(sampler2DArray(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(uv, ViewIndex), 0.0) / params.luminance_multiplier;
+#else
quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) / params.luminance_multiplier;
-#endif
-#endif
+#endif // USE_MULTIVIEW
+#endif // USES_QUARTER_RES_COLOR
+
+#endif //USE_CUBEMAP_PASS
{
@@ -236,14 +263,14 @@ void main() {
#if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS)
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
- if (scene_data.fog_enabled) {
+ if (sky_scene_data.fog_enabled) {
vec4 fog = fog_process(cube_normal, frag_color.rgb);
- frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a * scene_data.fog_sky_affect);
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a * sky_scene_data.fog_sky_affect);
}
- if (scene_data.volumetric_fog_enabled) {
+ if (sky_scene_data.volumetric_fog_enabled) {
vec4 fog = volumetric_fog_process(uv);
- frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a * scene_data.volumetric_fog_sky_affect);
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a * sky_scene_data.volumetric_fog_sky_affect);
}
if (custom_fog.a > 0.0) {
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index 9f6aa7adc0..a609076e2c 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -243,8 +243,14 @@ void main() {
if (params.trail_size > 1) {
if (params.trail_pass) {
+ if (particle >= params.total_particles * (params.trail_size - 1)) {
+ return;
+ }
particle += (particle / (params.trail_size - 1)) + 1;
} else {
+ if (particle >= params.total_particles) {
+ return;
+ }
particle *= params.trail_size;
}
}
@@ -298,12 +304,17 @@ void main() {
PARTICLE.flags = PARTICLE_FLAG_TRAILED | ((frame_history.data[0].frame & PARTICLE_FRAME_MASK) << PARTICLE_FRAME_SHIFT); //mark it as trailed, save in which frame it will start
PARTICLE.xform = particles.data[src_idx].xform;
}
-
+ if (!bool(particles.data[src_idx].flags & PARTICLE_FLAG_ACTIVE)) {
+ // Disable the entire trail if the parent is no longer active.
+ PARTICLE.flags = 0;
+ return;
+ }
if (bool(PARTICLE.flags & PARTICLE_FLAG_TRAILED) && ((PARTICLE.flags >> PARTICLE_FRAME_SHIFT) == (FRAME.frame & PARTICLE_FRAME_MASK))) { //check this is trailed and see if it should start now
// we just assume that this is the first frame of the particle, the rest is deterministic
PARTICLE.flags = PARTICLE_FLAG_ACTIVE | (particles.data[src_idx].flags & (PARTICLE_FRAME_MASK << PARTICLE_FRAME_SHIFT));
return; //- this appears like it should be correct, but it seems not to be.. wonder why.
}
+
} else {
PARTICLE.flags &= ~PARTICLE_FLAG_STARTED;
}
diff --git a/drivers/spirv-reflect/SCsub b/servers/rendering/renderer_rd/spirv-reflect/SCsub
index 1e7b3de0e6..4c27e5bef7 100644
--- a/drivers/spirv-reflect/SCsub
+++ b/servers/rendering/renderer_rd/spirv-reflect/SCsub
@@ -14,4 +14,4 @@ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_thirdparty = env.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources)
+env_thirdparty.add_source_files(env.servers_sources, thirdparty_sources)
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
index 1dd95969e6..637aff9aac 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
@@ -1315,6 +1315,10 @@ void LightStorage::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_s
ra->reflections.clear();
}
+
+ if (ra->render_buffers.is_valid()) {
+ ra->render_buffers->cleanup();
+ }
}
int LightStorage::reflection_atlas_get_size(RID p_ref_atlas) const {
@@ -1360,6 +1364,9 @@ void LightStorage::reflection_probe_release_atlas_index(RID p_instance) {
ERR_FAIL_COND(!atlas);
ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size());
atlas->reflections.write[rpi->atlas_index].owner = RID();
+
+ // TODO investigate if this is enough? shouldn't we be freeing our textures and framebuffers?
+
rpi->atlas_index = -1;
rpi->atlas = RID();
}
@@ -1398,6 +1405,10 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, false);
+ if (atlas->render_buffers.is_null()) {
+ atlas->render_buffers.instantiate();
+ }
+
RD::get_singleton()->draw_command_begin_label("Reflection probe render");
if (LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 256) {
@@ -1455,6 +1466,9 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_
Vector<RID> fb;
fb.push_back(atlas->depth_buffer);
atlas->depth_fb = RD::get_singleton()->framebuffer_create(fb);
+
+ atlas->render_buffers->cleanup();
+ atlas->render_buffers->configure_for_reflections(Size2i(atlas->size, atlas->size));
}
if (rpi->atlas_index == -1) {
@@ -1494,6 +1508,13 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_
return true;
}
+Ref<RenderSceneBuffers> LightStorage::reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) {
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas);
+ ERR_FAIL_COND_V(!atlas, Ref<RenderSceneBuffersRD>());
+
+ return atlas->render_buffers;
+}
+
bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!rpi, false);
@@ -1726,13 +1747,13 @@ void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_use
//erase lightmap users
if (lm->light_texture.is_valid()) {
- TextureStorage::Texture *t = texture_storage->get_singleton()->get_texture(lm->light_texture);
+ TextureStorage::Texture *t = texture_storage->get_texture(lm->light_texture);
if (t) {
t->lightmap_users.erase(p_lightmap);
}
}
- TextureStorage::Texture *t = texture_storage->get_singleton()->get_texture(p_light);
+ TextureStorage::Texture *t = texture_storage->get_texture(p_light);
lm->light_texture = p_light;
lm->uses_spherical_harmonics = p_uses_spherical_haromics;
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h
index 79006ad982..d31924eeb0 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h
@@ -38,6 +38,7 @@
#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
#include "servers/rendering/renderer_rd/environment/sky.h"
#include "servers/rendering/renderer_rd/storage_rd/forward_id_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/storage/light_storage.h"
#include "servers/rendering/storage/utilities.h"
@@ -256,6 +257,8 @@ private:
Vector<Reflection> reflections;
+ Ref<RenderSceneBuffersRD> render_buffers; // Further render buffers used.
+
ClusterBuilderRD *cluster_builder = nullptr; // only used if cluster builder is supported by the renderer.
};
@@ -846,6 +849,7 @@ public:
virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
+ virtual Ref<RenderSceneBuffers> reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) override;
virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
uint32_t reflection_probe_instance_get_resolution(RID p_instance);
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index 6703d8e7d0..709e4b449f 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -928,6 +928,104 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
}
///////////////////////////////////////////////////////////////////////////
+// MaterialStorage::ShaderData
+
+void MaterialStorage::ShaderData::set_path_hint(const String &p_hint) {
+ path = p_hint;
+}
+
+void MaterialStorage::ShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
+ if (!p_texture.is_valid()) {
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
+ }
+ }
+ } else {
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = HashMap<int, RID>();
+ }
+ default_texture_params[p_name][p_index] = p_texture;
+ }
+}
+
+Variant MaterialStorage::ShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
+ }
+ return Variant();
+}
+
+void MaterialStorage::ShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
+ SortArray<Pair<StringName, int>, ShaderLanguage::UniformOrderComparator> sorter;
+ LocalVector<Pair<StringName, int>> filtered_uniforms;
+
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ continue;
+ }
+ if (E.value.texture_order >= 0) {
+ filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.texture_order + 100000));
+ } else {
+ filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.order));
+ }
+ }
+ int uniform_count = filtered_uniforms.size();
+ sorter.sort(filtered_uniforms.ptr(), uniform_count);
+
+ String last_group;
+ for (int i = 0; i < uniform_count; i++) {
+ const StringName &uniform_name = filtered_uniforms[i].first;
+ const ShaderLanguage::ShaderNode::Uniform &uniform = uniforms[uniform_name];
+
+ String group = uniform.group;
+ if (!uniform.subgroup.is_empty()) {
+ group += "::" + uniform.subgroup;
+ }
+
+ if (group != last_group) {
+ PropertyInfo pi;
+ pi.usage = PROPERTY_USAGE_GROUP;
+ pi.name = group;
+ p_param_list->push_back(pi);
+
+ last_group = group;
+ }
+
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniform);
+ pi.name = uniform_name;
+ p_param_list->push_back(pi);
+ }
+}
+
+void MaterialStorage::ShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RendererMaterialStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E.value);
+ p.info.name = E.key; //supply name
+ p.index = E.value.instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool MaterialStorage::ShaderData::is_parameter_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+///////////////////////////////////////////////////////////////////////////
// MaterialStorage::MaterialData
void MaterialStorage::MaterialData::update_uniform_buffer(const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const HashMap<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) {
@@ -1221,6 +1319,10 @@ void MaterialStorage::MaterialData::update_textures(const HashMap<StringName, Va
roughness_detect_texture = tex;
roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R);
}
+ if (tex->render_target) {
+ tex->render_target->was_used = true;
+ render_target_cache.push_back(tex->render_target);
+ }
#endif
}
if (rd_texture.is_null()) {
@@ -1307,6 +1409,7 @@ bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<
if ((uint32_t)texture_cache.size() != tex_uniform_count || p_textures_dirty) {
texture_cache.resize(tex_uniform_count);
+ render_target_cache.clear();
p_textures_dirty = true;
//clear previous uniform set
@@ -1367,6 +1470,12 @@ bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<
return true;
}
+void MaterialStorage::MaterialData::set_as_used() {
+ for (int i = 0; i < render_target_cache.size(); i++) {
+ render_target_cache[i]->was_used = true;
+ }
+}
+
///////////////////////////////////////////////////////////////////////////
// MaterialStorage
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h
index a96fc847e1..989a0f7b45 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h
@@ -31,6 +31,8 @@
#ifndef MATERIAL_STORAGE_RD_H
#define MATERIAL_STORAGE_RD_H
+#include "texture_storage.h"
+
#include "core/math/projection.h"
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
@@ -54,24 +56,30 @@ public:
};
struct ShaderData {
- virtual void set_code(const String &p_Code) = 0;
- virtual void set_path_hint(const String &p_hint) = 0;
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) = 0;
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const = 0;
+ String path;
+ HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ HashMap<StringName, HashMap<int, RID>> default_texture_params;
- virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const = 0;
- virtual bool is_parameter_texture(const StringName &p_param) const = 0;
+ virtual void set_path_hint(const String &p_hint);
+ virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
+ virtual bool is_parameter_texture(const StringName &p_param) const;
+
+ virtual void set_code(const String &p_Code) = 0;
virtual bool is_animated() const = 0;
virtual bool casts_shadows() const = 0;
- virtual Variant get_default_parameter(const StringName &p_parameter) const = 0;
virtual RS::ShaderNativeSourceCode get_native_source_code() const { return RS::ShaderNativeSourceCode(); }
virtual ~ShaderData() {}
};
struct MaterialData {
+ Vector<RendererRD::TextureStorage::RenderTarget *> render_target_cache;
void update_uniform_buffer(const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const HashMap<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color);
void update_textures(const HashMap<StringName, Variant> &p_parameters, const HashMap<StringName, HashMap<int, RID>> &p_default_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color);
+ void set_as_used();
virtual void set_render_priority(int p_priority) = 0;
virtual void set_next_pass(RID p_pass) = 0;
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index 503a25184e..35fa3931f8 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -434,27 +434,8 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
}
if (mesh->surface_count == 0) {
- mesh->bone_aabbs = p_surface.bone_aabbs;
mesh->aabb = p_surface.aabb;
} else {
- if (mesh->bone_aabbs.size() < p_surface.bone_aabbs.size()) {
- // ArrayMesh::_surface_set_data only allocates bone_aabbs up to max_bone
- // Each surface may affect different numbers of bones.
- mesh->bone_aabbs.resize(p_surface.bone_aabbs.size());
- }
- for (int i = 0; i < p_surface.bone_aabbs.size(); i++) {
- const AABB &bone = p_surface.bone_aabbs[i];
- if (bone.has_volume()) {
- AABB &mesh_bone = mesh->bone_aabbs.write[i];
- if (mesh_bone != AABB()) {
- // Already initialized, merge AABBs.
- mesh_bone.merge_with(bone);
- } else {
- // Not yet initialized, copy the bone AABB.
- mesh_bone = bone;
- }
- }
- }
mesh->aabb.merge_with(p_surface.aabb);
}
@@ -715,6 +696,8 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
}
}
+ mesh->aabb = aabb;
+
mesh->skeleton_aabb_version = skeleton->version;
return aabb;
}
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
index 27c82213e4..a8feddc3b9 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
@@ -138,8 +138,6 @@ private:
Surface **surfaces = nullptr;
uint32_t surface_count = 0;
- Vector<AABB> bone_aabbs;
-
bool has_bone_weights = false;
AABB aabb;
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index 51aa81745b..708455706b 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -810,6 +810,15 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
//2D collision
Transform2D xform = p_particles->sdf_collision_transform; //will use dotproduct manually so invert beforehand
+
+ if (!p_particles->use_local_coords) {
+ Transform2D emission;
+ emission.columns[0] = Vector2(p_particles->emission_transform.basis.get_column(0).x, p_particles->emission_transform.basis.get_column(0).y);
+ emission.columns[1] = Vector2(p_particles->emission_transform.basis.get_column(1).x, p_particles->emission_transform.basis.get_column(1).y);
+ emission.set_origin(Vector2(p_particles->emission_transform.origin.x, p_particles->emission_transform.origin.y));
+ xform = xform * emission.affine_inverse();
+ }
+
Transform2D revert = xform.affine_inverse();
frame_params.collider_count = 1;
frame_params.colliders[0].transform[0] = xform.columns[0][0];
@@ -1107,6 +1116,7 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
if (m->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(m->uniform_set)) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, m->uniform_set, 3);
+ m->set_as_used();
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ParticlesShader::PushConstant));
@@ -1405,6 +1415,7 @@ void ParticlesStorage::update_particles() {
}
bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0;
+ bool updated = false;
if (particles->clear && particles->pre_process_time > 0.0) {
double frame_time;
@@ -1419,6 +1430,7 @@ void ParticlesStorage::update_particles() {
while (todo >= 0) {
_particles_process(particles, frame_time);
todo -= frame_time;
+ updated = true;
}
}
@@ -1440,9 +1452,10 @@ void ParticlesStorage::update_particles() {
}
double todo = particles->frame_remainder + delta;
- while (todo >= frame_time) {
+ while (todo >= frame_time || (particles->clear && !updated)) {
_particles_process(particles, frame_time);
todo -= decr;
+ updated = true;
}
particles->frame_remainder = todo;
@@ -1450,14 +1463,16 @@ void ParticlesStorage::update_particles() {
} else {
if (zero_time_scale) {
_particles_process(particles, 0.0);
+ updated = true;
} else {
_particles_process(particles, RendererCompositorRD::singleton->get_frame_delta_time());
+ updated = true;
}
}
//copy particles to instance buffer
- if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
+ if (updated && particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
//does not need view dependent operation, do copy here
ParticlesShader::CopyPushConstant copy_push_constant;
@@ -1534,9 +1549,6 @@ bool ParticlesStorage::particles_is_inactive(RID p_particles) const {
/* Particles SHADER */
-void ParticlesStorage::ParticlesShaderData::set_path_hint(const String &p_path) {
- path = p_path;
-}
void ParticlesStorage::ParticlesShaderData::set_code(const String &p_code) {
ParticlesStorage *particles_storage = ParticlesStorage::get_singleton();
//compile
@@ -1602,83 +1614,6 @@ void ParticlesStorage::ParticlesShaderData::set_code(const String &p_code) {
valid = true;
}
-void ParticlesStorage::ParticlesShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
- if (!p_texture.is_valid()) {
- if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
- default_texture_params[p_name].erase(p_index);
-
- if (default_texture_params[p_name].is_empty()) {
- default_texture_params.erase(p_name);
- }
- }
- } else {
- if (!default_texture_params.has(p_name)) {
- default_texture_params[p_name] = HashMap<int, RID>();
- }
- default_texture_params[p_name][p_index] = p_texture;
- }
-}
-
-void ParticlesStorage::ParticlesShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
- HashMap<int, StringName> order;
-
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- if (E.value.texture_order >= 0) {
- order[E.value.texture_order + 100000] = E.key;
- } else {
- order[E.value.order] = E.key;
- }
- }
-
- String last_group;
- for (const KeyValue<int, StringName> &E : order) {
- String group = uniforms[E.value].group;
- if (!uniforms[E.value].subgroup.is_empty()) {
- group += "::" + uniforms[E.value].subgroup;
- }
-
- if (group != last_group) {
- PropertyInfo pi;
- pi.usage = PROPERTY_USAGE_GROUP;
- pi.name = group;
- p_param_list->push_back(pi);
-
- last_group = group;
- }
-
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
- pi.name = E.value;
- p_param_list->push_back(pi);
- }
-}
-
-void ParticlesStorage::ParticlesShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
- for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererMaterialStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E.value);
- p.info.name = E.key; //supply name
- p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
- p_param_list->push_back(p);
- }
-}
-
-bool ParticlesStorage::ParticlesShaderData::is_parameter_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
bool ParticlesStorage::ParticlesShaderData::is_animated() const {
return false;
}
@@ -1687,15 +1622,6 @@ bool ParticlesStorage::ParticlesShaderData::casts_shadows() const {
return false;
}
-Variant ParticlesStorage::ParticlesShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
- }
- return Variant();
-}
-
RS::ShaderNativeSourceCode ParticlesStorage::ParticlesShaderData::get_native_source_code() const {
return ParticlesStorage::get_singleton()->particles_shader.shader.version_get_native_source_code(version);
}
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
index 49a8444e2f..0701dc95dd 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
@@ -313,15 +313,12 @@ private:
RID version;
bool uses_collision = false;
- HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
- String path;
String code;
- HashMap<StringName, HashMap<int, RID>> default_texture_params;
RID pipeline;
@@ -331,14 +328,8 @@ private:
uint32_t userdata_count = 0;
virtual void set_code(const String &p_Code);
- virtual void set_path_hint(const String &p_hint);
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
- virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
- virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
ParticlesShaderData() {}
@@ -464,6 +455,12 @@ public:
return particles->mode;
}
+ _FORCE_INLINE_ uint32_t particles_get_frame_counter(RID p_particles) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, false);
+ return particles->frame_counter;
+ }
+
_FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles, uint32_t &r_trail_divisor) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, 0);
@@ -494,9 +491,8 @@ public:
_FORCE_INLINE_ RID particles_get_instance_buffer_uniform_set(RID p_particles, RID p_shader, uint32_t p_set) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, RID());
- if (particles->particles_transforms_buffer_uniform_set.is_null()) {
+ if (particles->particles_transforms_buffer_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(particles->particles_transforms_buffer_uniform_set)) {
_particles_update_buffers(particles);
-
Vector<RD::Uniform> uniforms;
{
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 0c2092f03e..12ba29a0b8 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
@@ -202,6 +202,30 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna
vrs_texture = create_texture(RB_SCOPE_VRS, RB_TEXTURE, RD::DATA_FORMAT_R8_UINT, usage_bits, RD::TEXTURE_SAMPLES_1, vrs->get_vrs_texture_size(internal_size));
}
+ // (re-)configure any named buffers
+ for (KeyValue<StringName, Ref<RenderBufferCustomDataRD>> &E : data_buffers) {
+ E.value->configure(this);
+ }
+}
+
+void RenderSceneBuffersRD::configure_for_reflections(const Size2i p_reflection_size) {
+ // For now our render buffers for reflections are only used for effects/environment (Sky/Fog/Etc)
+ // Possibly at some point move our entire reflection atlas buffer management into this class
+
+ target_size = p_reflection_size;
+ internal_size = p_reflection_size;
+ render_target = RID();
+ fsr_sharpness = 0.0;
+ msaa_3d = RS::VIEWPORT_MSAA_DISABLED;
+ screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
+ use_taa = false;
+ use_debanding = false;
+ view_count = 1;
+
+ // cleanout any old buffers we had.
+ cleanup();
+
+ // (re-)configure any named buffers
for (KeyValue<StringName, Ref<RenderBufferCustomDataRD>> &E : data_buffers) {
E.value->configure(this);
}
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 6907f69b93..4b82f70e1a 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
@@ -140,6 +140,7 @@ public:
void cleanup();
virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
+ void configure_for_reflections(const Size2i p_reflection_size);
virtual void set_fsr_sharpness(float p_fsr_sharpness) override;
virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override;
virtual void set_use_debanding(bool p_use_debanding) override;
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 543eb0cb72..6a4359faf3 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -419,11 +419,12 @@ TextureStorage::TextureStorage() {
tformat.format = RD::DATA_FORMAT_R8_UINT;
tformat.width = 4;
tformat.height = 4;
- tformat.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
- if (RD::get_singleton()->has_feature(RD::SUPPORTS_ATTACHMENT_VRS)) {
- tformat.usage_bits |= RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT;
- }
+ tformat.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT;
tformat.texture_type = RD::TEXTURE_TYPE_2D;
+ if (!RD::get_singleton()->has_feature(RD::SUPPORTS_ATTACHMENT_VRS)) {
+ tformat.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+ tformat.format = RD::DATA_FORMAT_R8_UNORM;
+ }
Vector<uint8_t> pv;
pv.resize(4 * 4);
@@ -581,6 +582,9 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte
}
ct = t->canvas_texture;
+ if (t->render_target) {
+ t->render_target->was_used = true;
+ }
} else {
ct = canvas_texture_owner.get_or_null(p_texture);
}
@@ -611,6 +615,9 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte
} else {
u.append_id(t->rd_texture);
ct->size_cache = Size2i(t->width_2d, t->height_2d);
+ if (t->render_target) {
+ t->render_target->was_used = true;
+ }
}
uniforms.push_back(u);
}
@@ -626,6 +633,9 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte
} else {
u.append_id(t->rd_texture);
ct->use_normal_cache = true;
+ if (t->render_target) {
+ t->render_target->was_used = true;
+ }
}
uniforms.push_back(u);
}
@@ -641,6 +651,9 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte
} else {
u.append_id(t->rd_texture);
ct->use_specular_cache = true;
+ if (t->render_target) {
+ t->render_target->was_used = true;
+ }
}
uniforms.push_back(u);
}
@@ -1764,6 +1777,46 @@ Ref<Image> TextureStorage::_validate_texture_format(const Ref<Image> &p_image, T
r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
} break;
+ case Image::FORMAT_ASTC_4x4:
+ case Image::FORMAT_ASTC_4x4_HDR: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ASTC_4x4_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_ASTC_4x4_UNORM_BLOCK;
+ if (p_image->get_format() == Image::FORMAT_ASTC_4x4) {
+ r_format.format_srgb = RD::DATA_FORMAT_ASTC_4x4_SRGB_BLOCK;
+ }
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+
+ } break; // astc 4x4
+ case Image::FORMAT_ASTC_8x8:
+ case Image::FORMAT_ASTC_8x8_HDR: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK;
+ if (p_image->get_format() == Image::FORMAT_ASTC_8x8) {
+ r_format.format_srgb = RD::DATA_FORMAT_ASTC_8x8_SRGB_BLOCK;
+ }
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+
+ } break; // astc 8x8
default: {
}
@@ -2398,6 +2451,10 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
rt->color = RID();
rt->color_multisample = RID();
+ if (rt->texture.is_valid()) {
+ Texture *tex = get_texture(rt->texture);
+ tex->render_target = nullptr;
+ }
}
void TextureStorage::_update_render_target(RenderTarget *rt) {
@@ -2478,6 +2535,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
tex->rd_texture = RID();
tex->rd_texture_srgb = RID();
+ tex->render_target = rt;
//create shared textures to the color buffer,
//so transparent can be supported
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index f4737eb63d..0c70d3f938 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -108,6 +108,8 @@ private:
/* Texture API */
+ struct RenderTarget;
+
class Texture {
public:
TextureType type;
@@ -141,6 +143,7 @@ private:
Vector<BufferSlice3D> buffer_slices_3d;
uint32_t buffer_size_3d = 0;
+ RenderTarget *render_target = nullptr;
bool is_render_target;
bool is_proxy;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index cfc25fc577..675e81c62a 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -646,6 +646,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
geom->geometry_instance->set_surface_materials(instance->materials);
geom->geometry_instance->set_transform(instance->transform, instance->aabb, instance->transformed_aabb);
geom->geometry_instance->set_layer_mask(instance->layer_mask);
+ geom->geometry_instance->set_pivot_data(instance->sorting_offset, instance->use_aabb_center);
geom->geometry_instance->set_lod_bias(instance->lod_bias);
geom->geometry_instance->set_transparency(instance->transparency);
geom->geometry_instance->set_use_baked_light(instance->baked_light);
@@ -844,6 +845,20 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask)
}
}
+void RendererSceneCull::instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center) {
+ Instance *instance = instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ instance->sorting_offset = p_sorting_offset;
+ instance->use_aabb_center = p_use_aabb_center;
+
+ if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
+ geom->geometry_instance->set_pivot_data(p_sorting_offset, p_use_aabb_center);
+ }
+}
+
void RendererSceneCull::instance_geometry_set_transparency(RID p_instance, float p_transparency) {
Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
@@ -2930,7 +2945,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
scene_render->set_scene_pass(render_pass);
- if (p_render_buffers.is_valid()) {
+ if (p_render_buffers.is_valid() && p_reflection_probe.is_null()) {
//no rendering code here, this is only to set up what needs to be done, request regions, etc.
scene_render->sdfgi_update(p_render_buffers, p_environment, p_camera_data->main_transform.origin); //update conditions for SDFGI (whether its used or not)
}
@@ -3012,7 +3027,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
{ //sdfgi
cull.sdfgi.region_count = 0;
- if (p_render_buffers.is_valid()) {
+ if (p_render_buffers.is_valid() && p_reflection_probe.is_null()) {
cull.sdfgi.cascade_light_count = 0;
uint32_t prev_cascade = 0xFFFFFFFF;
@@ -3214,6 +3229,8 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
//render SDFGI
{
+ // Q: Should this whole block be skipped if we're rendering our reflection probe?
+
sdfgi_update_data.update_static = false;
if (cull.sdfgi.region_count > 0) {
@@ -3239,7 +3256,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
}
}
- if (p_render_buffers.is_valid()) {
+ if (p_render_buffers.is_valid() && p_reflection_probe.is_null()) {
sdfgi_update_data.directional_lights = &directional_lights;
sdfgi_update_data.positional_light_instances = scenario->dynamic_lights.ptr();
sdfgi_update_data.positional_light_count = scenario->dynamic_lights.size();
@@ -3392,7 +3409,7 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
RendererSceneRender::CameraData camera_data;
camera_data.set_camera(xform, cm, false, false);
- Ref<RenderSceneBuffers> render_buffers;
+ Ref<RenderSceneBuffers> render_buffers = RSG::light_storage->reflection_probe_atlas_get_render_buffers(scenario->reflection_atlas);
_render_scene(&camera_data, render_buffers, environment, RID(), RSG::light_storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, mesh_lod_threshold, use_shadows);
} else {
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index 2030af204d..106871edfd 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -459,6 +459,10 @@ public:
float extra_margin;
ObjectID object_id;
+ // sorting
+ float sorting_offset = 0.0;
+ bool use_aabb_center = true;
+
Vector<Color> lightmap_target_sh; //target is used for incrementally changing the SH over time, this avoids pops in some corner cases and when going interior <-> exterior
uint64_t last_frame_pass;
@@ -476,6 +480,7 @@ public:
Instance *instance = (Instance *)tracker->userdata;
switch (p_notification) {
case Dependency::DEPENDENCY_CHANGED_SKELETON_DATA:
+ case Dependency::DEPENDENCY_CHANGED_SKELETON_BONES:
case Dependency::DEPENDENCY_CHANGED_AABB: {
singleton->_instance_queue_update(instance, true, false);
@@ -491,8 +496,7 @@ public:
case Dependency::DEPENDENCY_CHANGED_REFLECTION_PROBE: {
singleton->_instance_queue_update(instance, true, true);
} break;
- case Dependency::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES:
- case Dependency::DEPENDENCY_CHANGED_SKELETON_BONES: {
+ case Dependency::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
//ignored
} break;
case Dependency::DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR: {
@@ -933,6 +937,7 @@ public:
virtual void instance_set_base(RID p_instance, RID p_base);
virtual void instance_set_scenario(RID p_instance, RID p_scenario);
virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask);
+ virtual void instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center);
virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform);
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id);
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight);
diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp
index e1ca5a7103..627e6941cf 100644
--- a/servers/rendering/renderer_scene_occlusion_cull.cpp
+++ b/servers/rendering/renderer_scene_occlusion_cull.cpp
@@ -60,6 +60,8 @@ void RendererSceneOcclusionCull::HZBuffer::clear() {
if (debug_image.is_valid()) {
debug_image.unref();
}
+
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(debug_texture);
}
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index ec19094537..28408ddb8e 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -32,8 +32,18 @@
#include "rendering_device_binds.h"
+#include "thirdparty/spirv-reflect/spirv_reflect.h"
+
RenderingDevice *RenderingDevice::singleton = nullptr;
+const char *RenderingDevice::shader_stage_names[RenderingDevice::SHADER_STAGE_MAX] = {
+ "Vertex",
+ "Fragment",
+ "TesselationControl",
+ "TesselationEvaluation",
+ "Compute",
+};
+
RenderingDevice *RenderingDevice::get_singleton() {
return singleton;
}
@@ -368,6 +378,323 @@ void RenderingDevice::_compute_list_set_push_constant(ComputeListID p_list, cons
compute_list_set_push_constant(p_list, p_data.ptr(), p_data_size);
}
+Error RenderingDevice::_reflect_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, SpirvReflectionData &r_reflection_data) {
+ r_reflection_data = {};
+
+ for (int i = 0; i < p_spirv.size(); i++) {
+ ShaderStage stage = p_spirv[i].shader_stage;
+ ShaderStage stage_flag = (ShaderStage)(1 << p_spirv[i].shader_stage);
+
+ if (p_spirv[i].shader_stage == SHADER_STAGE_COMPUTE) {
+ r_reflection_data.is_compute = true;
+ ERR_FAIL_COND_V_MSG(p_spirv.size() != 1, FAILED,
+ "Compute shaders can only receive one stage, dedicated to compute.");
+ }
+ ERR_FAIL_COND_V_MSG(r_reflection_data.stages_mask.has_flag(stage_flag), FAILED,
+ "Stage " + String(shader_stage_names[p_spirv[i].shader_stage]) + " submitted more than once.");
+
+ {
+ SpvReflectShaderModule module;
+ const uint8_t *spirv = p_spirv[i].spir_v.ptr();
+ SpvReflectResult result = spvReflectCreateShaderModule(p_spirv[i].spir_v.size(), spirv, &module);
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed parsing shader.");
+
+ if (r_reflection_data.is_compute) {
+ r_reflection_data.compute_local_size[0] = module.entry_points->local_size.x;
+ r_reflection_data.compute_local_size[1] = module.entry_points->local_size.y;
+ r_reflection_data.compute_local_size[2] = module.entry_points->local_size.z;
+ }
+ uint32_t binding_count = 0;
+ result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, nullptr);
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating descriptor bindings.");
+
+ if (binding_count > 0) {
+ // Parse bindings.
+
+ Vector<SpvReflectDescriptorBinding *> bindings;
+ bindings.resize(binding_count);
+ result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, bindings.ptrw());
+
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed getting descriptor bindings.");
+
+ for (uint32_t j = 0; j < binding_count; j++) {
+ const SpvReflectDescriptorBinding &binding = *bindings[j];
+
+ SpirvReflectionData::Uniform info{};
+
+ bool need_array_dimensions = false;
+ bool need_block_size = false;
+ bool may_be_writable = false;
+
+ switch (binding.descriptor_type) {
+ case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER: {
+ info.type = UNIFORM_TYPE_SAMPLER;
+ need_array_dimensions = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
+ info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ need_array_dimensions = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE: {
+ info.type = UNIFORM_TYPE_TEXTURE;
+ need_array_dimensions = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
+ info.type = UNIFORM_TYPE_IMAGE;
+ need_array_dimensions = true;
+ may_be_writable = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: {
+ info.type = UNIFORM_TYPE_TEXTURE_BUFFER;
+ need_array_dimensions = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
+ info.type = UNIFORM_TYPE_IMAGE_BUFFER;
+ need_array_dimensions = true;
+ may_be_writable = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
+ info.type = UNIFORM_TYPE_UNIFORM_BUFFER;
+ need_block_size = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
+ info.type = UNIFORM_TYPE_STORAGE_BUFFER;
+ need_block_size = true;
+ may_be_writable = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: {
+ ERR_PRINT("Dynamic uniform buffer not supported.");
+ continue;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
+ ERR_PRINT("Dynamic storage buffer not supported.");
+ continue;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
+ info.type = UNIFORM_TYPE_INPUT_ATTACHMENT;
+ need_array_dimensions = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
+ ERR_PRINT("Acceleration structure not supported.");
+ continue;
+ } break;
+ }
+
+ if (need_array_dimensions) {
+ if (binding.array.dims_count == 0) {
+ info.length = 1;
+ } else {
+ for (uint32_t k = 0; k < binding.array.dims_count; k++) {
+ if (k == 0) {
+ info.length = binding.array.dims[0];
+ } else {
+ info.length *= binding.array.dims[k];
+ }
+ }
+ }
+
+ } else if (need_block_size) {
+ info.length = binding.block.size;
+ } else {
+ info.length = 0;
+ }
+
+ if (may_be_writable) {
+ info.writable = !(binding.type_description->decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE) && !(binding.block.decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE);
+ } else {
+ info.writable = false;
+ }
+
+ info.binding = binding.binding;
+ uint32_t set = binding.set;
+
+ ERR_FAIL_COND_V_MSG(set >= MAX_UNIFORM_SETS, FAILED,
+ "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ").");
+
+ if (set < (uint32_t)r_reflection_data.uniforms.size()) {
+ // Check if this already exists.
+ bool exists = false;
+ for (int k = 0; k < r_reflection_data.uniforms[set].size(); k++) {
+ if (r_reflection_data.uniforms[set][k].binding == (uint32_t)info.binding) {
+ // Already exists, verify that it's the same type.
+ ERR_FAIL_COND_V_MSG(r_reflection_data.uniforms[set][k].type != info.type, FAILED,
+ "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform type.");
+
+ // Also, verify that it's the same size.
+ ERR_FAIL_COND_V_MSG(r_reflection_data.uniforms[set][k].length != info.length, FAILED,
+ "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform size.");
+
+ // Also, verify that it has the same writability.
+ ERR_FAIL_COND_V_MSG(r_reflection_data.uniforms[set][k].writable != info.writable, FAILED,
+ "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different writability.");
+
+ // Just append stage mask and return.
+ r_reflection_data.uniforms.write[set].write[k].stages_mask.set_flag(stage_flag);
+ exists = true;
+ break;
+ }
+ }
+
+ if (exists) {
+ continue; // Merged.
+ }
+ }
+
+ info.stages_mask.set_flag(stage_flag);
+
+ if (set >= (uint32_t)r_reflection_data.uniforms.size()) {
+ r_reflection_data.uniforms.resize(set + 1);
+ }
+
+ r_reflection_data.uniforms.write[set].push_back(info);
+ }
+ }
+
+ {
+ // Specialization constants.
+
+ uint32_t sc_count = 0;
+ result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, nullptr);
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating specialization constants.");
+
+ if (sc_count) {
+ Vector<SpvReflectSpecializationConstant *> spec_constants;
+ spec_constants.resize(sc_count);
+
+ result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, spec_constants.ptrw());
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining specialization constants.");
+
+ for (uint32_t j = 0; j < sc_count; j++) {
+ int32_t existing = -1;
+ SpirvReflectionData::SpecializationConstant sconst{};
+ SpvReflectSpecializationConstant *spc = spec_constants[j];
+
+ sconst.constant_id = spc->constant_id;
+ sconst.int_value = 0; // Clear previous value JIC.
+ switch (spc->constant_type) {
+ case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: {
+ sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+ sconst.bool_value = spc->default_value.int_bool_value != 0;
+ } break;
+ case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: {
+ sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
+ sconst.int_value = spc->default_value.int_bool_value;
+ } break;
+ case SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT: {
+ sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
+ sconst.float_value = spc->default_value.float_value;
+ } break;
+ }
+ sconst.stages_mask.set_flag(stage_flag);
+
+ for (int k = 0; k < r_reflection_data.specialization_constants.size(); k++) {
+ if (r_reflection_data.specialization_constants[k].constant_id == sconst.constant_id) {
+ ERR_FAIL_COND_V_MSG(r_reflection_data.specialization_constants[k].type != sconst.type, FAILED, "More than one specialization constant used for id (" + itos(sconst.constant_id) + "), but their types differ.");
+ ERR_FAIL_COND_V_MSG(r_reflection_data.specialization_constants[k].int_value != sconst.int_value, FAILED, "More than one specialization constant used for id (" + itos(sconst.constant_id) + "), but their default values differ.");
+ existing = k;
+ break;
+ }
+ }
+
+ if (existing > 0) {
+ r_reflection_data.specialization_constants.write[existing].stages_mask.set_flag(stage_flag);
+ } else {
+ r_reflection_data.specialization_constants.push_back(sconst);
+ }
+ }
+ }
+ }
+
+ if (stage == SHADER_STAGE_VERTEX) {
+ uint32_t iv_count = 0;
+ result = spvReflectEnumerateInputVariables(&module, &iv_count, nullptr);
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating input variables.");
+
+ if (iv_count) {
+ Vector<SpvReflectInterfaceVariable *> input_vars;
+ input_vars.resize(iv_count);
+
+ result = spvReflectEnumerateInputVariables(&module, &iv_count, input_vars.ptrw());
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining input variables.");
+
+ for (uint32_t j = 0; j < iv_count; j++) {
+ if (input_vars[j] && input_vars[j]->decoration_flags == 0) { // Regular input.
+ r_reflection_data.vertex_input_mask |= (1 << uint32_t(input_vars[j]->location));
+ }
+ }
+ }
+ }
+
+ if (stage == SHADER_STAGE_FRAGMENT) {
+ uint32_t ov_count = 0;
+ result = spvReflectEnumerateOutputVariables(&module, &ov_count, nullptr);
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating output variables.");
+
+ if (ov_count) {
+ Vector<SpvReflectInterfaceVariable *> output_vars;
+ output_vars.resize(ov_count);
+
+ result = spvReflectEnumerateOutputVariables(&module, &ov_count, output_vars.ptrw());
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining output variables.");
+
+ for (uint32_t j = 0; j < ov_count; j++) {
+ const SpvReflectInterfaceVariable *refvar = output_vars[j];
+ if (refvar != nullptr && refvar->built_in != SpvBuiltInFragDepth) {
+ r_reflection_data.fragment_output_mask |= 1 << refvar->location;
+ }
+ }
+ }
+ }
+
+ uint32_t pc_count = 0;
+ result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, nullptr);
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating push constants.");
+
+ if (pc_count) {
+ ERR_FAIL_COND_V_MSG(pc_count > 1, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "': Only one push constant is supported, which should be the same across shader stages.");
+
+ Vector<SpvReflectBlockVariable *> pconstants;
+ pconstants.resize(pc_count);
+ result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, pconstants.ptrw());
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining push constants.");
+#if 0
+ if (pconstants[0] == nullptr) {
+ Ref<FileAccess> f = FileAccess::open("res://popo.spv", FileAccess::WRITE);
+ f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t));
+ }
+#endif
+
+ ERR_FAIL_COND_V_MSG(r_reflection_data.push_constant_size && r_reflection_data.push_constant_size != pconstants[0]->size, FAILED,
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "': Push constant block must be the same across shader stages.");
+
+ r_reflection_data.push_constant_size = pconstants[0]->size;
+ r_reflection_data.push_constant_stages_mask.set_flag(stage_flag);
+
+ //print_line("Stage: " + String(shader_stage_names[stage]) + " push constant of size=" + itos(push_constant.push_constant_size));
+ }
+
+ // Destroy the reflection data when no longer required.
+ spvReflectDestroyShaderModule(&module);
+ }
+
+ r_reflection_data.stages_mask.set_flag(stage_flag);
+ }
+
+ return OK;
+}
+
void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_create", "format", "view", "data"), &RenderingDevice::_texture_create, DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("texture_create_shared", "view", "with_texture"), &RenderingDevice::_texture_create_shared);
@@ -806,7 +1133,7 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(INDEX_BUFFER_FORMAT_UINT16);
BIND_ENUM_CONSTANT(INDEX_BUFFER_FORMAT_UINT32);
- BIND_ENUM_CONSTANT(STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
+ BIND_BITFIELD_FLAG(STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
BIND_ENUM_CONSTANT(UNIFORM_TYPE_SAMPLER); //for sampling only (sampler GLSL type)
BIND_ENUM_CONSTANT(UNIFORM_TYPE_SAMPLER_WITH_TEXTURE); // for sampling only); but includes a texture); (samplerXX GLSL type)); first a sampler then a texture
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 27c3f77c5b..0adc78894a 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -749,11 +749,11 @@ public:
};
enum StorageBufferUsage {
- STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT = 1
+ STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT = 1,
};
virtual RID uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
- virtual RID storage_buffer_create(uint32_t p_size, const Vector<uint8_t> &p_data = Vector<uint8_t>(), uint32_t p_usage = 0) = 0;
+ virtual RID storage_buffer_create(uint32_t p_size, const Vector<uint8_t> &p_data = Vector<uint8_t>(), BitField<StorageBufferUsage> p_usage = 0) = 0;
virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
struct Uniform {
@@ -1301,6 +1301,10 @@ public:
RenderingDevice();
protected:
+ static const char *shader_stage_names[RenderingDevice::SHADER_STAGE_MAX];
+
+ static const uint32_t MAX_UNIFORM_SETS = 16;
+
//binders to script API
RID _texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data = Array());
RID _texture_create_shared(const Ref<RDTextureView> &p_view, RID p_with_texture);
@@ -1329,6 +1333,39 @@ protected:
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);
+
+ struct SpirvReflectionData {
+ BitField<ShaderStage> stages_mask;
+ uint32_t vertex_input_mask;
+ uint32_t fragment_output_mask;
+ bool is_compute;
+ uint32_t compute_local_size[3];
+ uint32_t push_constant_size;
+ BitField<ShaderStage> push_constant_stages_mask;
+
+ struct Uniform {
+ UniformType type;
+ uint32_t binding;
+ BitField<ShaderStage> stages_mask;
+ uint32_t length; // Size of arrays (in total elements), or ubos (in bytes * total elements).
+ bool writable;
+ };
+ Vector<Vector<Uniform>> uniforms;
+
+ struct SpecializationConstant {
+ PipelineSpecializationConstantType type;
+ uint32_t constant_id;
+ union {
+ uint32_t int_value;
+ float float_value;
+ bool bool_value;
+ };
+ BitField<ShaderStage> stages_mask;
+ };
+ Vector<SpecializationConstant> specialization_constants;
+ };
+
+ Error _reflect_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, SpirvReflectionData &r_reflection_data);
};
VARIANT_ENUM_CAST(RenderingDevice::DeviceType)
@@ -1348,7 +1385,7 @@ VARIANT_ENUM_CAST(RenderingDevice::SamplerRepeatMode)
VARIANT_ENUM_CAST(RenderingDevice::SamplerBorderColor)
VARIANT_ENUM_CAST(RenderingDevice::VertexFrequency)
VARIANT_ENUM_CAST(RenderingDevice::IndexBufferFormat)
-VARIANT_ENUM_CAST(RenderingDevice::StorageBufferUsage)
+VARIANT_BITFIELD_CAST(RenderingDevice::StorageBufferUsage)
VARIANT_ENUM_CAST(RenderingDevice::UniformType)
VARIANT_ENUM_CAST(RenderingDevice::RenderPrimitive)
VARIANT_ENUM_CAST(RenderingDevice::PolygonCullMode)
diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h
index 51b9cb2bcf..e3f29b51d5 100644
--- a/servers/rendering/rendering_method.h
+++ b/servers/rendering/rendering_method.h
@@ -72,6 +72,7 @@ public:
virtual void instance_set_base(RID p_instance, RID p_base) = 0;
virtual void instance_set_scenario(RID p_instance, RID p_scenario) = 0;
virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0;
+ virtual void instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center) = 0;
virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0;
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0;
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0;
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 662b582411..3f5b135d2a 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -762,6 +762,7 @@ public:
FUNC2(instance_set_base, RID, RID)
FUNC2(instance_set_scenario, RID, RID)
FUNC2(instance_set_layer_mask, RID, uint32_t)
+ FUNC3(instance_set_pivot_data, RID, float, bool)
FUNC2(instance_set_transform, RID, const Transform3D &)
FUNC2(instance_attach_object_instance_id, RID, ObjectID)
FUNC3(instance_set_blend_shape_weight, RID, int, float)
@@ -850,7 +851,7 @@ public:
FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &)
FUNC6(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool)
FUNC7(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, bool)
- FUNC7(canvas_item_add_msdf_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, int, float)
+ FUNC8(canvas_item_add_msdf_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, int, float, float)
FUNC5(canvas_item_add_lcd_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &)
FUNC10(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &)
FUNC6(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float)
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index 3604756fd8..00b6a8c44c 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -134,6 +134,8 @@ static String _interpstr(SL::DataInterpolation p_interp) {
return "flat ";
case SL::INTERPOLATION_SMOOTH:
return "";
+ case SL::INTERPOLATION_DEFAULT:
+ return "";
}
return "";
}
@@ -667,6 +669,9 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
fragment_varyings.insert(varying_name);
continue;
}
+ if (varying.type < SL::TYPE_INT) {
+ continue; // Ignore boolean types to prevent crashing (if varying is just declared).
+ }
String vcode;
String interp_mode = _interpstr(varying.interpolation);
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index e451fb35c2..8c732b3d5a 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -989,6 +989,18 @@ String ShaderLanguage::get_precision_name(DataPrecision p_type) {
return "";
}
+String ShaderLanguage::get_interpolation_name(DataInterpolation p_interpolation) {
+ switch (p_interpolation) {
+ case INTERPOLATION_FLAT:
+ return "flat";
+ case INTERPOLATION_SMOOTH:
+ return "smooth";
+ default:
+ break;
+ }
+ return "";
+}
+
String ShaderLanguage::get_datatype_name(DataType p_type) {
switch (p_type) {
case TYPE_VOID:
@@ -4417,13 +4429,17 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const {
}
bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message) {
- if (current_function != String("vertex") && current_function != String("fragment")) {
+ if (current_function != "vertex" && current_function != "fragment") {
*r_message = vformat(RTR("Varying may not be assigned in the '%s' function."), current_function);
return false;
}
switch (p_varying.stage) {
case ShaderNode::Varying::STAGE_UNKNOWN: // first assign
if (current_function == varying_function_names.vertex) {
+ if (p_varying.type < TYPE_INT) {
+ *r_message = vformat(RTR("Varying with '%s' data type may only be assigned in the 'fragment' function."), get_datatype_name(p_varying.type));
+ return false;
+ }
p_varying.stage = ShaderNode::Varying::STAGE_VERTEX;
} else if (current_function == varying_function_names.fragment) {
p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT;
@@ -5223,7 +5239,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (shader->varyings.has(varname)) {
switch (shader->varyings[varname].stage) {
case ShaderNode::Varying::STAGE_UNKNOWN: {
- _set_error(vformat(RTR("Varying '%s' must be assigned in the vertex or fragment function first."), varname));
+ _set_error(vformat(RTR("Varying '%s' must be assigned in the 'vertex' or 'fragment' function first."), varname));
return nullptr;
}
case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT:
@@ -5407,6 +5423,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
} else {
switch (var.stage) {
+ case ShaderNode::Varying::STAGE_UNKNOWN: {
+ if (var.type < TYPE_INT) {
+ if (current_function == varying_function_names.vertex) {
+ _set_error(vformat(RTR("Varying with '%s' data type may only be used in the 'fragment' function."), get_datatype_name(var.type)));
+ } else {
+ _set_error(vformat(RTR("Varying '%s' must be assigned in the 'fragment' function first."), identifier));
+ }
+ return nullptr;
+ }
+ } break;
case ShaderNode::Varying::STAGE_VERTEX:
if (current_function == varying_function_names.fragment || current_function == varying_function_names.light) {
var.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT;
@@ -8225,7 +8251,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
}
}
DataPrecision precision = PRECISION_DEFAULT;
- DataInterpolation interpolation = INTERPOLATION_SMOOTH;
+ DataInterpolation interpolation = INTERPOLATION_DEFAULT;
DataType type;
StringName name;
int array_size = 0;
@@ -8334,6 +8360,11 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
return ERR_PARSE_ERROR;
}
+ if (!is_uniform && interpolation != INTERPOLATION_DEFAULT && type < TYPE_INT) {
+ _set_error(vformat(RTR("Interpolation modifier '%s' cannot be used with boolean types."), get_interpolation_name(interpolation)));
+ return ERR_PARSE_ERROR;
+ }
+
if (!is_uniform && type > TYPE_MAT4) {
_set_error(RTR("Invalid data type for varying."));
return ERR_PARSE_ERROR;
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 2534d1f252..d34114589f 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -247,6 +247,7 @@ public:
enum DataInterpolation {
INTERPOLATION_FLAT,
INTERPOLATION_SMOOTH,
+ INTERPOLATION_DEFAULT,
};
enum Operator {
@@ -720,6 +721,12 @@ public:
Node(TYPE_SHADER) {}
};
+ struct UniformOrderComparator {
+ _FORCE_INLINE_ bool operator()(const Pair<StringName, int> &A, const Pair<StringName, int> &B) const {
+ return A.second < B.second;
+ }
+ };
+
struct Expression {
bool is_op;
union {
@@ -768,6 +775,7 @@ public:
static bool is_token_arg_qual(TokenType p_type);
static DataPrecision get_token_precision(TokenType p_type);
static String get_precision_name(DataPrecision p_type);
+ static String get_interpolation_name(DataInterpolation p_interpolation);
static String get_datatype_name(DataType p_type);
static String get_uniform_hint_name(ShaderNode::Uniform::Hint p_hint);
static String get_texture_filter_name(TextureFilter p_filter);
diff --git a/servers/rendering/storage/environment_storage.cpp b/servers/rendering/storage/environment_storage.cpp
index 9b1842f1d9..78ce4eb4d0 100644
--- a/servers/rendering/storage/environment_storage.cpp
+++ b/servers/rendering/storage/environment_storage.cpp
@@ -283,7 +283,7 @@ void RendererEnvironmentStorage::environment_set_volumetric_fog(RID p_env, bool
env->volumetric_fog_scattering = p_albedo;
env->volumetric_fog_emission = p_emission;
env->volumetric_fog_emission_energy = p_emission_energy;
- env->volumetric_fog_anisotropy = p_anisotropy,
+ env->volumetric_fog_anisotropy = p_anisotropy;
env->volumetric_fog_length = p_length;
env->volumetric_fog_detail_spread = p_detail_spread;
env->volumetric_fog_gi_inject = p_gi_inject;
diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h
index df5b893cd5..ea3b4d4c44 100644
--- a/servers/rendering/storage/light_storage.h
+++ b/servers/rendering/storage/light_storage.h
@@ -31,6 +31,7 @@
#ifndef LIGHT_STORAGE_H
#define LIGHT_STORAGE_H
+#include "render_scene_buffers.h"
#include "servers/rendering_server.h"
class RendererLightStorage {
@@ -142,6 +143,7 @@ public:
virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0;
virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0;
virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0;
+ virtual Ref<RenderSceneBuffers> reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) = 0;
virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;
/* LIGHTMAP */
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 8d6d756edc..de3bd8d3e0 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2480,6 +2480,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("instance_set_base", "instance", "base"), &RenderingServer::instance_set_base);
ClassDB::bind_method(D_METHOD("instance_set_scenario", "instance", "scenario"), &RenderingServer::instance_set_scenario);
ClassDB::bind_method(D_METHOD("instance_set_layer_mask", "instance", "mask"), &RenderingServer::instance_set_layer_mask);
+ ClassDB::bind_method(D_METHOD("instance_set_pivot_data", "instance", "sorting_offset", "use_aabb_center"), &RenderingServer::instance_set_pivot_data);
ClassDB::bind_method(D_METHOD("instance_set_transform", "instance", "transform"), &RenderingServer::instance_set_transform);
ClassDB::bind_method(D_METHOD("instance_attach_object_instance_id", "instance", "id"), &RenderingServer::instance_attach_object_instance_id);
ClassDB::bind_method(D_METHOD("instance_set_blend_shape_weight", "instance", "shape", "weight"), &RenderingServer::instance_set_blend_shape_weight);
@@ -2596,7 +2597,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect);
ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle);
ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose"), &RenderingServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("canvas_item_add_msdf_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "outline_size", "px_range"), &RenderingServer::canvas_item_add_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_msdf_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "outline_size", "px_range", "scale"), &RenderingServer::canvas_item_add_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(1.0), DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("canvas_item_add_lcd_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate"), &RenderingServer::canvas_item_add_lcd_texture_rect_region);
ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "clip_uv"), &RenderingServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true));
ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate"), &RenderingServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1)));
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 1d74bb54b9..f3d95e07cb 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -1209,6 +1209,7 @@ public:
virtual void instance_set_base(RID p_instance, RID p_base) = 0;
virtual void instance_set_scenario(RID p_instance, RID p_scenario) = 0;
virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0;
+ virtual void instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center) = 0;
virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0;
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0;
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0;
@@ -1339,7 +1340,7 @@ public:
virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0;
virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) = 0;
virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false) = 0;
- virtual void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0) = 0;
+ virtual void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0, float p_scale = 1.0) = 0;
virtual void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)) = 0;
virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1)) = 0;
virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0) = 0;
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index 39b87fc483..4baa1db9bf 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -240,8 +240,8 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(_shaped_text_get_spacing, "shaped", "spacing");
GDVIRTUAL_BIND(_shaped_text_add_string, "shaped", "text", "fonts", "size", "opentype_features", "language", "meta");
- GDVIRTUAL_BIND(_shaped_text_add_object, "shaped", "key", "size", "inline_align", "length");
- GDVIRTUAL_BIND(_shaped_text_resize_object, "shaped", "key", "size", "inline_align");
+ GDVIRTUAL_BIND(_shaped_text_add_object, "shaped", "key", "size", "inline_align", "length", "baseline");
+ GDVIRTUAL_BIND(_shaped_text_resize_object, "shaped", "key", "size", "inline_align", "baseline");
GDVIRTUAL_BIND(_shaped_get_span_count, "shaped");
GDVIRTUAL_BIND(_shaped_get_span_meta, "shaped", "index");
@@ -308,7 +308,7 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(_strip_diacritics, "string");
GDVIRTUAL_BIND(_is_valid_identifier, "string");
- GDVIRTUAL_BIND(_string_get_word_breaks, "string", "language");
+ GDVIRTUAL_BIND(_string_get_word_breaks, "string", "language", "chars_per_line");
GDVIRTUAL_BIND(_is_confusable, "string", "dict");
GDVIRTUAL_BIND(_spoof_check, "string");
@@ -1041,15 +1041,15 @@ bool TextServerExtension::shaped_text_add_string(const RID &p_shaped, const Stri
return ret;
}
-bool TextServerExtension::shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) {
+bool TextServerExtension::shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length, float p_baseline) {
bool ret = false;
- GDVIRTUAL_CALL(_shaped_text_add_object, p_shaped, p_key, p_size, p_inline_align, p_length, ret);
+ GDVIRTUAL_CALL(_shaped_text_add_object, p_shaped, p_key, p_size, p_inline_align, p_length, p_baseline, ret);
return ret;
}
-bool TextServerExtension::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
+bool TextServerExtension::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, float p_baseline) {
bool ret = false;
- GDVIRTUAL_CALL(_shaped_text_resize_object, p_shaped, p_key, p_size, p_inline_align, ret);
+ GDVIRTUAL_CALL(_shaped_text_resize_object, p_shaped, p_key, p_size, p_inline_align, p_baseline, ret);
return ret;
}
@@ -1379,9 +1379,9 @@ TypedArray<Vector2i> TextServerExtension::parse_structured_text(StructuredTextPa
return ret;
}
-PackedInt32Array TextServerExtension::string_get_word_breaks(const String &p_string, const String &p_language) const {
+PackedInt32Array TextServerExtension::string_get_word_breaks(const String &p_string, const String &p_language, int p_chars_per_line) const {
PackedInt32Array ret;
- GDVIRTUAL_CALL(_string_get_word_breaks, p_string, p_language, ret);
+ GDVIRTUAL_CALL(_string_get_word_breaks, p_string, p_language, p_chars_per_line, ret);
return ret;
}
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index 69f9a479ed..551e4e9087 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -395,11 +395,11 @@ public:
GDVIRTUAL2RC(int64_t, _shaped_text_get_spacing, RID, SpacingType);
virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override;
- virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) override;
- virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override;
+ virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1, float p_baseline = 0.0) override;
+ virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, float p_baseline = 0.0) override;
GDVIRTUAL7R(bool, _shaped_text_add_string, RID, const String &, const TypedArray<RID> &, int64_t, const Dictionary &, const String &, const Variant &);
- GDVIRTUAL5R(bool, _shaped_text_add_object, RID, const Variant &, const Size2 &, InlineAlignment, int64_t);
- GDVIRTUAL4R(bool, _shaped_text_resize_object, RID, const Variant &, const Size2 &, InlineAlignment);
+ GDVIRTUAL6R(bool, _shaped_text_add_object, RID, const Variant &, const Size2 &, InlineAlignment, int64_t, float);
+ GDVIRTUAL5R(bool, _shaped_text_resize_object, RID, const Variant &, const Size2 &, InlineAlignment, float);
virtual int64_t shaped_get_span_count(const RID &p_shaped) const override;
virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override;
@@ -510,8 +510,8 @@ public:
virtual String strip_diacritics(const String &p_string) const override;
GDVIRTUAL1RC(String, _strip_diacritics, const String &);
- virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override;
- GDVIRTUAL2RC(PackedInt32Array, _string_get_word_breaks, const String &, const String &);
+ virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "", int p_chars_per_line = 0) const override;
+ GDVIRTUAL3RC(PackedInt32Array, _string_get_word_breaks, const String &, const String &, int);
virtual bool is_valid_identifier(const String &p_string) const override;
GDVIRTUAL1RC(bool, _is_valid_identifier, const String &);
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 1b9cd28cfb..c0f235fe50 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -394,8 +394,8 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("shaped_text_get_spacing", "shaped", "spacing"), &TextServer::shaped_text_get_spacing);
ClassDB::bind_method(D_METHOD("shaped_text_add_string", "shaped", "text", "fonts", "size", "opentype_features", "language", "meta"), &TextServer::shaped_text_add_string, DEFVAL(Dictionary()), DEFVAL(""), DEFVAL(Variant()));
- ClassDB::bind_method(D_METHOD("shaped_text_add_object", "shaped", "key", "size", "inline_align", "length"), &TextServer::shaped_text_add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1));
- ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align"), &TextServer::shaped_text_resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER));
+ ClassDB::bind_method(D_METHOD("shaped_text_add_object", "shaped", "key", "size", "inline_align", "length", "baseline"), &TextServer::shaped_text_add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align", "baseline"), &TextServer::shaped_text_resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("shaped_get_span_count", "shaped"), &TextServer::shaped_get_span_count);
ClassDB::bind_method(D_METHOD("shaped_get_span_meta", "shaped", "index"), &TextServer::shaped_get_span_meta);
@@ -454,7 +454,7 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("parse_number", "number", "language"), &TextServer::parse_number, DEFVAL(""));
ClassDB::bind_method(D_METHOD("percent_sign", "language"), &TextServer::percent_sign, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("string_get_word_breaks", "string", "language"), &TextServer::string_get_word_breaks, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("string_get_word_breaks", "string", "language", "chars_per_line"), &TextServer::string_get_word_breaks, DEFVAL(""), DEFVAL(0));
ClassDB::bind_method(D_METHOD("is_confusable", "string", "dict"), &TextServer::is_confusable);
ClassDB::bind_method(D_METHOD("spoof_check", "string"), &TextServer::spoof_check);
diff --git a/servers/text_server.h b/servers/text_server.h
index 5da38a627a..0d94f45b79 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -420,8 +420,8 @@ public:
virtual int64_t shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const = 0;
virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) = 0;
- virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) = 0;
- virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) = 0;
+ virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1, float p_baseline = 0.0) = 0;
+ virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, float p_baseline = 0.0) = 0;
virtual int64_t shaped_get_span_count(const RID &p_shaped) const = 0;
virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const = 0;
@@ -493,7 +493,7 @@ public:
virtual String percent_sign(const String &p_language = "") const = 0;
// String functions.
- virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const = 0;
+ virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "", int p_chars_per_line = 0) const = 0;
virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const { return -1; };
virtual bool spoof_check(const String &p_string) const { return false; };
diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp
index ec4ae98397..b437ed1512 100644
--- a/servers/xr/xr_interface.cpp
+++ b/servers/xr/xr_interface.cpp
@@ -123,6 +123,7 @@ XRInterface::XRInterface() {}
XRInterface::~XRInterface() {
if (vrs.vrs_texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(vrs.vrs_texture);
vrs.vrs_texture = RID();
}
diff --git a/tests/core/config/test_project_settings.h b/tests/core/config/test_project_settings.h
new file mode 100644
index 0000000000..c99ba76a24
--- /dev/null
+++ b/tests/core/config/test_project_settings.h
@@ -0,0 +1,102 @@
+/*************************************************************************/
+/* test_project_settings.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_PROJECT_SETTINGS_H
+#define TEST_PROJECT_SETTINGS_H
+
+#include "core/config/project_settings.h"
+#include "core/variant/variant.h"
+#include "tests/test_macros.h"
+
+namespace TestProjectSettings {
+
+TEST_CASE("[ProjectSettings] Get existing setting") {
+ CHECK(ProjectSettings::get_singleton()->has_setting("application/config/name"));
+
+ Variant variant = ProjectSettings::get_singleton()->get_setting("application/config/name");
+ CHECK_EQ(variant.get_type(), Variant::STRING);
+
+ String name = variant;
+ CHECK_EQ(name, "GDScript Integration Test Suite");
+}
+
+TEST_CASE("[ProjectSettings] Default value is ignored if setting exists") {
+ CHECK(ProjectSettings::get_singleton()->has_setting("application/config/name"));
+
+ Variant variant = ProjectSettings::get_singleton()->get_setting("application/config/name", "SomeDefaultValue");
+ CHECK_EQ(variant.get_type(), Variant::STRING);
+
+ String name = variant;
+ CHECK_EQ(name, "GDScript Integration Test Suite");
+}
+
+TEST_CASE("[ProjectSettings] Non existing setting is null") {
+ CHECK_FALSE(ProjectSettings::get_singleton()->has_setting("not_existing_setting"));
+
+ Variant variant = ProjectSettings::get_singleton()->get_setting("not_existing_setting");
+ CHECK_EQ(variant.get_type(), Variant::NIL);
+}
+
+TEST_CASE("[ProjectSettings] Non existing setting should return default value") {
+ CHECK_FALSE(ProjectSettings::get_singleton()->has_setting("not_existing_setting"));
+
+ Variant variant = ProjectSettings::get_singleton()->get_setting("not_existing_setting");
+ CHECK_EQ(variant.get_type(), Variant::NIL);
+
+ variant = ProjectSettings::get_singleton()->get_setting("not_existing_setting", "my_nice_default_value");
+ CHECK_EQ(variant.get_type(), Variant::STRING);
+
+ String name = variant;
+ CHECK_EQ(name, "my_nice_default_value");
+
+ CHECK_FALSE(ProjectSettings::get_singleton()->has_setting("not_existing_setting"));
+}
+
+TEST_CASE("[ProjectSettings] Set value should be returned when retrieved") {
+ CHECK_FALSE(ProjectSettings::get_singleton()->has_setting("my_custom_setting"));
+
+ Variant variant = ProjectSettings::get_singleton()->get_setting("my_custom_setting");
+ CHECK_EQ(variant.get_type(), Variant::NIL);
+
+ ProjectSettings::get_singleton()->set_setting("my_custom_setting", true);
+ CHECK(ProjectSettings::get_singleton()->has_setting("my_custom_setting"));
+
+ variant = ProjectSettings::get_singleton()->get_setting("my_custom_setting");
+ CHECK_EQ(variant.get_type(), Variant::BOOL);
+
+ bool value = variant;
+ CHECK_EQ(true, value);
+
+ CHECK(ProjectSettings::get_singleton()->has_setting("my_custom_setting"));
+}
+
+} // namespace TestProjectSettings
+
+#endif // TEST_PROJECT_SETTINGS_H
diff --git a/tests/core/object/test_object.h b/tests/core/object/test_object.h
index f5c5de7fdf..5feb3a4054 100644
--- a/tests/core/object/test_object.h
+++ b/tests/core/object/test_object.h
@@ -281,6 +281,84 @@ TEST_CASE("[Object] Absent name getter") {
actual_value == Variant(),
"The returned value should equal nil variant.");
}
+
+TEST_CASE("[Object] Signals") {
+ Object object;
+
+ CHECK_FALSE(object.has_signal("my_custom_signal"));
+
+ List<MethodInfo> signals_before;
+ object.get_signal_list(&signals_before);
+
+ object.add_user_signal(MethodInfo("my_custom_signal"));
+
+ CHECK(object.has_signal("my_custom_signal"));
+
+ List<MethodInfo> signals_after;
+ object.get_signal_list(&signals_after);
+
+ // Should be one more signal.
+ CHECK_EQ(signals_before.size() + 1, signals_after.size());
+
+ SUBCASE("Adding the same user signal again should not have any effect") {
+ CHECK(object.has_signal("my_custom_signal"));
+ ERR_PRINT_OFF;
+ object.add_user_signal(MethodInfo("my_custom_signal"));
+ ERR_PRINT_ON;
+ CHECK(object.has_signal("my_custom_signal"));
+
+ List<MethodInfo> signals_after_existing_added;
+ object.get_signal_list(&signals_after_existing_added);
+
+ CHECK_EQ(signals_after.size(), signals_after_existing_added.size());
+ }
+
+ SUBCASE("Trying to add a preexisting signal should not have any effect") {
+ CHECK(object.has_signal("script_changed"));
+ ERR_PRINT_OFF;
+ object.add_user_signal(MethodInfo("script_changed"));
+ ERR_PRINT_ON;
+ CHECK(object.has_signal("script_changed"));
+
+ List<MethodInfo> signals_after_existing_added;
+ object.get_signal_list(&signals_after_existing_added);
+
+ CHECK_EQ(signals_after.size(), signals_after_existing_added.size());
+ }
+
+ SUBCASE("Adding an empty signal should not have any effect") {
+ CHECK_FALSE(object.has_signal(""));
+ ERR_PRINT_OFF;
+ object.add_user_signal(MethodInfo(""));
+ ERR_PRINT_ON;
+ CHECK_FALSE(object.has_signal(""));
+
+ List<MethodInfo> signals_after_empty_added;
+ object.get_signal_list(&signals_after_empty_added);
+
+ CHECK_EQ(signals_after.size(), signals_after_empty_added.size());
+ }
+
+ SUBCASE("Emitting a non existing signal will return an error") {
+ Error err = object.emit_signal("some_signal");
+ CHECK(err == ERR_UNAVAILABLE);
+ }
+
+ SUBCASE("Emitting an existing signal should call the connected method") {
+ Array empty_signal_args;
+ empty_signal_args.push_back(Array());
+
+ SIGNAL_WATCH(&object, "my_custom_signal");
+ SIGNAL_CHECK_FALSE("my_custom_signal");
+
+ Error err = object.emit_signal("my_custom_signal");
+ CHECK(err == OK);
+
+ SIGNAL_CHECK("my_custom_signal", empty_signal_args);
+ SIGNAL_UNWATCH(&object, "my_custom_signal");
+ }
+}
+
} // namespace TestObject
#endif // TEST_OBJECT_H
diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h
index 3940bdb37a..fa31a3a461 100644
--- a/tests/scene/test_code_edit.h
+++ b/tests/scene/test_code_edit.h
@@ -2871,6 +2871,89 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
CHECK(code_edit->get_text() == "\'\'\'");
}
+ SUBCASE("[CodeEdit] autocomplete with brace completion") {
+ code_edit->set_auto_brace_completion_enabled(true);
+ CHECK(code_edit->is_auto_brace_completion_enabled());
+
+ code_edit->insert_text_at_caret("(te)");
+ code_edit->set_caret_column(3);
+
+ // Full completion.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_FUNCTION, "test()", "test()");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "(test())");
+ CHECK(code_edit->get_caret_column() == 7);
+ code_edit->undo();
+
+ // With "arg".
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_FUNCTION, "test(", "test(");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "(test())");
+ CHECK(code_edit->get_caret_column() == 6);
+ code_edit->undo();
+
+ // brace completion disbaled
+ code_edit->set_auto_brace_completion_enabled(false);
+
+ // Full completion.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_FUNCTION, "test()", "test()");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "(test())");
+ CHECK(code_edit->get_caret_column() == 7);
+ code_edit->undo();
+
+ // With "arg".
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_FUNCTION, "test(", "test(");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "(test()");
+ CHECK(code_edit->get_caret_column() == 6);
+
+ // String
+ code_edit->set_auto_brace_completion_enabled(true);
+ code_edit->clear();
+ code_edit->insert_text_at_caret("\"\"");
+ code_edit->set_caret_column(1);
+
+ // Full completion.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test\"", "\"test\"");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "\"test\"");
+ CHECK(code_edit->get_caret_column() == 6);
+ code_edit->undo();
+
+ // With "arg".
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test", "\"test");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "\"\"test\"\"");
+ CHECK(code_edit->get_caret_column() == 7);
+ code_edit->undo();
+
+ // brace completion disbaled
+ code_edit->set_auto_brace_completion_enabled(false);
+
+ // Full completion.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test\"", "\"test\"");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "\"test\"");
+ CHECK(code_edit->get_caret_column() == 6);
+ code_edit->undo();
+
+ // With "arg".
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test", "\"test");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "\"\"test\"");
+ CHECK(code_edit->get_caret_column() == 7);
+ code_edit->undo();
+ }
+
SUBCASE("[CodeEdit] autocomplete") {
code_edit->set_code_completion_enabled(true);
CHECK(code_edit->is_code_completion_enabled());
@@ -3027,7 +3110,7 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
CHECK(code_edit->get_code_completion_selected_index() == 0);
Point2 caret_pos = code_edit->get_caret_draw_pos();
- caret_pos.y -= code_edit->get_line_height();
+ caret_pos.y += code_edit->get_line_height();
SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::WHEEL_DOWN, MouseButton::NONE, Key::NONE);
CHECK(code_edit->get_code_completion_selected_index() == 1);
@@ -3035,6 +3118,7 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
CHECK(code_edit->get_code_completion_selected_index() == 0);
/* Single click selects. */
+ caret_pos.y += code_edit->get_line_height() * 2;
SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
CHECK(code_edit->get_code_completion_selected_index() == 2);
diff --git a/tests/scene/test_gradient.h b/tests/scene/test_gradient.h
index b0e6128932..6049abbec2 100644
--- a/tests/scene/test_gradient.h
+++ b/tests/scene/test_gradient.h
@@ -42,7 +42,7 @@ TEST_CASE("[Gradient] Default gradient") {
Ref<Gradient> gradient = memnew(Gradient);
CHECK_MESSAGE(
- gradient->get_points_count() == 2,
+ gradient->get_point_count() == 2,
"Default gradient should contain the expected number of points.");
CHECK_MESSAGE(
@@ -77,7 +77,7 @@ TEST_CASE("[Gradient] Custom gradient (points specified in order)") {
gradient->set_points(points);
CHECK_MESSAGE(
- gradient->get_points_count() == 3,
+ gradient->get_point_count() == 3,
"Custom gradient should contain the expected number of points.");
CHECK_MESSAGE(
@@ -98,7 +98,7 @@ TEST_CASE("[Gradient] Custom gradient (points specified in order)") {
gradient->remove_point(1);
CHECK_MESSAGE(
- gradient->get_points_count() == 2,
+ gradient->get_point_count() == 2,
"Custom gradient should contain the expected number of points after removing one point.");
CHECK_MESSAGE(
gradient->get_color_at_offset(0.5).is_equal_approx(Color(0.5, 1, 0)),
@@ -119,7 +119,7 @@ TEST_CASE("[Gradient] Custom gradient (points specified out-of-order)") {
gradient->set_points(points);
CHECK_MESSAGE(
- gradient->get_points_count() == 6,
+ gradient->get_point_count() == 6,
"Custom out-of-order gradient should contain the expected number of points.");
CHECK_MESSAGE(
@@ -137,7 +137,7 @@ TEST_CASE("[Gradient] Custom gradient (points specified out-of-order)") {
gradient->remove_point(0);
CHECK_MESSAGE(
- gradient->get_points_count() == 5,
+ gradient->get_point_count() == 5,
"Custom out-of-order gradient should contain the expected number of points after removing one point.");
// The color will be clamped to the nearest point (which is at offset 0.2).
CHECK_MESSAGE(
diff --git a/tests/scene/test_node.h b/tests/scene/test_node.h
new file mode 100644
index 0000000000..68ec41f07a
--- /dev/null
+++ b/tests/scene/test_node.h
@@ -0,0 +1,415 @@
+/*************************************************************************/
+/* test_node.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_NODE_H
+#define TEST_NODE_H
+
+#include "scene/main/node.h"
+
+#include "tests/test_macros.h"
+
+namespace TestNode {
+
+TEST_CASE("[SceneTree][Node] Simple Add/Remove/Move/Find") {
+ Node *node = memnew(Node);
+
+ // Check initial scene tree setup.
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 0);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 1);
+
+ // Check initial node setup.
+ CHECK(node->get_name() == StringName());
+ CHECK_FALSE(node->is_inside_tree());
+ CHECK_EQ(node->get_parent(), nullptr);
+ ERR_PRINT_OFF;
+ CHECK(node->get_path().is_empty());
+ ERR_PRINT_ON;
+ CHECK_EQ(node->get_child_count(), 0);
+
+ SceneTree::get_singleton()->get_root()->add_child(node);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 1);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 2);
+
+ CHECK(node->get_name() != StringName());
+ CHECK(node->is_inside_tree());
+ CHECK_EQ(SceneTree::get_singleton()->get_root(), node->get_parent());
+ CHECK_FALSE(node->get_path().is_empty());
+ CHECK_EQ(node->get_child_count(), 0);
+
+ SUBCASE("Node should be accessible as first child") {
+ Node *child = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child, node);
+ }
+
+ SUBCASE("Node should be accessible via the node path") {
+ Node *child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node->get_path());
+ CHECK_EQ(child_by_path, node);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("Node"));
+ CHECK_EQ(child_by_path, nullptr);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("/root/Node"));
+ CHECK_EQ(child_by_path, nullptr);
+
+ node->set_name("Node");
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node->get_path());
+ CHECK_EQ(child_by_path, node);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("Node"));
+ CHECK_EQ(child_by_path, node);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("/root/Node"));
+ CHECK_EQ(child_by_path, node);
+ }
+
+ SUBCASE("Node should be accessible via group") {
+ List<Node *> nodes;
+ SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes);
+ CHECK(nodes.is_empty());
+
+ node->add_to_group("nodes");
+
+ SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes);
+ CHECK_EQ(nodes.size(), 1);
+ List<Node *>::Element *E = nodes.front();
+ CHECK_EQ(E->get(), node);
+ }
+
+ SUBCASE("Node should be possible to find") {
+ Node *child = SceneTree::get_singleton()->get_root()->find_child("Node", true, false);
+ CHECK_EQ(child, nullptr);
+
+ node->set_name("Node");
+
+ child = SceneTree::get_singleton()->get_root()->find_child("Node", true, false);
+ CHECK_EQ(child, node);
+ }
+
+ SUBCASE("Node should be possible to remove") {
+ SceneTree::get_singleton()->get_root()->remove_child(node);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 0);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 1);
+
+ CHECK_FALSE(node->is_inside_tree());
+ CHECK_EQ(node->get_parent(), nullptr);
+ ERR_PRINT_OFF;
+ CHECK(node->get_path().is_empty());
+ ERR_PRINT_ON;
+ }
+
+ SUBCASE("Node should be possible to move") {
+ SceneTree::get_singleton()->get_root()->move_child(node, 0);
+
+ Node *child = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child, node);
+ CHECK(node->is_inside_tree());
+ }
+
+ memdelete(node);
+}
+
+TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") {
+ Node *node1 = memnew(Node);
+ Node *node2 = memnew(Node);
+ Node *node1_1 = memnew(Node);
+
+ SceneTree::get_singleton()->get_root()->add_child(node1);
+ SceneTree::get_singleton()->get_root()->add_child(node2);
+
+ node1->add_child(node1_1);
+
+ CHECK(node1_1->is_inside_tree());
+ CHECK_EQ(node1_1->get_parent(), node1);
+ CHECK_EQ(node1->get_child_count(), 1);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 2);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
+
+ SUBCASE("Nodes should be accessible via get_child(..)") {
+ Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child1, node1);
+
+ Node *child2 = SceneTree::get_singleton()->get_root()->get_child(1);
+ CHECK_EQ(child2, node2);
+
+ Node *child1_1 = node1->get_child(0);
+ CHECK_EQ(child1_1, node1_1);
+ }
+
+ SUBCASE("Removed nodes should also remove their children from the scene tree") {
+ // Should also remove node1_1 from the scene tree.
+ SceneTree::get_singleton()->get_root()->remove_child(node1);
+
+ CHECK_EQ(node1->get_child_count(), 1);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 1);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 2);
+
+ // First child should now be the second node.
+ Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child1, node2);
+ }
+
+ SUBCASE("Removed children nodes should not affect their parent in the scene tree") {
+ node1->remove_child(node1_1);
+
+ CHECK_EQ(node1_1->get_parent(), nullptr);
+ CHECK_EQ(node1->get_child_count(), 0);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 3);
+ }
+
+ SUBCASE("Nodes should be in the expected order when a node is moved to the back") {
+ SceneTree::get_singleton()->get_root()->move_child(node1, 1);
+
+ Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child1, node2);
+
+ Node *child2 = SceneTree::get_singleton()->get_root()->get_child(1);
+ CHECK_EQ(child2, node1);
+ }
+
+ SUBCASE("Nodes should be in the expected order when a node is moved to the front") {
+ SceneTree::get_singleton()->get_root()->move_child(node2, 0);
+
+ Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child1, node2);
+
+ Node *child2 = SceneTree::get_singleton()->get_root()->get_child(1);
+ CHECK_EQ(child2, node1);
+ }
+
+ SUBCASE("Nodes should be in the expected order when reparented") {
+ CHECK_EQ(node2->get_child_count(), 0);
+
+ node1->remove_child(node1_1);
+ CHECK_EQ(node1->get_child_count(), 0);
+ CHECK_EQ(node1_1->get_parent(), nullptr);
+
+ node2->add_child(node1_1);
+ CHECK_EQ(node2->get_child_count(), 1);
+ CHECK_EQ(node1_1->get_parent(), node2);
+
+ Node *child = node2->get_child(0);
+ CHECK_EQ(child, node1_1);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 2);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
+ }
+
+ SUBCASE("Nodes should be possible to find") {
+ Node *child = SceneTree::get_singleton()->get_root()->find_child("NestedNode", true, false);
+ CHECK_EQ(child, nullptr);
+
+ node1->set_name("Node1");
+ node2->set_name("Node2");
+ node1_1->set_name("NestedNode");
+
+ child = SceneTree::get_singleton()->get_root()->find_child("NestedNode", true, false);
+ CHECK_EQ(child, node1_1);
+
+ // First node that matches with the name is node1.
+ child = SceneTree::get_singleton()->get_root()->find_child("Node?", true, false);
+ CHECK_EQ(child, node1);
+
+ SceneTree::get_singleton()->get_root()->move_child(node2, 0);
+
+ // It should be node2, as it is now the first one in the tree.
+ child = SceneTree::get_singleton()->get_root()->find_child("Node?", true, false);
+ CHECK_EQ(child, node2);
+ }
+
+ SUBCASE("Nodes should be accessible via their node path") {
+ Node *child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node1->get_path());
+ CHECK_EQ(child_by_path, node1);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node2->get_path());
+ CHECK_EQ(child_by_path, node2);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node1_1->get_path());
+ CHECK_EQ(child_by_path, node1_1);
+
+ node1->set_name("Node1");
+ node1_1->set_name("NestedNode");
+
+ child_by_path = node1->get_node_or_null(NodePath("NestedNode"));
+ CHECK_EQ(child_by_path, node1_1);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("/root/Node1/NestedNode"));
+ CHECK_EQ(child_by_path, node1_1);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("Node1/NestedNode"));
+ CHECK_EQ(child_by_path, node1_1);
+ }
+
+ SUBCASE("Nodes should be accessible via their groups") {
+ List<Node *> nodes;
+ SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes);
+ CHECK(nodes.is_empty());
+
+ SceneTree::get_singleton()->get_nodes_in_group("other_nodes", &nodes);
+ CHECK(nodes.is_empty());
+
+ node1->add_to_group("nodes");
+ node2->add_to_group("other_nodes");
+ node1_1->add_to_group("nodes");
+ node1_1->add_to_group("other_nodes");
+
+ SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes);
+ CHECK_EQ(nodes.size(), 2);
+
+ List<Node *>::Element *E = nodes.front();
+ CHECK_EQ(E->get(), node1);
+ E = E->next();
+ CHECK_EQ(E->get(), node1_1);
+
+ // Clear and try again with the other group.
+ nodes.clear();
+
+ SceneTree::get_singleton()->get_nodes_in_group("other_nodes", &nodes);
+ CHECK_EQ(nodes.size(), 2);
+
+ E = nodes.front();
+ CHECK_EQ(E->get(), node1_1);
+ E = E->next();
+ CHECK_EQ(E->get(), node2);
+
+ // Clear and try again with the other group and one node removed.
+ nodes.clear();
+
+ node1->remove_from_group("nodes");
+ SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes);
+ CHECK_EQ(nodes.size(), 1);
+
+ E = nodes.front();
+ CHECK_EQ(E->get(), node1_1);
+ }
+
+ memdelete(node1_1);
+ memdelete(node1);
+ memdelete(node2);
+}
+
+TEST_CASE("[Node] Processing") {
+ Node *node = memnew(Node);
+
+ SUBCASE("Processing") {
+ CHECK_FALSE(node->is_processing());
+
+ node->set_process(true);
+
+ CHECK(node->is_processing());
+
+ node->set_process(false);
+
+ CHECK_FALSE(node->is_processing());
+ }
+
+ SUBCASE("Physics processing") {
+ CHECK_FALSE(node->is_physics_processing());
+
+ node->set_physics_process(true);
+
+ CHECK(node->is_physics_processing());
+
+ node->set_physics_process(false);
+
+ CHECK_FALSE(node->is_physics_processing());
+ }
+
+ SUBCASE("Unhandled input processing") {
+ CHECK_FALSE(node->is_processing_unhandled_input());
+
+ node->set_process_unhandled_input(true);
+
+ CHECK(node->is_processing_unhandled_input());
+
+ node->set_process_unhandled_input(false);
+
+ CHECK_FALSE(node->is_processing_unhandled_input());
+ }
+
+ SUBCASE("Input processing") {
+ CHECK_FALSE(node->is_processing_input());
+
+ node->set_process_input(true);
+
+ CHECK(node->is_processing_input());
+
+ node->set_process_input(false);
+
+ CHECK_FALSE(node->is_processing_input());
+ }
+
+ SUBCASE("Unhandled key input processing") {
+ CHECK_FALSE(node->is_processing_unhandled_key_input());
+
+ node->set_process_unhandled_key_input(true);
+
+ CHECK(node->is_processing_unhandled_key_input());
+
+ node->set_process_unhandled_key_input(false);
+
+ CHECK_FALSE(node->is_processing_unhandled_key_input());
+ }
+
+ SUBCASE("Shortcut input processing") {
+ CHECK_FALSE(node->is_processing_shortcut_input());
+
+ node->set_process_shortcut_input(true);
+
+ CHECK(node->is_processing_shortcut_input());
+
+ node->set_process_shortcut_input(false);
+
+ CHECK_FALSE(node->is_processing_shortcut_input());
+ }
+
+ SUBCASE("Internal processing") {
+ CHECK_FALSE(node->is_processing_internal());
+
+ node->set_process_internal(true);
+
+ CHECK(node->is_processing_internal());
+
+ node->set_process_internal(false);
+
+ CHECK_FALSE(node->is_processing_internal());
+ }
+
+ memdelete(node);
+}
+
+} // namespace TestNode
+
+#endif // TEST_NODE_H
diff --git a/tests/scene/test_visual_shader.h b/tests/scene/test_visual_shader.h
new file mode 100644
index 0000000000..457f9ad6ac
--- /dev/null
+++ b/tests/scene/test_visual_shader.h
@@ -0,0 +1,151 @@
+/*************************************************************************/
+/* test_visual_shader.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_VISUAL_SHADER_H
+#define TEST_VISUAL_SHADER_H
+
+#include "scene/resources/visual_shader.h"
+
+#include "tests/test_macros.h"
+
+namespace TestVisualArray {
+
+TEST_CASE("[SceneTree][VisualShader] Object creation and parameter") {
+ Ref<VisualShader> vs = memnew(VisualShader);
+ CHECK(vs.is_valid());
+
+ CHECK(vs->get_mode() == Shader::MODE_SPATIAL);
+
+ for (int i = 1; i < Shader::MODE_MAX; i++) {
+ vs->set_mode((Shader::Mode)i);
+ CHECK(vs->get_mode() == i);
+ }
+}
+
+TEST_CASE("[SceneTree][VisualShader] Testing VisualShaderNodes") {
+ SUBCASE("Testing Node Creation") {
+ Ref<VisualShader> vs = memnew(VisualShader);
+ CHECK(vs.is_valid());
+
+ for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
+ Ref<VisualShaderNode> vsn = memnew(VisualShaderNodeInput);
+ CHECK(vsn.is_valid());
+ vs->add_node(VisualShader::Type(i), vsn, Vector2(1, 10), i + 2);
+ CHECK(vs->get_node(VisualShader::Type(i), i + 2) == vsn);
+ }
+
+ ERR_PRINT_OFF;
+
+ // Testing for Invalid entries.
+ Ref<VisualShaderNode> vsn5 = memnew(VisualShaderNodeInput);
+ Ref<VisualShaderNode> vsn6 = memnew(VisualShaderNodeInput);
+ CHECK(vsn6.is_valid());
+ CHECK(vsn5.is_valid());
+
+ vs->add_node(VisualShader::TYPE_SKY, vsn5, Vector2(1, 10), 0);
+ CHECK_FALSE(vs->get_node(VisualShader::TYPE_SKY, 0) == vsn6);
+ vs->add_node(VisualShader::TYPE_MAX, vsn6, Vector2(1, 10), 7);
+ CHECK_FALSE(vs->get_node(VisualShader::TYPE_SKY, 7) == vsn6);
+
+ ERR_PRINT_ON;
+ }
+
+ SUBCASE("Testing VisualShaderNode position getter and setter") {
+ Ref<VisualShader> vs = memnew(VisualShader);
+ CHECK(vs.is_valid());
+
+ Ref<VisualShaderNode> vsn1 = memnew(VisualShaderNodeInput);
+ CHECK(vsn1.is_valid());
+ vs->add_node(VisualShader::TYPE_COLLIDE, vsn1, Vector2(0, 0), 3);
+ CHECK(vs->get_node_position(VisualShader::TYPE_COLLIDE, 3) == Vector2(0, 0));
+ vs->set_node_position(VisualShader::TYPE_COLLIDE, 3, Vector2(1, 1));
+ CHECK(vs->get_node_position(VisualShader::TYPE_COLLIDE, 3) == Vector2(1, 1));
+
+ Ref<VisualShaderNode> vsn2 = memnew(VisualShaderNodeInput);
+ CHECK(vsn2.is_valid());
+ vs->add_node(VisualShader::TYPE_FOG, vsn2, Vector2(1, 2), 4);
+ CHECK(vs->get_node_position(VisualShader::TYPE_FOG, 4) == Vector2(1, 2));
+ vs->set_node_position(VisualShader::TYPE_FOG, 4, Vector2(2, 2));
+ CHECK(vs->get_node_position(VisualShader::TYPE_FOG, 4) == Vector2(2, 2));
+ }
+
+ SUBCASE("Testing VisualShaderNode ID") {
+ Ref<VisualShader> vs = memnew(VisualShader);
+ CHECK(vs.is_valid());
+
+ for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
+ Ref<VisualShaderNode> vsn = memnew(VisualShaderNodeInput);
+ CHECK(vsn.is_valid());
+ vs->add_node(VisualShader::Type(i), vsn, Vector2(1, 10), i + 2);
+ CHECK(vs->get_valid_node_id(VisualShader::Type(i)) - 1 == i + 2);
+ }
+ }
+
+ SUBCASE("Testing remove and replace VisualShaderNode") {
+ Ref<VisualShader> vs = memnew(VisualShader);
+ CHECK(vs.is_valid());
+
+ ERR_PRINT_OFF;
+
+ for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
+ Ref<VisualShaderNode> vsn = memnew(VisualShaderNodeInput);
+ CHECK(vsn.is_valid());
+ vs->add_node(VisualShader::Type(i), vsn, Vector2(1, 10), i + 2);
+ CHECK(vs->get_node(VisualShader::Type(i), i + 2) == vsn);
+ vs->remove_node(VisualShader::Type(i), i + 2);
+ CHECK_FALSE(vs->get_node(VisualShader::Type(i), i + 2) == vsn);
+ }
+
+ ERR_PRINT_ON;
+ }
+}
+
+TEST_CASE("[SceneTree][VisualShader] Testing Varyings") {
+ Ref<VisualShader> vs = memnew(VisualShader);
+
+ vs->add_varying("Test1", VisualShader::VARYING_MODE_FRAG_TO_LIGHT, VisualShader::VARYING_TYPE_TRANSFORM);
+ CHECK(vs->has_varying("Test1") == true);
+
+ vs->add_varying("Test2", VisualShader::VARYING_MODE_VERTEX_TO_FRAG_LIGHT, VisualShader::VARYING_TYPE_VECTOR_2D);
+ CHECK(vs->has_varying("Test2"));
+
+ CHECK_FALSE(vs->has_varying("Does_not_exits"));
+ ERR_PRINT_OFF;
+ vs->add_varying("Test3", VisualShader::VARYING_MODE_MAX, VisualShader::VARYING_TYPE_INT);
+ CHECK_FALSE(vs->has_varying("Test3"));
+
+ vs->add_varying("Test4", VisualShader::VARYING_MODE_FRAG_TO_LIGHT, VisualShader::VARYING_TYPE_MAX);
+ CHECK_FALSE(vs->has_varying("Test4"));
+ ERR_PRINT_ON;
+}
+
+} //namespace TestVisualArray
+
+#endif // TEST_VISUAL_SHADER_H
diff --git a/tests/servers/test_text_server.h b/tests/servers/test_text_server.h
index 297f7d2068..b3c120e0ba 100644
--- a/tests/servers/test_text_server.h
+++ b/tests/servers/test_text_server.h
@@ -593,12 +593,18 @@ TEST_SUITE("[TextServer]") {
String text1 = U"linguistically similar and effectively form";
// 14^ 22^ 26^ 38^
PackedInt32Array breaks = ts->string_get_word_breaks(text1, "en");
- CHECK(breaks.size() == 4);
- if (breaks.size() == 4) {
- CHECK(breaks[0] == 14);
- CHECK(breaks[1] == 22);
- CHECK(breaks[2] == 26);
- CHECK(breaks[3] == 38);
+ CHECK(breaks.size() == 10);
+ if (breaks.size() == 10) {
+ CHECK(breaks[0] == 0);
+ CHECK(breaks[1] == 14);
+ CHECK(breaks[2] == 15);
+ CHECK(breaks[3] == 22);
+ CHECK(breaks[4] == 23);
+ CHECK(breaks[5] == 26);
+ CHECK(breaks[6] == 27);
+ CHECK(breaks[7] == 38);
+ CHECK(breaks[8] == 39);
+ CHECK(breaks[9] == 43);
}
}
@@ -608,16 +614,26 @@ TEST_SUITE("[TextServer]") {
// 3^ 7^ 13^ 16^ 20^ 25^ 29^ 32^
PackedInt32Array breaks = ts->string_get_word_breaks(text2, "th");
- CHECK(breaks.size() == 8);
- if (breaks.size() == 8) {
- CHECK(breaks[0] == 3);
- CHECK(breaks[1] == 7);
- CHECK(breaks[2] == 13);
- CHECK(breaks[3] == 16);
- CHECK(breaks[4] == 20);
- CHECK(breaks[5] == 25);
- CHECK(breaks[6] == 29);
- CHECK(breaks[7] == 32);
+ CHECK(breaks.size() == 18);
+ if (breaks.size() == 18) {
+ CHECK(breaks[0] == 0);
+ CHECK(breaks[1] == 4);
+ CHECK(breaks[2] == 4);
+ CHECK(breaks[3] == 8);
+ CHECK(breaks[4] == 8);
+ CHECK(breaks[5] == 14);
+ CHECK(breaks[6] == 14);
+ CHECK(breaks[7] == 17);
+ CHECK(breaks[8] == 17);
+ CHECK(breaks[9] == 21);
+ CHECK(breaks[10] == 21);
+ CHECK(breaks[11] == 26);
+ CHECK(breaks[12] == 26);
+ CHECK(breaks[13] == 30);
+ CHECK(breaks[14] == 30);
+ CHECK(breaks[15] == 33);
+ CHECK(breaks[16] == 33);
+ CHECK(breaks[17] == 42);
}
}
}
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index d58c19ac32..3ef8e2de6f 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -30,6 +30,7 @@
#include "test_main.h"
+#include "tests/core/config/test_project_settings.h"
#include "tests/core/input/test_input_event_key.h"
#include "tests/core/input/test_shortcut.h"
#include "tests/core/io/test_config_file.h"
@@ -91,12 +92,14 @@
#include "tests/scene/test_code_edit.h"
#include "tests/scene/test_curve.h"
#include "tests/scene/test_gradient.h"
+#include "tests/scene/test_node.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"
#include "tests/scene/test_theme.h"
+#include "tests/scene/test_visual_shader.h"
#include "tests/servers/test_text_server.h"
#include "tests/test_validate_testing.h"
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 717cc835b0..017dabe9e5 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -230,7 +230,7 @@ Files extracted from upstream source:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 5.3.1 (970321db7bddbe8c579b73751fc655a924ea3ce6, 2022)
+- Version: 6.0.0 (afcae83a064843d71d47624bc162e121cc56c08b, 2022)
- License: MIT
Files extracted from upstream source:
@@ -345,7 +345,7 @@ Files extracted from upstream source:
## mbedtls
- Upstream: https://github.com/Mbed-TLS/mbedtls
-- Version: 2.18.1 (dd79db10014d85b26d11fe57218431f2e5ede6f2, 2022)
+- Version: 2.18.2 (89f040a5c938985c5f30728baed21e49d0846a53, 2022)
- License: Apache 2.0
File extracted from upstream release tarball:
@@ -355,12 +355,10 @@ File extracted from upstream release tarball:
- The `LICENSE` file.
- Applied the patch in `patches/1453.diff` (upstream PR:
https://github.com/ARMmbed/mbedtls/pull/1453).
+ Applied the patch in `patches/windows-arm64-hardclock.diff`
- Added 2 files `godot_core_mbedtls_platform.c` and `godot_core_mbedtls_config.h`
providing configuration for light bundling with core.
-Some changes have been made in order to fix Windows on ARM build errors.
-They are marked with `// -- GODOT start --` and `// -- GODOT end --`
-
## meshoptimizer
diff --git a/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh b/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh
index eef89a2879..fbd7c642ab 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh
@@ -49,7 +49,7 @@ struct Coverage
HBUINT16 format; /* Format identifier */
CoverageFormat1_3<SmallTypes> format1;
CoverageFormat2_4<SmallTypes> format2;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
CoverageFormat1_3<MediumTypes>format3;
CoverageFormat2_4<MediumTypes>format4;
#endif
@@ -65,7 +65,7 @@ struct Coverage
{
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return_trace (u.format3.sanitize (c));
case 4: return_trace (u.format4.sanitize (c));
#endif
@@ -74,10 +74,8 @@ struct Coverage
}
/* Has interface. */
- static constexpr unsigned SENTINEL = NOT_COVERED;
- typedef unsigned int value_t;
- value_t operator [] (hb_codepoint_t k) const { return get (k); }
- bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ unsigned operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k] != NOT_COVERED; }
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
@@ -87,7 +85,7 @@ struct Coverage
switch (u.format) {
case 1: return u.format1.get_coverage (glyph_id);
case 2: return u.format2.get_coverage (glyph_id);
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.get_coverage (glyph_id);
case 4: return u.format4.get_coverage (glyph_id);
#endif
@@ -100,7 +98,7 @@ struct Coverage
switch (u.format) {
case 1: return u.format1.get_population ();
case 2: return u.format2.get_population ();
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.get_population ();
case 4: return u.format4.get_population ();
#endif
@@ -127,7 +125,7 @@ struct Coverage
}
u.format = count <= num_ranges * 3 ? 1 : 2;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
if (count && last > 0xFFFFu)
u.format += 2;
#endif
@@ -136,7 +134,7 @@ struct Coverage
{
case 1: return_trace (u.format1.serialize (c, glyphs));
case 2: return_trace (u.format2.serialize (c, glyphs));
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return_trace (u.format3.serialize (c, glyphs));
case 4: return_trace (u.format4.serialize (c, glyphs));
#endif
@@ -166,7 +164,7 @@ struct Coverage
{
case 1: return u.format1.intersects (glyphs);
case 2: return u.format2.intersects (glyphs);
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.intersects (glyphs);
case 4: return u.format4.intersects (glyphs);
#endif
@@ -179,7 +177,7 @@ struct Coverage
{
case 1: return u.format1.intersects_coverage (glyphs, index);
case 2: return u.format2.intersects_coverage (glyphs, index);
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.intersects_coverage (glyphs, index);
case 4: return u.format4.intersects_coverage (glyphs, index);
#endif
@@ -196,7 +194,7 @@ struct Coverage
{
case 1: return u.format1.collect_coverage (glyphs);
case 2: return u.format2.collect_coverage (glyphs);
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.collect_coverage (glyphs);
case 4: return u.format4.collect_coverage (glyphs);
#endif
@@ -212,7 +210,7 @@ struct Coverage
{
case 1: return u.format1.intersect_set (glyphs, intersect_glyphs);
case 2: return u.format2.intersect_set (glyphs, intersect_glyphs);
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.intersect_set (glyphs, intersect_glyphs);
case 4: return u.format4.intersect_set (glyphs, intersect_glyphs);
#endif
@@ -225,13 +223,13 @@ struct Coverage
static constexpr bool is_sorted_iterator = true;
iter_t (const Coverage &c_ = Null (Coverage))
{
- memset (this, 0, sizeof (*this));
+ hb_memset (this, 0, sizeof (*this));
format = c_.u.format;
switch (format)
{
case 1: u.format1.init (c_.u.format1); return;
case 2: u.format2.init (c_.u.format2); return;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: u.format3.init (c_.u.format3); return;
case 4: u.format4.init (c_.u.format4); return;
#endif
@@ -244,7 +242,7 @@ struct Coverage
{
case 1: return u.format1.__more__ ();
case 2: return u.format2.__more__ ();
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.__more__ ();
case 4: return u.format4.__more__ ();
#endif
@@ -257,7 +255,7 @@ struct Coverage
{
case 1: u.format1.__next__ (); break;
case 2: u.format2.__next__ (); break;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: u.format3.__next__ (); break;
case 4: u.format4.__next__ (); break;
#endif
@@ -273,7 +271,7 @@ struct Coverage
{
case 1: return u.format1.get_glyph ();
case 2: return u.format2.get_glyph ();
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.get_glyph ();
case 4: return u.format4.get_glyph ();
#endif
@@ -287,7 +285,7 @@ struct Coverage
{
case 1: return u.format1 != o.u.format1;
case 2: return u.format2 != o.u.format2;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return u.format3 != o.u.format3;
case 4: return u.format4 != o.u.format4;
#endif
@@ -302,7 +300,7 @@ struct Coverage
{
case 1: it.u.format1 = u.format1.__end__ (); break;
case 2: it.u.format2 = u.format2.__end__ (); break;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: it.u.format3 = u.format3.__end__ (); break;
case 4: it.u.format4 = u.format4.__end__ (); break;
#endif
@@ -314,7 +312,7 @@ struct Coverage
private:
unsigned int format;
union {
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
CoverageFormat2_4<MediumTypes>::iter_t format4; /* Put this one first since it's larger; helps shut up compiler. */
CoverageFormat1_3<MediumTypes>::iter_t format3;
#endif
diff --git a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh
index 82fd48dc50..5d68e3d15e 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh
@@ -77,7 +77,14 @@ struct CoverageFormat1_3
bool intersects (const hb_set_t *glyphs) const
{
- /* TODO Speed up, using hb_set_next() and bsearch()? */
+ if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
+ {
+ for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ if (get_coverage (g) != NOT_COVERED)
+ return true;
+ return false;
+ }
+
for (const auto& g : glyphArray.as_array ())
if (glyphs->has (g))
return true;
diff --git a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh
index 974d094633..d7fcc35202 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh
@@ -80,8 +80,6 @@ struct CoverageFormat2_4
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
- /* TODO(iter) Write more efficiently? */
-
unsigned num_ranges = 0;
hb_codepoint_t last = (hb_codepoint_t) -2;
for (auto g: glyphs)
@@ -115,26 +113,22 @@ struct CoverageFormat2_4
bool intersects (const hb_set_t *glyphs) const
{
+ if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
+ {
+ for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ if (get_coverage (g) != NOT_COVERED)
+ return true;
+ return false;
+ }
+
return hb_any (+ hb_iter (rangeRecord)
| hb_map ([glyphs] (const RangeRecord<Types> &range) { return range.intersects (*glyphs); }));
}
bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{
- auto cmp = [] (const void *pk, const void *pr) -> int
- {
- unsigned index = * (const unsigned *) pk;
- const RangeRecord<Types> &range = * (const RangeRecord<Types> *) pr;
- if (index < range.value) return -1;
- if (index > (unsigned int) range.value + (range.last - range.first)) return +1;
- return 0;
- };
-
- auto arr = rangeRecord.as_array ();
- unsigned idx;
- if (hb_bsearch_impl (&idx, index,
- arr.arrayZ, arr.length, sizeof (arr[0]),
- (int (*)(const void *_key, const void *_item)) cmp))
- return arr.arrayZ[idx].intersects (*glyphs);
+ auto *range = rangeRecord.as_array ().bsearch (index);
+ if (range)
+ return range->intersects (*glyphs);
return false;
}
@@ -142,9 +136,14 @@ struct CoverageFormat2_4
hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
{
+ /* Break out of loop for overlapping, broken, tables,
+ * to avoid fuzzer timouts. */
+ hb_codepoint_t last = 0;
for (const auto& range : rangeRecord)
{
- hb_codepoint_t last = range.last;
+ if (unlikely (range.first < last))
+ break;
+ last = range.last;
for (hb_codepoint_t g = range.first - 1;
glyphs.next (&g) && g <= last;)
intersect_glyphs << g;
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh
index c99b6b2e4b..edf7099c07 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh
@@ -13,7 +13,7 @@ struct MarkBasePos
union {
HBUINT16 format; /* Format identifier */
MarkBasePosFormat1_2<SmallTypes> format1;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
MarkBasePosFormat1_2<MediumTypes> format2;
#endif
} u;
@@ -26,7 +26,7 @@ struct MarkBasePos
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh
index 8a4de9ffaa..09152fd876 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh
@@ -13,7 +13,7 @@ struct MarkLigPos
union {
HBUINT16 format; /* Format identifier */
MarkLigPosFormat1_2<SmallTypes> format1;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
MarkLigPosFormat1_2<MediumTypes> format2;
#endif
} u;
@@ -26,7 +26,7 @@ struct MarkLigPos
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh
index 74b5105c42..4118fc304f 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh
@@ -13,7 +13,7 @@ struct MarkMarkPos
union {
HBUINT16 format; /* Format identifier */
MarkMarkPosFormat1_2<SmallTypes> format1;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
MarkMarkPosFormat1_2<MediumTypes> format2;
#endif
} u;
@@ -26,7 +26,7 @@ struct MarkMarkPos
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh
index 72bfc43dc4..9823768cbc 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh
@@ -15,7 +15,7 @@ struct PairPos
HBUINT16 format; /* Format identifier */
PairPosFormat1_3<SmallTypes> format1;
PairPosFormat2_4<SmallTypes> format2;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
PairPosFormat1_3<MediumTypes> format3;
PairPosFormat2_4<MediumTypes> format4;
#endif
@@ -30,7 +30,7 @@ struct PairPos
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
#endif
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh
index ddf7313f94..9c9b268889 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh
@@ -51,8 +51,21 @@ struct PairPosFormat1_3
bool intersects (const hb_set_t *glyphs) const
{
+ auto &cov = this+coverage;
+
+ if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
+ {
+ for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ {
+ unsigned i = cov.get_coverage (g);
+ if ((this+pairSet[i]).intersects (glyphs, valueFormat))
+ return true;
+ }
+ return false;
+ }
+
return
- + hb_zip (this+coverage, pairSet)
+ + hb_zip (cov, pairSet)
| hb_filter (*glyphs, hb_first)
| hb_map (hb_second)
| hb_map ([glyphs, this] (const typename Types::template OffsetTo<PairSet> &_)
@@ -171,12 +184,16 @@ struct PairPosFormat1_3
unsigned format1 = 0;
unsigned format2 = 0;
for (const auto & _ :
- + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second))
+ + hb_zip (this+coverage, pairSet)
+ | hb_filter (glyphset, hb_first)
+ | hb_map (hb_second)
+ )
{
const PairSet& set = (this + _);
const PairValueRecord *record = &set.firstPairValueRecord;
- for (unsigned i = 0; i < set.len; i++)
+ unsigned count = set.len;
+ for (unsigned i = 0; i < count; i++)
{
if (record->intersects (glyphset))
{
@@ -185,6 +202,9 @@ struct PairPosFormat1_3
}
record = &StructAtOffset<const PairValueRecord> (record, record_size);
}
+
+ if (format1 == valueFormat[0] && format2 == valueFormat[1])
+ break;
}
return hb_pair (format1, format2);
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
index 83b093b988..9c87ac2b03 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -220,17 +220,25 @@ struct PairPosFormat2_4
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
- "kerning glyphs at %d,%d",
+ "try kerning glyphs at %d,%d",
c->buffer->idx, skippy_iter.idx);
}
applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
+ if (applied_first || applied_second)
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "kerned glyphs at %d,%d",
+ c->buffer->idx, skippy_iter.idx);
+ }
+
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
- "kerned glyphs at %d,%d",
+ "tried kerning glyphs at %d,%d",
c->buffer->idx, skippy_iter.idx);
}
@@ -241,10 +249,15 @@ struct PairPosFormat2_4
boring:
buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
+ if (len2)
+ {
+ skippy_iter.idx++;
+ // https://github.com/harfbuzz/harfbuzz/issues/3824
+ // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
+ buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
+ }
buffer->idx = skippy_iter.idx;
- if (len2)
- buffer->idx++;
return_trace (true);
}
@@ -309,6 +322,7 @@ struct PairPosFormat2_4
{
unsigned len1 = valueFormat1.get_len ();
unsigned len2 = valueFormat2.get_len ();
+ unsigned record_size = len1 + len2;
unsigned format1 = 0;
unsigned format2 = 0;
@@ -317,10 +331,13 @@ struct PairPosFormat2_4
{
for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
{
- unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+ unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size;
format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
}
+
+ if (format1 == valueFormat1 && format2 == valueFormat2)
+ break;
}
return hb_pair (format1, format2);
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
index aa48d933c3..a318f39913 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
@@ -112,24 +112,38 @@ struct PairSet
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
- "kerning glyphs at %d,%d",
+ "try kerning glyphs at %d,%d",
c->buffer->idx, pos);
}
bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
+ if (applied_first || applied_second)
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "kerned glyphs at %d,%d",
+ c->buffer->idx, pos);
+ }
+
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
- "kerned glyphs at %d,%d",
+ "tried kerning glyphs at %d,%d",
c->buffer->idx, pos);
}
if (applied_first || applied_second)
buffer->unsafe_to_break (buffer->idx, pos + 1);
+
if (len2)
- pos++;
+ {
+ pos++;
+ // https://github.com/harfbuzz/harfbuzz/issues/3824
+ // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
+ buffer->unsafe_to_break (buffer->idx, pos + 1);
+ }
buffer->idx = pos;
return_trace (true);
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh
index 4a9e9672eb..6c50c9717a 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh
@@ -84,7 +84,7 @@ struct AlternateSet
{
if (alternates.len && alternate_count)
{
- + alternates.sub_array (start_offset, alternate_count)
+ + alternates.as_array ().sub_array (start_offset, alternate_count)
| hb_sink (hb_array (alternate_glyphs, *alternate_count))
;
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh
index 37406179a2..9d7cd6fddf 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh
@@ -14,7 +14,7 @@ struct AlternateSubst
union {
HBUINT16 format; /* Format identifier */
AlternateSubstFormat1_2<SmallTypes> format1;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
AlternateSubstFormat1_2<MediumTypes> format2;
#endif
} u;
@@ -27,7 +27,7 @@ struct AlternateSubst
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
index 6caa80e056..cdb35f525b 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
@@ -118,7 +118,7 @@ struct Ligature
match_positions[i] += delta;
if (i)
*p++ = ',';
- snprintf (p, sizeof(buf), "%u", match_positions[i]);
+ snprintf (p, sizeof(buf) - (p - buf), "%u", match_positions[i]);
p += strlen(p);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh
index 63707972a8..7ba19e844c 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh
@@ -14,7 +14,7 @@ struct LigatureSubst
union {
HBUINT16 format; /* Format identifier */
LigatureSubstFormat1_2<SmallTypes> format1;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
LigatureSubstFormat1_2<MediumTypes> format2;
#endif
} u;
@@ -27,7 +27,7 @@ struct LigatureSubst
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh
index 852ca3eac5..95710ed2be 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh
@@ -14,7 +14,7 @@ struct MultipleSubst
union {
HBUINT16 format; /* Format identifier */
MultipleSubstFormat1_2<SmallTypes> format1;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
MultipleSubstFormat1_2<MediumTypes> format2;
#endif
} u;
@@ -28,7 +28,7 @@ struct MultipleSubst
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
index abf1c643ff..e2190078b8 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
@@ -117,7 +117,7 @@ struct Sequence
{
if (buf < p)
*p++ = ',';
- snprintf (p, sizeof(buf), "%u", i);
+ snprintf (p, sizeof(buf) - (p - buf), "%u", i);
p += strlen(p);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh
index 6942e6997f..7da8103168 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh
@@ -16,7 +16,7 @@ struct SingleSubst
HBUINT16 format; /* Format identifier */
SingleSubstFormat1_3<SmallTypes> format1;
SingleSubstFormat2_4<SmallTypes> format2;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
SingleSubstFormat1_3<MediumTypes> format3;
SingleSubstFormat2_4<MediumTypes> format4;
#endif
@@ -32,7 +32,7 @@ struct SingleSubst
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
#endif
@@ -55,7 +55,7 @@ struct SingleSubst
format = 1;
hb_codepoint_t mask = 0xFFFFu;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
if (+ glyphs
| hb_map_retains_sorting (hb_first)
| hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; }))
@@ -78,7 +78,7 @@ struct SingleSubst
| hb_map_retains_sorting (hb_first),
delta));
case 2: return_trace (u.format2.serialize (c, glyphs));
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: return_trace (u.format3.serialize (c,
+ glyphs
| hb_map_retains_sorting (hb_first),
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
index 13665d7ba1..1be21b98bc 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
@@ -57,7 +57,7 @@ struct SingleSubstFormat1_3
hb_codepoint_t max_before = intersection.get_max ();
hb_codepoint_t min_after = (min_before + d) & mask;
hb_codepoint_t max_after = (max_before + d) & mask;
- if (pop >= max_before - min_before &&
+ if (intersection.get_population () == max_before - min_before + 1 &&
((min_before <= min_after && min_after <= max_before) ||
(min_before <= max_after && max_after <= max_before)))
return;
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
index 5416299754..01df714525 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
@@ -36,8 +36,24 @@ struct SingleSubstFormat2_4
void closure (hb_closure_context_t *c) const
{
- + hb_zip (this+coverage, substitute)
- | hb_filter (c->parent_active_glyphs (), hb_first)
+ auto &cov = this+coverage;
+ auto &glyph_set = c->parent_active_glyphs ();
+
+ if (substitute.len > glyph_set.get_population () * 4)
+ {
+ for (auto g : glyph_set)
+ {
+ unsigned i = cov.get_coverage (g);
+ if (i == NOT_COVERED || i >= substitute.len)
+ continue;
+ c->output->add (substitute.arrayZ[i]);
+ }
+
+ return;
+ }
+
+ + hb_zip (cov, substitute)
+ | hb_filter (glyph_set, hb_first)
| hb_map (hb_second)
| hb_sink (c->output)
;
diff --git a/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
index fc8e309bc9..edf8cd8797 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
@@ -3,6 +3,7 @@
#include "../../hb-open-type.hh"
+#include "composite-iter.hh"
namespace OT {
@@ -121,7 +122,7 @@ struct CompositeGlyphRecord
if (flags & ARG_1_AND_2_ARE_WORDS)
{
// no overflow, copy and update value with deltas
- memcpy (out, this, len);
+ hb_memcpy (out, this, len);
const HBINT16 *px = reinterpret_cast<const HBINT16 *> (p);
HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val);
@@ -135,7 +136,7 @@ struct CompositeGlyphRecord
if (new_x <= 127 && new_x >= -128 &&
new_y <= 127 && new_y >= -128)
{
- memcpy (out, this, len);
+ hb_memcpy (out, this, len);
HBINT8 *o = reinterpret_cast<HBINT8 *> (out + len_before_val);
o[0] = new_x;
o[1] = new_y;
@@ -143,7 +144,7 @@ struct CompositeGlyphRecord
else
{
// int8 overflows after deltas applied
- memcpy (out, this, len_before_val);
+ hb_memcpy (out, this, len_before_val);
//update flags
CompositeGlyphRecord *o = reinterpret_cast<CompositeGlyphRecord *> (out);
@@ -152,14 +153,14 @@ struct CompositeGlyphRecord
HBINT16 new_value;
new_value = new_x;
- memcpy (out, &new_value, HBINT16::static_size);
+ hb_memcpy (out, &new_value, HBINT16::static_size);
out += HBINT16::static_size;
new_value = new_y;
- memcpy (out, &new_value, HBINT16::static_size);
+ hb_memcpy (out, &new_value, HBINT16::static_size);
out += HBINT16::static_size;
- memcpy (out, p+2, len - len_before_val - 2);
+ hb_memcpy (out, p+2, len - len_before_val - 2);
len += 2;
}
}
@@ -252,55 +253,7 @@ struct CompositeGlyphRecord
DEFINE_SIZE_MIN (4);
};
-struct composite_iter_t : hb_iter_with_fallback_t<composite_iter_t, const CompositeGlyphRecord &>
-{
- typedef const CompositeGlyphRecord *__item_t__;
- composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
- glyph (glyph_), current (nullptr), current_size (0)
- {
- set_current (current_);
- }
-
- composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
-
- item_t __item__ () const { return *current; }
- bool __more__ () const { return current; }
- void __next__ ()
- {
- if (!current->has_more ()) { current = nullptr; return; }
-
- set_current (&StructAtOffset<CompositeGlyphRecord> (current, current_size));
- }
- composite_iter_t __end__ () const { return composite_iter_t (); }
- bool operator != (const composite_iter_t& o) const
- { return current != o.current; }
-
-
- void set_current (__item_t__ current_)
- {
- if (!glyph.check_range (current_, CompositeGlyphRecord::min_size))
- {
- current = nullptr;
- current_size = 0;
- return;
- }
- unsigned size = current_->get_size ();
- if (!glyph.check_range (current_, size))
- {
- current = nullptr;
- current_size = 0;
- return;
- }
-
- current = current_;
- current_size = size;
- }
-
- private:
- hb_bytes_t glyph;
- __item_t__ current;
- unsigned current_size;
-};
+using composite_iter_t = composite_iter_tmpl<CompositeGlyphRecord>;
struct CompositeGlyph
{
@@ -382,7 +335,7 @@ struct CompositeGlyph
unsigned comp_len = component.get_size ();
if (component.is_anchored ())
{
- memcpy (p, &component, comp_len);
+ hb_memcpy (p, &component, comp_len);
p += comp_len;
}
else
@@ -398,7 +351,7 @@ struct CompositeGlyph
if (source_len > source_comp_len)
{
unsigned instr_len = source_len - source_comp_len;
- memcpy (p, (const char *)c + source_comp_len, instr_len);
+ hb_memcpy (p, (const char *)c + source_comp_len, instr_len);
p += instr_len;
}
diff --git a/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
index 0b25659acc..b7215b0170 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
@@ -7,6 +7,8 @@
#include "GlyphHeader.hh"
#include "SimpleGlyph.hh"
#include "CompositeGlyph.hh"
+#include "VarCompositeGlyph.hh"
+#include "coord-setter.hh"
namespace OT {
@@ -16,6 +18,11 @@ struct glyf_accelerator_t;
namespace glyf_impl {
+#ifndef HB_GLYF_MAX_POINTS
+#define HB_GLYF_MAX_POINTS 10000
+#endif
+
+
enum phantom_point_index_t
{
PHANTOM_LEFT = 0,
@@ -27,7 +34,7 @@ enum phantom_point_index_t
struct Glyph
{
- enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
+ enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE, VAR_COMPOSITE };
public:
composite_iter_t get_composite_iterator () const
@@ -35,6 +42,11 @@ struct Glyph
if (type != COMPOSITE) return composite_iter_t ();
return CompositeGlyph (*header, bytes).iter ();
}
+ var_composite_iter_t get_var_composite_iterator () const
+ {
+ if (type != VAR_COMPOSITE) return var_composite_iter_t ();
+ return VarCompositeGlyph (*header, bytes).iter ();
+ }
const hb_bytes_t trim_padding () const
{
@@ -108,25 +120,25 @@ struct Glyph
if (unlikely (!glyph_header)) return false;
}
- int xMin = 0, xMax = 0;
- int yMin = 0, yMax = 0;
+ float xMin = 0, xMax = 0;
+ float yMin = 0, yMax = 0;
if (all_points.length > 4)
{
- xMin = xMax = roundf (all_points[0].x);
- yMin = yMax = roundf (all_points[0].y);
+ xMin = xMax = all_points[0].x;
+ yMin = yMax = all_points[0].y;
}
for (unsigned i = 1; i < all_points.length - 4; i++)
{
- float rounded_x = roundf (all_points[i].x);
- float rounded_y = roundf (all_points[i].y);
- xMin = hb_min (xMin, rounded_x);
- xMax = hb_max (xMax, rounded_x);
- yMin = hb_min (yMin, rounded_y);
- yMax = hb_max (yMax, rounded_y);
+ float x = all_points[i].x;
+ float y = all_points[i].y;
+ xMin = hb_min (xMin, x);
+ xMax = hb_max (xMax, x);
+ yMin = hb_min (yMin, y);
+ yMax = hb_max (yMax, y);
}
- update_mtx (plan, xMin, yMax, all_points);
+ update_mtx (plan, roundf (xMin), roundf (yMax), all_points);
/*for empty glyphs: all_points only include phantom points.
*just update metrics and then return */
@@ -134,10 +146,10 @@ struct Glyph
return true;
glyph_header->numberOfContours = header->numberOfContours;
- glyph_header->xMin = xMin;
- glyph_header->yMin = yMin;
- glyph_header->xMax = xMax;
- glyph_header->yMax = yMax;
+ glyph_header->xMin = roundf (xMin);
+ glyph_header->yMin = roundf (yMin);
+ glyph_header->xMax = roundf (xMax);
+ glyph_header->yMax = roundf (yMax);
dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
return true;
@@ -199,15 +211,24 @@ struct Glyph
bool shift_points_hori = true,
bool use_my_metrics = true,
bool phantom_only = false,
+ hb_array_t<int> coords = hb_array_t<int> (),
unsigned int depth = 0) const
{
if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
+
+ if (!coords)
+ coords = hb_array (font->coords, font->num_coords);
+
contour_point_vector_t stack_points;
bool inplace = type == SIMPLE && all_points.length == 0;
/* Load into all_points if it's empty, as an optimization. */
contour_point_vector_t &points = inplace ? all_points : stack_points;
switch (type) {
+ case SIMPLE:
+ if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
+ return false;
+ break;
case COMPOSITE:
{
/* pseudo component points for each component in composite glyph */
@@ -215,20 +236,25 @@ struct Glyph
if (unlikely (!points.resize (num_points))) return false;
break;
}
- case SIMPLE:
- if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
- return false;
+#ifndef HB_NO_VAR_COMPOSITES
+ case VAR_COMPOSITE:
+ {
+ for (auto &item : get_var_composite_iterator ())
+ if (unlikely (!item.get_points (points))) return false;
+ }
+#endif
+ default:
break;
}
/* Init phantom points */
if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
- hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
+ hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
{
int lsb = 0;
int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
(int) header->xMin - lsb : 0;
- int tsb = 0;
+ HB_UNUSED int tsb = 0;
int v_orig = (int) header->yMax +
#ifndef HB_NO_VERTICAL
((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
@@ -257,7 +283,9 @@ struct Glyph
}
#ifndef HB_NO_VAR
- glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ());
+ glyf_accelerator.gvar->apply_deltas_to_points (gid,
+ coords,
+ points.as_array ());
#endif
// mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
@@ -283,11 +311,24 @@ struct Glyph
for (auto &item : get_composite_iterator ())
{
comp_points.reset ();
+
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
- .get_points (font, glyf_accelerator, comp_points,
- deltas, shift_points_hori, use_my_metrics, phantom_only, depth + 1)))
+ .get_points (font,
+ glyf_accelerator,
+ comp_points,
+ deltas,
+ shift_points_hori,
+ use_my_metrics,
+ phantom_only,
+ coords,
+ depth + 1)))
return false;
+ /* Copy phantom points from component if USE_MY_METRICS flag set */
+ if (use_my_metrics && item.is_use_my_metrics ())
+ for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
+ phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
+
/* Apply component transformation & translation */
item.transform_points (comp_points);
@@ -308,20 +349,63 @@ struct Glyph
}
}
+ all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
+
+ if (all_points.length > HB_GLYF_MAX_POINTS)
+ return false;
+
+ comp_index++;
+ }
+
+ all_points.extend (phantoms);
+ } break;
+#ifndef HB_NO_VAR_COMPOSITES
+ case VAR_COMPOSITE:
+ {
+ contour_point_vector_t comp_points;
+ hb_array_t<contour_point_t> points_left = points.as_array ();
+ for (auto &item : get_var_composite_iterator ())
+ {
+ hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item.get_num_points ());
+
+ comp_points.reset ();
+
+ coord_setter_t coord_setter (coords);
+ item.set_variations (coord_setter, record_points);
+
+ if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
+ .get_points (font,
+ glyf_accelerator,
+ comp_points,
+ deltas,
+ shift_points_hori,
+ use_my_metrics,
+ phantom_only,
+ coord_setter.get_coords (),
+ depth + 1)))
+ return false;
+
+ /* Apply component transformation */
+ item.transform_points (record_points, comp_points);
+
/* Copy phantom points from component if USE_MY_METRICS flag set */
if (use_my_metrics && item.is_use_my_metrics ())
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
- all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
+ all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
- comp_index++;
- }
+ if (all_points.length > HB_GLYF_MAX_POINTS)
+ return false;
+ points_left += item.get_num_points ();
+ }
all_points.extend (phantoms);
} break;
+#endif
default:
all_points.extend (phantoms);
+ break;
}
if (depth == 0 && shift_points_hori) /* Apply at top level */
@@ -360,6 +444,7 @@ struct Glyph
int num_contours = header->numberOfContours;
if (unlikely (num_contours == 0)) type = EMPTY;
else if (num_contours > 0) type = SIMPLE;
+ else if (num_contours == -2) type = VAR_COMPOSITE;
else type = COMPOSITE; /* negative numbers */
}
diff --git a/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
index d45f4eb350..2b4aa99d25 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
@@ -132,8 +132,8 @@ struct SimpleGlyph
if (unlikely (p + 1 > end)) return false;
unsigned int repeat_count = *p++;
unsigned stop = hb_min (i + repeat_count, count);
- for (; i < stop;)
- points_.arrayZ[i++].flag = flag;
+ for (; i < stop; i++)
+ points_.arrayZ[i].flag = flag;
}
}
return true;
@@ -223,33 +223,34 @@ struct SimpleGlyph
if (value > 0) flag |= same_flag;
else value = -value;
- coords.push ((uint8_t)value);
+ coords.arrayZ[coords.length++] = (uint8_t) value;
}
else
{
int16_t val = value;
- coords.push (val >> 8);
- coords.push (val & 0xff);
+ coords.arrayZ[coords.length++] = val >> 8;
+ coords.arrayZ[coords.length++] = val & 0xff;
}
}
static void encode_flag (uint8_t &flag,
uint8_t &repeat,
- uint8_t &lastflag,
+ uint8_t lastflag,
hb_vector_t<uint8_t> &flags /* OUT */)
{
if (flag == lastflag && repeat != 255)
{
- repeat = repeat + 1;
+ repeat++;
if (repeat == 1)
{
- flags.push(flag);
+ /* We know there's room. */
+ flags.arrayZ[flags.length++] = flag;
}
else
{
unsigned len = flags.length;
- flags[len-2] = flag | FLAG_REPEAT;
- flags[len-1] = repeat;
+ flags.arrayZ[len-2] = flag | FLAG_REPEAT;
+ flags.arrayZ[len-1] = repeat;
}
}
else
@@ -257,7 +258,6 @@ struct SimpleGlyph
repeat = 0;
flags.push (flag);
}
- lastflag = flag;
}
bool compile_bytes_with_deltas (const contour_point_vector_t &all_points,
@@ -269,7 +269,6 @@ struct SimpleGlyph
dest_bytes = hb_bytes_t ();
return true;
}
- //convert absolute values to relative values
unsigned num_points = all_points.length - 4;
hb_vector_t<uint8_t> flags, x_coords, y_coords;
@@ -277,23 +276,23 @@ struct SimpleGlyph
if (unlikely (!x_coords.alloc (2*num_points))) return false;
if (unlikely (!y_coords.alloc (2*num_points))) return false;
- uint8_t lastflag = 0, repeat = 0;
- int prev_x = 0.f, prev_y = 0.f;
-
+ uint8_t lastflag = 255, repeat = 0;
+ int prev_x = 0, prev_y = 0;
+
for (unsigned i = 0; i < num_points; i++)
{
- uint8_t flag = all_points[i].flag;
+ uint8_t flag = all_points.arrayZ[i].flag;
flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
- float cur_x = roundf (all_points[i].x);
- float cur_y = roundf (all_points[i].y);
+ int cur_x = roundf (all_points.arrayZ[i].x);
+ int cur_y = roundf (all_points.arrayZ[i].y);
encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
- if (i == 0) lastflag = flag + 1; //make lastflag != flag for the first point
encode_flag (flag, repeat, lastflag, flags);
prev_x = cur_x;
prev_y = cur_y;
+ lastflag = flag;
}
unsigned len_before_instrs = 2 * header.numberOfContours + 2;
@@ -303,29 +302,29 @@ struct SimpleGlyph
if (!no_hinting)
total_len += len_instrs;
- char *p = (char *) hb_calloc (total_len, sizeof (char));
+ char *p = (char *) hb_malloc (total_len);
if (unlikely (!p)) return false;
const char *src = bytes.arrayZ + GlyphHeader::static_size;
char *cur = p;
- memcpy (p, src, len_before_instrs);
+ hb_memcpy (p, src, len_before_instrs);
cur += len_before_instrs;
src += len_before_instrs;
if (!no_hinting)
{
- memcpy (cur, src, len_instrs);
+ hb_memcpy (cur, src, len_instrs);
cur += len_instrs;
}
- memcpy (cur, flags.arrayZ, flags.length);
+ hb_memcpy (cur, flags.arrayZ, flags.length);
cur += flags.length;
- memcpy (cur, x_coords.arrayZ, x_coords.length);
+ hb_memcpy (cur, x_coords.arrayZ, x_coords.length);
cur += x_coords.length;
- memcpy (cur, y_coords.arrayZ, y_coords.length);
+ hb_memcpy (cur, y_coords.arrayZ, y_coords.length);
dest_bytes = hb_bytes_t (p, total_len);
return true;
diff --git a/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
index 88fc93c435..1a0370c757 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
@@ -21,10 +21,18 @@ struct SubsetGlyph
bool serialize (hb_serialize_context_t *c,
bool use_short_loca,
- const hb_subset_plan_t *plan) const
+ const hb_subset_plan_t *plan,
+ hb_font_t *font)
{
TRACE_SERIALIZE (this);
+ if (font)
+ {
+ const OT::glyf_accelerator_t &glyf = *font->face->table.glyf;
+ if (!this->compile_bytes_with_deltas (plan, font, glyf))
+ return_trace (false);
+ }
+
hb_bytes_t dest_glyph = dest_start.copy (c);
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
unsigned int pad_length = use_short_loca ? padding () : 0;
diff --git a/thirdparty/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh
new file mode 100644
index 0000000000..0f4c71c83d
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh
@@ -0,0 +1,353 @@
+#ifndef OT_GLYF_VARCOMPOSITEGLYPH_HH
+#define OT_GLYF_VARCOMPOSITEGLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+#include "coord-setter.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct VarCompositeGlyphRecord
+{
+ protected:
+ enum var_composite_glyph_flag_t
+ {
+ USE_MY_METRICS = 0x0001,
+ AXIS_INDICES_ARE_SHORT = 0x0002,
+ UNIFORM_SCALE = 0x0004,
+ HAVE_TRANSLATE_X = 0x0008,
+ HAVE_TRANSLATE_Y = 0x0010,
+ HAVE_ROTATION = 0x0020,
+ HAVE_SCALE_X = 0x0040,
+ HAVE_SCALE_Y = 0x0080,
+ HAVE_SKEW_X = 0x0100,
+ HAVE_SKEW_Y = 0x0200,
+ HAVE_TCENTER_X = 0x0400,
+ HAVE_TCENTER_Y = 0x0800,
+ GID_IS_24 = 0x1000,
+ AXES_HAVE_VARIATION = 0x2000,
+ };
+
+ public:
+
+ unsigned int get_size () const
+ {
+ unsigned int size = min_size;
+
+ unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 4 : 3;
+ size += numAxes * axis_width;
+
+ // gid
+ size += 2;
+ if (flags & GID_IS_24) size += 1;
+
+ if (flags & HAVE_TRANSLATE_X) size += 2;
+ if (flags & HAVE_TRANSLATE_Y) size += 2;
+ if (flags & HAVE_ROTATION) size += 2;
+ if (flags & HAVE_SCALE_X) size += 2;
+ if (flags & HAVE_SCALE_Y) size += 2;
+ if (flags & HAVE_SKEW_X) size += 2;
+ if (flags & HAVE_SKEW_Y) size += 2;
+ if (flags & HAVE_TCENTER_X) size += 2;
+ if (flags & HAVE_TCENTER_Y) size += 2;
+
+ return size;
+ }
+
+ bool has_more () const { return true; }
+
+ bool is_use_my_metrics () const { return flags & USE_MY_METRICS; }
+
+ hb_codepoint_t get_gid () const
+ {
+ if (flags & GID_IS_24)
+ return StructAfter<const HBGlyphID24> (numAxes);
+ else
+ return StructAfter<const HBGlyphID16> (numAxes);
+ }
+
+ unsigned get_numAxes () const
+ {
+ return numAxes;
+ }
+
+ unsigned get_num_points () const
+ {
+ unsigned num = 0;
+ if (flags & AXES_HAVE_VARIATION) num += numAxes;
+ if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++;
+ if (flags & HAVE_ROTATION) num++;
+ if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++;
+ if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++;
+ if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++;
+ return num;
+ }
+
+ void transform_points (hb_array_t<contour_point_t> record_points,
+ contour_point_vector_t &points) const
+ {
+ float matrix[4];
+ contour_point_t trans;
+
+ get_transformation_from_points (record_points, matrix, trans);
+
+ points.transform (matrix);
+ points.translate (trans);
+ }
+
+ static inline void transform (float (&matrix)[4], contour_point_t &trans,
+ float (other)[6])
+ {
+ // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L268
+ float xx1 = other[0];
+ float xy1 = other[1];
+ float yx1 = other[2];
+ float yy1 = other[3];
+ float dx1 = other[4];
+ float dy1 = other[5];
+ float xx2 = matrix[0];
+ float xy2 = matrix[1];
+ float yx2 = matrix[2];
+ float yy2 = matrix[3];
+ float dx2 = trans.x;
+ float dy2 = trans.y;
+
+ matrix[0] = xx1*xx2 + xy1*yx2;
+ matrix[1] = xx1*xy2 + xy1*yy2;
+ matrix[2] = yx1*xx2 + yy1*yx2;
+ matrix[3] = yx1*xy2 + yy1*yy2;
+ trans.x = xx2*dx1 + yx2*dy1 + dx2;
+ trans.y = xy2*dx1 + yy2*dy1 + dy2;
+ }
+
+ static void translate (float (&matrix)[4], contour_point_t &trans,
+ float translateX, float translateY)
+ {
+ // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L213
+ float other[6] = {1.f, 0.f, 0.f, 1.f, translateX, translateY};
+ transform (matrix, trans, other);
+ }
+
+ static void scale (float (&matrix)[4], contour_point_t &trans,
+ float scaleX, float scaleY)
+ {
+ // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L224
+ float other[6] = {scaleX, 0.f, 0.f, scaleY, 0.f, 0.f};
+ transform (matrix, trans, other);
+ }
+
+ static void rotate (float (&matrix)[4], contour_point_t &trans,
+ float rotation)
+ {
+ // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
+ rotation = rotation * float (M_PI);
+ float c = cosf (rotation);
+ float s = sinf (rotation);
+ float other[6] = {c, s, -s, c, 0.f, 0.f};
+ transform (matrix, trans, other);
+ }
+
+ static void skew (float (&matrix)[4], contour_point_t &trans,
+ float skewX, float skewY)
+ {
+ // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
+ skewX = skewX * float (M_PI);
+ skewY = skewY * float (M_PI);
+ float other[6] = {1.f, tanf (skewY), tanf (skewX), 1.f, 0.f, 0.f};
+ transform (matrix, trans, other);
+ }
+
+ bool get_points (contour_point_vector_t &points) const
+ {
+ float translateX = 0.f;
+ float translateY = 0.f;
+ float rotation = 0.f;
+ float scaleX = 1.f * (1 << 12);
+ float scaleY = 1.f * (1 << 12);
+ float skewX = 0.f;
+ float skewY = 0.f;
+ float tCenterX = 0.f;
+ float tCenterY = 0.f;
+
+ if (unlikely (!points.resize (points.length + get_num_points ()))) return false;
+
+ unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
+ unsigned axes_size = numAxes * axis_width;
+
+ const F2DOT14 *q = (const F2DOT14 *) (axes_size +
+ (flags & GID_IS_24 ? 3 : 2) +
+ &StructAfter<const HBUINT8> (numAxes));
+
+ hb_array_t<contour_point_t> rec_points = points.as_array ().sub_array (points.length - get_num_points ());
+
+ unsigned count = numAxes;
+ if (flags & AXES_HAVE_VARIATION)
+ {
+ for (unsigned i = 0; i < count; i++)
+ rec_points[i].x = *q++;
+ rec_points += count;
+ }
+ else
+ q += count;
+
+ const HBUINT16 *p = (const HBUINT16 *) q;
+
+ if (flags & HAVE_TRANSLATE_X) translateX = * (const FWORD *) p++;
+ if (flags & HAVE_TRANSLATE_Y) translateY = * (const FWORD *) p++;
+ if (flags & HAVE_ROTATION) rotation = * (const F2DOT14 *) p++;
+ if (flags & HAVE_SCALE_X) scaleX = * (const F4DOT12 *) p++;
+ if (flags & HAVE_SCALE_Y) scaleY = * (const F4DOT12 *) p++;
+ if (flags & HAVE_SKEW_X) skewX = * (const F2DOT14 *) p++;
+ if (flags & HAVE_SKEW_Y) skewY = * (const F2DOT14 *) p++;
+ if (flags & HAVE_TCENTER_X) tCenterX = * (const FWORD *) p++;
+ if (flags & HAVE_TCENTER_Y) tCenterY = * (const FWORD *) p++;
+
+ if ((flags & UNIFORM_SCALE) && !(flags & HAVE_SCALE_Y))
+ scaleY = scaleX;
+
+ if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
+ {
+ rec_points[0].x = translateX;
+ rec_points[0].y = translateY;
+ rec_points++;
+ }
+ if (flags & HAVE_ROTATION)
+ {
+ rec_points[0].x = rotation;
+ rec_points++;
+ }
+ if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
+ {
+ rec_points[0].x = scaleX;
+ rec_points[0].y = scaleY;
+ rec_points++;
+ }
+ if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
+ {
+ rec_points[0].x = skewX;
+ rec_points[0].y = skewY;
+ rec_points++;
+ }
+ if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
+ {
+ rec_points[0].x = tCenterX;
+ rec_points[0].y = tCenterY;
+ rec_points++;
+ }
+ assert (!rec_points);
+
+ return true;
+ }
+
+ void get_transformation_from_points (hb_array_t<contour_point_t> rec_points,
+ float (&matrix)[4], contour_point_t &trans) const
+ {
+ if (flags & AXES_HAVE_VARIATION)
+ rec_points += numAxes;
+
+ matrix[0] = matrix[3] = 1.f;
+ matrix[1] = matrix[2] = 0.f;
+ trans.init (0.f, 0.f);
+
+ float translateX = 0.f;
+ float translateY = 0.f;
+ float rotation = 0.f;
+ float scaleX = 1.f;
+ float scaleY = 1.f;
+ float skewX = 0.f;
+ float skewY = 0.f;
+ float tCenterX = 0.f;
+ float tCenterY = 0.f;
+
+ if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
+ {
+ translateX = rec_points[0].x;
+ translateY = rec_points[0].y;
+ rec_points++;
+ }
+ if (flags & HAVE_ROTATION)
+ {
+ rotation = rec_points[0].x / (1 << 14);
+ rec_points++;
+ }
+ if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
+ {
+ scaleX = rec_points[0].x / (1 << 12);
+ scaleY = rec_points[0].y / (1 << 12);
+ rec_points++;
+ }
+ if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
+ {
+ skewX = rec_points[0].x / (1 << 14);
+ skewY = rec_points[0].y / (1 << 14);
+ rec_points++;
+ }
+ if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
+ {
+ tCenterX = rec_points[0].x;
+ tCenterY = rec_points[0].y;
+ rec_points++;
+ }
+ assert (!rec_points);
+
+ translate (matrix, trans, translateX + tCenterX, translateY + tCenterY);
+ rotate (matrix, trans, rotation);
+ scale (matrix, trans, scaleX, scaleY);
+ skew (matrix, trans, -skewX, skewY);
+ translate (matrix, trans, -tCenterX, -tCenterY);
+ }
+
+ void set_variations (coord_setter_t &setter,
+ hb_array_t<contour_point_t> rec_points) const
+ {
+ bool have_variations = flags & AXES_HAVE_VARIATION;
+ unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
+
+ const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2));
+ const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2));
+
+ const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + numAxes) : (HBUINT8 *) (q + numAxes)));
+
+ unsigned count = numAxes;
+ for (unsigned i = 0; i < count; i++)
+ {
+ unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++;
+
+ signed v = have_variations ? rec_points[i].x : *a++;
+
+ v += setter[axis_index];
+ v = hb_clamp (v, -(1<<14), (1<<14));
+ setter[axis_index] = v;
+ }
+ }
+
+ protected:
+ HBUINT16 flags;
+ HBUINT8 numAxes;
+ public:
+ DEFINE_SIZE_MIN (3);
+};
+
+using var_composite_iter_t = composite_iter_tmpl<VarCompositeGlyphRecord>;
+
+struct VarCompositeGlyph
+{
+ const GlyphHeader &header;
+ hb_bytes_t bytes;
+ VarCompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
+ header (header_), bytes (bytes_) {}
+
+ var_composite_iter_t iter () const
+ { return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); }
+
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_VARCOMPOSITEGLYPH_HH */
diff --git a/thirdparty/harfbuzz/src/OT/glyf/composite-iter.hh b/thirdparty/harfbuzz/src/OT/glyf/composite-iter.hh
new file mode 100644
index 0000000000..d05701f3d1
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/glyf/composite-iter.hh
@@ -0,0 +1,68 @@
+#ifndef OT_GLYF_COMPOSITE_ITER_HH
+#define OT_GLYF_COMPOSITE_ITER_HH
+
+
+#include "../../hb.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+template <typename CompositeGlyphRecord>
+struct composite_iter_tmpl : hb_iter_with_fallback_t<composite_iter_tmpl<CompositeGlyphRecord>,
+ const CompositeGlyphRecord &>
+{
+ typedef const CompositeGlyphRecord *__item_t__;
+ composite_iter_tmpl (hb_bytes_t glyph_, __item_t__ current_) :
+ glyph (glyph_), current (nullptr), current_size (0)
+ {
+ set_current (current_);
+ }
+
+ composite_iter_tmpl () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
+
+ const CompositeGlyphRecord & __item__ () const { return *current; }
+ bool __more__ () const { return current; }
+ void __next__ ()
+ {
+ if (!current->has_more ()) { current = nullptr; return; }
+
+ set_current (&StructAtOffset<CompositeGlyphRecord> (current, current_size));
+ }
+ composite_iter_tmpl __end__ () const { return composite_iter_tmpl (); }
+ bool operator != (const composite_iter_tmpl& o) const
+ { return current != o.current; }
+
+
+ void set_current (__item_t__ current_)
+ {
+ if (!glyph.check_range (current_, CompositeGlyphRecord::min_size))
+ {
+ current = nullptr;
+ current_size = 0;
+ return;
+ }
+ unsigned size = current_->get_size ();
+ if (!glyph.check_range (current_, size))
+ {
+ current = nullptr;
+ current_size = 0;
+ return;
+ }
+
+ current = current_;
+ current_size = size;
+ }
+
+ private:
+ hb_bytes_t glyph;
+ __item_t__ current;
+ unsigned current_size;
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+#endif /* OT_GLYF_COMPOSITE_ITER_HH */
diff --git a/thirdparty/harfbuzz/src/OT/glyf/coord-setter.hh b/thirdparty/harfbuzz/src/OT/glyf/coord-setter.hh
new file mode 100644
index 0000000000..df64ed5af7
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/glyf/coord-setter.hh
@@ -0,0 +1,34 @@
+#ifndef OT_GLYF_COORD_SETTER_HH
+#define OT_GLYF_COORD_SETTER_HH
+
+
+#include "../../hb.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct coord_setter_t
+{
+ coord_setter_t (hb_array_t<int> coords) :
+ coords (coords) {}
+
+ int& operator [] (unsigned idx)
+ {
+ if (coords.length < idx + 1)
+ coords.resize (idx + 1);
+ return coords[idx];
+ }
+
+ hb_array_t<int> get_coords ()
+ { return coords.as_array (); }
+
+ hb_vector_t<int> coords;
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+#endif /* OT_GLYF_COORD_SETTER_HH */
diff --git a/thirdparty/harfbuzz/src/OT/glyf/glyf.hh b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
index 5fb32f67f3..e6e985c38c 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
@@ -42,11 +42,15 @@ struct glyf
bool serialize (hb_serialize_context_t *c,
Iterator it,
bool use_short_loca,
- const hb_subset_plan_t *plan)
+ const hb_subset_plan_t *plan,
+ hb_font_t *font)
{
TRACE_SERIALIZE (this);
+
unsigned init_len = c->length ();
- for (const auto &_ : it) _.serialize (c, use_short_loca, plan);
+ for (auto &_ : it)
+ if (unlikely (!_.serialize (c, use_short_loca, plan, font)))
+ return false;
/* As a special case when all glyph in the font are empty, add a zero byte
* to the table, so that OTS doesn’t reject it, and to make the table work
@@ -74,10 +78,11 @@ struct glyf
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
_populate_subset_glyphs (c->plan, glyphs);
+ hb_font_t *font = nullptr;
if (!c->plan->pinned_at_default)
{
- if (!_compile_subset_glyphs_with_deltas (c->plan, &glyphs))
- return_trace (false);
+ font = _create_font_for_instancing (c->plan);
+ if (unlikely (!font)) return false;
}
auto padded_offsets =
@@ -85,11 +90,14 @@ struct glyf
| hb_map (&glyf_impl::SubsetGlyph::padded_size)
;
- unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0);
- bool use_short_loca = max_offset < 0x1FFFF;
-
+ bool use_short_loca = false;
+ if (likely (!c->plan->force_long_loca))
+ {
+ unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0);
+ use_short_loca = max_offset < 0x1FFFF;
+ }
- glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan);
+ glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan, font);
if (!use_short_loca) {
padded_offsets =
+ hb_iter (glyphs)
@@ -97,9 +105,12 @@ struct glyf
;
}
-
- if (!c->plan->pinned_at_default)
+ if (font)
+ {
_free_compiled_subset_glyphs (&glyphs);
+ hb_font_destroy (font);
+ }
+
if (unlikely (c->serializer->in_error ())) return_trace (false);
return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
padded_offsets,
@@ -110,9 +121,8 @@ struct glyf
_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
- bool
- _compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
- hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
+ hb_font_t *
+ _create_font_for_instancing (const hb_subset_plan_t *plan) const;
void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> *glyphs) const
{
@@ -394,7 +404,11 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
plan->pinned_at_default)
subset_glyph.source_glyph = glyf_impl::Glyph ();
else
- subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
+ {
+ /* If plan has an accelerator, the preprocessing step already trimmed glyphs.
+ * Don't trim them again! */
+ subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, !plan->accelerator);
+ }
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
subset_glyph.drop_hints_bytes ();
@@ -403,17 +417,15 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
}
}
-inline bool
-glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
- hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const
+inline hb_font_t *
+glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
{
- OT::glyf_accelerator_t glyf (plan->source);
hb_font_t *font = hb_font_create (plan->source);
- if (unlikely (!font)) return false;
+ if (unlikely (font == hb_font_get_empty ())) return nullptr;
hb_vector_t<hb_variation_t> vars;
if (unlikely (!vars.alloc (plan->user_axes_location->get_population ())))
- return false;
+ return nullptr;
for (auto _ : *plan->user_axes_location)
{
@@ -423,18 +435,10 @@ glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
vars.push (var);
}
+#ifndef HB_NO_VAR
hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ());
- for (auto& subset_glyph : *glyphs)
- {
- if (!const_cast<glyf_impl::SubsetGlyph &> (subset_glyph).compile_bytes_with_deltas (plan, font, glyf))
- {
- hb_font_destroy (font);
- return false;
- }
- }
-
- hb_font_destroy (font);
- return true;
+#endif
+ return font;
}
diff --git a/thirdparty/harfbuzz/src/graph/classdef-graph.hh b/thirdparty/harfbuzz/src/graph/classdef-graph.hh
index 0bda76ac2f..c2e24a7067 100644
--- a/thirdparty/harfbuzz/src/graph/classdef-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/classdef-graph.hh
@@ -112,7 +112,7 @@ struct ClassDef : public OT::ClassDef
{
case 1: return ((ClassDefFormat1*)this)->sanitize (vertex);
case 2: return ((ClassDefFormat2*)this)->sanitize (vertex);
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
// Not currently supported
case 3:
case 4:
diff --git a/thirdparty/harfbuzz/src/graph/coverage-graph.hh b/thirdparty/harfbuzz/src/graph/coverage-graph.hh
index 3c1022f090..49d0936315 100644
--- a/thirdparty/harfbuzz/src/graph/coverage-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/coverage-graph.hh
@@ -136,7 +136,7 @@ struct Coverage : public OT::Layout::Common::Coverage
{
case 1: return ((CoverageFormat1*)this)->sanitize (vertex);
case 2: return ((CoverageFormat2*)this)->sanitize (vertex);
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
// Not currently supported
case 3:
case 4:
diff --git a/thirdparty/harfbuzz/src/graph/graph.hh b/thirdparty/harfbuzz/src/graph/graph.hh
index 79c7e690a1..dc5b6a36fe 100644
--- a/thirdparty/harfbuzz/src/graph/graph.hh
+++ b/thirdparty/harfbuzz/src/graph/graph.hh
@@ -49,6 +49,50 @@ struct graph_t
unsigned end = 0;
unsigned priority = 0;
+
+ bool link_positions_valid (unsigned num_objects, bool removed_nil)
+ {
+ hb_set_t assigned_bytes;
+ for (const auto& l : obj.real_links)
+ {
+ if (l.objidx >= num_objects
+ || (removed_nil && !l.objidx))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Invalid graph. Invalid object index.");
+ return false;
+ }
+
+ unsigned start = l.position;
+ unsigned end = start + l.width - 1;
+
+ if (unlikely (l.width < 2 || l.width > 4))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Invalid graph. Invalid link width.");
+ return false;
+ }
+
+ if (unlikely (end >= table_size ()))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Invalid graph. Link position is out of bounds.");
+ return false;
+ }
+
+ if (unlikely (assigned_bytes.intersects (start, end)))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Invalid graph. Found offsets whose positions overlap.");
+ return false;
+ }
+
+ assigned_bytes.add_range (start, end);
+ }
+
+ return !assigned_bytes.in_error ();
+ }
+
void normalize ()
{
obj.real_links.qsort ();
@@ -132,7 +176,7 @@ struct graph_t
for (unsigned i = 0; i < parents.length; i++)
{
if (parents[i] != parent_index) continue;
- parents.remove (i);
+ parents.remove_unordered (i);
break;
}
}
@@ -148,7 +192,7 @@ struct graph_t
if ((obj.head + link.position) != offset)
continue;
- obj.real_links.remove (i);
+ obj.real_links.remove_unordered (i);
return;
}
}
@@ -286,8 +330,6 @@ struct graph_t
vertices_scratch_.alloc (objects.length);
for (unsigned i = 0; i < objects.length; i++)
{
- // TODO(grieger): check all links point to valid objects.
-
// If this graph came from a serialization buffer object 0 is the
// nil object. We don't need it for our purposes here so drop it.
if (i == 0 && !objects[i])
@@ -299,6 +341,9 @@ struct graph_t
vertex_t* v = vertices_.push ();
if (check_success (!vertices_.in_error ()))
v->obj = *objects[i];
+
+ check_success (v->link_positions_valid (objects.length, removed_nil));
+
if (!removed_nil) continue;
// Fix indices to account for removed nil object.
for (auto& l : v->obj.all_links_writer ()) {
@@ -418,6 +463,13 @@ struct graph_t
hb_swap (sorted_graph[new_id], vertices_[next_id]);
const vertex_t& next = sorted_graph[new_id];
+ if (unlikely (!check_success(new_id >= 0))) {
+ // We are out of ids. Which means we've visited a node more than once.
+ // This graph contains a cycle which is not allowed.
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Contains cycle.");
+ return;
+ }
+
id_map[next_id] = new_id--;
for (const auto& link : next.obj.all_links ()) {
@@ -580,7 +632,7 @@ struct graph_t
while (roots)
{
- unsigned next = HB_SET_VALUE_INVALID;
+ uint32_t next = HB_SET_VALUE_INVALID;
if (unlikely (!check_success (!roots.in_error ()))) break;
if (!roots.next (&next)) break;
@@ -661,8 +713,8 @@ struct graph_t
auto new_subgraph =
+ subgraph.keys ()
- | hb_map([&] (unsigned node_idx) {
- const unsigned *v;
+ | hb_map([&] (uint32_t node_idx) {
+ const uint32_t *v;
if (index_map.has (node_idx, &v)) return *v;
return node_idx;
})
@@ -672,10 +724,10 @@ struct graph_t
remap_obj_indices (index_map, parents.iter (), true);
// Update roots set with new indices as needed.
- unsigned next = HB_SET_VALUE_INVALID;
+ uint32_t next = HB_SET_VALUE_INVALID;
while (roots.next (&next))
{
- const unsigned *v;
+ const uint32_t *v;
if (index_map.has (next, &v))
{
roots.del (next);
@@ -690,7 +742,7 @@ struct graph_t
{
for (const auto& link : vertices_[node_idx].obj.all_links ())
{
- const unsigned *v;
+ const uint32_t *v;
if (subgraph.has (link.objidx, &v))
{
subgraph.set (link.objidx, *v + 1);
@@ -941,6 +993,72 @@ struct graph_t
return made_change;
}
+ bool is_fully_connected ()
+ {
+ update_parents();
+
+ if (root().parents)
+ // Root cannot have parents.
+ return false;
+
+ for (unsigned i = 0; i < root_idx (); i++)
+ {
+ if (!vertices_[i].parents)
+ return false;
+ }
+ return true;
+ }
+
+#if 0
+ /*
+ * Saves the current graph to a packed binary format which the repacker fuzzer takes
+ * as a seed.
+ */
+ void save_fuzzer_seed (hb_tag_t tag) const
+ {
+ FILE* f = fopen ("./repacker_fuzzer_seed", "w");
+ fwrite ((void*) &tag, sizeof (tag), 1, f);
+
+ uint16_t num_objects = vertices_.length;
+ fwrite ((void*) &num_objects, sizeof (num_objects), 1, f);
+
+ for (const auto& v : vertices_)
+ {
+ uint16_t blob_size = v.table_size ();
+ fwrite ((void*) &blob_size, sizeof (blob_size), 1, f);
+ fwrite ((const void*) v.obj.head, blob_size, 1, f);
+ }
+
+ uint16_t link_count = 0;
+ for (const auto& v : vertices_)
+ link_count += v.obj.real_links.length;
+
+ fwrite ((void*) &link_count, sizeof (link_count), 1, f);
+
+ typedef struct
+ {
+ uint16_t parent;
+ uint16_t child;
+ uint16_t position;
+ uint8_t width;
+ } link_t;
+
+ for (unsigned i = 0; i < vertices_.length; i++)
+ {
+ for (const auto& l : vertices_[i].obj.real_links)
+ {
+ link_t link {
+ (uint16_t) i, (uint16_t) l.objidx,
+ (uint16_t) l.position, (uint8_t) l.width
+ };
+ fwrite ((void*) &link, sizeof (link), 1, f);
+ }
+ }
+
+ fclose (f);
+ }
+#endif
+
void print_orphaned_nodes ()
{
if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
@@ -949,6 +1067,10 @@ struct graph_t
parents_invalid = true;
update_parents();
+ if (root().parents) {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges.");
+ }
+
for (unsigned i = 0; i < root_idx (); i++)
{
const auto& v = vertices_[i];
@@ -1065,6 +1187,11 @@ struct graph_t
}
}
+ for (unsigned i = 0; i < vertices_.length; i++)
+ // parents arrays must be accurate or downstream operations like cycle detection
+ // and sorting won't work correctly.
+ check_success (!vertices_[i].parents.in_error ());
+
parents_invalid = false;
}
@@ -1183,7 +1310,7 @@ struct graph_t
{
for (auto& link : vertices_[i].obj.all_links_writer ())
{
- const unsigned *v;
+ const uint32_t *v;
if (!id_map.has (link.objidx, &v)) continue;
if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh b/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
index e8d5bef9a8..c170638409 100644
--- a/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
@@ -201,7 +201,7 @@ struct Lookup : public OT::Lookup
+ new_subtable_count * OT::Offset16::static_size;
char* buffer = (char*) hb_calloc (1, new_size);
c.add_buffer (buffer);
- memcpy (buffer, v.obj.head, v.table_size());
+ hb_memcpy (buffer, v.obj.head, v.table_size());
v.obj.head = buffer;
v.obj.tail = buffer + new_size;
@@ -355,7 +355,7 @@ struct GSTAR : public OT::GSUBGPOS
{
switch (u.version.major) {
case 1: return u.version1.get_lookup_list_offset ();
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.get_lookup_list_offset ();
#endif
default: return 0;
@@ -374,7 +374,7 @@ struct GSTAR : public OT::GSUBGPOS
{
switch (u.version.major) {
case 1: find_lookups<SmallTypes> (graph, lookups); break;
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 2: find_lookups<MediumTypes> (graph, lookups); break;
#endif
}
diff --git a/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh b/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh
index e42a6042cc..84ef5f71b9 100644
--- a/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh
@@ -112,7 +112,7 @@ struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix
auto& child = c.graph.vertices_[child_idx];
child.remove_parent (this_index);
- o.real_links.remove (i);
+ o.real_links.remove_unordered (i);
num_links--;
i--;
}
@@ -372,7 +372,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
if (!mark_coverage) return false;
hb_set_t marks = sc.marks_for (0, count);
auto new_coverage =
- + hb_zip (hb_range (), mark_coverage.table->iter ())
+ + hb_enumerate (mark_coverage.table->iter ())
| hb_filter (marks, hb_first)
| hb_map_retains_sorting (hb_second)
;
@@ -431,7 +431,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
if (!mark_coverage) return false;
hb_set_t marks = sc.marks_for (start, end);
auto new_coverage =
- + hb_zip (hb_range (), mark_coverage.table->iter ())
+ + hb_enumerate (mark_coverage.table->iter ())
| hb_filter (marks, hb_first)
| hb_map_retains_sorting (hb_second)
;
@@ -477,7 +477,7 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
switch (u.format) {
case 1:
return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 2: HB_FALLTHROUGH;
// Don't split 24bit PairPos's.
#endif
@@ -494,7 +494,7 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
switch (u.format) {
case 1:
return ((MarkBasePosFormat1*)(&u.format1))->sanitize (vertex);
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 2: HB_FALLTHROUGH;
#endif
default:
diff --git a/thirdparty/harfbuzz/src/graph/pairpos-graph.hh b/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
index 8040778ea3..1c13eb24f9 100644
--- a/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
@@ -434,7 +434,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
char* start_addr = ((char*)&values[0]) + start * split_context.class1_record_size;
unsigned num_records = end - start;
- memcpy (&pair_pos_prime->values[0],
+ hb_memcpy (&pair_pos_prime->values[0],
start_addr,
num_records * split_context.class1_record_size);
@@ -611,7 +611,7 @@ struct PairPos : public OT::Layout::GPOS_impl::PairPos
return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
case 2:
return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index);
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: HB_FALLTHROUGH;
case 4: HB_FALLTHROUGH;
// Don't split 24bit PairPos's.
@@ -631,7 +631,7 @@ struct PairPos : public OT::Layout::GPOS_impl::PairPos
return ((PairPosFormat1*)(&u.format1))->sanitize (vertex);
case 2:
return ((PairPosFormat2*)(&u.format2))->sanitize (vertex);
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
case 3: HB_FALLTHROUGH;
case 4: HB_FALLTHROUGH;
#endif
diff --git a/thirdparty/harfbuzz/src/graph/serialize.hh b/thirdparty/harfbuzz/src/graph/serialize.hh
index ecc6cc5aea..d03a61bd19 100644
--- a/thirdparty/harfbuzz/src/graph/serialize.hh
+++ b/thirdparty/harfbuzz/src/graph/serialize.hh
@@ -33,6 +33,23 @@ struct overflow_record_t
{
unsigned parent;
unsigned child;
+
+ bool operator != (const overflow_record_t o) const
+ { return !(*this == o); }
+
+ inline bool operator == (const overflow_record_t& o) const
+ {
+ return parent == o.parent &&
+ child == o.child;
+ }
+
+ inline uint32_t hash () const
+ {
+ uint32_t current = 0;
+ current = current * 31 + hb_hash (parent);
+ current = current * 31 + hb_hash (child);
+ return current;
+ }
};
inline
@@ -94,6 +111,7 @@ will_overflow (graph_t& graph,
if (overflows) overflows->resize (0);
graph.update_positions ();
+ hb_hashmap_t<overflow_record_t*, bool> record_set;
const auto& vertices = graph.vertices_;
for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--)
{
@@ -109,7 +127,10 @@ will_overflow (graph_t& graph,
overflow_record_t r;
r.parent = parent_idx;
r.child = link.objidx;
+ if (record_set.has(&r)) continue; // don't keep duplicate overflows.
+
overflows->push (r);
+ record_set.set(&r, true);
}
}
@@ -223,7 +244,7 @@ inline hb_blob_t* serialize (const graph_t& graph)
return nullptr;
}
- memcpy (start, vertices[i].obj.head, size);
+ hb_memcpy (start, vertices[i].obj.head, size);
// Only real links needs to be serialized.
for (const auto& link : vertices[i].obj.real_links)
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
index aa4ad4cf3c..8b9190d0be 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
+++ b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
@@ -131,14 +131,14 @@ struct RearrangementSubtable
hb_glyph_info_t *info = buffer->info;
hb_glyph_info_t buf[4];
- memcpy (buf, info + start, l * sizeof (buf[0]));
- memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
+ hb_memcpy (buf, info + start, l * sizeof (buf[0]));
+ hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
if (l != r)
memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
- memcpy (info + start, buf + 2, r * sizeof (buf[0]));
- memcpy (info + end - l, buf, l * sizeof (buf[0]));
+ hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
+ hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
if (reverse_l)
{
buf[0] = info[end - 1];
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout.cc b/thirdparty/harfbuzz/src/hb-aat-layout.cc
index d60126fe19..78427b0d5a 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout.cc
+++ b/thirdparty/harfbuzz/src/hb-aat-layout.cc
@@ -289,7 +289,7 @@ is_deleted_glyph (const hb_glyph_info_t *info)
void
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
{
- hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph);
+ buffer->delete_glyphs_inplace (is_deleted_glyph);
}
/**
diff --git a/thirdparty/harfbuzz/src/hb-aat-map.hh b/thirdparty/harfbuzz/src/hb-aat-map.hh
index c914f58d70..d0ee7d672c 100644
--- a/thirdparty/harfbuzz/src/hb-aat-map.hh
+++ b/thirdparty/harfbuzz/src/hb-aat-map.hh
@@ -38,7 +38,7 @@ struct hb_aat_map_t
void init ()
{
- memset (this, 0, sizeof (*this));
+ hb_memset (this, 0, sizeof (*this));
chain_flags.init ();
}
void fini () { chain_flags.fini (); }
diff --git a/thirdparty/harfbuzz/src/hb-algs.hh b/thirdparty/harfbuzz/src/hb-algs.hh
index cc37c073da..d85a4afe10 100644
--- a/thirdparty/harfbuzz/src/hb-algs.hh
+++ b/thirdparty/harfbuzz/src/hb-algs.hh
@@ -236,17 +236,6 @@ struct
template <typename T> constexpr auto
impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
- template <typename T> constexpr uint32_t
- impl (const hb::shared_ptr<T>& v, hb_priority<1>) const
- {
- return v.get () ? v.get ()->hash () : 0;
- }
- template <typename T> constexpr uint32_t
- impl (const hb::unique_ptr<T>& v, hb_priority<1>) const
- {
- return v.get () ? v.get ()->hash () : 0;
- }
-
template <typename T> constexpr auto
impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v)))
@@ -495,6 +484,17 @@ struct
}
HB_FUNCOBJ (hb_equal);
+struct
+{
+ template <typename T> void
+ operator () (T& a, T& b) const
+ {
+ using std::swap; // allow ADL
+ swap (a, b);
+ }
+}
+HB_FUNCOBJ (hb_swap);
+
template <typename T1, typename T2>
struct hb_pair_t
@@ -507,7 +507,7 @@ struct hb_pair_t
hb_enable_if (std::is_default_constructible<U1>::value &&
std::is_default_constructible<U2>::value)>
hb_pair_t () : first (), second () {}
- hb_pair_t (T1 a, T2 b) : first (a), second (b) {}
+ hb_pair_t (T1 a, T2 b) : first (std::forward<T1> (a)), second (std::forward<T2> (b)) {}
template <typename Q1, typename Q2,
hb_enable_if (hb_is_convertible (T1, Q1) &&
@@ -524,6 +524,25 @@ struct hb_pair_t
bool operator > (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); }
bool operator <= (const pair_t& o) const { return !(*this > o); }
+ static int cmp (const void *pa, const void *pb)
+ {
+ pair_t *a = (pair_t *) pa;
+ pair_t *b = (pair_t *) pb;
+
+ if (a->first < b->first) return -1;
+ if (a->first > b->first) return +1;
+ if (a->second < b->second) return -1;
+ if (a->second > b->second) return +1;
+ return 0;
+ }
+
+ friend void swap (hb_pair_t& a, hb_pair_t& b)
+ {
+ hb_swap (a.first, b.first);
+ hb_swap (a.second, b.second);
+ }
+
+
T1 first;
T2 second;
};
@@ -570,17 +589,6 @@ struct
}
HB_FUNCOBJ (hb_clamp);
-struct
-{
- template <typename T> void
- operator () (T& a, T& b) const
- {
- using std::swap; // allow ADL
- swap (a, b);
- }
-}
-HB_FUNCOBJ (hb_swap);
-
/*
* Bithacks.
*/
@@ -849,19 +857,14 @@ hb_in_range (T u, T lo, T hi)
return (T)(u - lo) <= (T)(hi - lo);
}
template <typename T> static inline bool
-hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
+hb_in_ranges (T u, T lo1, T hi1)
{
- return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
+ return hb_in_range (u, lo1, hi1);
}
-template <typename T> static inline bool
-hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
+template <typename T, typename ...Ts> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, Ts... ds)
{
- return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
-}
-template <typename T> static inline bool
-hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3, T lo4, T hi4)
-{
- return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3) || hb_in_range (u, lo4, hi4);
+ return hb_in_range<T> (u, lo1, hi1) || hb_in_ranges<T> (u, ds...);
}
@@ -869,10 +872,18 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3, T lo4, T hi4)
* Overflow checking.
*/
-/* Consider __builtin_mul_overflow use here also */
static inline bool
-hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
+hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr)
{
+#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+ unsigned stack_result;
+ if (!result)
+ result = &stack_result;
+ return __builtin_mul_overflow (count, size, result);
+#endif
+
+ if (result)
+ *result = count * size;
return (size > 0) && (count >= ((unsigned int) -1) / size);
}
@@ -1164,9 +1175,12 @@ hb_qsort (void *base, size_t nel, size_t width,
}
-template <typename T, typename T2, typename T3> static inline void
-hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2)
+template <typename T, typename T2, typename T3 = int> static inline void
+hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2 = nullptr)
{
+ static_assert (hb_is_trivially_copy_assignable (T), "");
+ static_assert (hb_is_trivially_copy_assignable (T3), "");
+
for (unsigned int i = 1; i < len; i++)
{
unsigned int j = i;
@@ -1189,12 +1203,6 @@ hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *)
}
}
-template <typename T> static inline void
-hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
-{
- hb_stable_sort (array, len, compar, (int *) nullptr);
-}
-
static inline hb_bool_t
hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
{
@@ -1322,47 +1330,4 @@ struct
HB_FUNCOBJ (hb_dec);
-/* Compiler-assisted vectorization. */
-
-/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
- * basically a fixed-size bitset. */
-template <typename elt_t, unsigned int byte_size>
-struct hb_vector_size_t
-{
- elt_t& operator [] (unsigned int i) { return v[i]; }
- const elt_t& operator [] (unsigned int i) const { return v[i]; }
-
- void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
-
- template <typename Op>
- hb_vector_size_t process (const Op& op) const
- {
- hb_vector_size_t r;
- for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
- r.v[i] = op (v[i]);
- return r;
- }
- template <typename Op>
- hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
- {
- hb_vector_size_t r;
- for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
- r.v[i] = op (v[i], o.v[i]);
- return r;
- }
- hb_vector_size_t operator | (const hb_vector_size_t &o) const
- { return process (hb_bitwise_or, o); }
- hb_vector_size_t operator & (const hb_vector_size_t &o) const
- { return process (hb_bitwise_and, o); }
- hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
- { return process (hb_bitwise_xor, o); }
- hb_vector_size_t operator ~ () const
- { return process (hb_bitwise_neg); }
-
- private:
- static_assert (0 == byte_size % sizeof (elt_t), "");
- elt_t v[byte_size / sizeof (elt_t)];
-};
-
-
#endif /* HB_ALGS_HH */
diff --git a/thirdparty/harfbuzz/src/hb-array.hh b/thirdparty/harfbuzz/src/hb-array.hh
index 5884007c19..17562bc336 100644
--- a/thirdparty/harfbuzz/src/hb-array.hh
+++ b/thirdparty/harfbuzz/src/hb-array.hh
@@ -100,10 +100,18 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
/* Ouch. The operator== compares the contents of the array. For range-based for loops,
* it's best if we can just compare arrayZ, though comparing contents is still fast,
* but also would require that Type has operator==. As such, we optimize this operator
- * for range-based for loop and just compare arrayZ and length. */
+ * for range-based for loop and just compare arrayZ and length.
+ *
+ * The above comment is outdated now because we implemented separate begin/end to
+ * objects that were using hb_array_t for range-based loop before. */
bool operator != (const hb_array_t& o) const
{ return this->arrayZ != o.arrayZ || this->length != o.length; }
+ /* Faster range-based for loop without bounds-check. */
+ Type *begin () const { return arrayZ; }
+ Type *end () const { return arrayZ + length; }
+
+
/* Extra operators.
*/
Type * operator & () const { return arrayZ; }
@@ -112,11 +120,11 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
HB_INTERNAL bool operator == (const hb_array_t &o) const;
- uint32_t hash () const {
+ uint32_t hash () const
+ {
uint32_t current = 0;
- for (unsigned int i = 0; i < this->length; i++) {
- current = current * 31 + hb_hash (this->arrayZ[i]);
- }
+ for (auto &v : *this)
+ current = current * 31 + hb_hash (v);
return current;
}
@@ -184,23 +192,18 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
{
+ //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), "");
if (likely (length))
hb_qsort (arrayZ, length, this->get_item_size (), cmp_);
return hb_sorted_array_t<Type> (*this);
}
hb_sorted_array_t<Type> qsort ()
{
+ //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), "");
if (likely (length))
hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp);
return hb_sorted_array_t<Type> (*this);
}
- void qsort (unsigned int start, unsigned int end)
- {
- end = hb_min (end, length);
- assert (start <= end);
- if (likely (start < end))
- hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp);
- }
/*
* Other methods.
@@ -262,17 +265,31 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
void fini ()
{ hb_free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
- template <typename hb_serialize_context_t>
+ template <typename hb_serialize_context_t,
+ typename U = Type,
+ hb_enable_if (!(sizeof (U) < sizeof (long long) && hb_is_trivially_copy_assignable(hb_decay<Type>)))>
hb_array_t copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
auto* out = c->start_embed (arrayZ);
- if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ());
+ if (unlikely (!c->extend_size (out, get_size (), false))) return_trace (hb_array_t ());
for (unsigned i = 0; i < length; i++)
out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */
return_trace (hb_array_t (out, length));
}
+ template <typename hb_serialize_context_t,
+ typename U = Type,
+ hb_enable_if (sizeof (U) < sizeof (long long) && hb_is_trivially_copy_assignable(hb_decay<Type>))>
+ hb_array_t copy (hb_serialize_context_t *c) const
+ {
+ TRACE_SERIALIZE (this);
+ auto* out = c->start_embed (arrayZ);
+ if (unlikely (!c->extend_size (out, get_size (), false))) return_trace (hb_array_t ());
+ hb_memcpy (out, arrayZ, get_size ());
+ return_trace (hb_array_t (out, length));
+ }
+
template <typename hb_sanitize_context_t>
bool sanitize (hb_sanitize_context_t *c) const
{ return c->check_array (arrayZ, length); }
@@ -295,8 +312,8 @@ hb_array (T (&array_)[length_])
template <typename Type>
struct hb_sorted_array_t :
- hb_iter_t<hb_sorted_array_t<Type>, Type&>,
- hb_array_t<Type>
+ hb_array_t<Type>,
+ hb_iter_t<hb_sorted_array_t<Type>, Type&>
{
typedef hb_iter_t<hb_sorted_array_t, Type&> iter_base_t;
HB_ITER_USING (iter_base_t);
@@ -316,8 +333,8 @@ struct hb_sorted_array_t :
template <typename U,
hb_enable_if (hb_is_cr_convertible(U, Type))>
constexpr hb_sorted_array_t (const hb_array_t<U> &o) :
- hb_iter_t<hb_sorted_array_t, Type&> (),
- hb_array_t<Type> (o) {}
+ hb_array_t<Type> (o),
+ hb_iter_t<hb_sorted_array_t, Type&> () {}
template <typename U,
hb_enable_if (hb_is_cr_convertible(U, Type))>
hb_sorted_array_t& operator = (const hb_array_t<U> &o)
@@ -329,6 +346,11 @@ struct hb_sorted_array_t :
bool operator != (const hb_sorted_array_t& o) const
{ return this->arrayZ != o.arrayZ || this->length != o.length; }
+ /* Faster range-based for loop without bounds-check. */
+ Type *begin () const { return this->arrayZ; }
+ Type *end () const { return this->arrayZ + this->length; }
+
+
hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
{ return hb_sorted_array_t (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
@@ -421,18 +443,42 @@ inline bool hb_array_t<const unsigned char>::operator == (const hb_array_t<const
return 0 == hb_memcmp (arrayZ, o.arrayZ, length);
}
+
+/* Specialize hash() for byte arrays. */
+
template <>
-inline uint32_t hb_array_t<const char>::hash () const {
+inline uint32_t hb_array_t<const char>::hash () const
+{
uint32_t current = 0;
- for (unsigned int i = 0; i < this->length; i++)
- current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
+ unsigned i = 0;
+
+#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
+ ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__))
+ struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
+ for (; i + 4 <= this->length; i += 4)
+ current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v);
+#endif
+
+ for (; i < this->length; i++)
+ current = current * 31 + hb_hash (this->arrayZ[i]);
return current;
}
+
template <>
-inline uint32_t hb_array_t<const unsigned char>::hash () const {
+inline uint32_t hb_array_t<const unsigned char>::hash () const
+{
uint32_t current = 0;
- for (unsigned int i = 0; i < this->length; i++)
- current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
+ unsigned i = 0;
+
+#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
+ ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__))
+ struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
+ for (; i + 4 <= this->length; i += 4)
+ current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v);
+#endif
+
+ for (; i < this->length; i++)
+ current = current * 31 + hb_hash (this->arrayZ[i]);
return current;
}
diff --git a/thirdparty/harfbuzz/src/hb-bit-page.hh b/thirdparty/harfbuzz/src/hb-bit-page.hh
index 95ae1b7bf9..11987054f8 100644
--- a/thirdparty/harfbuzz/src/hb-bit-page.hh
+++ b/thirdparty/harfbuzz/src/hb-bit-page.hh
@@ -30,6 +30,53 @@
#include "hb.hh"
+
+/* Compiler-assisted vectorization. */
+
+/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
+ * basically a fixed-size bitset. */
+template <typename elt_t, unsigned int byte_size>
+struct hb_vector_size_t
+{
+ elt_t& operator [] (unsigned int i) { return v[i]; }
+ const elt_t& operator [] (unsigned int i) const { return v[i]; }
+
+ void clear (unsigned char v = 0) { hb_memset (this, v, sizeof (*this)); }
+
+ template <typename Op>
+ hb_vector_size_t process (const Op& op) const
+ {
+ hb_vector_size_t r;
+ for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+ r.v[i] = op (v[i]);
+ return r;
+ }
+ template <typename Op>
+ hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
+ {
+ hb_vector_size_t r;
+ for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+ r.v[i] = op (v[i], o.v[i]);
+ return r;
+ }
+ hb_vector_size_t operator | (const hb_vector_size_t &o) const
+ { return process (hb_bitwise_or, o); }
+ hb_vector_size_t operator & (const hb_vector_size_t &o) const
+ { return process (hb_bitwise_and, o); }
+ hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
+ { return process (hb_bitwise_xor, o); }
+ hb_vector_size_t operator ~ () const
+ { return process (hb_bitwise_neg); }
+
+ hb_array_t<const elt_t> iter () const
+ { return hb_array (v); }
+
+ private:
+ static_assert (0 == byte_size % sizeof (elt_t), "");
+ elt_t v[byte_size / sizeof (elt_t)];
+};
+
+
struct hb_bit_page_t
{
void init0 () { v.clear (); }
@@ -40,17 +87,17 @@ struct hb_bit_page_t
bool is_empty () const
{
- for (unsigned i = 0; i < len (); i++)
- if (v[i])
- return false;
- return true;
+ return
+ + hb_iter (v)
+ | hb_none
+ ;
}
uint32_t hash () const
{
- uint32_t h = 0;
- for (unsigned i = 0; i < len (); i++)
- h = h * 31 + hb_hash (v[i]);
- return h;
+ return
+ + hb_iter (v)
+ | hb_reduce ([] (uint32_t h, const elt_t &_) { return h * 31 + hb_hash (_); }, (uint32_t) 0u)
+ ;
}
void add (hb_codepoint_t g) { elt (g) |= mask (g); }
@@ -69,7 +116,7 @@ struct hb_bit_page_t
*la |= ~(mask (a) - 1);
la++;
- memset (la, 0xff, (char *) lb - (char *) la);
+ hb_memset (la, 0xff, (char *) lb - (char *) la);
*lb |= ((mask (b) << 1) - 1);
}
@@ -85,7 +132,7 @@ struct hb_bit_page_t
*la &= mask (a) - 1;
la++;
- memset (la, 0, (char *) lb - (char *) la);
+ hb_memset (la, 0, (char *) lb - (char *) la);
*lb &= ~((mask (b) << 1) - 1);
}
@@ -101,13 +148,13 @@ struct hb_bit_page_t
hb_codepoint_t *p,
unsigned int size) const
{
- unsigned int start_v = start_value >> ELT_BITS_LOG_2;
+ unsigned int start_v = start_value / ELT_BITS;
unsigned int start_bit = start_value & ELT_MASK;
unsigned int count = 0;
for (unsigned i = start_v; i < len () && count < size; i++)
{
elt_t bits = v[i];
- uint32_t v_base = base | (i << ELT_BITS_LOG_2);
+ uint32_t v_base = base | (i * ELT_BITS);
for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++)
{
if ((elt_t(1) << j) & bits) {
@@ -132,13 +179,13 @@ struct hb_bit_page_t
unsigned int size,
hb_codepoint_t *next_value) const
{
- unsigned int start_v = start_value >> ELT_BITS_LOG_2;
+ unsigned int start_v = start_value / ELT_BITS;
unsigned int start_bit = start_value & ELT_MASK;
unsigned int count = 0;
for (unsigned i = start_v; i < len () && count < size; i++)
{
elt_t bits = v[i];
- uint32_t v_offset = i << ELT_BITS_LOG_2;
+ uint32_t v_offset = i * ELT_BITS;
for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++)
{
if ((elt_t(1) << j) & bits)
@@ -161,7 +208,10 @@ struct hb_bit_page_t
bool is_equal (const hb_bit_page_t &other) const
{
- return 0 == hb_memcmp (&v, &other.v, sizeof (v));
+ for (unsigned i = 0; i < len (); i++)
+ if (v[i] != other.v[i])
+ return false;
+ return true;
}
bool is_subset (const hb_bit_page_t &larger_page) const
{
@@ -173,10 +223,10 @@ struct hb_bit_page_t
unsigned int get_population () const
{
- unsigned int pop = 0;
- for (unsigned int i = 0; i < len (); i++)
- pop += hb_popcount (v[i]);
- return pop;
+ return
+ + hb_iter (v)
+ | hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u)
+ ;
}
bool next (hb_codepoint_t *codepoint) const
@@ -262,8 +312,6 @@ struct hb_bit_page_t
typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
- static constexpr unsigned ELT_BITS_LOG_2 = 6;
- static_assert (1 << ELT_BITS_LOG_2 == ELT_BITS, "");
static constexpr unsigned ELT_MASK = ELT_BITS - 1;
static constexpr unsigned BITS = sizeof (vector_t) * 8;
diff --git a/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh b/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh
index 27fb0732ea..ff8aecc60c 100644
--- a/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh
+++ b/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh
@@ -123,10 +123,8 @@ struct hb_bit_set_invertible_t
bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; }
/* Has interface. */
- static constexpr bool SENTINEL = false;
- typedef bool value_t;
- value_t operator [] (hb_codepoint_t k) const { return get (k); }
- bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ bool operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k]; }
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
diff --git a/thirdparty/harfbuzz/src/hb-bit-set.hh b/thirdparty/harfbuzz/src/hb-bit-set.hh
index a63887efda..8de6e037fb 100644
--- a/thirdparty/harfbuzz/src/hb-bit-set.hh
+++ b/thirdparty/harfbuzz/src/hb-bit-set.hh
@@ -85,10 +85,10 @@ struct hb_bit_set_t
void err () { if (successful) successful = false; } /* TODO Remove */
bool in_error () const { return !successful; }
- bool resize (unsigned int count)
+ bool resize (unsigned int count, bool clear = true)
{
if (unlikely (!successful)) return false;
- if (unlikely (!pages.resize (count) || !page_map.resize (count)))
+ if (unlikely (!pages.resize (count, clear) || !page_map.resize (count, clear)))
{
pages.resize (page_map.length);
successful = false;
@@ -330,10 +330,8 @@ struct hb_bit_set_t
}
/* Has interface. */
- static constexpr bool SENTINEL = false;
- typedef bool value_t;
- value_t operator [] (hb_codepoint_t k) const { return get (k); }
- bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ bool operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k]; }
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
@@ -352,7 +350,7 @@ struct hb_bit_set_t
{
if (unlikely (!successful)) return;
unsigned int count = other.pages.length;
- if (unlikely (!resize (count)))
+ if (unlikely (!resize (count, false)))
return;
population = other.population;
@@ -391,7 +389,7 @@ struct hb_bit_set_t
bool is_subset (const hb_bit_set_t &larger_set) const
{
if (has_population () && larger_set.has_population () &&
- population != larger_set.population)
+ population > larger_set.population)
return false;
uint32_t spi = 0;
@@ -540,21 +538,21 @@ struct hb_bit_set_t
b = nb;
for (; a && b; )
{
- if (page_map[a - 1].major == other.page_map[b - 1].major)
+ if (page_map.arrayZ[a - 1].major == other.page_map.arrayZ[b - 1].major)
{
a--;
b--;
count--;
- page_map[count] = page_map[a];
+ page_map.arrayZ[count] = page_map.arrayZ[a];
page_at (count).v = op (page_at (a).v, other.page_at (b).v);
}
- else if (page_map[a - 1].major > other.page_map[b - 1].major)
+ else if (page_map.arrayZ[a - 1].major > other.page_map.arrayZ[b - 1].major)
{
a--;
if (passthru_left)
{
count--;
- page_map[count] = page_map[a];
+ page_map.arrayZ[count] = page_map.arrayZ[a];
}
}
else
@@ -563,8 +561,8 @@ struct hb_bit_set_t
if (passthru_right)
{
count--;
- page_map[count].major = other.page_map[b].major;
- page_map[count].index = next_page++;
+ page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
+ page_map.arrayZ[count].index = next_page++;
page_at (count).v = other.page_at (b).v;
}
}
@@ -574,15 +572,15 @@ struct hb_bit_set_t
{
a--;
count--;
- page_map[count] = page_map [a];
+ page_map.arrayZ[count] = page_map.arrayZ[a];
}
if (passthru_right)
while (b)
{
b--;
count--;
- page_map[count].major = other.page_map[b].major;
- page_map[count].index = next_page++;
+ page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
+ page_map.arrayZ[count].index = next_page++;
page_at (count).v = other.page_at (b).v;
}
assert (!count);
@@ -605,8 +603,6 @@ struct hb_bit_set_t
bool next (hb_codepoint_t *codepoint) const
{
- // TODO: this should be merged with prev() as both implementations
- // are very similar.
if (unlikely (*codepoint == INVALID)) {
*codepoint = get_min ();
return *codepoint != INVALID;
@@ -640,7 +636,7 @@ struct hb_bit_set_t
for (; i < page_map.length; i++)
{
- const page_map_t &current = page_map.arrayZ[i];
+ const page_map_t &current = page_map_array[i];
hb_codepoint_t m = pages_array[current.index].get_min ();
if (m != INVALID)
{
@@ -663,21 +659,21 @@ struct hb_bit_set_t
page_map_t map = {get_major (*codepoint), 0};
unsigned int i;
page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST);
- if (i < page_map.length && page_map[i].major == map.major)
+ if (i < page_map.length && page_map.arrayZ[i].major == map.major)
{
- if (pages[page_map[i].index].previous (codepoint))
+ if (pages[page_map.arrayZ[i].index].previous (codepoint))
{
- *codepoint += page_map[i].major * page_t::PAGE_BITS;
+ *codepoint += page_map.arrayZ[i].major * page_t::PAGE_BITS;
return true;
}
}
i--;
for (; (int) i >= 0; i--)
{
- hb_codepoint_t m = pages[page_map[i].index].get_max ();
+ hb_codepoint_t m = pages.arrayZ[page_map.arrayZ[i].index].get_max ();
if (m != INVALID)
{
- *codepoint = page_map[i].major * page_t::PAGE_BITS + m;
+ *codepoint = page_map.arrayZ[i].major * page_t::PAGE_BITS + m;
return true;
}
}
@@ -905,7 +901,7 @@ struct hb_bit_set_t
{
auto &cached_page = page_map.arrayZ[i];
if (cached_page.major == major)
- return &pages[cached_page.index];
+ return &pages.arrayZ[cached_page.index];
}
page_map_t map = {major, pages.length};
@@ -917,15 +913,15 @@ struct hb_bit_set_t
if (unlikely (!resize (pages.length + 1)))
return nullptr;
- pages[map.index].init0 ();
- memmove (page_map + i + 1,
- page_map + i,
+ pages.arrayZ[map.index].init0 ();
+ memmove (page_map.arrayZ + i + 1,
+ page_map.arrayZ + i,
(page_map.length - 1 - i) * page_map.item_size);
page_map[i] = map;
}
last_page_lookup = i;
- return &pages[page_map[i].index];
+ return &pages.arrayZ[page_map.arrayZ[i].index];
}
const page_t *page_for (hb_codepoint_t g) const
{
@@ -939,7 +935,7 @@ struct hb_bit_set_t
{
auto &cached_page = page_map.arrayZ[i];
if (cached_page.major == major)
- return &pages[cached_page.index];
+ return &pages.arrayZ[cached_page.index];
}
page_map_t key = {major};
@@ -947,10 +943,18 @@ struct hb_bit_set_t
return nullptr;
last_page_lookup = i;
- return &pages[page_map[i].index];
+ return &pages.arrayZ[page_map[i].index];
+ }
+ page_t &page_at (unsigned int i)
+ {
+ assert (i < page_map.length);
+ return pages.arrayZ[page_map.arrayZ[i].index];
+ }
+ const page_t &page_at (unsigned int i) const
+ {
+ assert (i < page_map.length);
+ return pages.arrayZ[page_map.arrayZ[i].index];
}
- page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
- const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
unsigned int get_major (hb_codepoint_t g) const { return g >> page_t::PAGE_BITS_LOG_2; }
unsigned int page_remainder (hb_codepoint_t g) const { return g & page_t::PAGE_BITMASK; }
hb_codepoint_t major_start (unsigned int major) const { return major << page_t::PAGE_BITS_LOG_2; }
diff --git a/thirdparty/harfbuzz/src/hb-blob.cc b/thirdparty/harfbuzz/src/hb-blob.cc
index 9bc12ea3fa..f0fda1fa4d 100644
--- a/thirdparty/harfbuzz/src/hb-blob.cc
+++ b/thirdparty/harfbuzz/src/hb-blob.cc
@@ -495,7 +495,7 @@ hb_blob_t::try_make_writable ()
DEBUG_MSG_FUNC (BLOB, this, "dupped successfully -> %p\n", this->data);
- memcpy (new_data, this->data, this->length);
+ hb_memcpy (new_data, this->data, this->length);
this->destroy_user_data ();
this->mode = HB_MEMORY_MODE_WRITABLE;
this->data = new_data;
diff --git a/thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh b/thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh
index 87095855d6..993bb1f698 100644
--- a/thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh
+++ b/thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh
@@ -32,7 +32,7 @@
#include "hb.hh"
-#line 36 "hb-buffer-deserialize-json.hh"
+#line 33 "hb-buffer-deserialize-json.hh"
static const unsigned char _deserialize_json_trans_keys[] = {
0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u,
48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u,
@@ -557,12 +557,12 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};
-#line 561 "hb-buffer-deserialize-json.hh"
+#line 554 "hb-buffer-deserialize-json.hh"
{
cs = deserialize_json_start;
}
-#line 566 "hb-buffer-deserialize-json.hh"
+#line 557 "hb-buffer-deserialize-json.hh"
{
int _slen;
int _trans;
@@ -590,8 +590,8 @@ _resume:
case 1:
#line 38 "hb-buffer-deserialize-json.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
break;
case 5:
@@ -774,7 +774,7 @@ _resume:
*end_ptr = p;
}
break;
-#line 778 "hb-buffer-deserialize-json.hh"
+#line 735 "hb-buffer-deserialize-json.hh"
}
_again:
diff --git a/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh b/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh
index 9062610de2..6b9b4282fc 100644
--- a/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh
+++ b/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh
@@ -32,32 +32,30 @@
#include "hb.hh"
-#line 36 "hb-buffer-deserialize-text.hh"
+#line 33 "hb-buffer-deserialize-text.hh"
static const unsigned char _deserialize_text_trans_keys[] = {
- 0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 45u, 57u,
- 48u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u,
- 44u, 57u, 43u, 124u, 45u, 57u, 48u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u,
+ 0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 48u, 57u,
+ 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u,
+ 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u,
9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u,
9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u,
- 9u, 124u, 9u, 124u, 9u, 124u, 0
+ 0
};
static const char _deserialize_text_key_spans[] = {
- 0, 83, 1, 1, 55, 77, 10, 13,
- 10, 10, 10, 13, 10, 1, 13, 10,
- 14, 82, 13, 10, 116, 116, 0, 77,
- 116, 116, 116, 116, 116, 116, 116, 116,
+ 0, 83, 1, 1, 55, 77, 10, 10,
+ 13, 10, 13, 10, 10, 13, 10, 1,
+ 13, 10, 14, 82, 116, 116, 0, 77,
116, 116, 116, 116, 116, 116, 116, 116,
- 116, 116, 116
+ 116, 116, 116, 116, 116, 116, 116, 116
};
static const short _deserialize_text_index_offsets[] = {
0, 0, 84, 86, 88, 144, 222, 233,
- 247, 258, 269, 280, 294, 305, 307, 321,
- 332, 347, 430, 444, 455, 572, 689, 690,
+ 244, 258, 269, 283, 294, 305, 319, 330,
+ 332, 346, 357, 372, 455, 572, 689, 690,
768, 885, 1002, 1119, 1236, 1353, 1470, 1587,
- 1704, 1821, 1938, 2055, 2172, 2289, 2406, 2523,
- 2640, 2757, 2874
+ 1704, 1821, 1938, 2055, 2172, 2289, 2406, 2523
};
static const char _deserialize_text_indicies[] = {
@@ -90,34 +88,34 @@ static const char _deserialize_text_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 4, 1, 8,
9, 9, 9, 9, 9, 9, 9, 9,
- 9, 1, 10, 1, 1, 11, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 1,
+ 9, 1, 10, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 1, 12, 1, 1,
13, 14, 14, 14, 14, 14, 14, 14,
14, 14, 1, 15, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 1, 17, 18,
- 18, 18, 18, 18, 18, 18, 18, 18,
- 1, 19, 1, 1, 20, 21, 21, 21,
+ 16, 16, 16, 16, 16, 1, 17, 1,
+ 1, 18, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 1, 20, 21, 21, 21,
21, 21, 21, 21, 21, 21, 1, 22,
23, 23, 23, 23, 23, 23, 23, 23,
- 23, 1, 24, 1, 25, 1, 1, 26,
- 27, 27, 27, 27, 27, 27, 27, 27,
- 27, 1, 28, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 1, 24, 1, 1,
- 1, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 1, 30, 30, 1, 1,
+ 23, 1, 24, 1, 1, 25, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 1,
+ 27, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 1, 29, 1, 30, 1, 1,
+ 31, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 1, 33, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 1, 29, 1,
+ 1, 1, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 1, 35, 35, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 30, 1,
- 1, 30, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 35,
+ 1, 1, 35, 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, 30, 30, 1,
+ 1, 1, 1, 1, 1, 1, 35, 35,
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, 30, 1, 31,
- 1, 1, 32, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 1, 34, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 1,
+ 1, 1, 1, 1, 1, 1, 35, 1,
36, 36, 36, 36, 36, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 36,
@@ -201,282 +199,235 @@ static const char _deserialize_text_indicies[] = {
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 56, 48,
- 57, 57, 57, 57, 57, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 57,
- 30, 30, 58, 30, 30, 30, 30, 30,
- 30, 30, 59, 1, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 60, 30, 30, 61,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 62, 63, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 64, 30, 57, 57, 57,
- 57, 57, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 57, 30, 30, 58,
- 30, 30, 30, 30, 30, 30, 30, 59,
- 1, 30, 30, 30, 65, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 30, 30,
- 30, 60, 30, 30, 61, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 62, 63, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 64, 30, 67, 67, 67, 67, 67, 1,
+ 57, 57, 57, 57, 57, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 57,
+ 35, 35, 58, 35, 35, 35, 35, 35,
+ 35, 35, 59, 1, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 60, 35, 35, 61,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 62, 63, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 64, 35, 65, 65, 65,
+ 65, 65, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 65, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 67, 1, 1, 68, 1, 1, 1,
- 1, 1, 1, 1, 1, 69, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 70, 1,
+ 1, 66, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 71, 1, 72,
- 72, 72, 72, 72, 1, 1, 1, 1,
+ 67, 1, 68, 68, 68, 68, 68, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 72, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 68, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 42, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 42, 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, 73, 1, 74, 74, 74, 74,
- 74, 48, 48, 48, 48, 48, 48, 48,
+ 1, 1, 1, 1, 1, 69, 1, 70,
+ 70, 70, 70, 70, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 74, 48, 48, 50, 48,
- 48, 48, 48, 48, 48, 48, 51, 1,
+ 48, 48, 48, 48, 48, 48, 70, 48,
+ 48, 50, 48, 48, 48, 48, 48, 48,
+ 48, 51, 1, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 52, 48, 48, 53, 48,
48, 48, 48, 48, 48, 48, 48, 48,
- 52, 48, 48, 53, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 54,
- 55, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 54, 55, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 56,
- 48, 75, 75, 75, 75, 75, 1, 1,
+ 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 56, 48, 71, 71, 71, 71,
+ 71, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 71, 1, 1, 72, 1,
+ 1, 1, 1, 1, 1, 1, 1, 73,
1, 1, 1, 1, 1, 1, 1, 1,
- 75, 1, 1, 76, 1, 1, 1, 1,
- 1, 1, 1, 77, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 78, 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, 45, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 74, 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, 79, 1, 80, 80,
- 80, 80, 80, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 75,
+ 1, 76, 76, 76, 76, 76, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 80, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 76, 1, 1, 77, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 81, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 78, 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, 82, 1, 80, 80, 80, 80, 80,
+ 1, 1, 1, 1, 79, 1, 76, 76,
+ 76, 76, 76, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 76, 1, 1,
+ 77, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 80, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 83, 83, 83, 83, 83, 83,
- 83, 83, 83, 83, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 78, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 81,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 79, 1, 71, 71, 71, 71, 71,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 82, 1,
- 84, 84, 84, 84, 84, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 84,
- 1, 1, 85, 1, 1, 1, 1, 1,
- 1, 1, 86, 1, 1, 1, 1, 1,
+ 1, 1, 71, 1, 1, 72, 1, 1,
+ 1, 1, 1, 1, 1, 1, 73, 1,
+ 1, 1, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 74,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 87, 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, 75, 1,
+ 80, 80, 80, 80, 80, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 88, 1, 84, 84, 84,
- 84, 84, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 80,
+ 1, 1, 81, 1, 1, 1, 1, 1,
+ 1, 1, 82, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 84, 1, 1, 85,
- 1, 1, 1, 1, 1, 1, 1, 86,
- 1, 1, 1, 1, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 83,
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, 45, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 87, 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, 84, 1, 85, 85, 85,
+ 85, 85, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 88, 1, 75, 75, 75, 75, 75, 1,
+ 1, 1, 1, 1, 85, 1, 1, 86,
+ 1, 1, 1, 1, 1, 1, 1, 87,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 75, 1, 1, 76, 1, 1, 1,
- 1, 1, 1, 1, 77, 1, 1, 1,
- 1, 89, 89, 89, 89, 89, 89, 89,
- 89, 89, 89, 1, 1, 1, 1, 1,
- 1, 78, 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, 45, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 88, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 79, 1, 90,
- 90, 90, 90, 90, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 90, 1,
- 1, 91, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 89, 1, 85, 85, 85, 85, 85, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 85, 1, 1, 86, 1, 1, 1,
+ 1, 1, 1, 1, 87, 1, 1, 1,
+ 1, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 92, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 88, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 93, 1, 90, 90, 90, 90,
- 90, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 90, 1, 1, 91, 1,
+ 1, 1, 1, 1, 1, 89, 1, 80,
+ 80, 80, 80, 80, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 80, 1,
+ 1, 81, 1, 1, 1, 1, 1, 1,
+ 1, 82, 1, 1, 1, 1, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90,
+ 1, 1, 1, 1, 1, 1, 83, 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, 45, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 92, 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, 93,
- 1, 67, 67, 67, 67, 67, 1, 1,
+ 1, 1, 84, 1, 65, 65, 65, 65,
+ 65, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 65, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 67, 1, 1, 68, 1, 1, 1, 1,
- 1, 1, 1, 1, 69, 1, 1, 1,
- 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 91, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 70, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 66, 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, 71, 1, 94, 94,
- 94, 94, 94, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 94, 30, 30,
- 58, 30, 30, 30, 30, 30, 30, 30,
- 59, 1, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 60, 30, 30, 61, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 62, 95, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 96, 30, 94, 94, 94, 94, 94,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 94, 30, 30, 58, 30, 30,
- 30, 30, 30, 30, 30, 59, 1, 30,
- 30, 30, 97, 97, 97, 97, 97, 97,
- 97, 97, 97, 97, 30, 30, 30, 60,
- 30, 30, 61, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 62, 95,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 96, 30,
- 0
+ 1, 1, 1, 1, 1, 1, 1, 67,
+ 1, 0
};
static const char _deserialize_text_trans_targs[] = {
1, 0, 2, 26, 3, 4, 20, 5,
- 24, 25, 8, 29, 40, 29, 40, 32,
- 37, 33, 34, 12, 13, 16, 13, 16,
- 14, 15, 35, 36, 35, 36, 27, 19,
- 38, 39, 38, 39, 21, 20, 6, 22,
+ 24, 25, 28, 39, 9, 31, 34, 31,
+ 34, 11, 32, 33, 32, 33, 35, 38,
+ 14, 15, 18, 15, 18, 16, 17, 36,
+ 37, 36, 37, 27, 21, 20, 6, 22,
23, 21, 22, 23, 21, 22, 23, 25,
- 27, 27, 28, 7, 9, 11, 17, 22,
- 31, 27, 28, 7, 9, 11, 17, 22,
- 31, 41, 42, 30, 10, 18, 22, 31,
- 30, 31, 31, 30, 10, 7, 11, 31,
- 30, 22, 31, 34, 30, 10, 7, 22,
- 31, 37, 30, 10, 22, 31, 27, 22,
- 31, 42
+ 27, 27, 7, 8, 12, 13, 19, 22,
+ 30, 27, 7, 8, 12, 13, 19, 22,
+ 30, 29, 22, 30, 29, 30, 30, 29,
+ 7, 10, 22, 30, 29, 7, 22, 30,
+ 29, 7, 8, 13, 30, 29, 7, 8,
+ 22, 30, 38, 39
};
static const char _deserialize_text_trans_actions[] = {
0, 0, 0, 0, 1, 0, 2, 0,
- 2, 2, 3, 4, 4, 5, 5, 4,
- 4, 4, 4, 3, 3, 3, 0, 0,
- 6, 3, 4, 4, 5, 5, 5, 3,
- 4, 4, 5, 5, 7, 8, 9, 7,
+ 2, 2, 3, 3, 4, 3, 3, 5,
+ 5, 4, 3, 3, 5, 5, 3, 3,
+ 4, 4, 4, 0, 0, 6, 4, 3,
+ 3, 5, 5, 5, 7, 8, 9, 7,
7, 0, 0, 0, 10, 10, 10, 8,
- 12, 13, 14, 15, 15, 15, 16, 11,
- 11, 18, 19, 20, 20, 20, 0, 17,
- 17, 4, 4, 21, 22, 22, 21, 21,
- 0, 0, 13, 10, 23, 23, 23, 10,
- 24, 24, 24, 5, 25, 26, 26, 25,
- 25, 5, 27, 28, 27, 27, 30, 29,
- 29, 5
+ 12, 13, 14, 14, 14, 14, 15, 11,
+ 11, 17, 18, 18, 18, 18, 0, 16,
+ 16, 19, 19, 19, 0, 0, 13, 20,
+ 21, 21, 20, 20, 22, 23, 22, 22,
+ 10, 24, 24, 24, 10, 25, 26, 26,
+ 25, 25, 5, 5
};
static const char _deserialize_text_eof_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 7, 0, 0, 0,
- 10, 10, 11, 17, 17, 21, 0, 11,
- 10, 24, 24, 25, 25, 10, 27, 27,
- 21, 29, 29
+ 10, 10, 11, 16, 19, 0, 11, 20,
+ 22, 22, 20, 10, 25, 25, 10, 19
};
static const int deserialize_text_start = 1;
@@ -509,12 +460,12 @@ _hb_buffer_deserialize_text (hb_buffer_t *buffer,
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};
-#line 513 "hb-buffer-deserialize-text.hh"
+#line 457 "hb-buffer-deserialize-text.hh"
{
cs = deserialize_text_start;
}
-#line 518 "hb-buffer-deserialize-text.hh"
+#line 460 "hb-buffer-deserialize-text.hh"
{
int _slen;
int _trans;
@@ -542,11 +493,11 @@ _resume:
case 1:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
break;
- case 3:
+ case 4:
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
@@ -560,7 +511,7 @@ _resume:
#line 56 "hb-buffer-deserialize-text.rl"
{ if (unlikely (!buffer->ensure_unicode ())) return false; }
break;
- case 20:
+ case 18:
#line 58 "hb-buffer-deserialize-text.rl"
{
/* TODO Unescape delimiters. */
@@ -574,7 +525,7 @@ _resume:
#line 66 "hb-buffer-deserialize-text.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
break;
- case 23:
+ case 24:
#line 68 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
break;
@@ -586,26 +537,26 @@ _resume:
#line 70 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
break;
- case 22:
+ case 21:
#line 71 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
break;
- case 28:
+ case 23:
#line 72 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
break;
- case 16:
+ case 15:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
break;
- case 4:
+ case 3:
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
@@ -621,7 +572,7 @@ _resume:
#line 56 "hb-buffer-deserialize-text.rl"
{ if (unlikely (!buffer->ensure_unicode ())) return false; }
break;
- case 17:
+ case 16:
#line 58 "hb-buffer-deserialize-text.rl"
{
/* TODO Unescape delimiters. */
@@ -639,18 +590,6 @@ _resume:
*end_ptr = p;
}
break;
- case 19:
-#line 58 "hb-buffer-deserialize-text.rl"
- {
- /* TODO Unescape delimiters. */
- if (!hb_font_glyph_from_string (font,
- tok, p - tok,
- &info.codepoint))
- return false;
-}
-#line 55 "hb-buffer-deserialize-text.rl"
- { if (unlikely (!buffer->ensure_glyphs ())) return false; }
- break;
case 7:
#line 66 "hb-buffer-deserialize-text.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
@@ -687,7 +626,7 @@ _resume:
*end_ptr = p;
}
break;
- case 21:
+ case 20:
#line 71 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
@@ -699,7 +638,7 @@ _resume:
*end_ptr = p;
}
break;
- case 27:
+ case 22:
#line 72 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
@@ -711,7 +650,7 @@ _resume:
*end_ptr = p;
}
break;
- case 24:
+ case 19:
#line 73 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.mask )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
@@ -726,8 +665,8 @@ _resume:
case 12:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
@@ -736,11 +675,11 @@ _resume:
#line 55 "hb-buffer-deserialize-text.rl"
{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
break;
- case 15:
+ case 14:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
@@ -755,7 +694,7 @@ _resume:
return false;
}
break;
- case 18:
+ case 17:
#line 58 "hb-buffer-deserialize-text.rl"
{
/* TODO Unescape delimiters. */
@@ -775,31 +714,11 @@ _resume:
*end_ptr = p;
}
break;
- case 29:
-#line 58 "hb-buffer-deserialize-text.rl"
- {
- /* TODO Unescape delimiters. */
- if (!hb_font_glyph_from_string (font,
- tok, p - tok,
- &info.codepoint))
- return false;
-}
-#line 73 "hb-buffer-deserialize-text.rl"
- { if (!parse_uint (tok, p, &info.mask )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
- {
- buffer->add_info (info);
- if (unlikely (!buffer->successful))
- return false;
- buffer->pos[buffer->len - 1] = pos;
- *end_ptr = p;
-}
- break;
case 11:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
@@ -822,54 +741,11 @@ _resume:
*end_ptr = p;
}
break;
- case 14:
-#line 38 "hb-buffer-deserialize-text.rl"
- {
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
- {
- tok = p;
-}
-#line 58 "hb-buffer-deserialize-text.rl"
- {
- /* TODO Unescape delimiters. */
- if (!hb_font_glyph_from_string (font,
- tok, p - tok,
- &info.codepoint))
- return false;
-}
-#line 55 "hb-buffer-deserialize-text.rl"
- { if (unlikely (!buffer->ensure_glyphs ())) return false; }
- break;
- case 30:
-#line 58 "hb-buffer-deserialize-text.rl"
- {
- /* TODO Unescape delimiters. */
- if (!hb_font_glyph_from_string (font,
- tok, p - tok,
- &info.codepoint))
- return false;
-}
-#line 73 "hb-buffer-deserialize-text.rl"
- { if (!parse_uint (tok, p, &info.mask )) return false; }
-#line 55 "hb-buffer-deserialize-text.rl"
- { if (unlikely (!buffer->ensure_glyphs ())) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
- {
- buffer->add_info (info);
- if (unlikely (!buffer->successful))
- return false;
- buffer->pos[buffer->len - 1] = pos;
- *end_ptr = p;
-}
- break;
case 13:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
@@ -894,7 +770,7 @@ _resume:
*end_ptr = p;
}
break;
-#line 898 "hb-buffer-deserialize-text.hh"
+#line 715 "hb-buffer-deserialize-text.hh"
}
_again:
@@ -906,7 +782,7 @@ _again:
if ( p == eof )
{
switch ( _deserialize_text_eof_actions[cs] ) {
- case 17:
+ case 16:
#line 58 "hb-buffer-deserialize-text.rl"
{
/* TODO Unescape delimiters. */
@@ -960,7 +836,7 @@ _again:
*end_ptr = p;
}
break;
- case 21:
+ case 20:
#line 71 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
@@ -972,7 +848,7 @@ _again:
*end_ptr = p;
}
break;
- case 27:
+ case 22:
#line 72 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
@@ -984,27 +860,7 @@ _again:
*end_ptr = p;
}
break;
- case 24:
-#line 73 "hb-buffer-deserialize-text.rl"
- { if (!parse_uint (tok, p, &info.mask )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
- {
- buffer->add_info (info);
- if (unlikely (!buffer->successful))
- return false;
- buffer->pos[buffer->len - 1] = pos;
- *end_ptr = p;
-}
- break;
- case 29:
-#line 58 "hb-buffer-deserialize-text.rl"
- {
- /* TODO Unescape delimiters. */
- if (!hb_font_glyph_from_string (font,
- tok, p - tok,
- &info.codepoint))
- return false;
-}
+ case 19:
#line 73 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.mask )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
@@ -1019,8 +875,8 @@ _again:
case 11:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
@@ -1043,7 +899,7 @@ _again:
*end_ptr = p;
}
break;
-#line 1047 "hb-buffer-deserialize-text.hh"
+#line 825 "hb-buffer-deserialize-text.hh"
}
}
diff --git a/thirdparty/harfbuzz/src/hb-buffer-serialize.cc b/thirdparty/harfbuzz/src/hb-buffer-serialize.cc
index d1e1775430..a458f2318f 100644
--- a/thirdparty/harfbuzz/src/hb-buffer-serialize.cc
+++ b/thirdparty/harfbuzz/src/hb-buffer-serialize.cc
@@ -183,7 +183,7 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
unsigned int l = p - b;
if (buf_size > l)
{
- memcpy (buf, b, l);
+ hb_memcpy (buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
@@ -241,7 +241,7 @@ _hb_buffer_serialize_unicode_json (hb_buffer_t *buffer,
unsigned int l = p - b;
if (buf_size > l)
{
- memcpy (buf, b, l);
+ hb_memcpy (buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
@@ -329,7 +329,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
unsigned int l = p - b;
if (buf_size > l)
{
- memcpy (buf, b, l);
+ hb_memcpy (buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
@@ -381,7 +381,7 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
unsigned int l = p - b;
if (buf_size > l)
{
- memcpy (buf, b, l);
+ hb_memcpy (buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
diff --git a/thirdparty/harfbuzz/src/hb-buffer-verify.cc b/thirdparty/harfbuzz/src/hb-buffer-verify.cc
index 5453e1ca94..1cd52b39b1 100644
--- a/thirdparty/harfbuzz/src/hb-buffer-verify.cc
+++ b/thirdparty/harfbuzz/src/hb-buffer-verify.cc
@@ -186,7 +186,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
bool ret = true;
hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
- if (diff)
+ if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed.");
ret = false;
@@ -313,7 +313,6 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
bool ret = true;
hb_buffer_diff_flags_t diff;
-
/*
* Shape the two fragment streams.
*/
@@ -382,7 +381,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
* Diff results.
*/
diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
- if (diff)
+ if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed.");
ret = false;
diff --git a/thirdparty/harfbuzz/src/hb-buffer.cc b/thirdparty/harfbuzz/src/hb-buffer.cc
index 57a5ae03ed..4b6c2d9eaa 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.cc
+++ b/thirdparty/harfbuzz/src/hb-buffer.cc
@@ -172,12 +172,13 @@ hb_buffer_t::enlarge (unsigned int size)
while (size >= new_allocated)
new_allocated += (new_allocated >> 1) + 32;
- static_assert ((sizeof (info[0]) == sizeof (pos[0])), "");
- if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]))))
+ unsigned new_bytes;
+ if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]), &new_bytes)))
goto done;
- new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_allocated * sizeof (pos[0]));
- new_info = (hb_glyph_info_t *) hb_realloc (info, new_allocated * sizeof (info[0]));
+ static_assert (sizeof (info[0]) == sizeof (pos[0]), "");
+ new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_bytes);
+ new_info = (hb_glyph_info_t *) hb_realloc (info, new_bytes);
done:
if (unlikely (!new_pos || !new_info))
@@ -208,7 +209,7 @@ hb_buffer_t::make_room_for (unsigned int num_in,
assert (have_output);
out_info = (hb_glyph_info_t *) pos;
- memcpy (out_info, info, out_len * sizeof (out_info[0]));
+ hb_memcpy (out_info, info, out_len * sizeof (out_info[0]));
}
return true;
@@ -229,7 +230,7 @@ hb_buffer_t::shift_forward (unsigned int count)
* Ideally, we should at least set Default_Ignorable bits on
* these, as well as consistent cluster values. But the former
* is layering violation... */
- memset (info + len, 0, (idx + count - len) * sizeof (info[0]));
+ hb_memset (info + len, 0, (idx + count - len) * sizeof (info[0]));
}
len += count;
idx += count;
@@ -298,8 +299,8 @@ hb_buffer_t::clear ()
out_len = 0;
out_info = info;
- memset (context, 0, sizeof context);
- memset (context_len, 0, sizeof context_len);
+ hb_memset (context, 0, sizeof context);
+ hb_memset (context_len, 0, sizeof context_len);
deallocate_var_all ();
serial = 0;
@@ -313,15 +314,14 @@ hb_buffer_t::enter ()
serial = 0;
shaping_failed = false;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
- if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR)))
+ unsigned mul;
+ if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul)))
{
- max_len = hb_max (len * HB_BUFFER_MAX_LEN_FACTOR,
- (unsigned) HB_BUFFER_MAX_LEN_MIN);
+ max_len = hb_max (mul, (unsigned) HB_BUFFER_MAX_LEN_MIN);
}
- if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR)))
+ if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR, &mul)))
{
- max_ops = hb_max (len * HB_BUFFER_MAX_OPS_FACTOR,
- (unsigned) HB_BUFFER_MAX_OPS_MIN);
+ max_ops = hb_max (mul, (unsigned) HB_BUFFER_MAX_OPS_MIN);
}
}
void
@@ -345,7 +345,7 @@ hb_buffer_t::add (hb_codepoint_t codepoint,
glyph = &info[len];
- memset (glyph, 0, sizeof (*glyph));
+ hb_memset (glyph, 0, sizeof (*glyph));
glyph->codepoint = codepoint;
glyph->mask = 0;
glyph->cluster = cluster;
@@ -606,6 +606,53 @@ done:
}
void
+hb_buffer_t::delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info))
+{
+ /* Merge clusters and delete filtered glyphs.
+ * NOTE! We can't use out-buffer as we have positioning data. */
+ unsigned int j = 0;
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (filter (&info[i]))
+ {
+ /* Merge clusters.
+ * Same logic as delete_glyph(), but for in-place removal. */
+
+ unsigned int cluster = info[i].cluster;
+ if (i + 1 < count && cluster == info[i + 1].cluster)
+ continue; /* Cluster survives; do nothing. */
+
+ if (j)
+ {
+ /* Merge cluster backward. */
+ if (cluster < info[j - 1].cluster)
+ {
+ unsigned int mask = info[i].mask;
+ unsigned int old_cluster = info[j - 1].cluster;
+ for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
+ set_cluster (info[k - 1], cluster, mask);
+ }
+ continue;
+ }
+
+ if (i + 1 < count)
+ merge_clusters (i, i + 2); /* Merge cluster forward. */
+
+ continue;
+ }
+
+ if (j != i)
+ {
+ info[j] = info[i];
+ pos[j] = pos[i];
+ }
+ j++;
+ }
+ len = j;
+}
+
+void
hb_buffer_t::guess_segment_properties ()
{
assert_unicode ();
@@ -933,7 +980,6 @@ hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer)
void
hb_buffer_set_direction (hb_buffer_t *buffer,
hb_direction_t direction)
-
{
if (unlikely (hb_object_is_immutable (buffer)))
return;
@@ -1385,9 +1431,9 @@ hb_buffer_set_length (hb_buffer_t *buffer,
/* Wipe the new space */
if (length > buffer->len) {
- memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
+ hb_memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
if (buffer->have_positions)
- memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
+ hb_memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
}
buffer->len = length;
@@ -1795,7 +1841,9 @@ hb_buffer_add_latin1 (hb_buffer_t *buffer,
* marks at stat of run.
*
* This function does not check the validity of @text, it is up to the caller
- * to ensure it contains a valid Unicode code points.
+ * to ensure it contains a valid Unicode scalar values. In contrast,
+ * hb_buffer_add_utf32() can be used that takes similar input but performs
+ * sanity-check on the input.
*
* Since: 0.9.31
**/
@@ -1858,9 +1906,9 @@ hb_buffer_append (hb_buffer_t *buffer,
hb_segment_properties_overlay (&buffer->props, &source->props);
- memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
+ hb_memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
if (buffer->have_positions)
- memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
+ hb_memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
{
@@ -2048,7 +2096,7 @@ hb_buffer_diff (hb_buffer_t *buffer,
result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;
if (buf_info->cluster != ref_info->cluster)
result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;
- if ((buf_info->mask & ~ref_info->mask & HB_GLYPH_FLAG_DEFINED))
+ if ((buf_info->mask ^ ref_info->mask) & HB_GLYPH_FLAG_DEFINED)
result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;
if (contains && ref_info->codepoint == dottedcircle_glyph)
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
@@ -2103,6 +2151,13 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
hb_buffer_message_func_t func,
void *user_data, hb_destroy_func_t destroy)
{
+ if (unlikely (hb_object_is_immutable (buffer)))
+ {
+ if (destroy)
+ destroy (user_data);
+ return;
+ }
+
if (buffer->message_destroy)
buffer->message_destroy (buffer->message_data);
diff --git a/thirdparty/harfbuzz/src/hb-buffer.hh b/thirdparty/harfbuzz/src/hb-buffer.hh
index 26c3f0fac8..bb1efe9dd3 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.hh
+++ b/thirdparty/harfbuzz/src/hb-buffer.hh
@@ -32,6 +32,7 @@
#include "hb.hh"
#include "hb-unicode.hh"
+#include "hb-set-digest.hh"
#ifndef HB_BUFFER_MAX_LEN_FACTOR
@@ -207,6 +208,14 @@ struct hb_buffer_t
hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; }
hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
+ hb_set_digest_t digest () const
+ {
+ hb_set_digest_t d;
+ d.init ();
+ d.add_array (&info[0].codepoint, len, sizeof (info[0]));
+ return d;
+ }
+
HB_INTERNAL void similar (const hb_buffer_t &src);
HB_INTERNAL void reset ();
HB_INTERNAL void clear ();
@@ -402,6 +411,8 @@ struct hb_buffer_t
HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end);
/* Merge clusters for deleting current glyph, and skip it. */
HB_INTERNAL void delete_glyph ();
+ HB_INTERNAL void delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info));
+
/* Adds glyph flags in mask to infos with clusters between start and end.
diff --git a/thirdparty/harfbuzz/src/hb-cache.hh b/thirdparty/harfbuzz/src/hb-cache.hh
index 897f313fbd..f8c8108f1f 100644
--- a/thirdparty/harfbuzz/src/hb-cache.hh
+++ b/thirdparty/harfbuzz/src/hb-cache.hh
@@ -46,7 +46,7 @@ struct hb_cache_t
>::type;
static_assert ((key_bits >= cache_bits), "");
- static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (item_t)), "");
+ static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
void init () { clear (); }
void fini () {}
diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh
index 5c2cb060a4..49805a89c5 100644
--- a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh
+++ b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh
@@ -284,65 +284,56 @@ struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
/* A byte string associated with the current offset and an error condition */
struct byte_str_ref_t
{
- byte_str_ref_t () { init (); }
-
- void init ()
- {
- str = hb_ubytes_t ();
- offset = 0;
- error = false;
- }
-
- void fini () {}
+ byte_str_ref_t ()
+ : str () {}
byte_str_ref_t (const hb_ubytes_t &str_, unsigned int offset_ = 0)
- : str (str_), offset (offset_), error (false) {}
+ : str (str_) { set_offset (offset_); }
void reset (const hb_ubytes_t &str_, unsigned int offset_ = 0)
{
str = str_;
- offset = offset_;
- error = false;
+ set_offset (offset_);
}
const unsigned char& operator [] (int i) {
- if (unlikely ((unsigned int) (offset + i) >= str.length))
+ if (unlikely ((unsigned int) (get_offset () + i) >= str.length))
{
set_error ();
return Null (unsigned char);
}
- return str[offset + i];
+ return str.arrayZ[get_offset () + i];
}
+ unsigned char head_unchecked () const { return str.arrayZ[get_offset ()]; }
+
/* Conversion to hb_ubytes_t */
- operator hb_ubytes_t () const { return str.sub_array (offset, str.length - offset); }
+ operator hb_ubytes_t () const { return str.sub_array (get_offset ()); }
hb_ubytes_t sub_array (unsigned int offset_, unsigned int len_) const
{ return str.sub_array (offset_, len_); }
bool avail (unsigned int count=1) const
- { return (!in_error () && offset + count <= str.length); }
+ { return get_offset () + count <= str.length; }
void inc (unsigned int count=1)
{
- if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length)))
- {
- offset += count;
- }
- else
- {
- offset = str.length;
- set_error ();
- }
+ /* Automatically puts us in error if count is out-of-range. */
+ set_offset (get_offset () + count);
}
- void set_error () { error = true; }
- bool in_error () const { return error; }
+ /* We (ab)use ubytes backwards_length as a cursor (called offset),
+ * as well as to store error condition. */
- hb_ubytes_t str;
- unsigned int offset; /* beginning of the sub-string within str */
+ unsigned get_offset () const { return str.backwards_length; }
+ void set_offset (unsigned offset) { str.backwards_length = offset; }
+
+ void set_error () { str.backwards_length = str.length + 1; }
+ bool in_error () const { return str.backwards_length > str.length; }
+
+ unsigned total_size () const { return str.length; }
protected:
- bool error;
+ hb_ubytes_t str;
};
using byte_str_array_t = hb_vector_t<hb_ubytes_t>;
@@ -491,8 +482,15 @@ struct arg_stack_t : cff_stack_t<ARG, 513>
/* an operator prefixed by its operands in a byte string */
struct op_str_t
{
- hb_ubytes_t str;
+ /* This used to have a hb_ubytes_t. Using a pointer and length
+ * in a particular order, saves 8 bytes in this struct and more
+ * in our parsed_cs_op_t subclass. */
+
+ const unsigned char *ptr = nullptr;
+
op_code_t op;
+
+ uint8_t length = 0;
};
/* base of OP_SERIALIZER */
@@ -503,9 +501,11 @@ struct op_serializer_t
{
TRACE_SERIALIZE (this);
- HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
+ unsigned char *d = c->allocate_size<unsigned char> (opstr.length);
if (unlikely (!d)) return_trace (false);
- memcpy (d, &opstr.str[0], opstr.str.length);
+ /* Faster than hb_memcpy for small strings. */
+ for (unsigned i = 0; i < opstr.length; i++)
+ d[i] = opstr.ptr[i];
return_trace (true);
}
};
@@ -529,16 +529,20 @@ struct parsed_values_t
{
VAL *val = values.push ();
val->op = op;
- val->str = str_ref.str.sub_array (opStart, str_ref.offset - opStart);
- opStart = str_ref.offset;
+ auto arr = str_ref.sub_array (opStart, str_ref.get_offset () - opStart);
+ val->ptr = arr.arrayZ;
+ val->length = arr.length;
+ opStart = str_ref.get_offset ();
}
void add_op (op_code_t op, const byte_str_ref_t& str_ref, const VAL &v)
{
VAL *val = values.push (v);
val->op = op;
- val->str = str_ref.sub_array ( opStart, str_ref.offset - opStart);
- opStart = str_ref.offset;
+ auto arr = str_ref.sub_array (opStart, str_ref.get_offset () - opStart);
+ val->ptr = arr.arrayZ;
+ val->length = arr.length;
+ opStart = str_ref.get_offset ();
}
bool has_op (op_code_t op) const
@@ -549,8 +553,7 @@ struct parsed_values_t
}
unsigned get_count () const { return values.length; }
- const VAL &get_value (unsigned int i) const { return values[i]; }
- const VAL &operator [] (unsigned int i) const { return get_value (i); }
+ const VAL &operator [] (unsigned int i) const { return values[i]; }
unsigned int opStart;
hb_vector_t<VAL> values;
@@ -565,23 +568,23 @@ struct interp_env_t
str_ref.reset (str_);
}
bool in_error () const
- { return error || str_ref.in_error () || argStack.in_error (); }
+ { return str_ref.in_error () || argStack.in_error (); }
- void set_error () { error = true; }
+ void set_error () { str_ref.set_error (); }
op_code_t fetch_op ()
{
op_code_t op = OpCode_Invalid;
if (unlikely (!str_ref.avail ()))
return OpCode_Invalid;
- op = (op_code_t)(unsigned char)str_ref[0];
+ op = (op_code_t) str_ref.head_unchecked ();
+ str_ref.inc ();
if (op == OpCode_escape) {
if (unlikely (!str_ref.avail ()))
return OpCode_Invalid;
- op = Make_OpCode_ESC(str_ref[1]);
+ op = Make_OpCode_ESC (str_ref.head_unchecked ());
str_ref.inc ();
}
- str_ref.inc ();
return op;
}
@@ -596,8 +599,6 @@ struct interp_env_t
str_ref;
arg_stack_t<ARG>
argStack;
- protected:
- bool error = false;
};
using num_interp_env_t = interp_env_t<>;
diff --git a/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh b/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh
index d0b9e7b086..00c25800e6 100644
--- a/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh
+++ b/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh
@@ -40,13 +40,15 @@ struct blend_arg_t : number_t
void set_real (double v) { reset_blends (); number_t::set_real (v); }
void set_blends (unsigned int numValues_, unsigned int valueIndex_,
- unsigned int numBlends, hb_array_t<const blend_arg_t> blends_)
+ hb_array_t<const blend_arg_t> blends_)
{
numValues = numValues_;
valueIndex = valueIndex_;
- deltas.resize (numBlends);
+ unsigned numBlends = blends_.length;
+ if (unlikely (!deltas.resize (numBlends)))
+ return;
for (unsigned int i = 0; i < numBlends; i++)
- deltas[i] = blends_[i];
+ deltas.arrayZ[i] = blends_.arrayZ[i];
}
bool blending () const { return deltas.length > 0; }
@@ -61,7 +63,6 @@ struct blend_arg_t : number_t
hb_vector_t<number_t> deltas;
};
-typedef interp_env_t<blend_arg_t> BlendInterpEnv;
typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t;
template <typename ELEM>
@@ -154,8 +155,9 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
{
if (likely (scalars.length == deltas.length))
{
- for (unsigned int i = 0; i < scalars.length; i++)
- v += (double) scalars[i] * deltas[i].to_real ();
+ unsigned count = scalars.length;
+ for (unsigned i = 0; i < count; i++)
+ v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real ();
}
}
return v;
@@ -220,7 +222,7 @@ struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PAR
const hb_array_t<const ELEM> blends,
unsigned n, unsigned i)
{
- arg.set_blends (n, i, blends.length, blends);
+ arg.set_blends (n, i, blends);
}
template <typename T = ELEM,
hb_enable_if (!hb_is_same (T, blend_arg_t))>
diff --git a/thirdparty/harfbuzz/src/hb-common.cc b/thirdparty/harfbuzz/src/hb-common.cc
index bbb6cd552b..e9f9cfeb5f 100644
--- a/thirdparty/harfbuzz/src/hb-common.cc
+++ b/thirdparty/harfbuzz/src/hb-common.cc
@@ -285,7 +285,7 @@ struct hb_language_item_t {
lang = (hb_language_t) hb_malloc(len);
if (likely (lang))
{
- memcpy((unsigned char *) lang, s, len);
+ hb_memcpy((unsigned char *) lang, s, len);
for (unsigned char *p = (unsigned char *) lang; *p; p++)
*p = canon_map[*p];
}
@@ -379,7 +379,7 @@ hb_language_from_string (const char *str, int len)
/* NUL-terminate it. */
char strbuf[64];
len = hb_min (len, (int) sizeof (strbuf) - 1);
- memcpy (strbuf, str, len);
+ hb_memcpy (strbuf, str, len);
strbuf[len] = '\0';
item = lang_find_or_insert (strbuf);
}
@@ -976,7 +976,7 @@ hb_feature_from_string (const char *str, int len,
}
if (feature)
- memset (feature, 0, sizeof (*feature));
+ hb_memset (feature, 0, sizeof (*feature));
return false;
}
@@ -1025,7 +1025,7 @@ hb_feature_to_string (hb_feature_t *feature,
}
assert (len < ARRAY_LENGTH (s));
len = hb_min (len, size - 1);
- memcpy (buf, s, len);
+ hb_memcpy (buf, s, len);
buf[len] = '\0';
}
@@ -1088,7 +1088,7 @@ hb_variation_from_string (const char *str, int len,
}
if (variation)
- memset (variation, 0, sizeof (*variation));
+ hb_memset (variation, 0, sizeof (*variation));
return false;
}
@@ -1136,7 +1136,7 @@ get_C_locale ()
/**
* hb_variation_to_string:
* @variation: an #hb_variation_t to convert
- * @buf: (array length=size) (out): output string
+ * @buf: (array length=size) (out caller-allocates): output string
* @size: the allocated size of @buf
*
* Converts an #hb_variation_t into a `NULL`-terminated string in the format
@@ -1166,7 +1166,7 @@ hb_variation_to_string (hb_variation_t *variation,
assert (len < ARRAY_LENGTH (s));
len = hb_min (len, size - 1);
- memcpy (buf, s, len);
+ hb_memcpy (buf, s, len);
buf[len] = '\0';
}
diff --git a/thirdparty/harfbuzz/src/hb-config.hh b/thirdparty/harfbuzz/src/hb-config.hh
index d56617f6a9..98b1e9d0cf 100644
--- a/thirdparty/harfbuzz/src/hb-config.hh
+++ b/thirdparty/harfbuzz/src/hb-config.hh
@@ -35,8 +35,9 @@
#include "config.h"
#endif
-#ifndef HB_BORING_EXPANSION
-#define HB_NO_BORING_EXPANSION
+#ifndef HB_EXPERIMENTAL_API
+#define HB_NO_BEYOND_64K
+#define HB_NO_VAR_COMPOSITES
#endif
#ifdef HB_TINY
@@ -84,6 +85,7 @@
#define HB_NO_OT_SHAPE_FRACTIONS
#define HB_NO_STYLE
#define HB_NO_SUBSET_LAYOUT
+#define HB_NO_VERTICAL
#define HB_NO_VAR
#endif
@@ -104,7 +106,7 @@
#ifdef HB_NO_BORING_EXPANSION
#define HB_NO_BEYOND_64K
-#define HB_NO_VARIATIONS2
+#define HB_NO_AVAR2
#endif
#ifdef HB_DISABLE_DEPRECATED
@@ -113,6 +115,11 @@
#define HB_IF_NOT_DEPRECATED(x) x
#endif
+#ifdef HB_NO_SHAPER
+#define HB_NO_OT_SHAPE
+#define HB_NO_AAT_SHAPE
+#endif
+
#ifdef HB_NO_AAT
#define HB_NO_OT_NAME_LANGUAGE_AAT
#define HB_NO_AAT_SHAPE
@@ -159,6 +166,7 @@
#define HB_NO_OT_SHAPER_HEBREW_FALLBACK
#define HB_NO_OT_SHAPER_THAI_FALLBACK
#define HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS
+#define HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
#endif
#ifdef NDEBUG
diff --git a/thirdparty/harfbuzz/src/hb-coretext.cc b/thirdparty/harfbuzz/src/hb-coretext.cc
index 99b33c001e..4267e0e13e 100644
--- a/thirdparty/harfbuzz/src/hb-coretext.cc
+++ b/thirdparty/harfbuzz/src/hb-coretext.cc
@@ -347,10 +347,13 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
hb_ot_var_axis_info_t info;
unsigned int c = 1;
hb_ot_var_get_axis_infos (font->face, i, &c, &info);
- CFDictionarySetValue (variations,
- CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag),
- CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &font->design_coords[i])
- );
+ float v = hb_clamp (font->design_coords[i], info.min_value, info.max_value);
+
+ CFNumberRef tag_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag);
+ CFNumberRef value_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &v);
+ CFDictionarySetValue (variations, tag_number, value_number);
+ CFRelease (tag_number);
+ CFRelease (value_number);
}
CFDictionaryRef attributes =
@@ -648,7 +651,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
} else {
active_feature_t *feature = active_features.lsearch (event->feature);
if (feature)
- active_features.remove (feature - active_features.arrayZ);
+ active_features.remove_ordered (feature - active_features.arrayZ);
}
}
}
diff --git a/thirdparty/harfbuzz/src/hb-draw.cc b/thirdparty/harfbuzz/src/hb-draw.cc
index 46797e64e6..72c203f24f 100644
--- a/thirdparty/harfbuzz/src/hb-draw.cc
+++ b/thirdparty/harfbuzz/src/hb-draw.cc
@@ -80,6 +80,56 @@ hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UN
void *user_data HB_UNUSED) {}
+static bool
+_hb_draw_funcs_set_preamble (hb_draw_funcs_t *dfuncs,
+ bool func_is_null,
+ void **user_data,
+ hb_destroy_func_t *destroy)
+{
+ if (hb_object_is_immutable (dfuncs))
+ {
+ if (*destroy)
+ (*destroy) (*user_data);
+ return false;
+ }
+
+ if (func_is_null)
+ {
+ if (*destroy)
+ (*destroy) (*user_data);
+ *destroy = nullptr;
+ *user_data = nullptr;
+ }
+
+ return true;
+}
+
+static bool
+_hb_draw_funcs_set_middle (hb_draw_funcs_t *dfuncs,
+ void *user_data,
+ hb_destroy_func_t destroy)
+{
+ if (user_data && !dfuncs->user_data)
+ {
+ dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data));
+ if (unlikely (!dfuncs->user_data))
+ goto fail;
+ }
+ if (destroy && !dfuncs->destroy)
+ {
+ dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy));
+ if (unlikely (!dfuncs->destroy))
+ goto fail;
+ }
+
+ return true;
+
+fail:
+ if (destroy)
+ (destroy) (user_data);
+ return false;
+}
+
#define HB_DRAW_FUNC_IMPLEMENT(name) \
\
void \
@@ -88,43 +138,24 @@ hb_draw_funcs_set_##name##_func (hb_draw_funcs_t *dfuncs, \
void *user_data, \
hb_destroy_func_t destroy) \
{ \
- if (hb_object_is_immutable (dfuncs)) \
- return; \
+ if (!_hb_draw_funcs_set_preamble (dfuncs, !func, &user_data, &destroy))\
+ return; \
\
if (dfuncs->destroy && dfuncs->destroy->name) \
dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name); \
\
- if (user_data && !dfuncs->user_data) \
- { \
- dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data)); \
- if (unlikely (!dfuncs->user_data)) \
- goto fail; \
- } \
- if (destroy && !dfuncs->destroy) \
- { \
- dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy)); \
- if (unlikely (!dfuncs->destroy)) \
- goto fail; \
- } \
+ if (!_hb_draw_funcs_set_middle (dfuncs, user_data, destroy)) \
+ return; \
\
- if (func) { \
+ if (func) \
dfuncs->func.name = func; \
- if (dfuncs->user_data) \
- dfuncs->user_data->name = user_data; \
- if (dfuncs->destroy) \
- dfuncs->destroy->name = destroy; \
- } else { \
+ else \
dfuncs->func.name = hb_draw_##name##_nil; \
- if (dfuncs->user_data) \
- dfuncs->user_data->name = nullptr; \
- if (dfuncs->destroy) \
- dfuncs->destroy->name = nullptr; \
- } \
- return; \
- \
-fail: \
- if (destroy) \
- destroy (user_data); \
+ \
+ if (dfuncs->user_data) \
+ dfuncs->user_data->name = user_data; \
+ if (dfuncs->destroy) \
+ dfuncs->destroy->name = destroy; \
}
HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
diff --git a/thirdparty/harfbuzz/src/hb-face.cc b/thirdparty/harfbuzz/src/hb-face.cc
index e7deb31dd8..8b4b635c7a 100644
--- a/thirdparty/harfbuzz/src/hb-face.cc
+++ b/thirdparty/harfbuzz/src/hb-face.cc
@@ -288,6 +288,7 @@ hb_face_destroy (hb_face_t *face)
{
if (!hb_object_destroy (face)) return;
+#ifndef HB_NO_SHAPER
for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
{
hb_face_t::plan_node_t *next = node->next;
@@ -295,6 +296,7 @@ hb_face_destroy (hb_face_t *face)
hb_free (node);
node = next;
}
+#endif
face->data.fini ();
face->table.fini ();
@@ -636,7 +638,7 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
struct face_table_info_t
{
hb_blob_t* data;
- unsigned order;
+ signed order;
};
struct hb_face_builder_data_t
@@ -784,16 +786,16 @@ hb_face_builder_create ()
hb_bool_t
hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
{
- if (tag == HB_MAP_VALUE_INVALID)
+ if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
return false;
- if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
+ if (tag == HB_MAP_VALUE_INVALID)
return false;
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
hb_blob_t* previous = data->tables.get (tag).data;
- if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), 0}))
+ if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), -1}))
{
hb_blob_destroy (blob);
return false;
@@ -819,13 +821,16 @@ void
hb_face_builder_sort_tables (hb_face_t *face,
const hb_tag_t *tags)
{
+ if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
+ return;
+
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
// Sort all unspecified tables after any specified tables.
for (auto& info : data->tables.values_ref())
- info.order = -1;
+ info.order = (unsigned) -1;
- unsigned order = 0;
+ signed order = 0;
for (const hb_tag_t* tag = tags;
*tag;
tag++)
diff --git a/thirdparty/harfbuzz/src/hb-face.hh b/thirdparty/harfbuzz/src/hb-face.hh
index 12e10d01e0..1bf0606e52 100644
--- a/thirdparty/harfbuzz/src/hb-face.hh
+++ b/thirdparty/harfbuzz/src/hb-face.hh
@@ -65,7 +65,9 @@ struct hb_face_t
hb_shape_plan_t *shape_plan;
plan_node_t *next;
};
+#ifndef HB_NO_SHAPER
hb_atomic_ptr_t<plan_node_t> shape_plans;
+#endif
hb_blob_t *reference_table (hb_tag_t tag) const
{
diff --git a/thirdparty/harfbuzz/src/hb-fallback-shape.cc b/thirdparty/harfbuzz/src/hb-fallback-shape.cc
index f8524ecc8e..c54ad8764b 100644
--- a/thirdparty/harfbuzz/src/hb-fallback-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-fallback-shape.cc
@@ -75,16 +75,6 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *features HB_UNUSED,
unsigned int num_features HB_UNUSED)
{
- /* TODO
- *
- * - Apply fallback kern.
- * - Handle Variation Selectors?
- * - Apply normalization?
- *
- * This will make the fallback shaper into a dumb "TrueType"
- * shaper which many people unfortunately still request.
- */
-
hb_codepoint_t space;
bool has_space = (bool) font->get_nominal_glyph (' ', &space);
diff --git a/thirdparty/harfbuzz/src/hb-font.cc b/thirdparty/harfbuzz/src/hb-font.cc
index 856bbdda32..0ce3e2608a 100644
--- a/thirdparty/harfbuzz/src/hb-font.cc
+++ b/thirdparty/harfbuzz/src/hb-font.cc
@@ -71,7 +71,7 @@ hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED,
hb_font_extents_t *extents,
void *user_data HB_UNUSED)
{
- memset (extents, 0, sizeof (*extents));
+ hb_memset (extents, 0, sizeof (*extents));
return false;
}
@@ -96,7 +96,7 @@ hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED,
hb_font_extents_t *extents,
void *user_data HB_UNUSED)
{
- memset (extents, 0, sizeof (*extents));
+ hb_memset (extents, 0, sizeof (*extents));
return false;
}
@@ -409,7 +409,7 @@ hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
- memset (extents, 0, sizeof (*extents));
+ hb_memset (extents, 0, sizeof (*extents));
return false;
}
@@ -518,6 +518,7 @@ typedef struct hb_font_get_glyph_shape_default_adaptor_t {
void *draw_data;
float x_scale;
float y_scale;
+ float slant;
} hb_font_get_glyph_shape_default_adaptor_t;
static void
@@ -530,9 +531,10 @@ hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED,
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
+ float slant = adaptor->slant;
adaptor->draw_funcs->emit_move_to (adaptor->draw_data, *st,
- x_scale * to_x, y_scale * to_y);
+ x_scale * to_x + slant * to_y, y_scale * to_y);
}
static void
@@ -544,12 +546,13 @@ hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
+ float slant = adaptor->slant;
- st->current_x *= x_scale;
- st->current_y *= y_scale;
+ st->current_x = st->current_x * x_scale + st->current_y * slant;
+ st->current_y = st->current_y * y_scale;
adaptor->draw_funcs->emit_line_to (adaptor->draw_data, *st,
- x_scale * to_x, y_scale * to_y);
+ x_scale * to_x + slant * to_y, y_scale * to_y);
}
static void
@@ -562,13 +565,14 @@ hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
+ float slant = adaptor->slant;
- st->current_x *= x_scale;
- st->current_y *= y_scale;
+ st->current_x = st->current_x * x_scale + st->current_y * slant;
+ st->current_y = st->current_y * y_scale;
adaptor->draw_funcs->emit_quadratic_to (adaptor->draw_data, *st,
- x_scale * control_x, y_scale * control_y,
- x_scale * to_x, y_scale * to_y);
+ x_scale * control_x + slant * control_y, y_scale * control_y,
+ x_scale * to_x + slant * to_y, y_scale * to_y);
}
static void
@@ -582,14 +586,15 @@ hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
+ float slant = adaptor->slant;
- st->current_x *= x_scale;
- st->current_y *= y_scale;
+ st->current_x = st->current_x * x_scale + st->current_y * slant;
+ st->current_y = st->current_y * y_scale;
adaptor->draw_funcs->emit_cubic_to (adaptor->draw_data, *st,
- x_scale * control1_x, y_scale * control1_y,
- x_scale * control2_x, y_scale * control2_y,
- x_scale * to_x, y_scale * to_y);
+ x_scale * control1_x + slant * control1_y, y_scale * control1_y,
+ x_scale * control2_x + slant * control2_y, y_scale * control2_y,
+ x_scale * to_x + slant * to_y, y_scale * to_y);
}
static void
@@ -623,8 +628,10 @@ hb_font_get_glyph_shape_default (hb_font_t *font,
hb_font_get_glyph_shape_default_adaptor_t adaptor = {
draw_funcs,
draw_data,
- (float) font->x_scale / (float) font->parent->x_scale,
- (float) font->y_scale / (float) font->parent->y_scale
+ font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f,
+ font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f,
+ font->parent->y_scale ? (font->slant - font->parent->slant) *
+ (float) font->x_scale / (float) font->parent->y_scale : 0.f
};
font->parent->get_glyph_shape (glyph,
@@ -822,6 +829,56 @@ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
}
+static bool
+_hb_font_funcs_set_preamble (hb_font_funcs_t *ffuncs,
+ bool func_is_null,
+ void **user_data,
+ hb_destroy_func_t *destroy)
+{
+ if (hb_object_is_immutable (ffuncs))
+ {
+ if (*destroy)
+ (*destroy) (*user_data);
+ return false;
+ }
+
+ if (func_is_null)
+ {
+ if (*destroy)
+ (*destroy) (*user_data);
+ *destroy = nullptr;
+ *user_data = nullptr;
+ }
+
+ return true;
+}
+
+static bool
+_hb_font_funcs_set_middle (hb_font_funcs_t *ffuncs,
+ void *user_data,
+ hb_destroy_func_t destroy)
+{
+ if (user_data && !ffuncs->user_data)
+ {
+ ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data));
+ if (unlikely (!ffuncs->user_data))
+ goto fail;
+ }
+ if (destroy && !ffuncs->destroy)
+ {
+ ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy));
+ if (unlikely (!ffuncs->destroy))
+ goto fail;
+ }
+
+ return true;
+
+fail:
+ if (destroy)
+ (destroy) (user_data);
+ return false;
+}
+
#define HB_FONT_FUNC_IMPLEMENT(name) \
\
void \
@@ -830,51 +887,24 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
void *user_data, \
hb_destroy_func_t destroy) \
{ \
- if (hb_object_is_immutable (ffuncs)) \
- goto fail; \
- \
- if (!func) \
- { \
- if (destroy) \
- destroy (user_data); \
- destroy = nullptr; \
- user_data = nullptr; \
- } \
+ if (!_hb_font_funcs_set_preamble (ffuncs, !func, &user_data, &destroy))\
+ return; \
\
if (ffuncs->destroy && ffuncs->destroy->name) \
ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name); \
\
- if (user_data && !ffuncs->user_data) \
- { \
- ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data)); \
- if (unlikely (!ffuncs->user_data)) \
- goto fail; \
- } \
- if (destroy && !ffuncs->destroy) \
- { \
- ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy)); \
- if (unlikely (!ffuncs->destroy)) \
- goto fail; \
- } \
+ if (!_hb_font_funcs_set_middle (ffuncs, user_data, destroy)) \
+ return; \
\
- if (func) { \
+ if (func) \
ffuncs->get.f.name = func; \
- if (ffuncs->user_data) \
- ffuncs->user_data->name = user_data; \
- if (ffuncs->destroy) \
- ffuncs->destroy->name = destroy; \
- } else { \
+ else \
ffuncs->get.f.name = hb_font_get_##name##_default; \
- if (ffuncs->user_data) \
- ffuncs->user_data->name = nullptr; \
- if (ffuncs->destroy) \
- ffuncs->destroy->name = nullptr; \
- } \
- return; \
- \
-fail: \
- if (destroy) \
- destroy (user_data); \
+ \
+ if (ffuncs->user_data) \
+ ffuncs->user_data->name = user_data; \
+ if (ffuncs->destroy) \
+ ffuncs->destroy->name = destroy; \
}
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
@@ -1323,7 +1353,7 @@ hb_font_get_glyph_from_name (hb_font_t *font,
* @draw_data: User data to pass to draw callbacks
*
* Fetches the glyph shape that corresponds to a glyph in the specified @font.
- * The shape is returned by way of calls to the callsbacks of the @dfuncs
+ * The shape is returned by way of calls to the callbacks of the @dfuncs
* objects, with @draw_data passed to them.
*
* Since: 4.0.0
@@ -1780,8 +1810,8 @@ hb_font_create_sub_font (hb_font_t *parent)
float *design_coords = (float *) hb_calloc (num_coords, sizeof (parent->design_coords[0]));
if (likely (coords && design_coords))
{
- memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0]));
- memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0]));
+ hb_memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0]));
+ hb_memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0]));
_hb_font_adopt_var_coords (font, coords, design_coords, num_coords);
}
else
@@ -2443,7 +2473,7 @@ hb_font_set_var_coords_design (hb_font_t *font,
}
if (coords_length)
- memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0]));
+ hb_memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0]));
hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized);
_hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
@@ -2519,8 +2549,8 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
if (coords_length)
{
- memcpy (copy, coords, coords_length * sizeof (coords[0]));
- memcpy (unmapped, coords, coords_length * sizeof (coords[0]));
+ hb_memcpy (copy, coords, coords_length * sizeof (coords[0]));
+ hb_memcpy (unmapped, coords, coords_length * sizeof (coords[0]));
}
/* Best effort design coords simulation */
diff --git a/thirdparty/harfbuzz/src/hb-font.hh b/thirdparty/harfbuzz/src/hb-font.hh
index bb402e23eb..6942d99c70 100644
--- a/thirdparty/harfbuzz/src/hb-font.hh
+++ b/thirdparty/harfbuzz/src/hb-font.hh
@@ -206,14 +206,14 @@ struct hb_font_t
hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
{
- memset (extents, 0, sizeof (*extents));
+ hb_memset (extents, 0, sizeof (*extents));
return klass->get.f.font_h_extents (this, user_data,
extents,
!klass->user_data ? nullptr : klass->user_data->font_h_extents);
}
hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
{
- memset (extents, 0, sizeof (*extents));
+ hb_memset (extents, 0, sizeof (*extents));
return klass->get.f.font_v_extents (this, user_data,
extents,
!klass->user_data ? nullptr : klass->user_data->font_v_extents);
@@ -342,7 +342,7 @@ struct hb_font_t
hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
hb_glyph_extents_t *extents)
{
- memset (extents, 0, sizeof (*extents));
+ hb_memset (extents, 0, sizeof (*extents));
return klass->get.f.glyph_extents (this, user_data,
glyph,
extents,
diff --git a/thirdparty/harfbuzz/src/hb-ft.cc b/thirdparty/harfbuzz/src/hb-ft.cc
index bcc1dd080f..3892dedc13 100644
--- a/thirdparty/harfbuzz/src/hb-ft.cc
+++ b/thirdparty/harfbuzz/src/hb-ft.cc
@@ -89,7 +89,7 @@ struct hb_ft_font_t
bool unref; /* Whether to destroy ft_face when done. */
bool transform; /* Whether to apply FT_Face's transform. */
- mutable hb_mutex_t lock;
+ mutable hb_mutex_t lock; /* Protects members below. */
FT_Face ft_face;
mutable unsigned cached_serial;
mutable hb_ft_advance_cache_t advance_cache;
@@ -732,16 +732,18 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
static int
_hb_ft_move_to (const FT_Vector *to,
- hb_draw_session_t *drawing)
+ void *arg)
{
+ hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
drawing->move_to (to->x, to->y);
return FT_Err_Ok;
}
static int
_hb_ft_line_to (const FT_Vector *to,
- hb_draw_session_t *drawing)
+ void *arg)
{
+ hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
drawing->line_to (to->x, to->y);
return FT_Err_Ok;
}
@@ -749,8 +751,9 @@ _hb_ft_line_to (const FT_Vector *to,
static int
_hb_ft_conic_to (const FT_Vector *control,
const FT_Vector *to,
- hb_draw_session_t *drawing)
+ void *arg)
{
+ hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
drawing->quadratic_to (control->x, control->y,
to->x, to->y);
return FT_Err_Ok;
@@ -760,8 +763,9 @@ static int
_hb_ft_cubic_to (const FT_Vector *control1,
const FT_Vector *control2,
const FT_Vector *to,
- hb_draw_session_t *drawing)
+ void *arg)
{
+ hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
drawing->cubic_to (control1->x, control1->y,
control2->x, control2->y,
to->x, to->y);
@@ -787,10 +791,10 @@ hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED,
return;
const FT_Outline_Funcs outline_funcs = {
- (FT_Outline_MoveToFunc) _hb_ft_move_to,
- (FT_Outline_LineToFunc) _hb_ft_line_to,
- (FT_Outline_ConicToFunc) _hb_ft_conic_to,
- (FT_Outline_CubicToFunc) _hb_ft_cubic_to,
+ _hb_ft_move_to,
+ _hb_ft_line_to,
+ _hb_ft_conic_to,
+ _hb_ft_cubic_to,
0, /* shift */
0, /* delta */
};
@@ -975,8 +979,9 @@ hb_ft_face_create_referenced (FT_Face ft_face)
}
static void
-hb_ft_face_finalize (FT_Face ft_face)
+hb_ft_face_finalize (void *arg)
{
+ FT_Face ft_face = (FT_Face) arg;
hb_face_destroy ((hb_face_t *) ft_face->generic.data);
}
@@ -1008,7 +1013,7 @@ hb_ft_face_create_cached (FT_Face ft_face)
ft_face->generic.finalizer (ft_face);
ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
- ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
+ ft_face->generic.finalizer = hb_ft_face_finalize;
}
return hb_face_reference ((hb_face_t *) ft_face->generic.data);
@@ -1217,8 +1222,9 @@ get_ft_library ()
}
static void
-_release_blob (FT_Face ft_face)
+_release_blob (void *arg)
{
+ FT_Face ft_face = (FT_Face) arg;
hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
}
@@ -1271,7 +1277,7 @@ hb_ft_font_set_funcs (hb_font_t *font)
ft_face->generic.data = blob;
- ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
+ ft_face->generic.finalizer = _release_blob;
_hb_ft_font_set_funcs (font, ft_face, true);
hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
diff --git a/thirdparty/harfbuzz/src/hb-glib.cc b/thirdparty/harfbuzz/src/hb-glib.cc
index 8ddc7ebad8..1da81696e7 100644
--- a/thirdparty/harfbuzz/src/hb-glib.cc
+++ b/thirdparty/harfbuzz/src/hb-glib.cc
@@ -129,32 +129,9 @@ hb_glib_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
{
#if GLIB_CHECK_VERSION(2,29,12)
return g_unichar_compose (a, b, ab);
+#else
+ return false;
#endif
-
- /* We don't ifdef-out the fallback code such that compiler always
- * sees it and makes sure it's compilable. */
-
- gchar utf8[12];
- gchar *normalized;
- int len;
- hb_bool_t ret;
-
- len = g_unichar_to_utf8 (a, utf8);
- len += g_unichar_to_utf8 (b, utf8 + len);
- normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFC);
- len = g_utf8_strlen (normalized, -1);
- if (unlikely (!len))
- return false;
-
- if (len == 1) {
- *ab = g_utf8_get_char (normalized);
- ret = true;
- } else {
- ret = false;
- }
-
- g_free (normalized);
- return ret;
}
static hb_bool_t
@@ -166,55 +143,9 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
{
#if GLIB_CHECK_VERSION(2,29,12)
return g_unichar_decompose (ab, a, b);
+#else
+ return false;
#endif
-
- /* We don't ifdef-out the fallback code such that compiler always
- * sees it and makes sure it's compilable. */
-
- gchar utf8[6];
- gchar *normalized;
- int len;
- hb_bool_t ret;
-
- len = g_unichar_to_utf8 (ab, utf8);
- normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFD);
- len = g_utf8_strlen (normalized, -1);
- if (unlikely (!len))
- return false;
-
- if (len == 1) {
- *a = g_utf8_get_char (normalized);
- *b = 0;
- ret = *a != ab;
- } else if (len == 2) {
- *a = g_utf8_get_char (normalized);
- *b = g_utf8_get_char (g_utf8_next_char (normalized));
- /* Here's the ugly part: if ab decomposes to a single character and
- * that character decomposes again, we have to detect that and undo
- * the second part :-(. */
- gchar *recomposed = g_utf8_normalize (normalized, -1, G_NORMALIZE_NFC);
- hb_codepoint_t c = g_utf8_get_char (recomposed);
- if (c != ab && c != *a) {
- *a = c;
- *b = 0;
- }
- g_free (recomposed);
- ret = true;
- } else {
- /* If decomposed to more than two characters, take the last one,
- * and recompose the rest to get the first component. */
- gchar *end = g_utf8_offset_to_pointer (normalized, len - 1);
- gchar *recomposed;
- *b = g_utf8_get_char (end);
- recomposed = g_utf8_normalize (normalized, end - normalized, G_NORMALIZE_NFC);
- /* We expect that recomposed has exactly one character now. */
- *a = g_utf8_get_char (recomposed);
- g_free (recomposed);
- ret = true;
- }
-
- g_free (normalized);
- return ret;
}
diff --git a/thirdparty/harfbuzz/src/hb-graphite2.cc b/thirdparty/harfbuzz/src/hb-graphite2.cc
index 4d0e687c75..9e068f8d84 100644
--- a/thirdparty/harfbuzz/src/hb-graphite2.cc
+++ b/thirdparty/harfbuzz/src/hb-graphite2.cc
@@ -318,7 +318,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
#undef ALLOCATE_ARRAY
- memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
+ hb_memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
hb_codepoint_t *pg = gids;
clusters[0].cluster = buffer->info[0].cluster;
diff --git a/thirdparty/harfbuzz/src/hb-iter.hh b/thirdparty/harfbuzz/src/hb-iter.hh
index 1a3ab43de0..b57f37b132 100644
--- a/thirdparty/harfbuzz/src/hb-iter.hh
+++ b/thirdparty/harfbuzz/src/hb-iter.hh
@@ -73,8 +73,10 @@ struct hb_iter_t
/* Operators. */
iter_t iter () const { return *thiz(); }
iter_t operator + () const { return *thiz(); }
- iter_t begin () const { return *thiz(); }
- iter_t end () const { return thiz()->__end__ (); }
+ iter_t _begin () const { return *thiz(); }
+ iter_t begin () const { return _begin (); }
+ iter_t _end () const { return thiz()->__end__ (); }
+ iter_t end () const { return _end (); }
explicit operator bool () const { return thiz()->__more__ (); }
unsigned len () const { return thiz()->__len__ (); }
/* The following can only be enabled if item_t is reference type. Otherwise
@@ -118,7 +120,9 @@ struct hb_iter_t
#define HB_ITER_USING(Name) \
using item_t = typename Name::item_t; \
+ using Name::_begin; \
using Name::begin; \
+ using Name::_end; \
using Name::end; \
using Name::get_item_size; \
using Name::is_iterator; \
@@ -377,7 +381,7 @@ struct hb_map_iter_t :
void __forward__ (unsigned n) { it += n; }
void __prev__ () { --it; }
void __rewind__ (unsigned n) { it -= n; }
- hb_map_iter_t __end__ () const { return hb_map_iter_t (it.end (), f); }
+ hb_map_iter_t __end__ () const { return hb_map_iter_t (it._end (), f); }
bool operator != (const hb_map_iter_t& o) const
{ return it != o.it; }
@@ -440,7 +444,7 @@ struct hb_filter_iter_t :
bool __more__ () const { return bool (it); }
void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
- hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); }
+ hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it._end (), p, f); }
bool operator != (const hb_filter_iter_t& o) const
{ return it != o.it; }
@@ -553,7 +557,7 @@ struct hb_zip_iter_t :
void __forward__ (unsigned n) { a += n; b += n; }
void __prev__ () { --a; --b; }
void __rewind__ (unsigned n) { a -= n; b -= n; }
- hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); }
+ hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a._end (), b._end ()); }
/* Note, we should stop if ANY of the iters reaches end. As such two compare
* unequal if both items are unequal, NOT if either is unequal. */
bool operator != (const hb_zip_iter_t& o) const
@@ -637,7 +641,7 @@ struct hb_concat_iter_t :
}
}
- hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a.end (), b.end ()); }
+ hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a._end (), b._end ()); }
bool operator != (const hb_concat_iter_t& o) const
{
return a != o.a
diff --git a/thirdparty/harfbuzz/src/hb-machinery.hh b/thirdparty/harfbuzz/src/hb-machinery.hh
index 2571f22e15..b555739cfb 100644
--- a/thirdparty/harfbuzz/src/hb-machinery.hh
+++ b/thirdparty/harfbuzz/src/hb-machinery.hh
@@ -136,6 +136,13 @@ static inline Type& StructAfter(TObject &X)
/*
* Lazy loaders.
+ *
+ * The lazy-loaders are thread-safe pointer-like objects that create their
+ * instead on-demand. They also support access to a "data" object that is
+ * necessary for creating their instance. The data object, if specified,
+ * is accessed via pointer math, located at a location before the position
+ * of the loader itself. This avoids having to store a pointer to data
+ * for every lazy-loader. Multiple lazy-loaders can access the same data.
*/
template <typename Data, unsigned int WheresData>
@@ -228,7 +235,8 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
bool cmpexch (Stored *current, Stored *value) const
{
- /* This *must* be called when there are no other threads accessing. */
+ /* This function can only be safely called directly if no
+ * other thread is accessing. */
return this->instance.cmpexch (current, value);
}
@@ -261,7 +269,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
hb_free (p);
}
-// private:
+ private:
/* Must only have one pointer. */
hb_atomic_ptr_t<Stored *> instance;
};
@@ -283,7 +291,7 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
{
auto c = hb_sanitize_context_t ();
if (core)
- c.set_num_glyphs (0); // So we don't recurse ad infinitum...
+ c.set_num_glyphs (0); // So we don't recurse ad infinitum, or doesn't need num_glyphs
return c.reference_table<T> (face);
}
static void destroy (hb_blob_t *p) { hb_blob_destroy (p); }
diff --git a/thirdparty/harfbuzz/src/hb-map.hh b/thirdparty/harfbuzz/src/hb-map.hh
index 8302e3f8c7..bfb1b3f768 100644
--- a/thirdparty/harfbuzz/src/hb-map.hh
+++ b/thirdparty/harfbuzz/src/hb-map.hh
@@ -43,9 +43,9 @@ struct hb_hashmap_t
hb_hashmap_t () { init (); }
~hb_hashmap_t () { fini (); }
- hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (population); hb_copy (o, *this); }
+ hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (o.population); hb_copy (o, *this); }
hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); }
- hb_hashmap_t& operator= (const hb_hashmap_t& o) { resize (population); hb_copy (o, *this); return *this; }
+ hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); resize (o.population); hb_copy (o, *this); return *this; }
hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; }
hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t ()
@@ -71,6 +71,11 @@ struct hb_hashmap_t
uint32_t is_tombstone_ : 1;
V value;
+ item_t () : key (),
+ hash (0),
+ is_used_ (false), is_tombstone_ (false),
+ value () {}
+
bool is_used () const { return is_used_; }
void set_used (bool is_used) { is_used_ = is_used; }
bool is_tombstone () const { return is_tombstone_; }
@@ -88,17 +93,8 @@ struct hb_hashmap_t
return minus_1;
};
- void clear ()
- {
- new (std::addressof (key)) K ();
- new (std::addressof (value)) V ();
- hash = 0;
- is_used_ = false;
- is_tombstone_ = false;
- }
-
- bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); }
- bool operator == (const item_t &o) { return *this == o.key; }
+ bool operator == (const K &o) const { return hb_deref (key) == hb_deref (o); }
+ bool operator == (const item_t &o) const { return *this == o.key; }
hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); }
hb_pair_t<const K &, const V &> get_pair_ref() const { return hb_pair_t<const K &, const V &> (key, value); }
@@ -107,8 +103,8 @@ struct hb_hashmap_t
};
hb_object_header_t header;
- bool successful; /* Allocations successful */
- unsigned int population; /* Not including tombstones. */
+ unsigned int successful : 1; /* Allocations successful */
+ unsigned int population : 31; /* Not including tombstones. */
unsigned int occupancy; /* Including tombstones. */
unsigned int mask;
unsigned int prime;
@@ -118,7 +114,10 @@ struct hb_hashmap_t
{
if (unlikely (!a.successful || !b.successful))
return;
- hb_swap (a.population, b.population);
+ unsigned tmp = a.population;
+ a.population = b.population;
+ b.population = tmp;
+ //hb_swap (a.population, b.population);
hb_swap (a.occupancy, b.occupancy);
hb_swap (a.mask, b.mask);
hb_swap (a.prime, b.prime);
@@ -160,7 +159,9 @@ struct hb_hashmap_t
{
if (unlikely (!successful)) return false;
- unsigned int power = hb_bit_storage (hb_max (population, new_population) * 2 + 8);
+ if (new_population != 0 && (new_population + new_population / 2) < mask) return true;
+
+ unsigned int power = hb_bit_storage (hb_max ((unsigned) population, new_population) * 2 + 8);
unsigned int new_size = 1u << power;
item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t));
if (unlikely (!new_items))
@@ -169,9 +170,9 @@ struct hb_hashmap_t
return false;
}
for (auto &_ : hb_iter (new_items, new_size))
- _.clear ();
+ new (&_) item_t ();
- unsigned int old_size = mask + 1;
+ unsigned int old_size = size ();
item_t *old_items = items;
/* Switch to new, empty, array. */
@@ -181,47 +182,82 @@ struct hb_hashmap_t
items = new_items;
/* Insert back old items. */
- if (old_items)
- for (unsigned int i = 0; i < old_size; i++)
+ for (unsigned int i = 0; i < old_size; i++)
+ {
+ if (old_items[i].is_real ())
{
- if (old_items[i].is_real ())
- {
- set_with_hash (old_items[i].key,
- old_items[i].hash,
- std::move (old_items[i].value));
- }
- old_items[i].~item_t ();
+ set_with_hash (std::move (old_items[i].key),
+ old_items[i].hash,
+ std::move (old_items[i].value));
}
+ old_items[i].~item_t ();
+ }
hb_free (old_items);
return true;
}
+ template <typename KK, typename VV>
+ bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool is_delete=false)
+ {
+ if (unlikely (!successful)) return false;
+ if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false;
+ item_t &item = item_for_hash (key, hash);
+
+ if (is_delete && !(item == key))
+ return true; /* Trying to delete non-existent key. */
+
+ if (item.is_used ())
+ {
+ occupancy--;
+ if (!item.is_tombstone ())
+ population--;
+ }
+
+ item.key = std::forward<KK> (key);
+ item.value = std::forward<VV> (value);
+ item.hash = hash;
+ item.set_used (true);
+ item.set_tombstone (is_delete);
+
+ occupancy++;
+ if (!is_delete)
+ population++;
+
+ return true;
+ }
+
+ template <typename VV>
+ bool set (const K &key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value)); }
template <typename VV>
- bool set (K key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value)); }
+ bool set (K &&key, VV&& value) { return set_with_hash (std::move (key), hb_hash (key), std::forward<VV> (value)); }
- const V& get (K key) const
+ const V& get_with_hash (const K &key, uint32_t hash) const
+ {
+ if (unlikely (!items)) return item_t::default_value ();
+ auto &item = item_for_hash (key, hash);
+ return item.is_real () && item == key ? item.value : item_t::default_value ();
+ }
+ const V& get (const K &key) const
{
if (unlikely (!items)) return item_t::default_value ();
- unsigned int i = bucket_for (key);
- return items[i].is_real () && items[i] == key ? items[i].value : item_t::default_value ();
+ return get_with_hash (key, hb_hash (key));
}
- void del (K key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); }
+ void del (const K &key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); }
/* Has interface. */
- typedef const V& value_t;
- value_t operator [] (K k) const { return get (k); }
+ const V& operator [] (K k) const { return get (k); }
template <typename VV=V>
bool has (K key, VV **vp = nullptr) const
{
if (unlikely (!items))
return false;
- unsigned int i = bucket_for (key);
- if (items[i].is_real () && items[i] == key)
+ auto &item = item_for_hash (key, hb_hash (key));
+ if (item.is_real () && item == key)
{
- if (vp) *vp = &items[i].value;
+ if (vp) *vp = std::addressof (item.value);
return true;
}
else
@@ -230,13 +266,18 @@ struct hb_hashmap_t
/* Projection. */
V operator () (K k) const { return get (k); }
+ unsigned size () const { return mask ? mask + 1 : 0; }
+
void clear ()
{
if (unlikely (!successful)) return;
- if (items)
- for (auto &_ : hb_iter (items, mask + 1))
- _.clear ();
+ for (auto &_ : hb_iter (items, size ()))
+ {
+ /* Reconstruct items. */
+ _.~item_t ();
+ new (&_) item_t ();
+ }
population = occupancy = 0;
}
@@ -246,11 +287,10 @@ struct hb_hashmap_t
uint32_t hash () const
{
- uint32_t h = 0;
- for (const auto &item : + hb_array (items, mask ? mask + 1 : 0)
- | hb_filter (&item_t::is_real))
- h ^= item.total_hash ();
- return h;
+ return
+ + iter_items ()
+ | hb_reduce ([] (uint32_t h, const item_t &_) { return h ^ _.total_hash (); }, (uint32_t) 0u)
+ ;
}
bool is_equal (const hb_hashmap_t &other) const
@@ -258,7 +298,7 @@ struct hb_hashmap_t
if (population != other.population) return false;
for (auto pair : iter ())
- if (get (pair.first) != pair.second)
+ if (other.get (pair.first) != pair.second)
return false;
return true;
@@ -271,87 +311,54 @@ struct hb_hashmap_t
/*
* Iterator
*/
- auto iter () const HB_AUTO_RETURN
+
+ auto iter_items () const HB_AUTO_RETURN
(
- + hb_array (items, mask ? mask + 1 : 0)
+ + hb_iter (items, size ())
| hb_filter (&item_t::is_real)
- | hb_map (&item_t::get_pair)
)
auto iter_ref () const HB_AUTO_RETURN
(
- + hb_array (items, mask ? mask + 1 : 0)
- | hb_filter (&item_t::is_real)
+ + iter_items ()
| hb_map (&item_t::get_pair_ref)
)
- auto keys () const HB_AUTO_RETURN
+ auto iter () const HB_AUTO_RETURN
(
- + hb_array (items, mask ? mask + 1 : 0)
- | hb_filter (&item_t::is_real)
- | hb_map (&item_t::key)
- | hb_map (hb_ridentity)
+ + iter_items ()
+ | hb_map (&item_t::get_pair)
)
auto keys_ref () const HB_AUTO_RETURN
(
- + hb_array (items, mask ? mask + 1 : 0)
- | hb_filter (&item_t::is_real)
+ + iter_items ()
| hb_map (&item_t::key)
)
- auto values () const HB_AUTO_RETURN
+ auto keys () const HB_AUTO_RETURN
(
- + hb_array (items, mask ? mask + 1 : 0)
- | hb_filter (&item_t::is_real)
- | hb_map (&item_t::value)
+ + keys_ref ()
| hb_map (hb_ridentity)
)
auto values_ref () const HB_AUTO_RETURN
(
- + hb_array (items, mask ? mask + 1 : 0)
- | hb_filter (&item_t::is_real)
+ + iter_items ()
| hb_map (&item_t::value)
)
+ auto values () const HB_AUTO_RETURN
+ (
+ + values_ref ()
+ | hb_map (hb_ridentity)
+ )
/* Sink interface. */
hb_hashmap_t& operator << (const hb_pair_t<K, V>& v)
{ set (v.first, v.second); return *this; }
-
- protected:
-
- template <typename VV>
- bool set_with_hash (K key, uint32_t hash, VV&& value, bool is_delete=false)
- {
- if (unlikely (!successful)) return false;
- if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false;
- unsigned int i = bucket_for_hash (key, hash);
-
- if (is_delete && items[i].key != key)
- return true; /* Trying to delete non-existent key. */
-
- if (items[i].is_used ())
- {
- occupancy--;
- if (!items[i].is_tombstone ())
- population--;
- }
-
- items[i].key = key;
- items[i].value = std::forward<VV> (value);
- items[i].hash = hash;
- items[i].set_used (true);
- items[i].set_tombstone (is_delete);
-
- occupancy++;
- if (!is_delete)
- population++;
-
- return true;
- }
-
- unsigned int bucket_for (const K &key) const
- {
- return bucket_for_hash (key, hb_hash (key));
- }
-
- unsigned int bucket_for_hash (const K &key, uint32_t hash) const
+ hb_hashmap_t& operator << (const hb_pair_t<K, V&&>& v)
+ { set (v.first, std::move (v.second)); return *this; }
+ hb_hashmap_t& operator << (const hb_pair_t<K&&, V>& v)
+ { set (std::move (v.first), v.second); return *this; }
+ hb_hashmap_t& operator << (const hb_pair_t<K&&, V&&>& v)
+ { set (std::move (v.first), std::move (v.second)); return *this; }
+
+ item_t& item_for_hash (const K &key, uint32_t hash) const
{
hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
unsigned int i = hash % prime;
@@ -360,12 +367,12 @@ struct hb_hashmap_t
while (items[i].is_used ())
{
if (items[i].hash == hash && items[i] == key)
- return i;
+ return items[i];
if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
tombstone = i;
i = (i + ++step) & mask;
}
- return tombstone == (unsigned) -1 ? i : tombstone;
+ return items[tombstone == (unsigned) -1 ? i : tombstone];
}
static unsigned int prime_for (unsigned int shift)
diff --git a/thirdparty/harfbuzz/src/hb-meta.hh b/thirdparty/harfbuzz/src/hb-meta.hh
index 52a6791e31..31aa7fa6f1 100644
--- a/thirdparty/harfbuzz/src/hb-meta.hh
+++ b/thirdparty/harfbuzz/src/hb-meta.hh
@@ -112,8 +112,7 @@ template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_ident
template <typename T> using hb_add_pointer = decltype (_hb_try_add_pointer<T> (hb_prioritize));
-/* TODO Add feature-parity to std::decay. */
-template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>;
+template <typename T> using hb_decay = typename std::decay<T>::type;
#define hb_is_convertible(From,To) std::is_convertible<From, To>::value
diff --git a/thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh b/thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh
index d40fdeaa82..46a20c91ea 100644
--- a/thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh
+++ b/thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh
@@ -166,7 +166,7 @@ hb_ms_setup_features (const hb_feature_t *features,
{
auto *feature = active_features.lsearch (event->feature);
if (feature)
- active_features.remove (feature - active_features.arrayZ);
+ active_features.remove_ordered (feature - active_features.arrayZ);
}
}
diff --git a/thirdparty/harfbuzz/src/hb-multimap.hh b/thirdparty/harfbuzz/src/hb-multimap.hh
new file mode 100644
index 0000000000..f0f95917aa
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-multimap.hh
@@ -0,0 +1,92 @@
+/*
+ * Copyright © 2022 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_MULTIMAP_HH
+#define HB_MULTIMAP_HH
+
+#include "hb.hh"
+#include "hb-map.hh"
+#include "hb-vector.hh"
+
+
+/*
+ * hb_multimap_t
+ */
+
+struct hb_multimap_t
+{
+ void add (hb_codepoint_t k, hb_codepoint_t v)
+ {
+ hb_codepoint_t *i;
+ if (multiples_indices.has (k, &i))
+ {
+ multiples_values[*i].push (v);
+ return;
+ }
+
+ hb_codepoint_t *old_v;
+ if (singulars.has (k, &old_v))
+ {
+ hb_codepoint_t old = *old_v;
+ singulars.del (k);
+
+ multiples_indices.set (k, multiples_values.length);
+ auto *vec = multiples_values.push ();
+
+ vec->push (old);
+ vec->push (v);
+
+ return;
+ }
+
+ singulars.set (k, v);
+ }
+
+ hb_array_t<const hb_codepoint_t> get (hb_codepoint_t k) const
+ {
+ hb_codepoint_t *v;
+ if (singulars.has (k, &v))
+ return hb_array (v, 1);
+
+ hb_codepoint_t *i;
+ if (multiples_indices.has (k, &i))
+ return multiples_values[*i].as_array ();
+
+ return hb_array_t<hb_codepoint_t> ();
+ }
+
+ bool in_error () const
+ {
+ return singulars.in_error () || multiples_indices.in_error () || multiples_values.in_error ();
+ }
+
+ protected:
+ hb_map_t singulars;
+ hb_map_t multiples_indices;
+ hb_vector_t<hb_vector_t<hb_codepoint_t>> multiples_values;
+};
+
+
+
+#endif /* HB_MULTIMAP_HH */
diff --git a/thirdparty/harfbuzz/src/hb-mutex.hh b/thirdparty/harfbuzz/src/hb-mutex.hh
index 6914b22450..053f9ddcc4 100644
--- a/thirdparty/harfbuzz/src/hb-mutex.hh
+++ b/thirdparty/harfbuzz/src/hb-mutex.hh
@@ -108,10 +108,11 @@ struct hb_mutex_t
struct hb_lock_t
{
- hb_lock_t (hb_mutex_t &mutex_) : mutex (mutex_) { mutex.lock (); }
- ~hb_lock_t () { mutex.unlock (); }
+ hb_lock_t (hb_mutex_t &mutex_) : mutex (&mutex_) { mutex->lock (); }
+ hb_lock_t (hb_mutex_t *mutex_) : mutex (mutex_) { if (mutex) mutex->lock (); }
+ ~hb_lock_t () { if (mutex) mutex->unlock (); }
private:
- hb_mutex_t &mutex;
+ hb_mutex_t *mutex;
};
diff --git a/thirdparty/harfbuzz/src/hb-number-parser.hh b/thirdparty/harfbuzz/src/hb-number-parser.hh
index 1a9dbba6dd..ec68c3a728 100644
--- a/thirdparty/harfbuzz/src/hb-number-parser.hh
+++ b/thirdparty/harfbuzz/src/hb-number-parser.hh
@@ -31,7 +31,7 @@
#include "hb.hh"
-#line 35 "hb-number-parser.hh"
+#line 32 "hb-number-parser.hh"
static const unsigned char _double_parser_trans_keys[] = {
0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u,
46u, 101u, 0
@@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
int cs;
-#line 139 "hb-number-parser.hh"
+#line 132 "hb-number-parser.hh"
{
cs = double_parser_start;
}
-#line 144 "hb-number-parser.hh"
+#line 135 "hb-number-parser.hh"
{
int _slen;
int _trans;
@@ -198,7 +198,7 @@ _resume:
exp_overflow = true;
}
break;
-#line 202 "hb-number-parser.hh"
+#line 187 "hb-number-parser.hh"
}
_again:
diff --git a/thirdparty/harfbuzz/src/hb-object.hh b/thirdparty/harfbuzz/src/hb-object.hh
index 9876c2923c..a23c25f7ca 100644
--- a/thirdparty/harfbuzz/src/hb-object.hh
+++ b/thirdparty/harfbuzz/src/hb-object.hh
@@ -80,7 +80,7 @@ struct hb_lockable_set_t
if (item)
{
item_t old = *item;
- *item = items[items.length - 1];
+ *item = std::move (items.tail ());
items.pop ();
l.unlock ();
old.fini ();
@@ -123,7 +123,7 @@ struct hb_lockable_set_t
l.lock ();
while (items.length)
{
- item_t old = items[items.length - 1];
+ item_t old = items.tail ();
items.pop ();
l.unlock ();
old.fini ();
diff --git a/thirdparty/harfbuzz/src/hb-open-file.hh b/thirdparty/harfbuzz/src/hb-open-file.hh
index 6eee5827c1..13570a46e0 100644
--- a/thirdparty/harfbuzz/src/hb-open-file.hh
+++ b/thirdparty/harfbuzz/src/hb-open-file.hh
@@ -90,7 +90,7 @@ typedef struct OpenTypeOffsetTable
{
if (table_count)
{
- + tables.sub_array (start_offset, table_count)
+ + tables.as_array ().sub_array (start_offset, table_count)
| hb_map (&TableRecord::tag)
| hb_sink (hb_array (table_tags, *table_count))
;
@@ -158,7 +158,7 @@ typedef struct OpenTypeOffsetTable
return_trace (false);
if (likely (len))
- memcpy (start, blob->data, len);
+ hb_memcpy (start, blob->data, len);
/* 4-byte alignment. */
c->align (4);
diff --git a/thirdparty/harfbuzz/src/hb-open-type.hh b/thirdparty/harfbuzz/src/hb-open-type.hh
index e66f451820..290799127a 100644
--- a/thirdparty/harfbuzz/src/hb-open-type.hh
+++ b/thirdparty/harfbuzz/src/hb-open-type.hh
@@ -148,7 +148,7 @@ struct HBFixed : Type
static_assert (Type::static_size * 8 > fraction_bits, "");
HBFixed& operator = (typename Type::type i ) { Type::operator= (i); return *this; }
- float to_float () const { return ((int32_t) Type::v) / shift; }
+ float to_float (float offset = 0) const { return ((int32_t) Type::v + offset) / shift; }
void set_float (float f) { Type::v = roundf (f * shift); }
public:
DEFINE_SIZE_STATIC (Type::static_size);
@@ -157,6 +157,9 @@ struct HBFixed : Type
/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
using F2DOT14 = HBFixed<HBINT16, 14>;
+/* 16-bit signed fixed number with the low 12 bits of fraction (4.12). */
+using F4DOT12 = HBFixed<HBINT16, 12>;
+
/* 32-bit signed fixed-point number (16.16). */
using F16DOT16 = HBFixed<HBINT32, 16>;
@@ -209,6 +212,12 @@ typedef Index NameID;
struct VarIdx : HBUINT32 {
static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu;
+ static_assert (NO_VARIATION == HB_OT_LAYOUT_NO_VARIATIONS_INDEX, "");
+ static uint32_t add (uint32_t i, unsigned short v)
+ {
+ if (i == NO_VARIATION) return i;
+ return i + v;
+ }
VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
};
DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx);
@@ -493,10 +502,10 @@ struct UnsizedArrayOf
void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
{ as_array (len).qsort (start, end); }
- bool serialize (hb_serialize_context_t *c, unsigned int items_len)
+ bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true)
{
TRACE_SERIALIZE (this);
- if (unlikely (!c->extend (this, items_len))) return_trace (false);
+ if (unlikely (!c->extend_size (this, get_size (items_len), clear))) return_trace (false);
return_trace (true);
}
template <typename Iterator,
@@ -504,8 +513,8 @@ struct UnsizedArrayOf
bool serialize (hb_serialize_context_t *c, Iterator items)
{
TRACE_SERIALIZE (this);
- unsigned count = items.len ();
- if (unlikely (!serialize (c, count))) return_trace (false);
+ unsigned count = hb_len (items);
+ if (unlikely (!serialize (c, count, false))) return_trace (false);
/* TODO Umm. Just exhaust the iterator instead? Being extra
* cautious right now.. */
for (unsigned i = 0; i < count; i++, ++items)
@@ -646,14 +655,9 @@ struct ArrayOf
operator iter_t () const { return iter (); }
operator writer_t () { return writer (); }
- hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
- { return as_array ().sub_array (start_offset, count); }
- hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
- { return as_array ().sub_array (start_offset, count); }
- hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
- { return as_array ().sub_array (start_offset, count); }
- hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
- { return as_array ().sub_array (start_offset, count); }
+ /* Faster range-based for loop. */
+ const Type *begin () const { return arrayZ; }
+ const Type *end () const { return arrayZ + len; }
template <typename T>
Type &lsearch (const T &x, Type &not_found = Crap (Type))
@@ -667,15 +671,15 @@ struct ArrayOf
unsigned int to_store = (unsigned int) -1) const
{ return as_array ().lfind (x, i, not_found, to_store); }
- void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
- { as_array ().qsort (start, end); }
+ void qsort ()
+ { as_array ().qsort (); }
- HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len)
+ HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len, bool clear = true)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
- if (unlikely (!c->extend (this))) return_trace (false);
+ if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false);
return_trace (true);
}
template <typename Iterator,
@@ -683,8 +687,8 @@ struct ArrayOf
HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items)
{
TRACE_SERIALIZE (this);
- unsigned count = items.len ();
- if (unlikely (!serialize (c, count))) return_trace (false);
+ unsigned count = hb_len (items);
+ if (unlikely (!serialize (c, count, false))) return_trace (false);
/* TODO Umm. Just exhaust the iterator instead? Being extra
* cautious right now.. */
for (unsigned i = 0; i < count; i++, ++items)
@@ -828,21 +832,25 @@ struct HeadlessArrayOf
operator iter_t () const { return iter (); }
operator writer_t () { return writer (); }
- bool serialize (hb_serialize_context_t *c, unsigned int items_len)
+ /* Faster range-based for loop. */
+ const Type *begin () const { return arrayZ; }
+ const Type *end () const { return arrayZ + get_length (); }
+
+ HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
- if (unlikely (!c->extend (this))) return_trace (false);
+ if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false);
return_trace (true);
}
template <typename Iterator,
hb_requires (hb_is_source_of (Iterator, Type))>
- bool serialize (hb_serialize_context_t *c, Iterator items)
+ HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items)
{
TRACE_SERIALIZE (this);
- unsigned count = items.len ();
- if (unlikely (!serialize (c, count))) return_trace (false);
+ unsigned count = hb_len (items);
+ if (unlikely (!serialize (c, count, false))) return_trace (false);
/* TODO Umm. Just exhaust the iterator instead? Being extra
* cautious right now.. */
for (unsigned i = 0; i < count; i++, ++items)
@@ -944,14 +952,9 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
operator iter_t () const { return iter (); }
operator writer_t () { return writer (); }
- hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
- { return as_array ().sub_array (start_offset, count); }
- hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
- { return as_array ().sub_array (start_offset, count); }
- hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
- { return as_array ().sub_array (start_offset, count); }
- hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
- { return as_array ().sub_array (start_offset, count); }
+ /* Faster range-based for loop. */
+ const Type *begin () const { return this->arrayZ; }
+ const Type *end () const { return this->arrayZ + this->len; }
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
{
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
index ae3b83a256..f22824fc69 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
@@ -66,95 +66,25 @@ struct CFFIndex
{
TRACE_SERIALIZE (this);
unsigned int size = get_size ();
- CFFIndex *out = c->allocate_size<CFFIndex> (size);
+ CFFIndex *out = c->allocate_size<CFFIndex> (size, false);
if (likely (out))
- memcpy (out, this, size);
+ hb_memcpy (out, this, size);
return_trace (out);
}
+ template <typename Iterable,
+ hb_requires (hb_is_iterable (Iterable))>
bool serialize (hb_serialize_context_t *c,
- unsigned int offSize_,
- const byte_str_array_t &byteArray)
+ const Iterable &iterable)
{
TRACE_SERIALIZE (this);
-
- if (byteArray.length == 0)
- {
- COUNT *dest = c->allocate_min<COUNT> ();
- if (unlikely (!dest)) return_trace (false);
- *dest = 0;
- return_trace (true);
- }
-
- /* serialize CFFIndex header */
- if (unlikely (!c->extend_min (this))) return_trace (false);
- this->count = byteArray.length;
- this->offSize = offSize_;
- if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
- return_trace (false);
-
- /* serialize indices */
- unsigned int offset = 1;
- unsigned int i = 0;
- for (; i < byteArray.length; i++)
- {
- set_offset_at (i, offset);
- offset += byteArray[i].get_size ();
- }
- set_offset_at (i, offset);
-
- /* serialize data */
- for (unsigned int i = 0; i < byteArray.length; i++)
- {
- const hb_ubytes_t &bs = byteArray[i];
- unsigned char *dest = c->allocate_size<unsigned char> (bs.length);
- if (unlikely (!dest)) return_trace (false);
- memcpy (dest, &bs[0], bs.length);
- }
-
- return_trace (true);
- }
-
- bool serialize (hb_serialize_context_t *c,
- unsigned int offSize_,
- const str_buff_vec_t &buffArray)
- {
- byte_str_array_t byteArray;
- byteArray.init ();
- byteArray.resize (buffArray.length);
- for (unsigned int i = 0; i < byteArray.length; i++)
- byteArray[i] = hb_ubytes_t (buffArray[i].arrayZ, buffArray[i].length);
- bool result = this->serialize (c, offSize_, byteArray);
- byteArray.fini ();
- return result;
- }
-
- template <typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
- bool serialize (hb_serialize_context_t *c,
- Iterator it)
- {
- TRACE_SERIALIZE (this);
- serialize_header(c, + it | hb_map ([] (const hb_ubytes_t &_) { return _.length; }));
+ auto it = hb_iter (iterable);
+ serialize_header(c, + it | hb_map (hb_iter) | hb_map (hb_len));
for (const auto &_ : +it)
- _.copy (c);
+ hb_iter (_).copy (c);
return_trace (true);
}
- bool serialize (hb_serialize_context_t *c,
- const byte_str_array_t &byteArray)
- { return serialize (c, + hb_iter (byteArray)); }
-
- bool serialize (hb_serialize_context_t *c,
- const str_buff_vec_t &buffArray)
- {
- auto it =
- + hb_iter (buffArray)
- | hb_map ([] (const str_buff_t &_) { return hb_ubytes_t (_.arrayZ, _.length); })
- ;
- return serialize (c, it);
- }
-
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize_header (hb_serialize_context_t *c,
@@ -171,7 +101,7 @@ struct CFFIndex
if (!this->count) return_trace (true);
if (unlikely (!c->extend (this->offSize))) return_trace (false);
this->offSize = off_size;
- if (unlikely (!c->allocate_size<HBUINT8> (off_size * (this->count + 1))))
+ if (unlikely (!c->allocate_size<HBUINT8> (off_size * (this->count + 1), false)))
return_trace (false);
/* serialize indices */
@@ -179,14 +109,27 @@ struct CFFIndex
unsigned int i = 0;
for (unsigned _ : +it)
{
- CFFIndex<COUNT>::set_offset_at (i++, offset);
+ set_offset_at (i++, offset);
offset += _;
}
- CFFIndex<COUNT>::set_offset_at (i, offset);
+ set_offset_at (i, offset);
return_trace (true);
}
+ template <typename Iterable,
+ hb_requires (hb_is_iterable (Iterable))>
+ static unsigned total_size (const Iterable &iterable)
+ {
+ auto it = + hb_iter (iterable) | hb_map (hb_iter) | hb_map (hb_len);
+ if (!it) return 0;
+
+ unsigned total = + it | hb_reduce (hb_add, 0);
+ unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
+
+ return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total;
+ }
+
void set_offset_at (unsigned int index, unsigned int offset)
{
assert (index <= count);
@@ -207,10 +150,14 @@ struct CFFIndex
unsigned int size = offSize;
const HBUINT8 *p = offsets + size * index;
- unsigned int offset = 0;
- for (; size; size--)
- offset = (offset << 8) + *p++;
- return offset;
+ switch (size)
+ {
+ case 1: return * (HBUINT8 *) p;
+ case 2: return * (HBUINT16 *) p;
+ case 3: return * (HBUINT24 *) p;
+ case 4: return * (HBUINT32 *) p;
+ default: return 0;
+ }
}
unsigned int length_at (unsigned int index) const
@@ -229,6 +176,7 @@ struct CFFIndex
hb_ubytes_t operator [] (unsigned int index) const
{
if (unlikely (index >= count)) return hb_ubytes_t ();
+ _hb_compiler_memory_r_barrier ();
unsigned length = length_at (index);
if (unlikely (!length)) return hb_ubytes_t ();
return hb_ubytes_t (data_base () + offset_at (index) - 1, length);
@@ -280,7 +228,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
if (unlikely (!c->extend_min (this))) return_trace (false);
this->count = dataArrayLen;
this->offSize = offSize_;
- if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
+ if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1), false)))
return_trace (false);
/* serialize indices */
@@ -288,10 +236,10 @@ struct CFFIndexOf : CFFIndex<COUNT>
unsigned int i = 0;
for (; i < dataArrayLen; i++)
{
- CFFIndex<COUNT>::set_offset_at (i, offset);
+ this->set_offset_at (i, offset);
offset += dataSizeArray[i];
}
- CFFIndex<COUNT>::set_offset_at (i, offset);
+ this->set_offset_at (i, offset);
/* serialize data */
for (unsigned int i = 0; i < dataArrayLen; i++)
@@ -324,13 +272,12 @@ struct Dict : UnsizedByteStr
template <typename T, typename V>
static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, V value, op_code_t intOp)
{
- // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation
- if (/*unlikely*/ (!serialize_int<T, V> (c, intOp, value)))
+ if (unlikely ((!serialize_int<T, V> (c, intOp, value))))
return false;
TRACE_SERIALIZE (this);
/* serialize the opcode */
- HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op));
+ HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op), false);
if (unlikely (!p)) return_trace (false);
if (Is_OpCode_ESC (op))
{
@@ -415,9 +362,8 @@ struct FDSelect0 {
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this))))
return_trace (false);
- for (unsigned int i = 0; i < c->get_num_glyphs (); i++)
- if (unlikely (!fds[i].sanitize (c)))
- return_trace (false);
+ if (unlikely (!c->check_array (fds, c->get_num_glyphs ())))
+ return_trace (false);
return_trace (true);
}
@@ -471,14 +417,20 @@ struct FDSelect3_4
return_trace (true);
}
- hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+ static int _cmp_range (const void *_key, const void *_item)
{
- unsigned int i;
- for (i = 1; i < nRanges (); i++)
- if (glyph < ranges[i].first)
- break;
+ hb_codepoint_t glyph = * (hb_codepoint_t *) _key;
+ FDSelect3_4_Range<GID_TYPE, FD_TYPE> *range = (FDSelect3_4_Range<GID_TYPE, FD_TYPE> *) _item;
- return (hb_codepoint_t) ranges[i - 1].fd;
+ if (glyph < range[0].first) return -1;
+ if (glyph < range[1].first) return 0;
+ return +1;
+ }
+
+ hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+ {
+ auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range);
+ return range ? range->fd : ranges[nRanges () - 1].fd;
}
GID_TYPE &nRanges () { return ranges.len; }
@@ -501,9 +453,9 @@ struct FDSelect
{
TRACE_SERIALIZE (this);
unsigned int size = src.get_size (num_glyphs);
- FDSelect *dest = c->allocate_size<FDSelect> (size);
+ FDSelect *dest = c->allocate_size<FDSelect> (size, false);
if (unlikely (!dest)) return_trace (false);
- memcpy (dest, &src, size);
+ hb_memcpy (dest, &src, size);
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
index 17b0296616..bb856c9ddb 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
@@ -175,7 +175,7 @@ struct Encoding
unsigned int size = src.get_size ();
Encoding *dest = c->allocate_size<Encoding> (size);
if (unlikely (!dest)) return_trace (false);
- memcpy (dest, &src, size);
+ hb_memcpy (dest, &src, size);
return_trace (true);
}
@@ -471,7 +471,7 @@ struct Charset
unsigned int size = src.get_size (num_glyphs);
Charset *dest = c->allocate_size<Charset> (size);
if (unlikely (!dest)) return_trace (false);
- memcpy (dest, &src, size);
+ hb_memcpy (dest, &src, size);
return_trace (true);
}
@@ -617,7 +617,6 @@ struct CFF1StringIndex : CFF1Index
}
byte_str_array_t bytesArray;
- bytesArray.init ();
if (!bytesArray.resize (sidmap.get_population ()))
return_trace (false);
for (unsigned int i = 0; i < strings.count; i++)
@@ -628,7 +627,6 @@ struct CFF1StringIndex : CFF1Index
}
bool result = CFF1Index::serialize (c, bytesArray);
- bytesArray.fini ();
return_trace (result);
}
};
@@ -813,7 +811,7 @@ struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
break;
default:
- env.last_offset = env.str_ref.offset;
+ env.last_offset = env.str_ref.get_offset ();
top_dict_opset_t<cff1_top_dict_val_t>::process_op (op, env, dictval);
/* Record this operand below if stack is empty, otherwise done */
if (!env.argStack.is_empty ()) return;
@@ -1295,10 +1293,10 @@ struct cff1
}
protected:
- hb_blob_t *blob = nullptr;
hb_sanitize_context_t sc;
public:
+ hb_blob_t *blob = nullptr;
const Encoding *encoding = nullptr;
const Charset *charset = nullptr;
const CFF1NameIndex *nameIndex = nullptr;
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh
index 746160dc8e..9081930bbe 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh
@@ -56,7 +56,7 @@ struct CFF2FDSelect
unsigned int size = src.get_size (num_glyphs);
CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
if (unlikely (!dest)) return_trace (false);
- memcpy (dest, &src, size);
+ hb_memcpy (dest, &src, size);
return_trace (true);
}
@@ -124,7 +124,7 @@ struct CFF2VariationStore
unsigned int size_ = varStore->get_size ();
CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
if (unlikely (!dest)) return_trace (false);
- memcpy (dest, varStore, size_);
+ hb_memcpy (dest, varStore, size_);
return_trace (true);
}
@@ -483,13 +483,18 @@ struct cff2
blob = nullptr;
}
+ hb_map_t *create_glyph_to_sid_map () const
+ {
+ return nullptr;
+ }
+
bool is_valid () const { return blob; }
protected:
- hb_blob_t *blob = nullptr;
hb_sanitize_context_t sc;
public:
+ hb_blob_t *blob = nullptr;
cff2_top_dict_values_t topDict;
const CFF2Subrs *globalSubrs = nullptr;
const CFF2VariationStore *varStore = nullptr;
diff --git a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
index 09c9fe93f3..523196fa79 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
@@ -909,7 +909,7 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
hb_codepoint_t first = arrayZ[i].startUnicodeValue;
hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
(hb_codepoint_t) HB_UNICODE_MAX);
- out->add_range (first, hb_min (last, 0x10FFFFu));
+ out->add_range (first, last);
}
}
@@ -925,37 +925,75 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
unsigned init_len = c->length ();
- hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID;
- int count = -1;
-
- for (const UnicodeValueRange& _ : as_array ())
+ if (this->len > unicodes->get_population () * hb_bit_storage ((unsigned) this->len))
{
- for (const unsigned addcnt : hb_range ((unsigned) _.additionalCount + 1))
+ hb_codepoint_t start = HB_SET_VALUE_INVALID;
+ hb_codepoint_t end = HB_SET_VALUE_INVALID;
+
+ for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
+ unicodes->next (&u);)
{
- unsigned curEntry = (unsigned) _.startUnicodeValue + addcnt;
- if (!unicodes->has (curEntry)) continue;
- count += 1;
- if (lastCode == HB_MAP_VALUE_INVALID)
- lastCode = curEntry;
- else if (lastCode + count != curEntry)
+ if (!as_array ().bsearch (u))
+ continue;
+ if (start == HB_SET_VALUE_INVALID)
{
+ start = u;
+ end = start - 1;
+ }
+ if (end + 1 != u || end - start == 255)
+ {
UnicodeValueRange rec;
- rec.startUnicodeValue = lastCode;
- rec.additionalCount = count - 1;
+ rec.startUnicodeValue = start;
+ rec.additionalCount = end - start;
c->copy<UnicodeValueRange> (rec);
-
- lastCode = curEntry;
- count = 0;
+ start = u;
}
+ end = u;
+ }
+ if (start != HB_SET_VALUE_INVALID)
+ {
+ UnicodeValueRange rec;
+ rec.startUnicodeValue = start;
+ rec.additionalCount = end - start;
+ c->copy<UnicodeValueRange> (rec);
}
- }
- if (lastCode != HB_MAP_VALUE_INVALID)
+ }
+ else
{
- UnicodeValueRange rec;
- rec.startUnicodeValue = lastCode;
- rec.additionalCount = count;
- c->copy<UnicodeValueRange> (rec);
+ hb_codepoint_t lastCode = HB_SET_VALUE_INVALID;
+ int count = -1;
+
+ for (const UnicodeValueRange& _ : *this)
+ {
+ hb_codepoint_t curEntry = (hb_codepoint_t) (_.startUnicodeValue - 1);
+ hb_codepoint_t end = curEntry + _.additionalCount + 2;
+
+ for (; unicodes->next (&curEntry) && curEntry < end;)
+ {
+ count += 1;
+ if (lastCode == HB_SET_VALUE_INVALID)
+ lastCode = curEntry;
+ else if (lastCode + count != curEntry)
+ {
+ UnicodeValueRange rec;
+ rec.startUnicodeValue = lastCode;
+ rec.additionalCount = count - 1;
+ c->copy<UnicodeValueRange> (rec);
+
+ lastCode = curEntry;
+ count = 0;
+ }
+ }
+ }
+
+ if (lastCode != HB_MAP_VALUE_INVALID)
+ {
+ UnicodeValueRange rec;
+ rec.startUnicodeValue = lastCode;
+ rec.additionalCount = count;
+ c->copy<UnicodeValueRange> (rec);
+ }
}
if (c->length () - init_len == 0)
@@ -1474,32 +1512,80 @@ struct EncodingRecord
DEFINE_SIZE_STATIC (8);
};
+struct cmap;
+
struct SubtableUnicodesCache {
private:
- const void* base;
- hb_hashmap_t<intptr_t, hb::unique_ptr<hb_set_t>> cached_unicodes;
+ hb_blob_ptr_t<cmap> base_blob;
+ const char* base;
+ hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> cached_unicodes;
public:
+
+ static SubtableUnicodesCache* create (hb_blob_ptr_t<cmap> source_table)
+ {
+ SubtableUnicodesCache* cache =
+ (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache));
+ new (cache) SubtableUnicodesCache (source_table);
+ return cache;
+ }
+
+ static void destroy (void* value) {
+ if (!value) return;
+
+ SubtableUnicodesCache* cache = (SubtableUnicodesCache*) value;
+ cache->~SubtableUnicodesCache ();
+ hb_free (cache);
+ }
+
SubtableUnicodesCache(const void* cmap_base)
- : base(cmap_base), cached_unicodes() {}
+ : base_blob(),
+ base ((const char*) cmap_base),
+ cached_unicodes ()
+ {}
+
+ SubtableUnicodesCache(hb_blob_ptr_t<cmap> base_blob_)
+ : base_blob(base_blob_),
+ base ((const char *) base_blob.get()),
+ cached_unicodes ()
+ {}
+
+ ~SubtableUnicodesCache()
+ {
+ base_blob.destroy ();
+ }
+
+ bool same_base(const void* other) const
+ {
+ return other == (const void*) base;
+ }
- hb_set_t* set_for (const EncodingRecord* record)
+ const hb_set_t* set_for (const EncodingRecord* record,
+ SubtableUnicodesCache& mutable_cache) const
{
- if (!cached_unicodes.has ((intptr_t) record))
+ if (cached_unicodes.has ((unsigned) ((const char *) record - base)))
+ return cached_unicodes.get ((unsigned) ((const char *) record - base));
+
+ return mutable_cache.set_for (record);
+ }
+
+ const hb_set_t* set_for (const EncodingRecord* record)
+ {
+ if (!cached_unicodes.has ((unsigned) ((const char *) record - base)))
{
hb_set_t *s = hb_set_create ();
if (unlikely (s->in_error ()))
return hb_set_get_empty ();
-
+
(base+record->subtable).collect_unicodes (s);
- if (unlikely (!cached_unicodes.set ((intptr_t) record, hb::unique_ptr<hb_set_t> {s})))
+ if (unlikely (!cached_unicodes.set ((unsigned) ((const char *) record - base), hb::unique_ptr<hb_set_t> {s})))
return hb_set_get_empty ();
return s;
}
- return cached_unicodes.get ((intptr_t) record);
+ return cached_unicodes.get ((unsigned) ((const char *) record - base));
}
};
@@ -1523,13 +1609,30 @@ struct cmap
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
+
+ static SubtableUnicodesCache* create_filled_cache(hb_blob_ptr_t<cmap> source_table) {
+ const cmap* cmap = source_table.get();
+ auto it =
+ + hb_iter (cmap->encodingRecord)
+ | hb_filter ([&](const EncodingRecord& _) {
+ return cmap::filter_encoding_records_for_subset (cmap, _);
+ })
+ ;
+
+ SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table);
+ for (const EncodingRecord& _ : it)
+ cache->set_for(&_); // populate the cache for this encoding record.
+
+ return cache;
+ }
+
template<typename Iterator, typename EncodingRecIter,
hb_requires (hb_is_iterator (EncodingRecIter))>
bool serialize (hb_serialize_context_t *c,
Iterator it,
EncodingRecIter encodingrec_iter,
const void *base,
- const hb_subset_plan_t *plan,
+ hb_subset_plan_t *plan,
bool drop_format_4 = false)
{
if (unlikely (!c->extend_min ((*this)))) return false;
@@ -1538,7 +1641,14 @@ struct cmap
unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
auto snap = c->snapshot ();
- SubtableUnicodesCache unicodes_cache (base);
+ SubtableUnicodesCache local_unicodes_cache (base);
+ const SubtableUnicodesCache* unicodes_cache = &local_unicodes_cache;
+
+ if (plan->accelerator &&
+ plan->accelerator->cmap_cache &&
+ plan->accelerator->cmap_cache->same_base (base))
+ unicodes_cache = plan->accelerator->cmap_cache;
+
for (const EncodingRecord& _ : encodingrec_iter)
{
if (c->in_error ())
@@ -1547,7 +1657,7 @@ struct cmap
unsigned format = (base+_.subtable).u.format;
if (format != 4 && format != 12 && format != 14) continue;
- hb_set_t* unicodes_set = unicodes_cache.set_for (&_);
+ const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache);
if (!drop_format_4 && format == 4)
{
@@ -1566,7 +1676,13 @@ struct cmap
else if (format == 12)
{
- if (_can_drop (_, *unicodes_set, base, unicodes_cache, + it | hb_map (hb_first), encodingrec_iter)) continue;
+ if (_can_drop (_,
+ *unicodes_set,
+ base,
+ *unicodes_cache,
+ local_unicodes_cache,
+ + it | hb_map (hb_first), encodingrec_iter))
+ continue;
c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx);
}
else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
@@ -1585,7 +1701,8 @@ struct cmap
bool _can_drop (const EncodingRecord& cmap12,
const hb_set_t& cmap12_unicodes,
const void* base,
- SubtableUnicodesCache& unicodes_cache,
+ const SubtableUnicodesCache& unicodes_cache,
+ SubtableUnicodesCache& local_unicodes_cache,
Iterator subset_unicodes,
EncodingRecordIterator encoding_records)
{
@@ -1616,7 +1733,7 @@ struct cmap
|| (base+_.subtable).get_language() != target_language)
continue;
- hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_);
+ const hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_, local_unicodes_cache);
auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes);
@@ -1653,17 +1770,9 @@ struct cmap
auto encodingrec_iter =
+ hb_iter (encodingRecord)
- | hb_filter ([&] (const EncodingRecord& _)
- {
- if ((_.platformID == 0 && _.encodingID == 3) ||
- (_.platformID == 0 && _.encodingID == 4) ||
- (_.platformID == 3 && _.encodingID == 1) ||
- (_.platformID == 3 && _.encodingID == 10) ||
- (this + _.subtable).u.format == 14)
- return true;
-
- return false;
- })
+ | hb_filter ([&](const EncodingRecord& _) {
+ return cmap::filter_encoding_records_for_subset (this, _);
+ })
;
if (unlikely (!encodingrec_iter.len ())) return_trace (false);
@@ -1692,7 +1801,11 @@ struct cmap
{ return (_.second != HB_MAP_VALUE_INVALID); })
;
- return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan));
+ return_trace (cmap_prime->serialize (c->serializer,
+ it,
+ encodingrec_iter,
+ this,
+ c->plan));
}
const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
@@ -1928,6 +2041,19 @@ struct cmap
encodingRecord.sanitize (c, this));
}
+ private:
+
+ static bool filter_encoding_records_for_subset(const cmap* cmap,
+ const EncodingRecord& _)
+ {
+ return
+ (_.platformID == 0 && _.encodingID == 3) ||
+ (_.platformID == 0 && _.encodingID == 4) ||
+ (_.platformID == 3 && _.encodingID == 1) ||
+ (_.platformID == 3 && _.encodingID == 10) ||
+ (cmap + _.subtable).u.format == 14;
+ }
+
protected:
HBUINT16 version; /* Table version number (0). */
SortedArray16Of<EncodingRecord>
diff --git a/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh
index 23fa56c4f6..3246894d39 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh
@@ -67,7 +67,7 @@ _copy_data_to_cbdt (hb_vector_t<char> *cbdt_prime,
{
unsigned int new_len = cbdt_prime->length + length;
if (unlikely (!cbdt_prime->alloc (new_len))) return false;
- memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length);
+ hb_memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length);
cbdt_prime->length = new_len;
return true;
}
@@ -468,13 +468,13 @@ struct IndexSubtableRecord
if (unlikely (!c->serializer->check_success (records->resize (records->length + 1))))
return_trace (false);
- (*records)[records->length - 1].firstGlyphIndex = 1;
- (*records)[records->length - 1].lastGlyphIndex = 0;
+ records->tail ().firstGlyphIndex = 1;
+ records->tail ().lastGlyphIndex = 0;
bitmap_size_context->size += IndexSubtableRecord::min_size;
c->serializer->push ();
- if (unlikely (!add_new_subtable (c, bitmap_size_context, &((*records)[records->length - 1]), lookup, base, start)))
+ if (unlikely (!add_new_subtable (c, bitmap_size_context, &(records->tail ()), lookup, base, start)))
{
c->serializer->pop_discard ();
c->serializer->revert (snap);
diff --git a/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
index 908bf550f0..1af9d30937 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
@@ -39,11 +39,7 @@
#define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
#ifndef HB_COLRV1_MAX_NESTING_LEVEL
-#define HB_COLRV1_MAX_NESTING_LEVEL 100
-#endif
-
-#ifndef COLRV1_ENABLE_SUBSETTING
-#define COLRV1_ENABLE_SUBSETTING 1
+#define HB_COLRV1_MAX_NESTING_LEVEL 16
#endif
namespace OT {
@@ -188,6 +184,7 @@ struct Variable
protected:
T value;
+ public:
VarIdx varIdxBase;
public:
DEFINE_SIZE_STATIC (4 + T::static_size);
@@ -196,6 +193,8 @@ struct Variable
template <typename T>
struct NoVariable
{
+ static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
+
NoVariable<T>* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
@@ -888,6 +887,11 @@ struct PaintComposite
DEFINE_SIZE_STATIC (8);
};
+struct ClipBoxData
+{
+ int xMin, yMin, xMax, yMax;
+};
+
struct ClipBoxFormat1
{
bool sanitize (hb_sanitize_context_t *c) const
@@ -896,6 +900,14 @@ struct ClipBoxFormat1
return_trace (c->check_struct (this));
}
+ void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const
+ {
+ clip_box.xMin = xMin;
+ clip_box.yMin = yMin;
+ clip_box.xMax = xMax;
+ clip_box.yMax = yMax;
+ }
+
public:
HBUINT8 format; /* format = 1(noVar) or 2(Var)*/
FWORD xMin;
@@ -906,7 +918,20 @@ struct ClipBoxFormat1
DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size);
};
-struct ClipBoxFormat2 : Variable<ClipBoxFormat1> {};
+struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
+{
+ void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const
+ {
+ value.get_clip_box(clip_box, instancer);
+ if (instancer)
+ {
+ clip_box.xMin += _hb_roundf (instancer (varIdxBase, 0));
+ clip_box.yMin += _hb_roundf (instancer (varIdxBase, 1));
+ clip_box.xMax += _hb_roundf (instancer (varIdxBase, 2));
+ clip_box.yMax += _hb_roundf (instancer (varIdxBase, 3));
+ }
+ }
+};
struct ClipBox
{
@@ -932,6 +957,28 @@ struct ClipBox
}
}
+ bool get_extents (hb_glyph_extents_t *extents,
+ const VarStoreInstancer &instancer) const
+ {
+ ClipBoxData clip_box;
+ switch (u.format) {
+ case 1:
+ u.format1.get_clip_box (clip_box, instancer);
+ break;
+ case 2:
+ u.format2.get_clip_box (clip_box, instancer);
+ break;
+ default:
+ return false;
+ }
+
+ extents->x_bearing = clip_box.xMin;
+ extents->y_bearing = clip_box.yMax;
+ extents->width = clip_box.xMax - clip_box.xMin;
+ extents->height = clip_box.yMin - clip_box.yMax;
+ return true;
+ }
+
protected:
union {
HBUINT8 format; /* Format identifier */
@@ -942,6 +989,9 @@ struct ClipBox
struct ClipRecord
{
+ int cmp (hb_codepoint_t g) const
+ { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
+
ClipRecord* copy (hb_serialize_context_t *c, const void *base) const
{
TRACE_SERIALIZE (this);
@@ -957,6 +1007,13 @@ struct ClipRecord
return_trace (c->check_struct (this) && clipBox.sanitize (c, base));
}
+ bool get_extents (hb_glyph_extents_t *extents,
+ const void *base,
+ const VarStoreInstancer &instancer) const
+ {
+ return (base+clipBox).get_extents (extents, instancer);
+ }
+
public:
HBUINT16 startGlyphID; // first gid clip applies to
HBUINT16 endGlyphID; // last gid clip applies to, inclusive
@@ -964,6 +1021,7 @@ struct ClipRecord
public:
DEFINE_SIZE_STATIC (7);
};
+DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
struct ClipList
{
@@ -1052,11 +1110,26 @@ struct ClipList
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
+ // TODO Make a formatted struct!
return_trace (c->check_struct (this) && clips.sanitize (c, this));
}
+ bool
+ get_extents (hb_codepoint_t gid,
+ hb_glyph_extents_t *extents,
+ const VarStoreInstancer &instancer) const
+ {
+ auto *rec = clips.as_array ().bsearch (gid);
+ if (rec)
+ {
+ rec->get_extents (extents, this, instancer);
+ return true;
+ }
+ return false;
+ }
+
HBUINT8 format; // Set to 1.
- Array32Of<ClipRecord> clips; // Clip records, sorted by startGlyphID
+ SortedArray32Of<ClipRecord> clips; // Clip records, sorted by startGlyphID
public:
DEFINE_SIZE_ARRAY_SIZED (5, clips);
};
@@ -1359,7 +1432,7 @@ struct COLR
(this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
(this+layersZ).sanitize (c, numLayers) &&
(version == 0 ||
- (COLRV1_ENABLE_SUBSETTING && version == 1 &&
+ (version == 1 &&
baseGlyphList.sanitize (c, this) &&
layerList.sanitize (c, this) &&
clipList.sanitize (c, this) &&
@@ -1516,6 +1589,30 @@ struct COLR
return_trace (true);
}
+ bool
+ get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+ {
+ if (version != 1)
+ return false;
+
+ VarStoreInstancer instancer (this+varStore,
+ this+varIdxMap,
+ hb_array (font->coords, font->num_coords));
+
+ if ((this+clipList).get_extents (glyph,
+ extents,
+ instancer))
+ {
+ extents->x_bearing = font->em_scale_x (extents->x_bearing);
+ extents->y_bearing = font->em_scale_x (extents->y_bearing);
+ extents->width = font->em_scale_x (extents->width);
+ extents->height = font->em_scale_x (extents->height);
+ return true;
+ }
+
+ return false;
+ }
+
protected:
HBUINT16 version; /* Table version number (starts at 0). */
HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */
diff --git a/thirdparty/harfbuzz/src/hb-ot-face-table-list.hh b/thirdparty/harfbuzz/src/hb-ot-face-table-list.hh
index c05034b3bb..c9da36c1bb 100644
--- a/thirdparty/harfbuzz/src/hb-ot-face-table-list.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-face-table-list.hh
@@ -56,9 +56,9 @@ HB_OT_CORE_TABLE (OT, maxp)
#if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT)
HB_OT_ACCELERATOR (OT, cmap)
#endif
-HB_OT_TABLE (OT, hhea)
+HB_OT_CORE_TABLE (OT, hhea)
HB_OT_ACCELERATOR (OT, hmtx)
-HB_OT_TABLE (OT, OS2)
+HB_OT_CORE_TABLE (OT, OS2)
#if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE)
HB_OT_ACCELERATOR (OT, post)
#endif
@@ -66,7 +66,7 @@ HB_OT_ACCELERATOR (OT, post)
HB_OT_ACCELERATOR (OT, name)
#endif
#ifndef HB_NO_STYLE
-HB_OT_TABLE (OT, STAT)
+HB_OT_CORE_TABLE (OT, STAT)
#endif
#ifndef HB_NO_META
HB_OT_ACCELERATOR (OT, meta)
@@ -74,9 +74,9 @@ HB_OT_ACCELERATOR (OT, meta)
/* Vertical layout. */
#ifndef HB_NO_VERTICAL
-HB_OT_TABLE (OT, vhea)
+HB_OT_CORE_TABLE (OT, vhea)
HB_OT_ACCELERATOR (OT, vmtx)
-HB_OT_TABLE (OT, VORG)
+HB_OT_CORE_TABLE (OT, VORG)
#endif
/* TrueType outlines. */
@@ -91,15 +91,15 @@ HB_OT_ACCELERATOR (OT, cff2)
/* OpenType variations. */
#ifndef HB_NO_VAR
-HB_OT_TABLE (OT, fvar)
-HB_OT_TABLE (OT, avar)
+HB_OT_CORE_TABLE (OT, fvar)
+HB_OT_CORE_TABLE (OT, avar)
HB_OT_ACCELERATOR (OT, gvar)
-HB_OT_TABLE (OT, MVAR)
+HB_OT_CORE_TABLE (OT, MVAR)
#endif
/* Legacy kern. */
#ifndef HB_NO_OT_KERN
-HB_OT_TABLE (OT, kern)
+HB_OT_CORE_TABLE (OT, kern)
#endif
/* OpenType shaping. */
@@ -107,12 +107,12 @@ HB_OT_TABLE (OT, kern)
HB_OT_ACCELERATOR (OT, GDEF)
HB_OT_ACCELERATOR (OT, GSUB)
HB_OT_ACCELERATOR (OT, GPOS)
-//HB_OT_TABLE (OT, JSTF)
+//HB_OT_CORE_TABLE (OT, JSTF)
#endif
/* OpenType baseline. */
#ifndef HB_NO_BASE
-HB_OT_TABLE (OT, BASE)
+HB_OT_CORE_TABLE (OT, BASE)
#endif
/* AAT shaping. */
@@ -129,8 +129,8 @@ HB_OT_TABLE (AAT, feat)
/* OpenType color fonts. */
#ifndef HB_NO_COLOR
-HB_OT_TABLE (OT, COLR)
-HB_OT_TABLE (OT, CPAL)
+HB_OT_CORE_TABLE (OT, COLR)
+HB_OT_CORE_TABLE (OT, CPAL)
HB_OT_ACCELERATOR (OT, CBDT)
HB_OT_ACCELERATOR (OT, sbix)
HB_OT_ACCELERATOR (OT, SVG)
@@ -138,7 +138,7 @@ HB_OT_ACCELERATOR (OT, SVG)
/* OpenType math. */
#ifndef HB_NO_MATH
-HB_OT_TABLE (OT, MATH)
+HB_OT_CORE_TABLE (OT, MATH)
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-font.cc b/thirdparty/harfbuzz/src/hb-ot-font.cc
index 825b30853c..8405103423 100644
--- a/thirdparty/harfbuzz/src/hb-ot-font.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-font.cc
@@ -45,6 +45,7 @@
#include "hb-ot-vorg-table.hh"
#include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-color-sbix-table.hh"
+#include "hb-ot-color-colr-table.hh"
/**
@@ -350,13 +351,15 @@ hb_ot_get_glyph_extents (hb_font_t *font,
if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
#endif
+#if !defined(HB_NO_COLOR)
+ if (ot_face->COLR->get_extents (font, glyph, extents)) return true;
+#endif
if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
#ifndef HB_NO_OT_FONT_CFF
if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
#endif
- // TODO Hook up side-bearings variations.
return false;
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
index 579abf011a..0f424f5aa6 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
@@ -478,7 +478,7 @@ struct IndexArray : Array16Of<Index>
{
if (_count)
{
- + this->sub_array (start_offset, _count)
+ + this->as_array ().sub_array (start_offset, _count)
| hb_sink (hb_array (_indexes, *_count))
;
}
@@ -658,7 +658,7 @@ struct FeatureParamsCharacterVariants
{
if (char_count)
{
- + characters.sub_array (start_offset, char_count)
+ + characters.as_array ().sub_array (start_offset, char_count)
| hb_sink (hb_array (chars, *char_count))
;
}
@@ -932,7 +932,7 @@ struct RecordArrayOf : SortedArray16Of<Record<Type>>
{
if (record_count)
{
- + this->sub_array (start_offset, record_count)
+ + this->as_array ().sub_array (start_offset, record_count)
| hb_map (&Record<Type>::tag)
| hb_sink (hb_array (record_tags, *record_count))
;
@@ -980,18 +980,16 @@ struct RecordListOfFeature : RecordListOf<Feature>
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
- unsigned count = this->len;
-
- + hb_zip (*this, hb_range (count))
- | hb_filter (l->feature_index_map, hb_second)
- | hb_apply ([l, out, this] (const hb_pair_t<const Record<Feature>&, unsigned>& _)
+ + hb_enumerate (*this)
+ | hb_filter (l->feature_index_map, hb_first)
+ | hb_apply ([l, out, this] (const hb_pair_t<unsigned, const Record<Feature>&>& _)
{
const Feature *f_sub = nullptr;
const Feature **f = nullptr;
- if (l->feature_substitutes_map->has (_.second, &f))
+ if (l->feature_substitutes_map->has (_.first, &f))
f_sub = *f;
- subset_record_array (l, out, this, f_sub) (_.first);
+ subset_record_array (l, out, this, f_sub) (_.second);
})
;
@@ -1079,7 +1077,7 @@ struct LangSys
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
- const unsigned *v;
+ const uint32_t *v;
out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
if (!l->visitFeatureIndex (featureIndex.len))
@@ -1147,7 +1145,6 @@ struct Script
return;
}
- unsigned langsys_count = get_lang_sys_count ();
if (has_default_lang_sys ())
{
//only collect features from non-redundant langsys
@@ -1156,24 +1153,24 @@ struct Script
d.collect_features (c);
}
- for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
+ for (auto _ : + hb_enumerate (langSys))
{
- const LangSys& l = this+_.first.offset;
+ const LangSys& l = this+_.second.offset;
if (!c->visitLangsys (l.get_feature_count ())) continue;
if (l.compare (d, c->duplicate_feature_map)) continue;
l.collect_features (c);
- c->script_langsys_map->get (script_index)->add (_.second);
+ c->script_langsys_map->get (script_index)->add (_.first);
}
}
else
{
- for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
+ for (auto _ : + hb_enumerate (langSys))
{
- const LangSys& l = this+_.first.offset;
+ const LangSys& l = this+_.second.offset;
if (!c->visitLangsys (l.get_feature_count ())) continue;
l.collect_features (c);
- c->script_langsys_map->get (script_index)->add (_.second);
+ c->script_langsys_map->get (script_index)->add (_.first);
}
}
}
@@ -1211,10 +1208,9 @@ struct Script
const hb_set_t *active_langsys = l->script_langsys_map->get (l->cur_script_index);
if (active_langsys)
{
- unsigned count = langSys.len;
- + hb_zip (langSys, hb_range (count))
- | hb_filter (active_langsys, hb_second)
- | hb_map (hb_first)
+ + hb_enumerate (langSys)
+ | hb_filter (active_langsys, hb_first)
+ | hb_map (hb_second)
| hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); })
| hb_apply (subset_record_array (l, &(out->langSys), this))
;
@@ -1250,12 +1246,11 @@ struct RecordListOfScript : RecordListOf<Script>
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
- unsigned count = this->len;
- for (auto _ : + hb_zip (*this, hb_range (count)))
+ for (auto _ : + hb_enumerate (*this))
{
auto snap = c->serializer->snapshot ();
- l->cur_script_index = _.second;
- bool ret = _.first.subset (l, this);
+ l->cur_script_index = _.first;
+ bool ret = _.second.subset (l, this);
if (!ret) c->serializer->revert (snap);
else out->len++;
}
@@ -1388,7 +1383,13 @@ struct Lookup
outMarkFilteringSet = markFilteringSet;
}
- return_trace (out->subTable.len);
+ // Always keep the lookup even if it's empty. The rest of layout subsetting depends on lookup
+ // indices being consistent with those computed during planning. So if an empty lookup is
+ // discarded during the subset phase it will invalidate all subsequent lookup indices.
+ // Generally we shouldn't end up with an empty lookup as we pre-prune them during the planning
+ // phase, but it can happen in rare cases such as when during closure subtable is considered
+ // degenerate (see: https://github.com/harfbuzz/harfbuzz/issues/3853)
+ return true;
}
template <typename TSubTable>
@@ -1454,10 +1455,9 @@ struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType>
auto *out = c->serializer->start_embed (this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
- unsigned count = this->len;
- + hb_zip (*this, hb_range (count))
- | hb_filter (l->lookup_index_map, hb_second)
- | hb_map (hb_first)
+ + hb_enumerate (*this)
+ | hb_filter (l->lookup_index_map, hb_first)
+ | hb_map (hb_second)
| hb_apply (subset_offset_array (c, *out, this))
;
return_trace (true);
@@ -1491,7 +1491,7 @@ static bool ClassDef_remap_and_serialize (hb_serialize_context_t *c,
klass_map->set (0, 0);
unsigned idx = klass_map->has (0) ? 1 : 0;
- for (const unsigned k: klasses.iter ())
+ for (const unsigned k: klasses)
{
if (klass_map->has (k)) continue;
klass_map->set (k, idx);
@@ -1524,6 +1524,11 @@ struct ClassDefFormat1_3
return classValue[(unsigned int) (glyph_id - startGlyph)];
}
+ unsigned get_population () const
+ {
+ return classValue.len;
+ }
+
template<typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c,
@@ -1548,7 +1553,7 @@ struct ClassDefFormat1_3
startGlyph = glyph_min;
if (unlikely (!classValue.serialize (c, glyph_count))) return_trace (false);
- for (const hb_pair_t<hb_codepoint_t, unsigned> gid_klass_pair : + it)
+ for (const hb_pair_t<hb_codepoint_t, uint32_t> gid_klass_pair : + it)
{
unsigned idx = gid_klass_pair.first - glyph_min;
classValue[idx] = gid_klass_pair.second;
@@ -1639,11 +1644,10 @@ struct ClassDefFormat1_3
bool intersects (const hb_set_t *glyphs) const
{
- /* TODO Speed up, using hb_set_next()? */
hb_codepoint_t start = startGlyph;
hb_codepoint_t end = startGlyph + classValue.len;
for (hb_codepoint_t iter = startGlyph - 1;
- hb_set_next (glyphs, &iter) && iter < end;)
+ glyphs->next (&iter) && iter < end;)
if (classValue[iter - start]) return true;
return false;
}
@@ -1654,10 +1658,10 @@ struct ClassDefFormat1_3
{
/* Match if there's any glyph that is not listed! */
hb_codepoint_t g = HB_SET_VALUE_INVALID;
- if (!hb_set_next (glyphs, &g)) return false;
+ if (!glyphs->next (&g)) return false;
if (g < startGlyph) return true;
g = startGlyph + count - 1;
- if (hb_set_next (glyphs, &g)) return true;
+ if (glyphs->next (&g)) return true;
/* Fall through. */
}
/* TODO Speed up, using set overlap first? */
@@ -1675,12 +1679,12 @@ struct ClassDefFormat1_3
if (klass == 0)
{
unsigned start_glyph = startGlyph;
- for (unsigned g = HB_SET_VALUE_INVALID;
- hb_set_next (glyphs, &g) && g < start_glyph;)
+ for (uint32_t g = HB_SET_VALUE_INVALID;
+ glyphs->next (&g) && g < start_glyph;)
intersect_glyphs->add (g);
- for (unsigned g = startGlyph + count - 1;
- hb_set_next (glyphs, &g);)
+ for (uint32_t g = startGlyph + count - 1;
+ glyphs-> next (&g);)
intersect_glyphs->add (g);
return;
@@ -1696,7 +1700,7 @@ struct ClassDefFormat1_3
unsigned start_glyph = startGlyph;
unsigned end_glyph = start_glyph + count;
for (unsigned g = startGlyph - 1;
- hb_set_next (glyphs, &g) && g < end_glyph;)
+ glyphs->next (&g) && g < end_glyph;)
if (classValue.arrayZ[g - start_glyph] == klass)
intersect_glyphs->add (g);
#endif
@@ -1739,6 +1743,14 @@ struct ClassDefFormat2_4
return rangeRecord.bsearch (glyph_id).value;
}
+ unsigned get_population () const
+ {
+ typename Types::large_int ret = 0;
+ for (const auto &r : rangeRecord)
+ ret += r.get_population ();
+ return ret > UINT_MAX ? UINT_MAX : (unsigned) ret;
+ }
+
template<typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c,
@@ -1802,28 +1814,45 @@ struct ClassDefFormat2_4
{
TRACE_SUBSET (this);
const hb_map_t &glyph_map = *c->plan->glyph_map_gsub;
+ const hb_set_t &glyph_set = *c->plan->glyphset_gsub ();
hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass;
hb_set_t orig_klasses;
- unsigned num_source_glyphs = c->plan->source->get_num_glyphs ();
- unsigned count = rangeRecord.len;
- for (unsigned i = 0; i < count; i++)
+ if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2
+ < get_population ())
{
- unsigned klass = rangeRecord[i].value;
- if (!klass) continue;
- hb_codepoint_t start = rangeRecord[i].first;
- hb_codepoint_t end = hb_min (rangeRecord[i].last + 1, num_source_glyphs);
- for (hb_codepoint_t g = start; g < end; g++)
+ for (hb_codepoint_t g : glyph_set)
{
- hb_codepoint_t new_gid = glyph_map[g];
+ unsigned klass = get_class (g);
+ if (!klass) continue;
+ hb_codepoint_t new_gid = glyph_map[g];
if (new_gid == HB_MAP_VALUE_INVALID) continue;
- if (glyph_filter && !glyph_filter->has (g)) continue;
-
+ if (glyph_filter && !glyph_filter->has (g)) continue;
glyph_and_klass.push (hb_pair (new_gid, klass));
orig_klasses.add (klass);
}
}
+ else
+ {
+ unsigned num_source_glyphs = c->plan->source->get_num_glyphs ();
+ for (auto &range : rangeRecord)
+ {
+ unsigned klass = range.value;
+ if (!klass) continue;
+ hb_codepoint_t start = range.first;
+ hb_codepoint_t end = hb_min (range.last + 1, num_source_glyphs);
+ for (hb_codepoint_t g = start; g < end; g++)
+ {
+ hb_codepoint_t new_gid = glyph_map[g];
+ if (new_gid == HB_MAP_VALUE_INVALID) continue;
+ if (glyph_filter && !glyph_filter->has (g)) continue;
+
+ glyph_and_klass.push (hb_pair (new_gid, klass));
+ orig_klasses.add (klass);
+ }
+ }
+ }
const hb_set_t& glyphset = *c->plan->glyphset_gsub ();
unsigned glyph_count = glyph_filter
@@ -1850,10 +1879,9 @@ struct ClassDefFormat2_4
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{
- unsigned int count = rangeRecord.len;
- for (unsigned int i = 0; i < count; i++)
- if (rangeRecord[i].value)
- if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
+ for (auto &range : rangeRecord)
+ if (range.value)
+ if (unlikely (!range.collect_coverage (glyphs)))
return false;
return true;
}
@@ -1861,11 +1889,10 @@ struct ClassDefFormat2_4
template <typename set_t>
bool collect_class (set_t *glyphs, unsigned int klass) const
{
- unsigned int count = rangeRecord.len;
- for (unsigned int i = 0; i < count; i++)
+ for (auto &range : rangeRecord)
{
- if (rangeRecord[i].value == klass)
- if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
+ if (range.value == klass)
+ if (unlikely (!range.collect_coverage (glyphs)))
return false;
}
return true;
@@ -1873,32 +1900,32 @@ struct ClassDefFormat2_4
bool intersects (const hb_set_t *glyphs) const
{
- /* TODO Speed up, using hb_set_next() and bsearch()? */
- unsigned int count = rangeRecord.len;
- for (unsigned int i = 0; i < count; i++)
+ if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
{
- const auto& range = rangeRecord[i];
- if (range.intersects (*glyphs) && range.value)
- return true;
+ for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ if (get_class (g))
+ return true;
+ return false;
}
- return false;
+
+ return hb_any (+ hb_iter (rangeRecord)
+ | hb_map ([glyphs] (const RangeRecord<Types> &range) { return range.intersects (*glyphs) && range.value; }));
}
bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
{
- unsigned int count = rangeRecord.len;
if (klass == 0)
{
/* Match if there's any glyph that is not listed! */
hb_codepoint_t g = HB_SET_VALUE_INVALID;
- for (unsigned int i = 0; i < count; i++)
+ for (auto &range : rangeRecord)
{
- if (!hb_set_next (glyphs, &g))
+ if (!glyphs->next (&g))
break;
- if (g < rangeRecord[i].first)
+ if (g < range.first)
return true;
- g = rangeRecord[i].last;
+ g = range.last;
}
- if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
+ if (g != HB_SET_VALUE_INVALID && glyphs->next (&g))
return true;
/* Fall through. */
}
@@ -1910,49 +1937,49 @@ struct ClassDefFormat2_4
void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
{
- unsigned count = rangeRecord.len;
if (klass == 0)
{
hb_codepoint_t g = HB_SET_VALUE_INVALID;
- for (unsigned int i = 0; i < count; i++)
+ for (auto &range : rangeRecord)
{
- if (!hb_set_next (glyphs, &g))
+ if (!glyphs->next (&g))
goto done;
- while (g < rangeRecord[i].first)
+ while (g < range.first)
{
intersect_glyphs->add (g);
- if (!hb_set_next (glyphs, &g))
+ if (!glyphs->next (&g))
goto done;
}
- g = rangeRecord[i].last;
+ g = range.last;
}
- while (hb_set_next (glyphs, &g))
+ while (glyphs->next (&g))
intersect_glyphs->add (g);
done:
return;
}
-#if 0
- /* The following implementation is faster asymptotically, but slower
- * in practice. */
- if ((count >> 3) > glyphs->get_population ())
+ unsigned count = rangeRecord.len;
+ if (count > glyphs->get_population () * hb_bit_storage (count) * 8)
{
for (hb_codepoint_t g = HB_SET_VALUE_INVALID;
- hb_set_next (glyphs, &g);)
- if (rangeRecord.as_array ().bfind (g))
+ glyphs->next (&g);)
+ {
+ unsigned i;
+ if (rangeRecord.as_array ().bfind (g, &i) &&
+ rangeRecord.arrayZ[i].value == klass)
intersect_glyphs->add (g);
+ }
return;
}
-#endif
- for (unsigned int i = 0; i < count; i++)
+ for (auto &range : rangeRecord)
{
- if (rangeRecord[i].value != klass) continue;
+ if (range.value != klass) continue;
- unsigned end = rangeRecord[i].last + 1;
- for (hb_codepoint_t g = rangeRecord[i].first - 1;
- hb_set_next (glyphs, &g) && g < end;)
+ unsigned end = range.last + 1;
+ for (hb_codepoint_t g = range.first - 1;
+ glyphs->next (&g) && g < end;)
intersect_glyphs->add (g);
}
}
@@ -1961,25 +1988,24 @@ struct ClassDefFormat2_4
{
if (glyphs->is_empty ()) return;
- unsigned count = rangeRecord.len;
hb_codepoint_t g = HB_SET_VALUE_INVALID;
- for (unsigned int i = 0; i < count; i++)
+ for (auto &range : rangeRecord)
{
- if (!hb_set_next (glyphs, &g))
+ if (!glyphs->next (&g))
break;
- if (g < rangeRecord[i].first)
+ if (g < range.first)
{
intersect_classes->add (0);
break;
}
- g = rangeRecord[i].last;
+ g = range.last;
}
- if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
+ if (g != HB_SET_VALUE_INVALID && glyphs->next (&g))
intersect_classes->add (0);
- for (const auto& record : rangeRecord.iter ())
- if (record.intersects (*glyphs))
- intersect_classes->add (record.value);
+ for (const auto& range : rangeRecord)
+ if (range.intersects (*glyphs))
+ intersect_classes->add (range.value);
}
protected:
@@ -1994,10 +2020,8 @@ struct ClassDefFormat2_4
struct ClassDef
{
/* Has interface. */
- static constexpr unsigned SENTINEL = 0;
- typedef unsigned int value_t;
- value_t operator [] (hb_codepoint_t k) const { return get (k); }
- bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ unsigned operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k]; }
/* Projection. */
hb_codepoint_t operator () (hb_codepoint_t k) const { return get (k); }
@@ -2015,6 +2039,19 @@ struct ClassDef
}
}
+ unsigned get_population () const
+ {
+ switch (u.format) {
+ case 1: return u.format1.get_population ();
+ case 2: return u.format2.get_population ();
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.get_population ();
+ case 4: return u.format4.get_population ();
+#endif
+ default:return NOT_COVERED;
+ }
+ }
+
template<typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero)
@@ -2332,7 +2369,7 @@ struct VarRegionList
{
unsigned int backward = region_map.backward (r);
if (backward >= region_count) return_trace (false);
- memcpy (&axesZ[axisCount * r], &src->axesZ[axisCount * backward], VarRegionAxis::static_size * axisCount);
+ hb_memcpy (&axesZ[axisCount * r], &src->axesZ[axisCount * backward], VarRegionAxis::static_size * axisCount);
}
return_trace (true);
@@ -2442,21 +2479,26 @@ struct VarData
unsigned ri_count = src->regionIndices.len;
enum delta_size_t { kZero=0, kNonWord, kWord };
hb_vector_t<delta_size_t> delta_sz;
- hb_vector_t<unsigned int> ri_map; /* maps old index to new index */
+ hb_vector_t<unsigned int> ri_map; /* maps new index to old index */
delta_sz.resize (ri_count);
ri_map.resize (ri_count);
unsigned int new_word_count = 0;
unsigned int r;
+ const HBUINT8 *src_delta_bytes = src->get_delta_bytes ();
+ unsigned src_row_size = src->get_row_size ();
+ unsigned src_word_count = src->wordCount ();
+ bool src_long_words = src->longWords ();
+
bool has_long = false;
- if (src->longWords ())
+ if (src_long_words)
{
- for (r = 0; r < ri_count; r++)
+ for (r = 0; r < src_word_count; r++)
{
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
{
unsigned int old = inner_map.backward (i);
- int32_t delta = src->get_item_delta (old, r);
+ int32_t delta = src->get_item_delta_fast (old, r, src_delta_bytes, src_row_size);
if (delta < -65536 || 65535 < delta)
{
has_long = true;
@@ -2470,11 +2512,13 @@ struct VarData
signed max_threshold = has_long ? +65535 : +127;
for (r = 0; r < ri_count; r++)
{
+ bool short_circuit = src_long_words == has_long && src_word_count <= r;
+
delta_sz[r] = kZero;
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
{
unsigned int old = inner_map.backward (i);
- int32_t delta = src->get_item_delta (old, r);
+ int32_t delta = src->get_item_delta_fast (old, r, src_delta_bytes, src_row_size);
if (delta < min_threshold || max_threshold < delta)
{
delta_sz[r] = kWord;
@@ -2482,7 +2526,11 @@ struct VarData
break;
}
else if (delta != 0)
+ {
delta_sz[r] = kNonWord;
+ if (short_circuit)
+ break;
+ }
}
}
@@ -2492,7 +2540,8 @@ struct VarData
for (r = 0; r < ri_count; r++)
if (delta_sz[r])
{
- ri_map[r] = (delta_sz[r] == kWord)? word_index++ : non_word_index++;
+ unsigned new_r = (delta_sz[r] == kWord)? word_index++ : non_word_index++;
+ ri_map[new_r] = r;
new_ri_count++;
}
@@ -2502,14 +2551,20 @@ struct VarData
if (unlikely (!c->extend (this))) return_trace (false);
- for (r = 0; r < ri_count; r++)
- if (delta_sz[r]) regionIndices[ri_map[r]] = region_map[src->regionIndices[r]];
+ for (r = 0; r < new_ri_count; r++)
+ regionIndices[r] = region_map[src->regionIndices[ri_map[r]]];
- for (unsigned int i = 0; i < itemCount; i++)
+ HBUINT8 *delta_bytes = get_delta_bytes ();
+ unsigned row_size = get_row_size ();
+ unsigned count = itemCount;
+ for (unsigned int i = 0; i < count; i++)
{
- unsigned int old = inner_map.backward (i);
- for (unsigned int r = 0; r < ri_count; r++)
- if (delta_sz[r]) set_item_delta (i, ri_map[r], src->get_item_delta (old, r));
+ unsigned int old = inner_map.backward (i);
+ for (unsigned int r = 0; r < new_ri_count; r++)
+ set_item_delta_fast (i, r,
+ src->get_item_delta_fast (old, ri_map[r],
+ src_delta_bytes, src_row_size),
+ delta_bytes, row_size);
}
return_trace (true);
@@ -2517,12 +2572,15 @@ struct VarData
void collect_region_refs (hb_set_t &region_indices, const hb_inc_bimap_t &inner_map) const
{
+ const HBUINT8 *delta_bytes = get_delta_bytes ();
+ unsigned row_size = get_row_size ();
+
for (unsigned int r = 0; r < regionIndices.len; r++)
{
- unsigned int region = regionIndices[r];
+ unsigned int region = regionIndices.arrayZ[r];
if (region_indices.has (region)) continue;
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
- if (get_item_delta (inner_map.backward (i), r) != 0)
+ if (get_item_delta_fast (inner_map.backward (i), r, delta_bytes, row_size) != 0)
{
region_indices.add (region);
break;
@@ -2537,10 +2595,12 @@ struct VarData
HBUINT8 *get_delta_bytes ()
{ return &StructAfter<HBUINT8> (regionIndices); }
- int32_t get_item_delta (unsigned int item, unsigned int region) const
+ int32_t get_item_delta_fast (unsigned int item, unsigned int region,
+ const HBUINT8 *delta_bytes, unsigned row_size) const
{
- if ( item >= itemCount || unlikely (region >= regionIndices.len)) return 0;
- const HBINT8 *p = (const HBINT8 *) get_delta_bytes () + item * get_row_size ();
+ if (unlikely (item >= itemCount || region >= regionIndices.len)) return 0;
+
+ const HBINT8 *p = (const HBINT8 *) delta_bytes + item * row_size;
unsigned word_count = wordCount ();
bool is_long = longWords ();
if (is_long)
@@ -2558,10 +2618,17 @@ struct VarData
return (p + HBINT16::static_size * word_count)[region - word_count];
}
}
+ int32_t get_item_delta (unsigned int item, unsigned int region) const
+ {
+ return get_item_delta_fast (item, region,
+ get_delta_bytes (),
+ get_row_size ());
+ }
- void set_item_delta (unsigned int item, unsigned int region, int32_t delta)
+ void set_item_delta_fast (unsigned int item, unsigned int region, int32_t delta,
+ HBUINT8 *delta_bytes, unsigned row_size)
{
- HBINT8 *p = (HBINT8 *)get_delta_bytes () + item * get_row_size ();
+ HBINT8 *p = (HBINT8 *) delta_bytes + item * row_size;
unsigned word_count = wordCount ();
bool is_long = longWords ();
if (is_long)
@@ -2579,6 +2646,12 @@ struct VarData
(p + HBINT16::static_size * word_count)[region - word_count] = delta;
}
}
+ void set_item_delta (unsigned int item, unsigned int region, int32_t delta)
+ {
+ set_item_delta_fast (item, region, delta,
+ get_delta_bytes (),
+ get_row_size ());
+ }
bool longWords () const { return wordSizeCount & 0x8000u /* LONG_WORDS */; }
unsigned wordCount () const { return wordSizeCount & 0x7FFFu /* WORD_DELTA_COUNT_MASK */; }
@@ -2642,6 +2715,14 @@ struct VariationStore
unsigned int inner = index & 0xFFFF;
return get_delta (outer, inner, coords, coord_count, cache);
}
+ float get_delta (unsigned int index,
+ hb_array_t<int> coords,
+ VarRegionList::cache_t *cache = nullptr) const
+ {
+ return get_delta (index,
+ coords.arrayZ, coords.length,
+ cache);
+ }
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -2948,7 +3029,7 @@ struct ConditionSet
// all conditions met
if (num_kept_cond == 0) return DROP_COND_WITH_VAR;
-
+
//check if condition_set is unique with variations
if (c->conditionset_map->has (p))
//duplicate found, drop the entire record
@@ -3420,17 +3501,16 @@ struct VariationDevice
{
TRACE_SERIALIZE (this);
if (!layout_variation_idx_delta_map) return_trace (nullptr);
- auto snap = c->snapshot ();
+
+ hb_pair_t<unsigned, int> *v;
+ if (!layout_variation_idx_delta_map->has (varIdx, &v))
+ return_trace (nullptr);
+
+ c->start_zerocopy (this->static_size);
auto *out = c->embed (this);
if (unlikely (!out)) return_trace (nullptr);
- /* TODO Just get() and bail if NO_VARIATION. Needs to setup the map to return that. */
- if (!layout_variation_idx_delta_map->has (varIdx))
- {
- c->revert (snap);
- return_trace (nullptr);
- }
- unsigned new_idx = hb_first (layout_variation_idx_delta_map->get (varIdx));
+ unsigned new_idx = hb_first (*v);
out->varIdx = new_idx;
return_trace (out);
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh
index 22925fdfa9..a84edef162 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh
@@ -73,7 +73,7 @@ struct AttachList
if (point_count)
{
- + points.sub_array (start_offset, point_count)
+ + points.as_array ().sub_array (start_offset, point_count)
| hb_sink (hb_array (point_array, *point_count))
;
}
@@ -322,7 +322,7 @@ struct LigGlyph
{
if (caret_count)
{
- + carets.sub_array (start_offset, caret_count)
+ + carets.as_array ().sub_array (start_offset, caret_count)
| hb_map (hb_add (this))
| hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
| hb_sink (hb_array (caret_array, *caret_count))
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
index d1d94255f4..04ccefd108 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
@@ -100,8 +100,8 @@ struct hb_closure_context_t :
bool is_lookup_done (unsigned int lookup_index)
{
- if (done_lookups_glyph_count->in_error () ||
- done_lookups_glyph_set->in_error ())
+ if (unlikely (done_lookups_glyph_count->in_error () ||
+ done_lookups_glyph_set->in_error ()))
return true;
/* Have we visited this lookup with the current set of glyphs? */
@@ -535,7 +535,12 @@ struct hb_ot_apply_context_t :
bool next (unsigned *unsafe_to = nullptr)
{
assert (num_items > 0);
- while (idx + num_items < end)
+ /* The alternate condition below is faster at string boundaries,
+ * but produces subpar "unsafe-to-concat" values. */
+ signed stop = (signed) end - (signed) num_items;
+ if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT)
+ stop = (signed) end - 1;
+ while ((signed) idx < stop)
{
idx++;
hb_glyph_info_t &info = c->buffer->info[idx];
@@ -568,7 +573,12 @@ struct hb_ot_apply_context_t :
bool prev (unsigned *unsafe_from = nullptr)
{
assert (num_items > 0);
- while (idx > num_items - 1)
+ /* The alternate condition below is faster at string boundaries,
+ * but produces subpar "unsafe-to-concat" values. */
+ unsigned stop = num_items - 1;
+ if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT)
+ stop = 1 - 1;
+ while (idx > stop)
{
idx--;
hb_glyph_info_t &info = c->buffer->out_info[idx];
@@ -672,6 +682,7 @@ struct hb_ot_apply_context_t :
const GDEF &gdef;
const VariationStore &var_store;
VariationStore::cache_t *var_store_cache;
+ hb_set_digest_t digest;
hb_direction_t direction;
hb_mask_t lookup_mask = 1;
@@ -707,6 +718,7 @@ struct hb_ot_apply_context_t :
nullptr
#endif
),
+ digest (buffer_->digest ()),
direction (buffer_->props.direction),
has_glyph_classes (gdef.has_glyph_classes ())
{ init_iters (); }
@@ -781,8 +793,10 @@ struct hb_ot_apply_context_t :
void _set_glyph_class (hb_codepoint_t glyph_index,
unsigned int class_guess = 0,
bool ligature = false,
- bool component = false) const
+ bool component = false)
{
+ digest.add (glyph_index);
+
if (new_syllables != (unsigned) -1)
buffer->cur().syllable() = new_syllables;
@@ -815,24 +829,24 @@ struct hb_ot_apply_context_t :
_hb_glyph_info_set_glyph_props (&buffer->cur(), props);
}
- void replace_glyph (hb_codepoint_t glyph_index) const
+ void replace_glyph (hb_codepoint_t glyph_index)
{
_set_glyph_class (glyph_index);
(void) buffer->replace_glyph (glyph_index);
}
- void replace_glyph_inplace (hb_codepoint_t glyph_index) const
+ void replace_glyph_inplace (hb_codepoint_t glyph_index)
{
_set_glyph_class (glyph_index);
buffer->cur().codepoint = glyph_index;
}
void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
- unsigned int class_guess) const
+ unsigned int class_guess)
{
_set_glyph_class (glyph_index, class_guess, true);
(void) buffer->replace_glyph (glyph_index);
}
void output_glyph_for_component (hb_codepoint_t glyph_index,
- unsigned int class_guess) const
+ unsigned int class_guess)
{
_set_glyph_class (glyph_index, class_guess, false, true);
(void) buffer->output_glyph (glyph_index);
@@ -844,7 +858,7 @@ struct hb_accelerate_subtables_context_t :
hb_dispatch_context_t<hb_accelerate_subtables_context_t>
{
template <typename Type>
- static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
+ static inline bool apply_to (const void *obj, hb_ot_apply_context_t *c)
{
const Type *typed_obj = (const Type *) obj;
return typed_obj->apply (c);
@@ -852,30 +866,30 @@ struct hb_accelerate_subtables_context_t :
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
template <typename T>
- static inline auto apply_cached_ (const T *obj, OT::hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply (c, true) )
+ static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply (c, true) )
template <typename T>
- static inline auto apply_cached_ (const T *obj, OT::hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
+ static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
template <typename Type>
- static inline bool apply_cached_to (const void *obj, OT::hb_ot_apply_context_t *c)
+ static inline bool apply_cached_to (const void *obj, hb_ot_apply_context_t *c)
{
const Type *typed_obj = (const Type *) obj;
return apply_cached_ (typed_obj, c, hb_prioritize);
}
template <typename T>
- static inline auto cache_func_ (const T *obj, OT::hb_ot_apply_context_t *c, bool enter, hb_priority<1>) HB_RETURN (bool, obj->cache_func (c, enter) )
+ static inline auto cache_func_ (const T *obj, hb_ot_apply_context_t *c, bool enter, hb_priority<1>) HB_RETURN (bool, obj->cache_func (c, enter) )
template <typename T>
- static inline bool cache_func_ (const T *obj, OT::hb_ot_apply_context_t *c, bool enter, hb_priority<0>) { return false; }
+ static inline bool cache_func_ (const T *obj, hb_ot_apply_context_t *c, bool enter, hb_priority<0>) { return false; }
template <typename Type>
- static inline bool cache_func_to (const void *obj, OT::hb_ot_apply_context_t *c, bool enter)
+ static inline bool cache_func_to (const void *obj, hb_ot_apply_context_t *c, bool enter)
{
const Type *typed_obj = (const Type *) obj;
return cache_func_ (typed_obj, c, enter, hb_prioritize);
}
#endif
- typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
- typedef bool (*hb_cache_func_t) (const void *obj, OT::hb_ot_apply_context_t *c, bool enter);
+ typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c);
+ typedef bool (*hb_cache_func_t) (const void *obj, hb_ot_apply_context_t *c, bool enter);
struct hb_applicable_t
{
@@ -901,20 +915,20 @@ struct hb_accelerate_subtables_context_t :
obj_.get_coverage ().collect_coverage (&digest);
}
- bool apply (OT::hb_ot_apply_context_t *c) const
+ bool apply (hb_ot_apply_context_t *c) const
{
return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
}
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
- bool apply_cached (OT::hb_ot_apply_context_t *c) const
+ bool apply_cached (hb_ot_apply_context_t *c) const
{
return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c);
}
- bool cache_enter (OT::hb_ot_apply_context_t *c) const
+ bool cache_enter (hb_ot_apply_context_t *c) const
{
return cache_func (obj, c, true);
}
- void cache_leave (OT::hb_ot_apply_context_t *c) const
+ void cache_leave (hb_ot_apply_context_t *c) const
{
cache_func (obj, c, false);
}
@@ -988,8 +1002,8 @@ struct hb_accelerate_subtables_context_t :
};
-typedef bool (*intersects_func_t) (const hb_set_t *glyphs, unsigned value, const void *data);
-typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs);
+typedef bool (*intersects_func_t) (const hb_set_t *glyphs, unsigned value, const void *data, void *cache);
+typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, void *cache);
typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, unsigned value, const void *data);
typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
@@ -1012,16 +1026,25 @@ struct ChainContextApplyFuncs
};
-static inline bool intersects_glyph (const hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED)
+static inline bool intersects_glyph (const hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED, void *cache HB_UNUSED)
{
return glyphs->has (value);
}
-static inline bool intersects_class (const hb_set_t *glyphs, unsigned value, const void *data)
+static inline bool intersects_class (const hb_set_t *glyphs, unsigned value, const void *data, void *cache)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
- return class_def.intersects_class (glyphs, value);
+ hb_map_t *map = (hb_map_t *) cache;
+
+ hb_codepoint_t *cached_v;
+ if (map->has (value, &cached_v))
+ return *cached_v;
+
+ bool v = class_def.intersects_class (glyphs, value);
+ map->set (value, v);
+
+ return v;
}
-static inline bool intersects_coverage (const hb_set_t *glyphs, unsigned value, const void *data)
+static inline bool intersects_coverage (const hb_set_t *glyphs, unsigned value, const void *data, void *cache HB_UNUSED)
{
Offset16To<Coverage> coverage;
coverage = value;
@@ -1029,17 +1052,36 @@ static inline bool intersects_coverage (const hb_set_t *glyphs, unsigned value,
}
-static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs, HB_UNUSED void *cache)
{
unsigned g = reinterpret_cast<const HBUINT16 *>(data)[value];
intersected_glyphs->add (g);
}
-static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+
+using intersected_class_cache_t = hb_hashmap_t<unsigned, hb_set_t>;
+
+static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, void *cache)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
- class_def.intersected_class_glyphs (glyphs, value, intersected_glyphs);
+
+ intersected_class_cache_t *map = (intersected_class_cache_t *) cache;
+
+ hb_set_t *cached_v;
+ if (map->has (value, &cached_v))
+ {
+ intersected_glyphs->union_ (*cached_v);
+ return;
+ }
+
+ hb_set_t v;
+ class_def.intersected_class_glyphs (glyphs, value, &v);
+
+ intersected_glyphs->union_ (v);
+
+ map->set (value, std::move (v));
}
-static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+
+static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, HB_UNUSED void *cache)
{
Offset16To<Coverage> coverage;
coverage = value;
@@ -1052,10 +1094,11 @@ static inline bool array_is_subset_of (const hb_set_t *glyphs,
unsigned int count,
const HBUINT values[],
intersects_func_t intersects_func,
- const void *intersects_data)
+ const void *intersects_data,
+ void *cache)
{
for (const auto &_ : + hb_iter (values, count))
- if (!intersects_func (glyphs, _, intersects_data)) return false;
+ if (!intersects_func (glyphs, _, intersects_data, cache)) return false;
return true;
}
@@ -1492,7 +1535,8 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c,
unsigned value,
ContextFormat context_format,
const void *data,
- intersected_glyphs_func_t intersected_glyphs_func)
+ intersected_glyphs_func_t intersected_glyphs_func,
+ void *cache)
{
hb_set_t *covered_seq_indicies = hb_set_create ();
for (unsigned int i = 0; i < lookupCount; i++)
@@ -1513,7 +1557,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c,
pos_glyphs.add (value);
break;
case ContextFormat::ClassBasedContext:
- intersected_glyphs_func (&c->parent_active_glyphs (), data, value, &pos_glyphs);
+ intersected_glyphs_func (&c->parent_active_glyphs (), data, value, &pos_glyphs, cache);
break;
case ContextFormat::CoverageBasedContext:
pos_glyphs.set (c->parent_active_glyphs ());
@@ -1530,7 +1574,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c,
input_value = input[seqIndex - 1];
}
- intersected_glyphs_func (c->glyphs, input_data, input_value, &pos_glyphs);
+ intersected_glyphs_func (c->glyphs, input_data, input_value, &pos_glyphs, cache);
}
}
@@ -1710,6 +1754,8 @@ struct ContextClosureLookupContext
ContextClosureFuncs funcs;
ContextFormat context_format;
const void *intersects_data;
+ void *intersects_cache;
+ void *intersected_glyphs_cache;
};
struct ContextCollectGlyphsLookupContext
@@ -1732,7 +1778,9 @@ static inline bool context_intersects (const hb_set_t *glyphs,
{
return array_is_subset_of (glyphs,
inputCount ? inputCount - 1 : 0, input,
- lookup_context.funcs.intersects, lookup_context.intersects_data);
+ lookup_context.funcs.intersects,
+ lookup_context.intersects_data,
+ lookup_context.intersects_cache);
}
template <typename HBUINT>
@@ -1753,7 +1801,8 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
value,
lookup_context.context_format,
lookup_context.intersects_data,
- lookup_context.funcs.intersected_glyphs);
+ lookup_context.funcs.intersected_glyphs,
+ lookup_context.intersected_glyphs_cache);
}
template <typename HBUINT>
@@ -1777,7 +1826,7 @@ static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
const HBUINT input[], /* Array of input values--start with second glyph */
unsigned int lookupCount HB_UNUSED,
const LookupRecord lookupRecord[] HB_UNUSED,
- ContextApplyLookupContext &lookup_context)
+ const ContextApplyLookupContext &lookup_context)
{
return would_match_input (c,
inputCount, input,
@@ -1790,7 +1839,7 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
const HBUINT input[], /* Array of input values--start with second glyph */
unsigned int lookupCount,
const LookupRecord lookupRecord[],
- ContextApplyLookupContext &lookup_context)
+ const ContextApplyLookupContext &lookup_context)
{
unsigned match_end = 0;
unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
@@ -1858,7 +1907,7 @@ struct Rule
}
bool would_apply (hb_would_apply_context_t *c,
- ContextApplyLookupContext &lookup_context) const
+ const ContextApplyLookupContext &lookup_context) const
{
const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
(inputZ.as_array (inputCount ? inputCount - 1 : 0));
@@ -1869,7 +1918,7 @@ struct Rule
}
bool apply (hb_ot_apply_context_t *c,
- ContextApplyLookupContext &lookup_context) const
+ const ContextApplyLookupContext &lookup_context) const
{
TRACE_APPLY (this);
const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
@@ -1989,7 +2038,7 @@ struct RuleSet
}
bool would_apply (hb_would_apply_context_t *c,
- ContextApplyLookupContext &lookup_context) const
+ const ContextApplyLookupContext &lookup_context) const
{
return
+ hb_iter (rule)
@@ -2000,7 +2049,7 @@ struct RuleSet
}
bool apply (hb_ot_apply_context_t *c,
- ContextApplyLookupContext &lookup_context) const
+ const ContextApplyLookupContext &lookup_context) const
{
TRACE_APPLY (this);
return_trace (
@@ -2108,7 +2157,7 @@ struct ContextFormat1_4
void closure_lookups (hb_closure_lookups_context_t *c) const
{
struct ContextClosureLookupContext lookup_context = {
- {intersects_glyph, intersected_glyph},
+ {intersects_glyph, nullptr},
ContextFormat::SimpleContext,
nullptr
};
@@ -2220,10 +2269,12 @@ struct ContextFormat2_5
const ClassDef &class_def = this+classDef;
+ hb_map_t cache;
struct ContextClosureLookupContext lookup_context = {
- {intersects_class, intersected_class_glyphs},
+ {intersects_class, nullptr},
ContextFormat::ClassBasedContext,
- &class_def
+ &class_def,
+ &cache
};
hb_set_t retained_coverage_glyphs;
@@ -2259,10 +2310,14 @@ struct ContextFormat2_5
const ClassDef &class_def = this+classDef;
+ hb_map_t cache;
+ intersected_class_cache_t intersected_cache;
struct ContextClosureLookupContext lookup_context = {
{intersects_class, intersected_class_glyphs},
ContextFormat::ClassBasedContext,
- &class_def
+ &class_def,
+ &cache,
+ &intersected_cache
};
+ hb_enumerate (ruleSet)
@@ -2286,10 +2341,12 @@ struct ContextFormat2_5
const ClassDef &class_def = this+classDef;
+ hb_map_t cache;
struct ContextClosureLookupContext lookup_context = {
- {intersects_class, intersected_class_glyphs},
+ {intersects_class, nullptr},
ContextFormat::ClassBasedContext,
- &class_def
+ &class_def,
+ &cache
};
+ hb_iter (ruleSet)
@@ -2407,6 +2464,7 @@ struct ContextFormat2_5
const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
bool ret = true;
int non_zero_index = -1, index = 0;
+ auto snapshot = c->serializer->snapshot();
for (const auto& _ : + hb_enumerate (ruleSet)
| hb_filter (klass_map, hb_first))
{
@@ -2418,8 +2476,10 @@ struct ContextFormat2_5
}
if (coverage_glyph_classes.has (_.first) &&
- o->serialize_subset (c, _.second, this, lookup_map, &klass_map))
+ o->serialize_subset (c, _.second, this, lookup_map, &klass_map)) {
non_zero_index = index;
+ snapshot = c->serializer->snapshot();
+ }
index++;
}
@@ -2433,6 +2493,7 @@ struct ContextFormat2_5
out->ruleSet.pop ();
index--;
}
+ c->serializer->revert (snapshot);
return_trace (bool (out->ruleSet));
}
@@ -2469,7 +2530,7 @@ struct ContextFormat3
return false;
struct ContextClosureLookupContext lookup_context = {
- {intersects_coverage, intersected_coverage_glyphs},
+ {intersects_coverage, nullptr},
ContextFormat::CoverageBasedContext,
this
};
@@ -2655,6 +2716,8 @@ struct ChainContextClosureLookupContext
ContextClosureFuncs funcs;
ContextFormat context_format;
const void *intersects_data[3];
+ void *intersects_cache[3];
+ void *intersected_glyphs_cache;
};
struct ChainContextCollectGlyphsLookupContext
@@ -2681,13 +2744,19 @@ static inline bool chain_context_intersects (const hb_set_t *glyphs,
{
return array_is_subset_of (glyphs,
backtrackCount, backtrack,
- lookup_context.funcs.intersects, lookup_context.intersects_data[0])
+ lookup_context.funcs.intersects,
+ lookup_context.intersects_data[0],
+ lookup_context.intersects_cache[0])
&& array_is_subset_of (glyphs,
inputCount ? inputCount - 1 : 0, input,
- lookup_context.funcs.intersects, lookup_context.intersects_data[1])
+ lookup_context.funcs.intersects,
+ lookup_context.intersects_data[1],
+ lookup_context.intersects_cache[1])
&& array_is_subset_of (glyphs,
lookaheadCount, lookahead,
- lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
+ lookup_context.funcs.intersects,
+ lookup_context.intersects_data[2],
+ lookup_context.intersects_cache[2]);
}
template <typename HBUINT>
@@ -2714,7 +2783,8 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
value,
lookup_context.context_format,
lookup_context.intersects_data[1],
- lookup_context.funcs.intersected_glyphs);
+ lookup_context.funcs.intersected_glyphs,
+ lookup_context.intersected_glyphs_cache);
}
template <typename HBUINT>
@@ -2752,7 +2822,7 @@ static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c
const HBUINT lookahead[] HB_UNUSED,
unsigned int lookupCount HB_UNUSED,
const LookupRecord lookupRecord[] HB_UNUSED,
- ChainContextApplyLookupContext &lookup_context)
+ const ChainContextApplyLookupContext &lookup_context)
{
return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
&& would_match_input (c,
@@ -2770,7 +2840,7 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
const HBUINT lookahead[],
unsigned int lookupCount,
const LookupRecord lookupRecord[],
- ChainContextApplyLookupContext &lookup_context)
+ const ChainContextApplyLookupContext &lookup_context)
{
unsigned end_index = c->buffer->idx;
unsigned match_end = 0;
@@ -2864,7 +2934,7 @@ struct ChainRule
}
bool would_apply (hb_would_apply_context_t *c,
- ChainContextApplyLookupContext &lookup_context) const
+ const ChainContextApplyLookupContext &lookup_context) const
{
const auto &input = StructAfter<decltype (inputX)> (backtrack);
const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
@@ -2876,7 +2946,8 @@ struct ChainRule
lookup.arrayZ, lookup_context);
}
- bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+ bool apply (hb_ot_apply_context_t *c,
+ const ChainContextApplyLookupContext &lookup_context) const
{
TRACE_APPLY (this);
const auto &input = StructAfter<decltype (inputX)> (backtrack);
@@ -3042,7 +3113,8 @@ struct ChainRuleSet
;
}
- bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+ bool would_apply (hb_would_apply_context_t *c,
+ const ChainContextApplyLookupContext &lookup_context) const
{
return
+ hb_iter (rule)
@@ -3052,7 +3124,8 @@ struct ChainRuleSet
;
}
- bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+ bool apply (hb_ot_apply_context_t *c,
+ const ChainContextApplyLookupContext &lookup_context) const
{
TRACE_APPLY (this);
return_trace (
@@ -3166,7 +3239,7 @@ struct ChainContextFormat1_4
void closure_lookups (hb_closure_lookups_context_t *c) const
{
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_glyph, intersected_glyph},
+ {intersects_glyph, nullptr},
ContextFormat::SimpleContext,
{nullptr, nullptr, nullptr}
};
@@ -3278,12 +3351,14 @@ struct ChainContextFormat2_5
const ClassDef &input_class_def = this+inputClassDef;
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+ hb_map_t caches[3] = {};
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_class, intersected_class_glyphs},
+ {intersects_class, nullptr},
ContextFormat::ClassBasedContext,
{&backtrack_class_def,
&input_class_def,
- &lookahead_class_def}
+ &lookahead_class_def},
+ {&caches[0], &caches[1], &caches[2]}
};
hb_set_t retained_coverage_glyphs;
@@ -3321,12 +3396,16 @@ struct ChainContextFormat2_5
const ClassDef &input_class_def = this+inputClassDef;
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+ hb_map_t caches[3] = {};
+ intersected_class_cache_t intersected_cache;
struct ChainContextClosureLookupContext lookup_context = {
{intersects_class, intersected_class_glyphs},
ContextFormat::ClassBasedContext,
{&backtrack_class_def,
&input_class_def,
- &lookahead_class_def}
+ &lookahead_class_def},
+ {&caches[0], &caches[1], &caches[2]},
+ &intersected_cache
};
+ hb_enumerate (ruleSet)
@@ -3352,12 +3431,14 @@ struct ChainContextFormat2_5
const ClassDef &input_class_def = this+inputClassDef;
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+ hb_map_t caches[3] = {};
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_class, intersected_class_glyphs},
+ {intersects_class, nullptr},
ContextFormat::ClassBasedContext,
{&backtrack_class_def,
&input_class_def,
- &lookahead_class_def}
+ &lookahead_class_def},
+ {&caches[0], &caches[1], &caches[2]}
};
+ hb_iter (ruleSet)
@@ -3587,7 +3668,7 @@ struct ChainContextFormat3
const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_coverage, intersected_coverage_glyphs},
+ {intersects_coverage, nullptr},
ContextFormat::CoverageBasedContext,
{this, this, this}
};
@@ -3938,13 +4019,14 @@ struct hb_ot_layout_lookup_accelerator_t
template <typename TLookup>
void init (const TLookup &lookup)
{
- digest.init ();
- lookup.collect_coverage (&digest);
-
subtables.init ();
- OT::hb_accelerate_subtables_context_t c_accelerate_subtables (subtables);
+ hb_accelerate_subtables_context_t c_accelerate_subtables (subtables);
lookup.dispatch (&c_accelerate_subtables);
+ digest.init ();
+ for (auto& subtable : hb_iter (subtables))
+ digest.add (subtable.digest);
+
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
cache_user_idx = c_accelerate_subtables.cache_user_idx;
for (unsigned i = 0; i < subtables.length; i++)
@@ -3962,21 +4044,25 @@ struct hb_ot_layout_lookup_accelerator_t
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
if (use_cache)
{
- for (unsigned int i = 0; i < subtables.length; i++)
- if (subtables[i].apply_cached (c))
- return true;
+ return
+ + hb_iter (subtables)
+ | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply_cached (c); })
+ | hb_any
+ ;
}
else
#endif
{
- for (unsigned int i = 0; i < subtables.length; i++)
- if (subtables[i].apply (c))
- return true;
+ return
+ + hb_iter (subtables)
+ | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply (c); })
+ | hb_any
+ ;
}
return false;
}
- bool cache_enter (OT::hb_ot_apply_context_t *c) const
+ bool cache_enter (hb_ot_apply_context_t *c) const
{
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
return cache_user_idx != (unsigned) -1 &&
@@ -3985,7 +4071,7 @@ struct hb_ot_layout_lookup_accelerator_t
return false;
#endif
}
- void cache_leave (OT::hb_ot_apply_context_t *c) const
+ void cache_leave (hb_ot_apply_context_t *c) const
{
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
subtables[cache_user_idx].cache_leave (c);
@@ -3993,8 +4079,8 @@ struct hb_ot_layout_lookup_accelerator_t
}
- private:
hb_set_digest_t digest;
+ private:
hb_accelerate_subtables_context_t::array_t subtables;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
unsigned cache_user_idx = (unsigned) -1;
@@ -4255,11 +4341,11 @@ struct GSUBGPOS
hb_set_t *lookup_indexes /* IN/OUT */) const
{
hb_set_t visited_lookups, inactive_lookups;
- OT::hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
+ hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
c.set_recurse_func (TLookup::template dispatch_recurse_func<hb_closure_lookups_context_t>);
- for (unsigned lookup_index : + hb_iter (lookup_indexes))
+ for (unsigned lookup_index : *lookup_indexes)
reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index);
hb_set_union (lookup_indexes, &visited_lookups);
@@ -4301,7 +4387,7 @@ struct GSUBGPOS
}
#endif
- for (unsigned i : feature_indices->iter())
+ for (unsigned i : hb_iter (feature_indices))
{
hb_tag_t tag = get_feature_tag (i);
if (tag == HB_TAG ('p', 'r', 'e', 'f'))
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.cc b/thirdparty/harfbuzz/src/hb-ot-layout.cc
index dbb30076a2..e8091ec3e0 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.cc
@@ -1465,56 +1465,6 @@ hb_ot_layout_substitute_start (hb_font_t *font,
_hb_ot_layout_set_glyph_props (font, buffer);
}
-void
-hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer,
- bool (*filter) (const hb_glyph_info_t *info))
-{
- /* Merge clusters and delete filtered glyphs.
- * NOTE! We can't use out-buffer as we have positioning data. */
- unsigned int j = 0;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- hb_glyph_position_t *pos = buffer->pos;
- for (unsigned int i = 0; i < count; i++)
- {
- if (filter (&info[i]))
- {
- /* Merge clusters.
- * Same logic as buffer->delete_glyph(), but for in-place removal. */
-
- unsigned int cluster = info[i].cluster;
- if (i + 1 < count && cluster == info[i + 1].cluster)
- continue; /* Cluster survives; do nothing. */
-
- if (j)
- {
- /* Merge cluster backward. */
- if (cluster < info[j - 1].cluster)
- {
- unsigned int mask = info[i].mask;
- unsigned int old_cluster = info[j - 1].cluster;
- for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
- buffer->set_cluster (info[k - 1], cluster, mask);
- }
- continue;
- }
-
- if (i + 1 < count)
- buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
-
- continue;
- }
-
- if (j != i)
- {
- info[j] = info[i];
- pos[j] = pos[i];
- }
- j++;
- }
- buffer->len = j;
-}
-
/**
* hb_ot_layout_lookup_substitute_closure:
* @face: #hb_face_t to work upon
@@ -1867,7 +1817,7 @@ apply_forward (OT::hb_ot_apply_context_t *c,
while (buffer->idx < buffer->len && buffer->successful)
{
bool applied = false;
- if (accel.may_have (buffer->cur().codepoint) &&
+ if (accel.digest.may_have (buffer->cur().codepoint) &&
(buffer->cur().mask & c->lookup_mask) &&
c->check_glyph_property (&buffer->cur(), c->lookup_props))
{
@@ -1894,7 +1844,7 @@ apply_backward (OT::hb_ot_apply_context_t *c,
hb_buffer_t *buffer = c->buffer;
do
{
- if (accel.may_have (buffer->cur().codepoint) &&
+ if (accel.digest.may_have (buffer->cur().codepoint) &&
(buffer->cur().mask & c->lookup_mask) &&
c->check_glyph_property (&buffer->cur(), c->lookup_props))
ret |= accel.apply (c, false);
@@ -1908,15 +1858,16 @@ apply_backward (OT::hb_ot_apply_context_t *c,
}
template <typename Proxy>
-static inline void
+static inline bool
apply_string (OT::hb_ot_apply_context_t *c,
const typename Proxy::Lookup &lookup,
const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
+ bool ret = false;
hb_buffer_t *buffer = c->buffer;
if (unlikely (!buffer->len || !c->lookup_mask))
- return;
+ return ret;
c->set_lookup_props (lookup.get_props ());
@@ -1927,7 +1878,7 @@ apply_string (OT::hb_ot_apply_context_t *c,
buffer->clear_output ();
buffer->idx = 0;
- apply_forward (c, accel);
+ ret = apply_forward (c, accel);
if (!Proxy::always_inplace)
buffer->sync ();
@@ -1937,8 +1888,10 @@ apply_string (OT::hb_ot_apply_context_t *c,
/* in-place backward substitution/positioning */
assert (!buffer->have_output);
buffer->idx = buffer->len - 1;
- apply_backward (c, accel);
+ ret = apply_backward (c, accel);
}
+
+ return ret;
}
template <typename Proxy>
@@ -1957,23 +1910,42 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
const stage_map_t *stage = &stages[table_index][stage_index];
for (; i < stage->last_lookup; i++)
{
- unsigned int lookup_index = lookups[table_index][i].index;
- if (!buffer->message (font, "start lookup %d", lookup_index)) continue;
- c.set_lookup_index (lookup_index);
- c.set_lookup_mask (lookups[table_index][i].mask);
- c.set_auto_zwj (lookups[table_index][i].auto_zwj);
- c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
- c.set_random (lookups[table_index][i].random);
- c.set_per_syllable (lookups[table_index][i].per_syllable);
-
- apply_string<Proxy> (&c,
- proxy.table.get_lookup (lookup_index),
- proxy.accels[lookup_index]);
- (void) buffer->message (font, "end lookup %d", lookup_index);
+ auto &lookup = lookups[table_index][i];
+
+ unsigned int lookup_index = lookup.index;
+ if (!buffer->message (font, "start lookup %d feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag))) continue;
+
+ /* c.digest is a digest of all the current glyphs in the buffer
+ * (plus some past glyphs).
+ *
+ * Only try applying the lookup if there is any overlap. */
+ if (proxy.accels[lookup_index].digest.may_have (c.digest))
+ {
+ c.set_lookup_index (lookup_index);
+ c.set_lookup_mask (lookup.mask);
+ c.set_auto_zwj (lookup.auto_zwj);
+ c.set_auto_zwnj (lookup.auto_zwnj);
+ c.set_random (lookup.random);
+ c.set_per_syllable (lookup.per_syllable);
+
+ apply_string<Proxy> (&c,
+ proxy.table.get_lookup (lookup_index),
+ proxy.accels[lookup_index]);
+ }
+ else
+ (void) buffer->message (font, "skipped lookup %d feature '%c%c%c%c' because no glyph matches", lookup_index, HB_UNTAG (lookup.feature_tag));
+
+ (void) buffer->message (font, "end lookup %d feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag));
}
if (stage->pause_func)
- stage->pause_func (plan, font, buffer);
+ {
+ if (stage->pause_func (plan, font, buffer))
+ {
+ /* Refresh working buffer digest since buffer changed. */
+ c.digest = buffer->digest ();
+ }
+ }
}
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.hh b/thirdparty/harfbuzz/src/hb-ot-layout.hh
index de06610cb5..9505d5f147 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.hh
@@ -102,10 +102,6 @@ HB_INTERNAL void
hb_ot_layout_substitute_start (hb_font_t *font,
hb_buffer_t *buffer);
-HB_INTERNAL void
-hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer,
- bool (*filter) (const hb_glyph_info_t *info));
-
namespace OT {
struct hb_ot_apply_context_t;
struct hb_ot_layout_lookup_accelerator_t;
@@ -552,7 +548,7 @@ _hb_glyph_info_clear_substituted (hb_glyph_info_t *info)
info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
}
-static inline void
+static inline bool
_hb_clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
@@ -561,6 +557,7 @@ _hb_clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
_hb_glyph_info_clear_substituted (&info[i]);
+ return false;
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-map.cc b/thirdparty/harfbuzz/src/hb-ot-map.cc
index 39215b335f..8882dbaccb 100644
--- a/thirdparty/harfbuzz/src/hb-ot-map.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-map.cc
@@ -45,7 +45,7 @@ void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_o
hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
const hb_segment_properties_t &props_)
{
- memset (this, 0, sizeof (*this));
+ hb_memset (this, 0, sizeof (*this));
feature_infos.init ();
for (unsigned int table_index = 0; table_index < 2; table_index++)
@@ -133,7 +133,8 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
bool auto_zwnj,
bool auto_zwj,
bool random,
- bool per_syllable)
+ bool per_syllable,
+ hb_tag_t feature_tag)
{
unsigned int lookup_indices[32];
unsigned int offset, len;
@@ -162,6 +163,7 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
lookup->auto_zwj = auto_zwj;
lookup->random = random;
lookup->per_syllable = per_syllable;
+ lookup->feature_tag = feature_tag;
}
offset += len;
@@ -212,24 +214,26 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
if (feature_infos.length)
{
feature_infos.qsort ();
+ auto *f = feature_infos.arrayZ;
unsigned int j = 0;
- for (unsigned int i = 1; i < feature_infos.length; i++)
- if (feature_infos[i].tag != feature_infos[j].tag)
- feature_infos[++j] = feature_infos[i];
+ unsigned count = feature_infos.length;
+ for (unsigned int i = 1; i < count; i++)
+ if (f[i].tag != f[j].tag)
+ f[++j] = f[i];
else {
- if (feature_infos[i].flags & F_GLOBAL) {
- feature_infos[j].flags |= F_GLOBAL;
- feature_infos[j].max_value = feature_infos[i].max_value;
- feature_infos[j].default_value = feature_infos[i].default_value;
+ if (f[i].flags & F_GLOBAL) {
+ f[j].flags |= F_GLOBAL;
+ f[j].max_value = f[i].max_value;
+ f[j].default_value = f[i].default_value;
} else {
- if (feature_infos[j].flags & F_GLOBAL)
- feature_infos[j].flags ^= F_GLOBAL;
- feature_infos[j].max_value = hb_max (feature_infos[j].max_value, feature_infos[i].max_value);
+ if (f[j].flags & F_GLOBAL)
+ f[j].flags ^= F_GLOBAL;
+ f[j].max_value = hb_max (f[j].max_value, f[i].max_value);
/* Inherit default_value from j */
}
- feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK);
- feature_infos[j].stage[0] = hb_min (feature_infos[j].stage[0], feature_infos[i].stage[0]);
- feature_infos[j].stage[1] = hb_min (feature_infos[j].stage[1], feature_infos[i].stage[1]);
+ f[j].flags |= (f[i].flags & F_HAS_FALLBACK);
+ f[j].stage[0] = hb_min (f[j].stage[0], f[i].stage[0]);
+ f[j].stage[1] = hb_min (f[j].stage[1], f[i].stage[1]);
}
feature_infos.shrink (j + 1);
}
@@ -239,7 +243,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
unsigned int next_bit = hb_popcount (HB_GLYPH_FLAG_DEFINED) + 1;
- for (unsigned int i = 0; i < feature_infos.length; i++)
+ unsigned count = feature_infos.length;
+ for (unsigned int i = 0; i < count; i++)
{
const feature_info_t *info = &feature_infos[i];
@@ -308,7 +313,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
map->_1_mask = (1u << map->shift) & map->mask;
map->needs_fallback = !found;
}
- feature_infos.shrink (0); /* Done with these */
+ //feature_infos.shrink (0); /* Done with these */
add_gsub_pause (nullptr);
@@ -317,6 +322,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
for (unsigned int table_index = 0; table_index < 2; table_index++)
{
/* Collect lookup indices for features */
+ auto &lookups = m.lookups[table_index];
unsigned int stage_index = 0;
unsigned int last_num_lookups = 0;
@@ -329,36 +335,39 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
key.variations_index[table_index],
global_bit_mask);
- for (unsigned i = 0; i < m.features.length; i++)
- if (m.features[i].stage[table_index] == stage)
+ for (auto &feature : m.features)
+ {
+ if (feature.stage[table_index] == stage)
add_lookups (m, table_index,
- m.features[i].index[table_index],
+ feature.index[table_index],
key.variations_index[table_index],
- m.features[i].mask,
- m.features[i].auto_zwnj,
- m.features[i].auto_zwj,
- m.features[i].random,
- m.features[i].per_syllable);
+ feature.mask,
+ feature.auto_zwnj,
+ feature.auto_zwj,
+ feature.random,
+ feature.per_syllable,
+ feature.tag);
+ }
/* Sort lookups and merge duplicates */
- if (last_num_lookups < m.lookups[table_index].length)
+ if (last_num_lookups < lookups.length)
{
- m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].length);
+ lookups.as_array ().sub_array (last_num_lookups, lookups.length - last_num_lookups).qsort ();
unsigned int j = last_num_lookups;
- for (unsigned int i = j + 1; i < m.lookups[table_index].length; i++)
- if (m.lookups[table_index][i].index != m.lookups[table_index][j].index)
- m.lookups[table_index][++j] = m.lookups[table_index][i];
+ for (unsigned int i = j + 1; i < lookups.length; i++)
+ if (lookups.arrayZ[i].index != lookups.arrayZ[j].index)
+ lookups.arrayZ[++j] = lookups.arrayZ[i];
else
{
- m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
- m.lookups[table_index][j].auto_zwnj &= m.lookups[table_index][i].auto_zwnj;
- m.lookups[table_index][j].auto_zwj &= m.lookups[table_index][i].auto_zwj;
+ lookups.arrayZ[j].mask |= lookups.arrayZ[i].mask;
+ lookups.arrayZ[j].auto_zwnj &= lookups.arrayZ[i].auto_zwnj;
+ lookups.arrayZ[j].auto_zwj &= lookups.arrayZ[i].auto_zwj;
}
- m.lookups[table_index].shrink (j + 1);
+ lookups.shrink (j + 1);
}
- last_num_lookups = m.lookups[table_index].length;
+ last_num_lookups = lookups.length;
if (stage_index < stages[table_index].length && stages[table_index][stage_index].index == stage) {
hb_ot_map_t::stage_map_t *stage_map = m.stages[table_index].push ();
diff --git a/thirdparty/harfbuzz/src/hb-ot-map.hh b/thirdparty/harfbuzz/src/hb-ot-map.hh
index a7b5eec30d..efc8cae96a 100644
--- a/thirdparty/harfbuzz/src/hb-ot-map.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-map.hh
@@ -69,6 +69,7 @@ struct hb_ot_map_t
unsigned short random : 1;
unsigned short per_syllable : 1;
hb_mask_t mask;
+ hb_tag_t feature_tag;
HB_INTERNAL static int cmp (const void *pa, const void *pb)
{
@@ -78,7 +79,9 @@ struct hb_ot_map_t
}
};
- typedef void (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
+ /* Pause functions return true if new glyph indices might have been
+ * added to the buffer. This is used to update buffer digest. */
+ typedef bool (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
struct stage_map_t {
unsigned int last_lookup; /* Cumulative */
@@ -87,13 +90,13 @@ struct hb_ot_map_t
void init ()
{
- memset (this, 0, sizeof (*this));
+ hb_memset (this, 0, sizeof (*this));
- features.init ();
+ features.init0 ();
for (unsigned int table_index = 0; table_index < 2; table_index++)
{
- lookups[table_index].init ();
- stages[table_index].init ();
+ lookups[table_index].init0 ();
+ stages[table_index].init0 ();
}
}
void fini ()
@@ -239,7 +242,8 @@ struct hb_ot_map_builder_t
bool auto_zwnj = true,
bool auto_zwj = true,
bool random = false,
- bool per_syllable = false);
+ bool per_syllable = false,
+ hb_tag_t feature_tag = HB_TAG(' ',' ',' ',' '));
struct feature_info_t {
hb_tag_t tag;
diff --git a/thirdparty/harfbuzz/src/hb-ot-math-table.hh b/thirdparty/harfbuzz/src/hb-ot-math-table.hh
index d834d94371..93953370e2 100644
--- a/thirdparty/harfbuzz/src/hb-ot-math-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-math-table.hh
@@ -77,11 +77,11 @@ struct MathConstants
HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2);
if (unlikely (!p)) return_trace (nullptr);
- memcpy (p, percentScaleDown, HBINT16::static_size * 2);
+ hb_memcpy (p, percentScaleDown, HBINT16::static_size * 2);
HBUINT16 *m = c->allocate_size<HBUINT16> (HBUINT16::static_size * 2);
if (unlikely (!m)) return_trace (nullptr);
- memcpy (m, minHeight, HBUINT16::static_size * 2);
+ hb_memcpy (m, minHeight, HBUINT16::static_size * 2);
unsigned count = ARRAY_LENGTH (mathValueRecords);
for (unsigned i = 0; i < count; i++)
@@ -786,7 +786,7 @@ struct MathGlyphAssembly
if (parts_count)
{
int64_t mult = font->dir_mult (direction);
- for (auto _ : hb_zip (partRecords.sub_array (start_offset, parts_count),
+ for (auto _ : hb_zip (partRecords.as_array ().sub_array (start_offset, parts_count),
hb_array (parts, *parts_count)))
_.first.extract (_.second, mult, font);
}
@@ -855,7 +855,7 @@ struct MathGlyphConstruction
if (variants_count)
{
int64_t mult = font->dir_mult (direction);
- for (auto _ : hb_zip (mathGlyphVariantRecord.sub_array (start_offset, variants_count),
+ for (auto _ : hb_zip (mathGlyphVariantRecord.as_array ().sub_array (start_offset, variants_count),
hb_array (variants, *variants_count)))
_.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-meta-table.hh b/thirdparty/harfbuzz/src/hb-ot-meta-table.hh
index 93e64c5327..e1b68bcf91 100644
--- a/thirdparty/harfbuzz/src/hb-ot-meta-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-meta-table.hh
@@ -84,7 +84,7 @@ struct meta
{
if (count)
{
- + table->dataMaps.sub_array (start_offset, count)
+ + table->dataMaps.as_array ().sub_array (start_offset, count)
| hb_map (&DataMap::get_tag)
| hb_map ([](hb_tag_t tag) { return (hb_ot_meta_tag_t) tag; })
| hb_sink (hb_array (entries, *count))
diff --git a/thirdparty/harfbuzz/src/hb-ot-name-table.hh b/thirdparty/harfbuzz/src/hb-ot-name-table.hh
index 1f2131ffcc..6f4461cc15 100644
--- a/thirdparty/harfbuzz/src/hb-ot-name-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-name-table.hh
@@ -30,10 +30,55 @@
#include "hb-open-type.hh"
#include "hb-ot-name-language.hh"
#include "hb-aat-layout.hh"
+#include "hb-utf.hh"
namespace OT {
+template <typename in_utf_t, typename out_utf_t>
+inline unsigned int
+hb_ot_name_convert_utf (hb_bytes_t bytes,
+ unsigned int *text_size /* IN/OUT */,
+ typename out_utf_t::codepoint_t *text /* OUT */)
+{
+ unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t);
+ const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ;
+ const typename in_utf_t::codepoint_t *src_end = src + src_len;
+
+ typename out_utf_t::codepoint_t *dst = text;
+
+ hb_codepoint_t unicode;
+ const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
+
+ if (text_size && *text_size)
+ {
+ (*text_size)--; /* Save room for NUL-termination. */
+ const typename out_utf_t::codepoint_t *dst_end = text + *text_size;
+
+ while (src < src_end && dst < dst_end)
+ {
+ const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement);
+ typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode);
+ if (dst_next == dst)
+ break; /* Out-of-room. */
+
+ dst = dst_next;
+ src = src_next;
+ }
+
+ *text_size = dst - text;
+ *dst = 0; /* NUL-terminate. */
+ }
+
+ /* Accumulate length of rest. */
+ unsigned int dst_len = dst - text;
+ while (src < src_end)
+ {
+ src = in_utf_t::next (src, src_end, &unicode, replacement);
+ dst_len += out_utf_t::encode_len (unicode);
+ }
+ return dst_len;
+}
#define entry_score var.u16[0]
#define entry_index var.u16[1]
@@ -97,12 +142,68 @@ struct NameRecord
return UNSUPPORTED;
}
- NameRecord* copy (hb_serialize_context_t *c, const void *base) const
+ NameRecord* copy (hb_serialize_context_t *c, const void *base
+#ifdef HB_EXPERIMENTAL_API
+ , const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides
+#endif
+ ) const
{
TRACE_SERIALIZE (this);
+ HB_UNUSED auto snap = c->snapshot ();
auto *out = c->embed (this);
if (unlikely (!out)) return_trace (nullptr);
- out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length);
+#ifdef HB_EXPERIMENTAL_API
+ hb_ot_name_record_ids_t record_ids (platformID, encodingID, languageID, nameID);
+ hb_bytes_t* name_bytes;
+
+ if (name_table_overrides->has (record_ids, &name_bytes)) {
+ hb_bytes_t encoded_bytes = *name_bytes;
+ char *name_str_utf16_be = nullptr;
+
+ if (platformID != 1)
+ {
+ unsigned text_size = hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, nullptr, nullptr);
+
+ text_size++; // needs to consider NULL terminator for use in hb_ot_name_convert_utf()
+ unsigned byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
+ name_str_utf16_be = (char *) hb_calloc (byte_len, 1);
+ if (!name_str_utf16_be)
+ {
+ c->revert (snap);
+ return_trace (nullptr);
+ }
+ hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, &text_size,
+ (hb_utf16_be_t::codepoint_t *) name_str_utf16_be);
+
+ unsigned encoded_byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
+ if (!encoded_byte_len || !c->check_assign (out->length, encoded_byte_len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
+ c->revert (snap);
+ hb_free (name_str_utf16_be);
+ return_trace (nullptr);
+ }
+
+ encoded_bytes = hb_bytes_t (name_str_utf16_be, encoded_byte_len);
+ }
+ else
+ {
+ // mac platform, copy the UTF-8 string(all ascii characters) as is
+ if (!c->check_assign (out->length, encoded_bytes.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
+ c->revert (snap);
+ return_trace (nullptr);
+ }
+ }
+
+ out->offset = 0;
+ c->push ();
+ encoded_bytes.copy (c);
+ c->add_link (out->offset, c->pop_pack (), hb_serialize_context_t::Tail, 0);
+ hb_free (name_str_utf16_be);
+ }
+ else
+#endif
+ {
+ out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length);
+ }
return_trace (out);
}
@@ -216,29 +317,61 @@ struct name
hb_requires (hb_is_source_of (Iterator, const NameRecord &))>
bool serialize (hb_serialize_context_t *c,
Iterator it,
- const void *src_string_pool)
+ const void *src_string_pool
+#ifdef HB_EXPERIMENTAL_API
+ , const hb_vector_t<hb_ot_name_record_ids_t>& insert_name_records
+ , const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides
+#endif
+ )
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min ((*this)))) return_trace (false);
+ unsigned total_count = it.len ()
+#ifdef HB_EXPERIMENTAL_API
+ + insert_name_records.length
+#endif
+ ;
this->format = 0;
- this->count = it.len ();
+ if (!c->check_assign (this->count, total_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return false;
- NameRecord *name_records = (NameRecord *) hb_calloc (it.len (), NameRecord::static_size);
+ NameRecord *name_records = (NameRecord *) hb_calloc (total_count, NameRecord::static_size);
if (unlikely (!name_records)) return_trace (false);
- hb_array_t<NameRecord> records (name_records, it.len ());
+ hb_array_t<NameRecord> records (name_records, total_count);
for (const NameRecord& record : it)
{
+ hb_memcpy (name_records, &record, NameRecord::static_size);
+ name_records++;
+ }
+
+#ifdef HB_EXPERIMENTAL_API
+ for (unsigned i = 0; i < insert_name_records.length; i++)
+ {
+ const hb_ot_name_record_ids_t& ids = insert_name_records[i];
+ NameRecord record;
+ record.platformID = ids.platform_id;
+ record.encodingID = ids.encoding_id;
+ record.languageID = ids.language_id;
+ record.nameID = ids.name_id;
+ record.length = 0; // handled in NameRecord copy()
+ record.offset = 0;
memcpy (name_records, &record, NameRecord::static_size);
name_records++;
}
+#endif
records.qsort ();
- c->copy_all (records, src_string_pool);
+ c->copy_all (records,
+ src_string_pool
+#ifdef HB_EXPERIMENTAL_API
+ , name_table_overrides
+#endif
+ );
hb_free (records.arrayZ);
@@ -256,6 +389,11 @@ struct name
name *name_prime = c->serializer->start_embed<name> ();
if (unlikely (!name_prime)) return_trace (false);
+#ifdef HB_EXPERIMENTAL_API
+ const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides =
+ c->plan->name_table_overrides;
+#endif
+
auto it =
+ nameRecordZ.as_array (count)
| hb_filter (c->plan->name_ids, &NameRecord::nameID)
@@ -265,10 +403,48 @@ struct name
(c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY)
|| namerecord.isUnicode ();
})
+#ifdef HB_EXPERIMENTAL_API
+ | hb_filter ([&] (const NameRecord& namerecord) {
+ if (name_table_overrides->is_empty ())
+ return true;
+ hb_ot_name_record_ids_t rec_ids (namerecord.platformID,
+ namerecord.encodingID,
+ namerecord.languageID,
+ namerecord.nameID);
+
+ hb_bytes_t *p;
+ if (name_table_overrides->has (rec_ids, &p) &&
+ (*p).length == 0)
+ return false;
+ return true;
+ })
+#endif
;
- name_prime->serialize (c->serializer, it, std::addressof (this + stringOffset));
- return_trace (name_prime->count);
+#ifdef HB_EXPERIMENTAL_API
+ hb_vector_t<hb_ot_name_record_ids_t> insert_name_records;
+ if (!name_table_overrides->is_empty ())
+ {
+ if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population ())))
+ return_trace (false);
+ for (const auto& record_ids : name_table_overrides->keys ())
+ {
+ if (name_table_overrides->get (record_ids).length == 0)
+ continue;
+ if (has_name_record_with_ids (record_ids))
+ continue;
+ insert_name_records.push (record_ids);
+ }
+ }
+#endif
+
+ return (name_prime->serialize (c->serializer, it,
+ std::addressof (this + stringOffset)
+#ifdef HB_EXPERIMENTAL_API
+ , insert_name_records
+ , name_table_overrides
+#endif
+ ));
}
bool sanitize_records (hb_sanitize_context_t *c) const
@@ -378,6 +554,23 @@ struct name
hb_vector_t<hb_ot_name_entry_t> names;
};
+ private:
+ // sometimes NameRecords are not sorted in the font file, so use linear search
+ // here
+ bool has_name_record_with_ids (const hb_ot_name_record_ids_t& record_ids) const
+ {
+ for (const auto& record : nameRecordZ.as_array (count))
+ {
+ if (record.platformID == record_ids.platform_id &&
+ record.encodingID == record_ids.encoding_id &&
+ record.languageID == record_ids.language_id &&
+ record.nameID == record_ids.name_id)
+ return true;
+ }
+ return false;
+ }
+
+ public:
/* We only implement format 0 for now. */
HBUINT16 format; /* Format selector (=0/1). */
HBUINT16 count; /* Number of name records. */
diff --git a/thirdparty/harfbuzz/src/hb-ot-name.cc b/thirdparty/harfbuzz/src/hb-ot-name.cc
index c35ac5b3dc..6adf1e8fbe 100644
--- a/thirdparty/harfbuzz/src/hb-ot-name.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-name.cc
@@ -64,52 +64,6 @@ hb_ot_name_list_names (hb_face_t *face,
return (const hb_ot_name_entry_t *) name.names;
}
-
-template <typename in_utf_t, typename out_utf_t>
-static inline unsigned int
-hb_ot_name_convert_utf (hb_bytes_t bytes,
- unsigned int *text_size /* IN/OUT */,
- typename out_utf_t::codepoint_t *text /* OUT */)
-{
- unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t);
- const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ;
- const typename in_utf_t::codepoint_t *src_end = src + src_len;
-
- typename out_utf_t::codepoint_t *dst = text;
-
- hb_codepoint_t unicode;
- const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
-
- if (text_size && *text_size)
- {
- (*text_size)--; /* Same room for NUL-termination. */
- const typename out_utf_t::codepoint_t *dst_end = text + *text_size;
-
- while (src < src_end && dst < dst_end)
- {
- const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement);
- typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode);
- if (dst_next == dst)
- break; /* Out-of-room. */
-
- dst = dst_next;
- src = src_next;
- }
-
- *text_size = dst - text;
- *dst = 0; /* NUL-terminate. */
- }
-
- /* Accumulate length of rest. */
- unsigned int dst_len = dst - text;
- while (src < src_end)
- {
- src = in_utf_t::next (src, src_end, &unicode, replacement);
- dst_len += out_utf_t::encode_len (unicode);
- }
- return dst_len;
-}
-
template <typename utf_t>
static inline unsigned int
hb_ot_name_get_utf (hb_face_t *face,
@@ -130,10 +84,10 @@ hb_ot_name_get_utf (hb_face_t *face,
hb_bytes_t bytes = name.get_name (idx);
if (width == 2) /* UTF16-BE */
- return hb_ot_name_convert_utf<hb_utf16_be_t, utf_t> (bytes, text_size, text);
+ return OT::hb_ot_name_convert_utf<hb_utf16_be_t, utf_t> (bytes, text_size, text);
if (width == 1) /* ASCII */
- return hb_ot_name_convert_utf<hb_ascii_t, utf_t> (bytes, text_size, text);
+ return OT::hb_ot_name_convert_utf<hb_ascii_t, utf_t> (bytes, text_size, text);
}
if (text_size)
@@ -227,5 +181,4 @@ hb_ot_name_get_utf32 (hb_face_t *face,
return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
}
-
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
index c6e8fad6fc..5b017d56a6 100644
--- a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
@@ -212,17 +212,6 @@ struct OS2
TRACE_SUBSET (this);
OS2 *os2_prime = c->serializer->embed (this);
if (unlikely (!os2_prime)) return_trace (false);
- if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
- return_trace (true);
-
- /* when --gids option is not used, no need to do collect_mapping that is
- * iterating all codepoints in each subtable, which is not efficient */
- uint16_t min_cp, max_cp;
- find_min_and_max_codepoint (c->plan->unicodes, &min_cp, &max_cp);
- os2_prime->usFirstCharIndex = min_cp;
- os2_prime->usLastCharIndex = max_cp;
-
- _update_unicode_ranges (c->plan->unicodes, os2_prime->ulUnicodeRange);
if (c->plan->user_axes_location->has (HB_TAG ('w','g','h','t')) &&
!c->plan->pinned_at_default)
@@ -244,6 +233,18 @@ struct OS2
return_trace (false);
}
+ if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
+ return_trace (true);
+
+ /* when --gids option is not used, no need to do collect_mapping that is
+ * iterating all codepoints in each subtable, which is not efficient */
+ uint16_t min_cp, max_cp;
+ find_min_and_max_codepoint (c->plan->unicodes, &min_cp, &max_cp);
+ os2_prime->usFirstCharIndex = min_cp;
+ os2_prime->usLastCharIndex = max_cp;
+
+ _update_unicode_ranges (c->plan->unicodes, os2_prime->ulUnicodeRange);
+
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh b/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh
index 4d427e5431..951e6395d6 100644
--- a/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh
@@ -78,14 +78,14 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
post::accelerator_t _post (c->plan->source);
- hb_hashmap_t<hb_bytes_t, unsigned, true> glyph_name_to_new_index;
+ hb_hashmap_t<hb_bytes_t, uint32_t, true> glyph_name_to_new_index;
for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
{
hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
unsigned old_index = glyphNameIndex[old_gid];
unsigned new_index;
- const unsigned *new_index2;
+ const uint32_t *new_index2;
if (old_index <= 257) new_index = old_index;
else if (old_new_index_map.has (old_index, &new_index2))
{
diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table.hh b/thirdparty/harfbuzz/src/hb-ot-post-table.hh
index 59c1de3784..a04b80357b 100644
--- a/thirdparty/harfbuzz/src/hb-ot-post-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-post-table.hh
@@ -84,7 +84,7 @@ struct post
post *post_prime = c->allocate_min<post> ();
if (unlikely (!post_prime)) return_trace (false);
- memcpy (post_prime, this, post::min_size);
+ hb_memcpy (post_prime, this, post::min_size);
if (!glyph_names)
return_trace (c->check_assign (post_prime->version.major, 3,
HB_SERIALIZE_ERROR_INT_OVERFLOW)); // Version 3 does not have any glyph names.
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
index 7db0b25b73..897377aa15 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
@@ -341,7 +341,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
{
unsigned int end;
for (end = buffer->idx + 1; end < count; end++)
- if (unlikely (_hb_glyph_info_is_unicode_mark (&buffer->info[end])))
+ if (_hb_glyph_info_is_unicode_mark (&buffer->info[end]))
break;
if (end < count)
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.cc b/thirdparty/harfbuzz/src/hb-ot-shape.cc
index 249b5a864c..bbdfc214a1 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape.cc
@@ -91,9 +91,11 @@ hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *fac
script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE;
script_fallback_mark_positioning = shaper->fallback_position;
+#ifndef HB_NO_AAT_SHAPE
/* https://github.com/harfbuzz/harfbuzz/issues/1528 */
if (apply_morx && shaper != &_hb_ot_shaper_default)
shaper = &_hb_ot_shaper_dumber;
+#endif
}
void
@@ -864,7 +866,7 @@ hb_ot_hide_default_ignorables (hb_buffer_t *buffer,
}
}
else
- hb_ot_layout_delete_glyphs_inplace (buffer, _hb_glyph_info_is_default_ignorable);
+ buffer->delete_glyphs_inplace (_hb_glyph_info_is_default_ignorable);
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.hh b/thirdparty/harfbuzz/src/hb-ot-shape.hh
index cd6f15cbe2..ace28602f6 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape.hh
@@ -51,7 +51,7 @@ struct hb_ot_shape_plan_key_t
bool equal (const hb_ot_shape_plan_key_t *other)
{
- return 0 == memcmp (this, other, sizeof (*this));
+ return 0 == hb_memcmp (this, other, sizeof (*this));
}
};
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc
index ed2748b828..2332ae3697 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc
@@ -161,22 +161,23 @@ static const struct arabic_state_table_entry {
};
-static void
+static bool
arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
record_stch (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
deallocate_buffer_var (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
+ return false;
}
static void
@@ -412,19 +413,19 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan,
setup_masks_arabic_plan (arabic_plan, buffer, plan->props.script);
}
-static void
+static bool
arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
#ifdef HB_NO_OT_SHAPER_ARABIC_FALLBACK
- return;
+ return false;
#endif
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
if (!arabic_plan->do_fallback)
- return;
+ return false;
retry:
arabic_fallback_plan_t *fallback_plan = arabic_plan->fallback_plan;
@@ -440,6 +441,7 @@ retry:
}
arabic_fallback_plan_shape (fallback_plan, font, buffer);
+ return true;
}
/*
@@ -450,14 +452,14 @@ retry:
* marks can use it as well.
*/
-static void
+static bool
record_stch (const hb_ot_shape_plan_t *plan,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
if (!arabic_plan->has_stch)
- return;
+ return false;
/* 'stch' feature was just applied. Look for anything that multiplied,
* and record it for stch treatment later. Note that rtlm, frac, etc
@@ -473,6 +475,7 @@ record_stch (const hb_ot_shape_plan_t *plan,
info[i].arabic_shaping_action() = comp % 2 ? STCH_REPEATING : STCH_FIXED;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH;
}
+ return false;
}
static void
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-default.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-default.cc
index 2f6f499eec..f0404a4d2c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-default.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-default.cc
@@ -49,6 +49,7 @@ const hb_ot_shaper_t _hb_ot_shaper_default =
true, /* fallback_position */
};
+#ifndef HB_NO_AAT_SHAPE
/* Same as default but no mark advance zeroing / fallback positioning.
* Dumbest shaper ever, basically. */
const hb_ot_shaper_t _hb_ot_shaper_dumber =
@@ -68,6 +69,7 @@ const hb_ot_shaper_t _hb_ot_shaper_dumber =
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};
+#endif
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh
index d52b13f616..d6c67b81bd 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh
@@ -53,7 +53,7 @@ enum indic_syllable_type_t {
};
-#line 57 "hb-ot-shaper-indic-machine.hh"
+#line 54 "hb-ot-shaper-indic-machine.hh"
#define indic_syllable_machine_ex_A 9u
#define indic_syllable_machine_ex_C 1u
#define indic_syllable_machine_ex_CM 16u
@@ -61,6 +61,7 @@ enum indic_syllable_type_t {
#define indic_syllable_machine_ex_DOTTEDCIRCLE 11u
#define indic_syllable_machine_ex_H 4u
#define indic_syllable_machine_ex_M 7u
+#define indic_syllable_machine_ex_MPst 13u
#define indic_syllable_machine_ex_N 3u
#define indic_syllable_machine_ex_PLACEHOLDER 10u
#define indic_syllable_machine_ex_RS 12u
@@ -75,268 +76,302 @@ enum indic_syllable_type_t {
#define indic_syllable_machine_ex_ZWNJ 5u
-#line 79 "hb-ot-shaper-indic-machine.hh"
+#line 75 "hb-ot-shaper-indic-machine.hh"
static const unsigned char _indic_syllable_machine_trans_keys[] = {
- 8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 4u, 12u, 4u, 8u, 8u, 8u,
- 5u, 7u, 5u, 8u, 4u, 8u, 4u, 12u, 4u, 12u, 4u, 12u, 8u, 8u, 5u, 7u,
- 5u, 8u, 4u, 8u, 4u, 8u, 4u, 12u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u,
- 4u, 8u, 5u, 8u, 8u, 8u, 1u, 18u, 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u,
- 5u, 9u, 5u, 9u, 9u, 9u, 5u, 9u, 1u, 15u, 1u, 15u, 1u, 15u, 3u, 9u,
- 4u, 9u, 5u, 9u, 4u, 9u, 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 3u, 16u,
- 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u, 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u,
- 5u, 9u, 9u, 9u, 5u, 9u, 1u, 15u, 1u, 15u, 3u, 9u, 4u, 9u, 5u, 9u,
- 4u, 9u, 5u, 9u, 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 3u, 16u, 4u, 8u,
- 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u, 3u, 16u, 1u, 15u, 5u, 9u, 9u, 9u,
- 5u, 9u, 1u, 15u, 1u, 15u, 3u, 9u, 4u, 9u, 5u, 9u, 3u, 16u, 4u, 9u,
- 5u, 9u, 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 4u, 12u, 4u, 8u, 3u, 16u,
- 3u, 16u, 4u, 16u, 1u, 15u, 3u, 16u, 1u, 15u, 5u, 9u, 9u, 9u, 5u, 9u,
- 1u, 15u, 1u, 15u, 3u, 9u, 4u, 9u, 5u, 9u, 3u, 16u, 4u, 9u, 5u, 9u,
- 5u, 9u, 3u, 9u, 5u, 9u, 1u, 16u, 3u, 16u, 1u, 16u, 4u, 12u, 5u, 9u,
- 9u, 9u, 5u, 9u, 1u, 15u, 3u, 9u, 5u, 9u, 5u, 9u, 9u, 9u, 5u, 9u,
- 1u, 15u, 0
+ 8u, 8u, 4u, 13u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u,
+ 8u, 8u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 4u, 13u,
+ 8u, 8u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 8u, 8u,
+ 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 5u, 13u, 8u, 8u, 1u, 18u,
+ 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u, 5u, 9u, 5u, 9u, 9u, 9u, 5u, 9u,
+ 1u, 15u, 1u, 15u, 1u, 15u, 3u, 13u, 4u, 13u, 5u, 13u, 5u, 13u, 4u, 13u,
+ 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 3u, 16u, 3u, 16u, 3u, 16u, 4u, 16u,
+ 1u, 15u, 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u, 5u, 9u, 9u, 9u, 5u, 9u,
+ 1u, 15u, 1u, 15u, 3u, 13u, 4u, 13u, 5u, 13u, 5u, 13u, 4u, 13u, 5u, 9u,
+ 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 3u, 16u, 4u, 13u, 3u, 16u, 3u, 16u,
+ 4u, 16u, 1u, 15u, 3u, 16u, 1u, 15u, 5u, 9u, 9u, 9u, 5u, 9u, 1u, 15u,
+ 1u, 15u, 3u, 13u, 4u, 13u, 5u, 13u, 5u, 13u, 3u, 16u, 4u, 13u, 5u, 9u,
+ 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 4u, 13u, 4u, 13u, 3u, 16u, 3u, 16u,
+ 4u, 16u, 1u, 15u, 3u, 16u, 1u, 15u, 5u, 9u, 9u, 9u, 5u, 9u, 1u, 15u,
+ 1u, 15u, 3u, 13u, 4u, 13u, 5u, 13u, 5u, 13u, 3u, 16u, 4u, 13u, 5u, 9u,
+ 5u, 9u, 3u, 9u, 5u, 9u, 1u, 16u, 3u, 16u, 1u, 16u, 4u, 13u, 5u, 13u,
+ 5u, 13u, 9u, 9u, 5u, 9u, 1u, 15u, 3u, 9u, 5u, 9u, 5u, 9u, 9u, 9u,
+ 5u, 9u, 1u, 15u, 0
};
static const char _indic_syllable_machine_key_spans[] = {
- 1, 5, 3, 4, 5, 9, 5, 1,
- 3, 4, 5, 9, 9, 9, 1, 3,
- 4, 5, 5, 9, 1, 3, 4, 5,
- 5, 4, 1, 18, 14, 14, 13, 15,
- 5, 5, 1, 5, 15, 15, 15, 7,
- 6, 5, 6, 5, 7, 5, 14, 14,
- 14, 14, 13, 15, 14, 14, 13, 15,
- 5, 1, 5, 15, 15, 7, 6, 5,
- 6, 5, 5, 7, 5, 14, 14, 5,
- 14, 14, 13, 15, 14, 15, 5, 1,
- 5, 15, 15, 7, 6, 5, 14, 6,
- 5, 5, 7, 5, 14, 9, 5, 14,
- 14, 13, 15, 14, 15, 5, 1, 5,
- 15, 15, 7, 6, 5, 14, 6, 5,
- 5, 7, 5, 16, 14, 16, 9, 5,
- 1, 5, 15, 7, 5, 5, 1, 5,
- 15
+ 1, 10, 9, 9, 1, 10, 10, 10,
+ 1, 9, 9, 1, 10, 10, 10, 10,
+ 1, 9, 9, 1, 10, 10, 10, 1,
+ 9, 9, 1, 10, 10, 9, 1, 18,
+ 14, 14, 13, 15, 5, 5, 1, 5,
+ 15, 15, 15, 11, 10, 9, 9, 10,
+ 5, 7, 5, 14, 14, 14, 14, 13,
+ 15, 14, 14, 13, 15, 5, 1, 5,
+ 15, 15, 11, 10, 9, 9, 10, 5,
+ 5, 7, 5, 14, 14, 10, 14, 14,
+ 13, 15, 14, 15, 5, 1, 5, 15,
+ 15, 11, 10, 9, 9, 14, 10, 5,
+ 5, 7, 5, 14, 10, 10, 14, 14,
+ 13, 15, 14, 15, 5, 1, 5, 15,
+ 15, 11, 10, 9, 9, 14, 10, 5,
+ 5, 7, 5, 16, 14, 16, 10, 9,
+ 9, 1, 5, 15, 7, 5, 5, 1,
+ 5, 15
};
static const short _indic_syllable_machine_index_offsets[] = {
- 0, 2, 8, 12, 17, 23, 33, 39,
- 41, 45, 50, 56, 66, 76, 86, 88,
- 92, 97, 103, 109, 119, 121, 125, 130,
- 136, 142, 147, 149, 168, 183, 198, 212,
- 228, 234, 240, 242, 248, 264, 280, 296,
- 304, 311, 317, 324, 330, 338, 344, 359,
- 374, 389, 404, 418, 434, 449, 464, 478,
- 494, 500, 502, 508, 524, 540, 548, 555,
- 561, 568, 574, 580, 588, 594, 609, 624,
- 630, 645, 660, 674, 690, 705, 721, 727,
- 729, 735, 751, 767, 775, 782, 788, 803,
- 810, 816, 822, 830, 836, 851, 861, 867,
- 882, 897, 911, 927, 942, 958, 964, 966,
- 972, 988, 1004, 1012, 1019, 1025, 1040, 1047,
- 1053, 1059, 1067, 1073, 1090, 1105, 1122, 1132,
- 1138, 1140, 1146, 1162, 1170, 1176, 1182, 1184,
- 1190
+ 0, 2, 13, 23, 33, 35, 46, 57,
+ 68, 70, 80, 90, 92, 103, 114, 125,
+ 136, 138, 148, 158, 160, 171, 182, 193,
+ 195, 205, 215, 217, 228, 239, 249, 251,
+ 270, 285, 300, 314, 330, 336, 342, 344,
+ 350, 366, 382, 398, 410, 421, 431, 441,
+ 452, 458, 466, 472, 487, 502, 517, 532,
+ 546, 562, 577, 592, 606, 622, 628, 630,
+ 636, 652, 668, 680, 691, 701, 711, 722,
+ 728, 734, 742, 748, 763, 778, 789, 804,
+ 819, 833, 849, 864, 880, 886, 888, 894,
+ 910, 926, 938, 949, 959, 969, 984, 995,
+ 1001, 1007, 1015, 1021, 1036, 1047, 1058, 1073,
+ 1088, 1102, 1118, 1133, 1149, 1155, 1157, 1163,
+ 1179, 1195, 1207, 1218, 1228, 1238, 1253, 1264,
+ 1270, 1276, 1284, 1290, 1307, 1322, 1339, 1350,
+ 1360, 1370, 1372, 1378, 1394, 1402, 1408, 1414,
+ 1416, 1422
};
static const unsigned char _indic_syllable_machine_indicies[] = {
- 1, 0, 2, 3, 3, 4, 1, 0,
- 3, 3, 4, 0, 3, 3, 4, 1,
- 0, 5, 3, 3, 4, 1, 0, 2,
- 3, 3, 4, 1, 0, 0, 0, 6,
- 0, 8, 9, 9, 10, 11, 7, 11,
- 7, 9, 9, 10, 7, 9, 9, 10,
- 11, 7, 12, 9, 9, 10, 11, 7,
- 8, 9, 9, 10, 11, 7, 7, 7,
- 13, 7, 8, 9, 9, 10, 11, 7,
- 7, 7, 14, 7, 16, 17, 17, 18,
- 19, 15, 15, 15, 20, 15, 19, 15,
- 17, 17, 18, 21, 17, 17, 18, 19,
- 15, 16, 17, 17, 18, 19, 15, 22,
- 17, 17, 18, 19, 15, 24, 25, 25,
- 26, 27, 23, 23, 23, 28, 23, 27,
- 23, 25, 25, 26, 23, 25, 25, 26,
- 27, 23, 24, 25, 25, 26, 27, 23,
- 29, 25, 25, 26, 27, 23, 17, 17,
- 18, 1, 0, 31, 30, 33, 34, 35,
- 36, 37, 38, 18, 19, 39, 40, 40,
- 20, 32, 41, 42, 43, 44, 45, 32,
- 47, 48, 49, 50, 4, 1, 51, 46,
- 46, 6, 46, 46, 46, 52, 46, 53,
- 48, 54, 54, 4, 1, 51, 46, 46,
- 46, 46, 46, 46, 52, 46, 48, 54,
- 54, 4, 1, 51, 46, 46, 46, 46,
- 46, 46, 52, 46, 33, 46, 46, 46,
- 55, 56, 46, 1, 51, 46, 46, 46,
- 46, 46, 33, 46, 57, 57, 46, 1,
- 51, 46, 51, 46, 46, 58, 51, 46,
- 51, 46, 51, 46, 46, 46, 51, 46,
- 33, 46, 59, 46, 57, 57, 46, 1,
- 51, 46, 46, 46, 46, 46, 33, 46,
- 33, 46, 46, 46, 57, 57, 46, 1,
- 51, 46, 46, 46, 46, 46, 33, 46,
- 33, 46, 46, 46, 57, 56, 46, 1,
- 51, 46, 46, 46, 46, 46, 33, 46,
- 60, 61, 62, 62, 4, 1, 51, 46,
- 61, 62, 62, 4, 1, 51, 46, 62,
- 62, 4, 1, 51, 46, 63, 64, 64,
- 4, 1, 51, 46, 55, 65, 46, 1,
- 51, 46, 55, 46, 57, 57, 46, 1,
- 51, 46, 57, 65, 46, 1, 51, 46,
- 47, 48, 54, 54, 4, 1, 51, 46,
- 46, 46, 46, 46, 46, 52, 46, 47,
- 48, 49, 54, 4, 1, 51, 46, 46,
- 6, 46, 46, 46, 52, 46, 67, 68,
- 69, 70, 10, 11, 71, 66, 66, 14,
- 66, 66, 66, 72, 66, 73, 68, 74,
- 70, 10, 11, 71, 66, 66, 66, 66,
- 66, 66, 72, 66, 68, 74, 70, 10,
- 11, 71, 66, 66, 66, 66, 66, 66,
- 72, 66, 75, 66, 66, 66, 76, 77,
- 66, 11, 71, 66, 66, 66, 66, 66,
- 75, 66, 78, 68, 79, 80, 10, 11,
- 71, 66, 66, 13, 66, 66, 66, 72,
- 66, 81, 68, 74, 74, 10, 11, 71,
- 66, 66, 66, 66, 66, 66, 72, 66,
- 68, 74, 74, 10, 11, 71, 66, 66,
- 66, 66, 66, 66, 72, 66, 75, 66,
- 66, 66, 82, 77, 66, 11, 71, 66,
- 66, 66, 66, 66, 75, 66, 71, 66,
- 66, 83, 71, 66, 71, 66, 71, 66,
- 66, 66, 71, 66, 75, 66, 84, 66,
- 82, 82, 66, 11, 71, 66, 66, 66,
- 66, 66, 75, 66, 75, 66, 66, 66,
- 82, 82, 66, 11, 71, 66, 66, 66,
- 66, 66, 75, 66, 85, 86, 87, 87,
- 10, 11, 71, 66, 86, 87, 87, 10,
- 11, 71, 66, 87, 87, 10, 11, 71,
- 66, 88, 89, 89, 10, 11, 71, 66,
- 76, 90, 66, 11, 71, 66, 82, 82,
- 66, 11, 71, 66, 76, 66, 82, 82,
- 66, 11, 71, 66, 82, 90, 66, 11,
- 71, 66, 78, 68, 74, 74, 10, 11,
- 71, 66, 66, 66, 66, 66, 66, 72,
- 66, 78, 68, 79, 74, 10, 11, 71,
- 66, 66, 13, 66, 66, 66, 72, 66,
- 8, 9, 9, 10, 11, 66, 67, 68,
- 74, 70, 10, 11, 71, 66, 66, 66,
- 66, 66, 66, 72, 66, 92, 36, 93,
- 93, 18, 19, 39, 91, 91, 91, 91,
- 91, 91, 43, 91, 36, 93, 93, 18,
- 19, 39, 91, 91, 91, 91, 91, 91,
- 43, 91, 94, 91, 91, 91, 95, 96,
- 91, 19, 39, 91, 91, 91, 91, 91,
- 94, 91, 35, 36, 97, 98, 18, 19,
- 39, 91, 91, 20, 91, 91, 91, 43,
- 91, 94, 91, 91, 91, 99, 96, 91,
- 19, 39, 91, 91, 91, 91, 91, 94,
- 91, 39, 91, 91, 100, 39, 91, 39,
- 91, 39, 91, 91, 91, 39, 91, 94,
- 91, 101, 91, 99, 99, 91, 19, 39,
- 91, 91, 91, 91, 91, 94, 91, 94,
- 91, 91, 91, 99, 99, 91, 19, 39,
- 91, 91, 91, 91, 91, 94, 91, 102,
- 103, 104, 104, 18, 19, 39, 91, 103,
- 104, 104, 18, 19, 39, 91, 104, 104,
- 18, 19, 39, 91, 35, 36, 93, 93,
- 18, 19, 39, 91, 91, 91, 91, 91,
- 91, 43, 91, 105, 106, 106, 18, 19,
- 39, 91, 95, 107, 91, 19, 39, 91,
- 99, 99, 91, 19, 39, 91, 95, 91,
- 99, 99, 91, 19, 39, 91, 99, 107,
- 91, 19, 39, 91, 35, 36, 97, 93,
- 18, 19, 39, 91, 91, 20, 91, 91,
- 91, 43, 91, 16, 17, 17, 18, 19,
- 108, 108, 108, 20, 108, 16, 17, 17,
- 18, 19, 108, 110, 111, 112, 113, 26,
- 27, 114, 109, 109, 28, 109, 109, 109,
- 115, 109, 116, 111, 113, 113, 26, 27,
- 114, 109, 109, 109, 109, 109, 109, 115,
- 109, 111, 113, 113, 26, 27, 114, 109,
- 109, 109, 109, 109, 109, 115, 109, 117,
- 109, 109, 109, 118, 119, 109, 27, 114,
- 109, 109, 109, 109, 109, 117, 109, 110,
- 111, 112, 40, 26, 27, 114, 109, 109,
- 28, 109, 109, 109, 115, 109, 117, 109,
- 109, 109, 120, 119, 109, 27, 114, 109,
- 109, 109, 109, 109, 117, 109, 114, 109,
- 109, 121, 114, 109, 114, 109, 114, 109,
- 109, 109, 114, 109, 117, 109, 122, 109,
- 120, 120, 109, 27, 114, 109, 109, 109,
- 109, 109, 117, 109, 117, 109, 109, 109,
- 120, 120, 109, 27, 114, 109, 109, 109,
- 109, 109, 117, 109, 123, 124, 125, 125,
- 26, 27, 114, 109, 124, 125, 125, 26,
- 27, 114, 109, 125, 125, 26, 27, 114,
- 109, 110, 111, 113, 113, 26, 27, 114,
- 109, 109, 109, 109, 109, 109, 115, 109,
- 126, 127, 127, 26, 27, 114, 109, 118,
- 128, 109, 27, 114, 109, 120, 120, 109,
- 27, 114, 109, 118, 109, 120, 120, 109,
- 27, 114, 109, 120, 128, 109, 27, 114,
- 109, 33, 34, 35, 36, 97, 93, 18,
- 19, 39, 40, 40, 20, 91, 91, 33,
- 43, 91, 47, 129, 49, 50, 4, 1,
- 51, 46, 46, 6, 46, 46, 46, 52,
- 46, 33, 34, 35, 36, 130, 131, 18,
- 132, 133, 46, 40, 20, 46, 46, 33,
- 43, 46, 16, 134, 134, 18, 132, 51,
- 46, 46, 20, 46, 133, 46, 46, 135,
- 133, 46, 133, 46, 133, 46, 46, 46,
- 133, 46, 33, 46, 59, 16, 134, 134,
- 18, 132, 51, 46, 46, 46, 46, 46,
- 33, 46, 137, 136, 138, 138, 136, 31,
- 139, 136, 138, 138, 136, 31, 139, 136,
- 139, 136, 136, 140, 139, 136, 139, 136,
- 139, 136, 136, 136, 139, 136, 33, 108,
- 108, 108, 108, 108, 108, 108, 108, 40,
- 108, 108, 108, 108, 33, 108, 0
+ 1, 0, 2, 3, 3, 4, 5, 0,
+ 0, 0, 0, 4, 0, 3, 3, 4,
+ 6, 0, 0, 0, 0, 4, 0, 3,
+ 3, 4, 5, 0, 0, 0, 0, 4,
+ 0, 4, 0, 7, 3, 3, 4, 5,
+ 0, 0, 0, 0, 4, 0, 2, 3,
+ 3, 4, 5, 0, 0, 0, 8, 4,
+ 0, 10, 11, 11, 12, 13, 9, 9,
+ 9, 9, 12, 9, 14, 9, 11, 11,
+ 12, 15, 9, 9, 9, 9, 12, 9,
+ 11, 11, 12, 13, 9, 9, 9, 9,
+ 12, 9, 12, 9, 16, 11, 11, 12,
+ 13, 9, 9, 9, 9, 12, 9, 10,
+ 11, 11, 12, 13, 9, 9, 9, 17,
+ 12, 9, 10, 11, 11, 12, 13, 9,
+ 9, 9, 18, 12, 9, 20, 21, 21,
+ 22, 23, 19, 19, 19, 24, 22, 19,
+ 25, 19, 21, 21, 22, 27, 26, 26,
+ 26, 26, 22, 26, 21, 21, 22, 23,
+ 19, 19, 19, 19, 22, 19, 22, 26,
+ 20, 21, 21, 22, 23, 19, 19, 19,
+ 19, 22, 19, 28, 21, 21, 22, 23,
+ 19, 19, 19, 19, 22, 19, 30, 31,
+ 31, 32, 33, 29, 29, 29, 34, 32,
+ 29, 35, 29, 31, 31, 32, 36, 29,
+ 29, 29, 29, 32, 29, 31, 31, 32,
+ 33, 29, 29, 29, 29, 32, 29, 32,
+ 29, 30, 31, 31, 32, 33, 29, 29,
+ 29, 29, 32, 29, 37, 31, 31, 32,
+ 33, 29, 29, 29, 29, 32, 29, 21,
+ 21, 22, 38, 0, 0, 0, 0, 22,
+ 0, 40, 39, 42, 43, 44, 45, 46,
+ 47, 22, 23, 48, 49, 49, 24, 22,
+ 50, 51, 52, 53, 54, 41, 56, 57,
+ 58, 59, 4, 5, 60, 55, 55, 8,
+ 4, 55, 55, 61, 55, 62, 57, 63,
+ 63, 4, 5, 60, 55, 55, 55, 4,
+ 55, 55, 61, 55, 57, 63, 63, 4,
+ 5, 60, 55, 55, 55, 4, 55, 55,
+ 61, 55, 42, 55, 55, 55, 64, 65,
+ 55, 1, 60, 55, 55, 55, 55, 55,
+ 42, 55, 66, 66, 55, 1, 60, 55,
+ 60, 55, 55, 67, 60, 55, 60, 55,
+ 60, 55, 55, 55, 60, 55, 42, 55,
+ 68, 55, 66, 66, 55, 1, 60, 55,
+ 55, 55, 55, 55, 42, 55, 42, 55,
+ 55, 55, 66, 66, 55, 1, 60, 55,
+ 55, 55, 55, 55, 42, 55, 42, 55,
+ 55, 55, 66, 65, 55, 1, 60, 55,
+ 55, 55, 55, 55, 42, 55, 69, 70,
+ 71, 71, 4, 5, 60, 55, 55, 55,
+ 4, 55, 70, 71, 71, 4, 5, 60,
+ 55, 55, 55, 4, 55, 71, 71, 4,
+ 5, 60, 55, 55, 55, 4, 55, 60,
+ 55, 55, 67, 60, 55, 55, 55, 4,
+ 55, 72, 73, 73, 4, 5, 60, 55,
+ 55, 55, 4, 55, 64, 74, 55, 1,
+ 60, 55, 64, 55, 66, 66, 55, 1,
+ 60, 55, 66, 74, 55, 1, 60, 55,
+ 56, 57, 63, 63, 4, 5, 60, 55,
+ 55, 55, 4, 55, 55, 61, 55, 56,
+ 57, 58, 63, 4, 5, 60, 55, 55,
+ 8, 4, 55, 55, 61, 55, 76, 77,
+ 78, 79, 12, 13, 80, 75, 75, 18,
+ 12, 75, 75, 81, 75, 82, 77, 83,
+ 79, 12, 13, 80, 75, 75, 75, 12,
+ 75, 75, 81, 75, 77, 83, 79, 12,
+ 13, 80, 75, 75, 75, 12, 75, 75,
+ 81, 75, 84, 75, 75, 75, 85, 86,
+ 75, 14, 80, 75, 75, 75, 75, 75,
+ 84, 75, 87, 77, 88, 89, 12, 13,
+ 80, 75, 75, 17, 12, 75, 75, 81,
+ 75, 90, 77, 83, 83, 12, 13, 80,
+ 75, 75, 75, 12, 75, 75, 81, 75,
+ 77, 83, 83, 12, 13, 80, 75, 75,
+ 75, 12, 75, 75, 81, 75, 84, 75,
+ 75, 75, 91, 86, 75, 14, 80, 75,
+ 75, 75, 75, 75, 84, 75, 80, 75,
+ 75, 92, 80, 75, 80, 75, 80, 75,
+ 75, 75, 80, 75, 84, 75, 93, 75,
+ 91, 91, 75, 14, 80, 75, 75, 75,
+ 75, 75, 84, 75, 84, 75, 75, 75,
+ 91, 91, 75, 14, 80, 75, 75, 75,
+ 75, 75, 84, 75, 94, 95, 96, 96,
+ 12, 13, 80, 75, 75, 75, 12, 75,
+ 95, 96, 96, 12, 13, 80, 75, 75,
+ 75, 12, 75, 96, 96, 12, 13, 80,
+ 75, 75, 75, 12, 75, 80, 75, 75,
+ 92, 80, 75, 75, 75, 12, 75, 97,
+ 98, 98, 12, 13, 80, 75, 75, 75,
+ 12, 75, 85, 99, 75, 14, 80, 75,
+ 91, 91, 75, 14, 80, 75, 85, 75,
+ 91, 91, 75, 14, 80, 75, 91, 99,
+ 75, 14, 80, 75, 87, 77, 83, 83,
+ 12, 13, 80, 75, 75, 75, 12, 75,
+ 75, 81, 75, 87, 77, 88, 83, 12,
+ 13, 80, 75, 75, 17, 12, 75, 75,
+ 81, 75, 10, 11, 11, 12, 13, 75,
+ 75, 75, 75, 12, 75, 76, 77, 83,
+ 79, 12, 13, 80, 75, 75, 75, 12,
+ 75, 75, 81, 75, 101, 45, 102, 102,
+ 22, 23, 48, 100, 100, 100, 22, 100,
+ 100, 52, 100, 45, 102, 102, 22, 23,
+ 48, 100, 100, 100, 22, 100, 100, 52,
+ 100, 103, 100, 100, 100, 104, 105, 100,
+ 25, 48, 100, 100, 100, 100, 100, 103,
+ 100, 44, 45, 106, 107, 22, 23, 48,
+ 100, 100, 24, 22, 100, 100, 52, 100,
+ 103, 100, 100, 100, 108, 105, 100, 25,
+ 48, 100, 100, 100, 100, 100, 103, 100,
+ 48, 100, 100, 109, 48, 100, 48, 100,
+ 48, 100, 100, 100, 48, 100, 103, 100,
+ 110, 100, 108, 108, 100, 25, 48, 100,
+ 100, 100, 100, 100, 103, 100, 103, 100,
+ 100, 100, 108, 108, 100, 25, 48, 100,
+ 100, 100, 100, 100, 103, 100, 111, 112,
+ 113, 113, 22, 23, 48, 100, 100, 100,
+ 22, 100, 112, 113, 113, 22, 23, 48,
+ 100, 100, 100, 22, 100, 113, 113, 22,
+ 23, 48, 100, 100, 100, 22, 100, 48,
+ 100, 100, 109, 48, 100, 100, 100, 22,
+ 100, 44, 45, 102, 102, 22, 23, 48,
+ 100, 100, 100, 22, 100, 100, 52, 100,
+ 114, 115, 115, 22, 23, 48, 100, 100,
+ 100, 22, 100, 104, 116, 100, 25, 48,
+ 100, 108, 108, 100, 25, 48, 100, 104,
+ 100, 108, 108, 100, 25, 48, 100, 108,
+ 116, 100, 25, 48, 100, 44, 45, 106,
+ 102, 22, 23, 48, 100, 100, 24, 22,
+ 100, 100, 52, 100, 20, 21, 21, 22,
+ 23, 117, 117, 117, 24, 22, 117, 20,
+ 21, 21, 22, 23, 117, 117, 117, 117,
+ 22, 117, 119, 120, 121, 122, 32, 33,
+ 123, 118, 118, 34, 32, 118, 118, 124,
+ 118, 125, 120, 122, 122, 32, 33, 123,
+ 118, 118, 118, 32, 118, 118, 124, 118,
+ 120, 122, 122, 32, 33, 123, 118, 118,
+ 118, 32, 118, 118, 124, 118, 126, 118,
+ 118, 118, 127, 128, 118, 35, 123, 118,
+ 118, 118, 118, 118, 126, 118, 119, 120,
+ 121, 49, 32, 33, 123, 118, 118, 34,
+ 32, 118, 118, 124, 118, 126, 118, 118,
+ 118, 129, 128, 118, 35, 123, 118, 118,
+ 118, 118, 118, 126, 118, 123, 118, 118,
+ 130, 123, 118, 123, 118, 123, 118, 118,
+ 118, 123, 118, 126, 118, 131, 118, 129,
+ 129, 118, 35, 123, 118, 118, 118, 118,
+ 118, 126, 118, 126, 118, 118, 118, 129,
+ 129, 118, 35, 123, 118, 118, 118, 118,
+ 118, 126, 118, 132, 133, 134, 134, 32,
+ 33, 123, 118, 118, 118, 32, 118, 133,
+ 134, 134, 32, 33, 123, 118, 118, 118,
+ 32, 118, 134, 134, 32, 33, 123, 118,
+ 118, 118, 32, 118, 123, 118, 118, 130,
+ 123, 118, 118, 118, 32, 118, 119, 120,
+ 122, 122, 32, 33, 123, 118, 118, 118,
+ 32, 118, 118, 124, 118, 135, 136, 136,
+ 32, 33, 123, 118, 118, 118, 32, 118,
+ 127, 137, 118, 35, 123, 118, 129, 129,
+ 118, 35, 123, 118, 127, 118, 129, 129,
+ 118, 35, 123, 118, 129, 137, 118, 35,
+ 123, 118, 42, 43, 44, 45, 106, 102,
+ 22, 23, 48, 49, 49, 24, 22, 100,
+ 42, 52, 100, 56, 138, 58, 59, 4,
+ 5, 60, 55, 55, 8, 4, 55, 55,
+ 61, 55, 42, 43, 44, 45, 139, 140,
+ 22, 141, 142, 55, 49, 24, 22, 55,
+ 42, 52, 55, 20, 143, 143, 22, 141,
+ 60, 55, 55, 24, 22, 55, 60, 55,
+ 55, 67, 60, 55, 55, 55, 22, 55,
+ 142, 55, 55, 144, 142, 55, 55, 55,
+ 22, 55, 142, 55, 142, 55, 55, 55,
+ 142, 55, 42, 55, 68, 20, 143, 143,
+ 22, 141, 60, 55, 55, 55, 22, 55,
+ 42, 55, 146, 145, 147, 147, 145, 40,
+ 148, 145, 147, 147, 145, 40, 148, 145,
+ 148, 145, 145, 149, 148, 145, 148, 145,
+ 148, 145, 145, 145, 148, 145, 42, 117,
+ 117, 117, 117, 117, 117, 117, 117, 49,
+ 117, 117, 117, 117, 42, 117, 0
};
static const unsigned char _indic_syllable_machine_trans_targs[] = {
- 27, 33, 38, 2, 39, 45, 46, 27,
- 55, 8, 61, 56, 68, 69, 72, 27,
- 77, 15, 83, 78, 86, 27, 91, 27,
- 100, 21, 106, 101, 109, 114, 27, 125,
- 27, 28, 48, 73, 75, 93, 94, 79,
- 95, 115, 116, 87, 123, 128, 27, 29,
- 31, 5, 47, 34, 42, 30, 1, 32,
- 36, 0, 35, 37, 40, 41, 3, 43,
- 4, 44, 27, 49, 51, 12, 71, 57,
- 64, 50, 6, 52, 66, 59, 53, 11,
- 70, 54, 7, 58, 60, 62, 63, 9,
- 65, 10, 67, 27, 74, 17, 76, 89,
- 81, 13, 92, 14, 80, 82, 84, 85,
- 16, 88, 18, 90, 27, 27, 96, 98,
- 19, 23, 102, 110, 97, 99, 112, 104,
- 20, 103, 105, 107, 108, 22, 111, 24,
- 113, 117, 118, 122, 119, 120, 25, 121,
- 27, 124, 26, 126, 127
+ 31, 37, 42, 2, 43, 46, 4, 50,
+ 51, 31, 60, 9, 66, 69, 61, 11,
+ 74, 75, 78, 31, 83, 17, 89, 92,
+ 93, 84, 31, 19, 98, 31, 107, 24,
+ 113, 116, 117, 108, 26, 122, 127, 31,
+ 134, 31, 32, 53, 79, 81, 100, 101,
+ 85, 102, 123, 124, 94, 132, 137, 31,
+ 33, 35, 6, 52, 38, 47, 34, 1,
+ 36, 40, 0, 39, 41, 44, 45, 3,
+ 48, 5, 49, 31, 54, 56, 14, 77,
+ 62, 70, 55, 7, 57, 72, 64, 58,
+ 13, 76, 59, 8, 63, 65, 67, 68,
+ 10, 71, 12, 73, 31, 80, 20, 82,
+ 96, 87, 15, 99, 16, 86, 88, 90,
+ 91, 18, 95, 21, 97, 31, 31, 103,
+ 105, 22, 27, 109, 118, 104, 106, 120,
+ 111, 23, 110, 112, 114, 115, 25, 119,
+ 28, 121, 125, 126, 131, 128, 129, 29,
+ 130, 31, 133, 30, 135, 136
};
static const char _indic_syllable_machine_trans_actions[] = {
- 1, 0, 2, 0, 2, 2, 2, 3,
- 2, 0, 2, 0, 2, 2, 2, 4,
- 2, 0, 5, 0, 5, 6, 2, 7,
- 2, 0, 2, 0, 2, 2, 8, 0,
- 11, 2, 2, 5, 0, 12, 12, 0,
- 2, 5, 2, 5, 2, 0, 13, 2,
- 0, 0, 2, 0, 2, 2, 0, 2,
- 2, 0, 0, 2, 2, 2, 0, 0,
- 0, 2, 14, 2, 0, 0, 2, 0,
- 2, 2, 0, 2, 2, 2, 2, 0,
+ 1, 0, 2, 0, 2, 0, 0, 2,
+ 2, 3, 2, 0, 2, 0, 0, 0,
+ 2, 2, 2, 4, 2, 0, 5, 0,
+ 5, 0, 6, 0, 2, 7, 2, 0,
+ 2, 0, 2, 0, 0, 2, 0, 8,
+ 0, 11, 2, 2, 5, 0, 12, 12,
+ 0, 2, 5, 2, 5, 2, 0, 13,
+ 2, 0, 0, 2, 0, 2, 2, 0,
2, 2, 0, 0, 2, 2, 2, 0,
- 0, 0, 2, 15, 5, 0, 5, 2,
- 2, 0, 5, 0, 0, 2, 5, 5,
- 0, 0, 0, 2, 16, 17, 2, 0,
- 0, 0, 0, 2, 2, 2, 2, 2,
- 0, 0, 2, 2, 2, 0, 0, 0,
- 2, 0, 18, 18, 0, 0, 0, 0,
- 19, 2, 0, 0, 0
+ 0, 0, 2, 14, 2, 0, 0, 2,
+ 0, 2, 2, 0, 2, 2, 2, 2,
+ 0, 2, 2, 0, 0, 2, 2, 2,
+ 0, 0, 0, 2, 15, 5, 0, 5,
+ 2, 2, 0, 5, 0, 0, 2, 5,
+ 5, 0, 0, 0, 2, 16, 17, 2,
+ 0, 0, 0, 0, 2, 2, 2, 2,
+ 2, 0, 0, 2, 2, 2, 0, 0,
+ 0, 2, 0, 18, 18, 0, 0, 0,
+ 0, 19, 2, 0, 0, 0
};
static const char _indic_syllable_machine_to_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 9, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 9,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -349,14 +384,16 @@ static const char _indic_syllable_machine_to_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0
};
static const char _indic_syllable_machine_from_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 10, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 10,
+ 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -369,41 +406,42 @@ static const char _indic_syllable_machine_from_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0
+ 0, 0
};
static const short _indic_syllable_machine_eof_trans[] = {
- 1, 1, 1, 1, 1, 1, 8, 8,
- 8, 8, 8, 8, 8, 16, 16, 22,
- 16, 16, 16, 24, 24, 24, 24, 24,
- 24, 1, 31, 0, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47,
- 67, 67, 67, 67, 67, 67, 67, 67,
- 67, 67, 67, 67, 67, 67, 67, 67,
- 67, 67, 67, 67, 67, 67, 67, 67,
- 67, 92, 92, 92, 92, 92, 92, 92,
- 92, 92, 92, 92, 92, 92, 92, 92,
- 92, 92, 92, 92, 92, 109, 109, 110,
- 110, 110, 110, 110, 110, 110, 110, 110,
- 110, 110, 110, 110, 110, 110, 110, 110,
- 110, 110, 110, 92, 47, 47, 47, 47,
- 47, 47, 47, 137, 137, 137, 137, 137,
- 109
+ 1, 1, 1, 1, 1, 1, 1, 10,
+ 10, 10, 10, 10, 10, 10, 10, 20,
+ 20, 27, 20, 27, 20, 20, 30, 30,
+ 30, 30, 30, 30, 30, 1, 40, 0,
+ 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 76, 101,
+ 101, 101, 101, 101, 101, 101, 101, 101,
+ 101, 101, 101, 101, 101, 101, 101, 101,
+ 101, 101, 101, 101, 118, 118, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 101, 56, 56, 56, 56,
+ 56, 56, 56, 56, 146, 146, 146, 146,
+ 146, 118
};
-static const int indic_syllable_machine_start = 27;
-static const int indic_syllable_machine_first_final = 27;
+static const int indic_syllable_machine_start = 31;
+static const int indic_syllable_machine_first_final = 31;
static const int indic_syllable_machine_error = -1;
-static const int indic_syllable_machine_en_main = 27;
+static const int indic_syllable_machine_en_main = 31;
#line 58 "hb-ot-shaper-indic-machine.rl"
-#line 117 "hb-ot-shaper-indic-machine.rl"
+#line 118 "hb-ot-shaper-indic-machine.rl"
#define found_syllable(syllable_type) \
@@ -412,7 +450,7 @@ static const int indic_syllable_machine_en_main = 27;
for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ if (syllable_serial == 16) syllable_serial = 1; \
} HB_STMT_END
inline void
@@ -422,7 +460,7 @@ find_syllables_indic (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 426 "hb-ot-shaper-indic-machine.hh"
+#line 453 "hb-ot-shaper-indic-machine.hh"
{
cs = indic_syllable_machine_start;
ts = 0;
@@ -430,7 +468,7 @@ find_syllables_indic (hb_buffer_t *buffer)
act = 0;
}
-#line 137 "hb-ot-shaper-indic-machine.rl"
+#line 138 "hb-ot-shaper-indic-machine.rl"
p = 0;
@@ -438,7 +476,7 @@ find_syllables_indic (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 442 "hb-ot-shaper-indic-machine.hh"
+#line 465 "hb-ot-shaper-indic-machine.hh"
{
int _slen;
int _trans;
@@ -452,7 +490,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 456 "hb-ot-shaper-indic-machine.hh"
+#line 477 "hb-ot-shaper-indic-machine.hh"
}
_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -475,51 +513,51 @@ _eof_trans:
{te = p+1;}
break;
case 11:
-#line 113 "hb-ot-shaper-indic-machine.rl"
+#line 114 "hb-ot-shaper-indic-machine.rl"
{te = p+1;{ found_syllable (indic_non_indic_cluster); }}
break;
case 13:
-#line 108 "hb-ot-shaper-indic-machine.rl"
+#line 109 "hb-ot-shaper-indic-machine.rl"
{te = p;p--;{ found_syllable (indic_consonant_syllable); }}
break;
case 14:
-#line 109 "hb-ot-shaper-indic-machine.rl"
+#line 110 "hb-ot-shaper-indic-machine.rl"
{te = p;p--;{ found_syllable (indic_vowel_syllable); }}
break;
case 17:
-#line 110 "hb-ot-shaper-indic-machine.rl"
+#line 111 "hb-ot-shaper-indic-machine.rl"
{te = p;p--;{ found_syllable (indic_standalone_cluster); }}
break;
case 19:
-#line 111 "hb-ot-shaper-indic-machine.rl"
+#line 112 "hb-ot-shaper-indic-machine.rl"
{te = p;p--;{ found_syllable (indic_symbol_cluster); }}
break;
case 15:
-#line 112 "hb-ot-shaper-indic-machine.rl"
+#line 113 "hb-ot-shaper-indic-machine.rl"
{te = p;p--;{ found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
break;
case 16:
-#line 113 "hb-ot-shaper-indic-machine.rl"
+#line 114 "hb-ot-shaper-indic-machine.rl"
{te = p;p--;{ found_syllable (indic_non_indic_cluster); }}
break;
case 1:
-#line 108 "hb-ot-shaper-indic-machine.rl"
+#line 109 "hb-ot-shaper-indic-machine.rl"
{{p = ((te))-1;}{ found_syllable (indic_consonant_syllable); }}
break;
case 3:
-#line 109 "hb-ot-shaper-indic-machine.rl"
+#line 110 "hb-ot-shaper-indic-machine.rl"
{{p = ((te))-1;}{ found_syllable (indic_vowel_syllable); }}
break;
case 7:
-#line 110 "hb-ot-shaper-indic-machine.rl"
+#line 111 "hb-ot-shaper-indic-machine.rl"
{{p = ((te))-1;}{ found_syllable (indic_standalone_cluster); }}
break;
case 8:
-#line 111 "hb-ot-shaper-indic-machine.rl"
+#line 112 "hb-ot-shaper-indic-machine.rl"
{{p = ((te))-1;}{ found_syllable (indic_symbol_cluster); }}
break;
case 4:
-#line 112 "hb-ot-shaper-indic-machine.rl"
+#line 113 "hb-ot-shaper-indic-machine.rl"
{{p = ((te))-1;}{ found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
break;
case 6:
@@ -540,19 +578,19 @@ _eof_trans:
case 18:
#line 1 "NONE"
{te = p+1;}
-#line 108 "hb-ot-shaper-indic-machine.rl"
+#line 109 "hb-ot-shaper-indic-machine.rl"
{act = 1;}
break;
case 5:
#line 1 "NONE"
{te = p+1;}
-#line 112 "hb-ot-shaper-indic-machine.rl"
+#line 113 "hb-ot-shaper-indic-machine.rl"
{act = 5;}
break;
case 12:
#line 1 "NONE"
{te = p+1;}
-#line 113 "hb-ot-shaper-indic-machine.rl"
+#line 114 "hb-ot-shaper-indic-machine.rl"
{act = 6;}
break;
#line 559 "hb-ot-shaper-indic-machine.hh"
@@ -564,7 +602,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 568 "hb-ot-shaper-indic-machine.hh"
+#line 566 "hb-ot-shaper-indic-machine.hh"
}
if ( ++p != pe )
@@ -580,7 +618,7 @@ _again:
}
-#line 145 "hb-ot-shaper-indic-machine.rl"
+#line 146 "hb-ot-shaper-indic-machine.rl"
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc
index bf6a2757bb..d9fb0510e4 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc
@@ -42,6 +42,7 @@
#define OT_PLACEHOLDER I_Cat(PLACEHOLDER)
#define OT_DOTTEDCIRCLE I_Cat(DOTTEDCIRCLE)
#define OT_RS I_Cat(RS)
+#define OT_MPst I_Cat(MPst)
#define OT_Repha I_Cat(Repha)
#define OT_Ra I_Cat(Ra)
#define OT_CM I_Cat(CM)
@@ -80,9 +81,10 @@ static_assert (OT_VPst == M_Cat(VPst), "");
#define _OT_CS OT_CS /* 2 chars; CS */
#define _OT_DC OT_DOTTEDCIRCLE /* 1 chars; DOTTEDCIRCLE */
#define _OT_H OT_H /* 11 chars; H */
-#define _OT_M OT_M /* 143 chars; M */
+#define _OT_M OT_M /* 142 chars; M */
#define _OT_MH OT_MH /* 1 chars; MH */
#define _OT_ML OT_ML /* 1 chars; ML */
+#define _OT_MP OT_MPst /* 1 chars; MPst */
#define _OT_MR OT_MR /* 1 chars; MR */
#define _OT_MW OT_MW /* 2 chars; MW */
#define _OT_MY OT_MY /* 3 chars; MY */
@@ -200,7 +202,7 @@ static const uint16_t indic_table[] = {
/* 0A28 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
/* 0A30 */ _(R,C), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(X,X),
/* 0A38 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(X,X), _(M,AP), _(M,LM),
- /* 0A40 */ _(M,AP), _(M,AP), _(M,AP), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP),
+ /* 0A40 */_(MP,AP), _(M,AP), _(M,AP), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP),
/* 0A48 */ _(M,AP), _(X,X), _(X,X), _(M,AP), _(M,AP), _(H,B), _(X,X), _(X,X),
/* 0A50 */ _(X,X), _(M,B), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
/* 0A58 */ _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(X,X), _(C,C), _(X,X),
@@ -451,15 +453,12 @@ static const uint16_t indic_table[] = {
/* Grantha */
/* 11300 */ _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(X,X), _(X,X), _(X,X),
- /* 11308 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
- /* 11310 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
- /* 11318 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
- /* 11320 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
- /* 11328 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
- /* 11330 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+
+#define indic_offset_0x11338u 1720
+
/* 11338 */ _(X,X), _(X,X), _(X,X), _(N,X), _(N,X), _(X,X), _(X,X), _(X,X),
-}; /* Table items: 1776; occupancy: 69% */
+}; /* Table items: 1728; occupancy: 71% */
uint16_t
hb_indic_get_categories (hb_codepoint_t u)
@@ -497,7 +496,8 @@ hb_indic_get_categories (hb_codepoint_t u)
break;
case 0x11u:
- if (hb_in_range<hb_codepoint_t> (u, 0x11300u, 0x1133Fu)) return indic_table[u - 0x11300u + indic_offset_0x11300u];
+ if (hb_in_range<hb_codepoint_t> (u, 0x11300u, 0x11307u)) return indic_table[u - 0x11300u + indic_offset_0x11300u];
+ if (hb_in_range<hb_codepoint_t> (u, 0x11338u, 0x1133Fu)) return indic_table[u - 0x11338u + indic_offset_0x11338u];
break;
default:
@@ -519,6 +519,7 @@ hb_indic_get_categories (hb_codepoint_t u)
#undef _OT_M
#undef _OT_MH
#undef _OT_ML
+#undef _OT_MP
#undef _OT_MR
#undef _OT_MW
#undef _OT_MY
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc
index 55509c1101..7652210d9d 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc
@@ -223,15 +223,15 @@ enum {
INDIC_BASIC_FEATURES = INDIC_INIT, /* Don't forget to update this! */
};
-static void
+static bool
setup_syllables_indic (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
initial_reordering_indic (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
final_reordering_indic (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
@@ -413,7 +413,7 @@ setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
set_indic_properties (info[i]);
}
-static void
+static bool
setup_syllables_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
@@ -422,6 +422,7 @@ setup_syllables_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
find_syllables_indic (buffer);
foreach_syllable (buffer, start, end)
buffer->unsafe_to_break (start, end);
+ return false;
}
static int
@@ -714,6 +715,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
}
}
} else if (info[i].indic_position() != POS_SMVD) {
+ if (info[i].indic_category() == I_Cat(MPst) &&
+ i > start && info[i - 1].indic_category() == I_Cat(SM))
+ info[i - 1].indic_position() = info[i].indic_position();
last_pos = (indic_position_t) info[i].indic_position();
}
}
@@ -729,7 +733,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
if (info[j].indic_position() < POS_SMVD)
info[j].indic_position() = info[i].indic_position();
last = i;
- } else if (info[i].indic_category() == I_Cat(M))
+ } else if (FLAG_UNSAFE (info[i].indic_category()) & (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst))))
last = i;
}
@@ -742,14 +746,40 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
/* Sit tight, rock 'n roll! */
hb_stable_sort (info + start, end - start, compare_indic_order);
- /* Find base again */
+
+ /* Find base again; also flip left-matra sequence. */
+ unsigned first_left_matra = end;
+ unsigned last_left_matra = end;
base = end;
for (unsigned int i = start; i < end; i++)
+ {
if (info[i].indic_position() == POS_BASE_C)
{
base = i;
break;
}
+ else if (info[i].indic_position() == POS_PRE_M)
+ {
+ if (first_left_matra == end)
+ first_left_matra = i;
+ last_left_matra = i;
+ }
+ }
+ /* https://github.com/harfbuzz/harfbuzz/issues/3863 */
+ if (first_left_matra < last_left_matra)
+ {
+ /* No need to merge clusters, handled later. */
+ buffer->reverse_range (first_left_matra, last_left_matra + 1);
+ /* Reverse back nuktas, etc. */
+ unsigned i = first_left_matra;
+ for (unsigned j = i; j <= last_left_matra; j++)
+ if (FLAG_UNSAFE (info[j].indic_category()) & (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst))))
+ {
+ buffer->reverse_range (i, j + 1);
+ i = j + 1;
+ }
+ }
+
/* Things are out-of-control for post base positions, they may shuffle
* around like crazy. In old-spec mode, we move halants around, so in
* that case merge all clusters after base. Otherwise, check the sort
@@ -955,25 +985,29 @@ initial_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
}
}
-static void
+static bool
initial_reordering_indic (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
+ bool ret = false;
if (!buffer->message (font, "start reordering indic initial"))
- return;
+ return ret;
update_consonant_positions_indic (plan, font, buffer);
- hb_syllabic_insert_dotted_circles (font, buffer,
- indic_broken_cluster,
- I_Cat(DOTTEDCIRCLE),
- I_Cat(Repha),
- POS_END);
+ if (hb_syllabic_insert_dotted_circles (font, buffer,
+ indic_broken_cluster,
+ I_Cat(DOTTEDCIRCLE),
+ I_Cat(Repha),
+ POS_END))
+ ret = true;
foreach_syllable (buffer, start, end)
initial_reordering_syllable_indic (plan, font->face, buffer, start, end);
(void) buffer->message (font, "end reordering indic initial");
+
+ return ret;
}
static void
@@ -1116,7 +1150,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
{
search:
while (new_pos > start &&
- !(is_one_of (info[new_pos], (FLAG (I_Cat(M)) | FLAG (I_Cat(H))))))
+ !(is_one_of (info[new_pos], (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst)) | FLAG (I_Cat(H))))))
new_pos--;
/* If we found no Halant we are done.
@@ -1316,7 +1350,8 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
unlikely (is_halant (info[new_reph_pos])))
{
for (unsigned int i = base + 1; i < new_reph_pos; i++)
- if (info[i].indic_category() == I_Cat(M)) {
+ if (FLAG_UNSAFE (info[i].indic_category()) & (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst))))
+ {
/* Ok, got it. */
new_reph_pos--;
}
@@ -1376,7 +1411,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
{
while (new_pos > start &&
- !(is_one_of (info[new_pos - 1], FLAG(I_Cat(M)) | FLAG (I_Cat(H)))))
+ !(is_one_of (info[new_pos - 1], FLAG (I_Cat(M)) | FLAG (I_Cat(MPst)) | FLAG (I_Cat(H)))))
new_pos--;
}
@@ -1439,13 +1474,13 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
}
-static void
+static bool
final_reordering_indic (const hb_ot_shape_plan_t *plan,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
- if (unlikely (!count)) return;
+ if (unlikely (!count)) return false;
if (buffer->message (font, "start reordering indic final")) {
foreach_syllable (buffer, start, end)
@@ -1455,6 +1490,8 @@ final_reordering_indic (const hb_ot_shape_plan_t *plan,
HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
+
+ return false;
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh
index e18bd75ef1..fd91ee0caf 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh
@@ -48,7 +48,7 @@ enum khmer_syllable_type_t {
};
-#line 52 "hb-ot-shaper-khmer-machine.hh"
+#line 49 "hb-ot-shaper-khmer-machine.hh"
#define khmer_syllable_machine_ex_C 1u
#define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u
#define khmer_syllable_machine_ex_H 4u
@@ -66,7 +66,7 @@ enum khmer_syllable_type_t {
#define khmer_syllable_machine_ex_ZWNJ 5u
-#line 70 "hb-ot-shaper-khmer-machine.hh"
+#line 65 "hb-ot-shaper-khmer-machine.hh"
static const unsigned char _khmer_syllable_machine_trans_keys[] = {
5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u,
5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u,
@@ -284,7 +284,7 @@ static const int khmer_syllable_machine_en_main = 21;
for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ if (syllable_serial == 16) syllable_serial = 1; \
} HB_STMT_END
inline void
@@ -294,7 +294,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 298 "hb-ot-shaper-khmer-machine.hh"
+#line 287 "hb-ot-shaper-khmer-machine.hh"
{
cs = khmer_syllable_machine_start;
ts = 0;
@@ -310,7 +310,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 314 "hb-ot-shaper-khmer-machine.hh"
+#line 299 "hb-ot-shaper-khmer-machine.hh"
{
int _slen;
int _trans;
@@ -324,7 +324,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 328 "hb-ot-shaper-khmer-machine.hh"
+#line 311 "hb-ot-shaper-khmer-machine.hh"
}
_keys = _khmer_syllable_machine_trans_keys + (cs<<1);
@@ -394,7 +394,7 @@ _eof_trans:
#line 98 "hb-ot-shaper-khmer-machine.rl"
{act = 3;}
break;
-#line 398 "hb-ot-shaper-khmer-machine.hh"
+#line 368 "hb-ot-shaper-khmer-machine.hh"
}
_again:
@@ -403,7 +403,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 407 "hb-ot-shaper-khmer-machine.hh"
+#line 375 "hb-ot-shaper-khmer-machine.hh"
}
if ( ++p != pe )
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-khmer.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer.cc
index d9795589fa..019a285102 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-khmer.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer.cc
@@ -89,11 +89,11 @@ set_khmer_properties (hb_glyph_info_t &info)
info.khmer_category() = (khmer_category_t) (type & 0xFFu);
}
-static void
+static bool
setup_syllables_khmer (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
reorder_khmer (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
@@ -192,7 +192,7 @@ setup_masks_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
set_khmer_properties (info[i]);
}
-static void
+static bool
setup_syllables_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
@@ -201,6 +201,7 @@ setup_syllables_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
find_syllables_khmer (buffer);
foreach_syllable (buffer, start, end)
buffer->unsafe_to_break (start, end);
+ return false;
}
@@ -303,23 +304,27 @@ reorder_syllable_khmer (const hb_ot_shape_plan_t *plan,
}
}
-static void
+static bool
reorder_khmer (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
+ bool ret = false;
if (buffer->message (font, "start reordering khmer"))
{
- hb_syllabic_insert_dotted_circles (font, buffer,
- khmer_broken_cluster,
- K_Cat(DOTTEDCIRCLE),
- (unsigned) -1);
+ if (hb_syllabic_insert_dotted_circles (font, buffer,
+ khmer_broken_cluster,
+ K_Cat(DOTTEDCIRCLE),
+ (unsigned) -1))
+ ret = true;
foreach_syllable (buffer, start, end)
reorder_syllable_khmer (plan, font->face, buffer, start, end);
(void) buffer->message (font, "end reordering khmer");
}
HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_category);
+
+ return ret;
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh
index b109708937..87cded4ed8 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh
@@ -50,7 +50,7 @@ enum myanmar_syllable_type_t {
};
-#line 54 "hb-ot-shaper-myanmar-machine.hh"
+#line 51 "hb-ot-shaper-myanmar-machine.hh"
#define myanmar_syllable_machine_ex_A 9u
#define myanmar_syllable_machine_ex_As 32u
#define myanmar_syllable_machine_ex_C 1u
@@ -77,7 +77,7 @@ enum myanmar_syllable_type_t {
#define myanmar_syllable_machine_ex_ZWNJ 5u
-#line 81 "hb-ot-shaper-myanmar-machine.hh"
+#line 76 "hb-ot-shaper-myanmar-machine.hh"
static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
1u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u,
5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 39u, 3u, 39u,
@@ -433,7 +433,7 @@ static const int myanmar_syllable_machine_en_main = 0;
for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ if (syllable_serial == 16) syllable_serial = 1; \
} HB_STMT_END
inline void
@@ -443,7 +443,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 447 "hb-ot-shaper-myanmar-machine.hh"
+#line 436 "hb-ot-shaper-myanmar-machine.hh"
{
cs = myanmar_syllable_machine_start;
ts = 0;
@@ -459,7 +459,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 463 "hb-ot-shaper-myanmar-machine.hh"
+#line 448 "hb-ot-shaper-myanmar-machine.hh"
{
int _slen;
int _trans;
@@ -473,7 +473,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 477 "hb-ot-shaper-myanmar-machine.hh"
+#line 460 "hb-ot-shaper-myanmar-machine.hh"
}
_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -519,7 +519,7 @@ _eof_trans:
#line 113 "hb-ot-shaper-myanmar-machine.rl"
{te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }}
break;
-#line 523 "hb-ot-shaper-myanmar-machine.hh"
+#line 498 "hb-ot-shaper-myanmar-machine.hh"
}
_again:
@@ -528,7 +528,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 532 "hb-ot-shaper-myanmar-machine.hh"
+#line 505 "hb-ot-shaper-myanmar-machine.hh"
}
if ( ++p != pe )
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar.cc
index 78bd8de524..1b2a085a8d 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar.cc
@@ -98,11 +98,11 @@ is_consonant_myanmar (const hb_glyph_info_t &info)
}
-static void
+static bool
setup_syllables_myanmar (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
reorder_myanmar (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
@@ -150,7 +150,7 @@ setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
set_myanmar_properties (info[i]);
}
-static void
+static bool
setup_syllables_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
@@ -159,6 +159,7 @@ setup_syllables_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
find_syllables_myanmar (buffer);
foreach_syllable (buffer, start, end)
buffer->unsafe_to_break (start, end);
+ return false;
}
static int
@@ -270,6 +271,33 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer,
/* Sit tight, rock 'n roll! */
buffer->sort (start, end, compare_myanmar_order);
+
+ /* Flip left-matra sequence. */
+ unsigned first_left_matra = end;
+ unsigned last_left_matra = end;
+ for (unsigned int i = start; i < end; i++)
+ {
+ if (info[i].myanmar_position() == POS_PRE_M)
+ {
+ if (first_left_matra == end)
+ first_left_matra = i;
+ last_left_matra = i;
+ }
+ }
+ /* https://github.com/harfbuzz/harfbuzz/issues/3863 */
+ if (first_left_matra < last_left_matra)
+ {
+ /* No need to merge clusters, done already? */
+ buffer->reverse_range (first_left_matra, last_left_matra + 1);
+ /* Reverse back VS, etc. */
+ unsigned i = first_left_matra;
+ for (unsigned j = i; j <= last_left_matra; j++)
+ if (info[j].myanmar_category() == M_Cat(VPre))
+ {
+ buffer->reverse_range (i, j + 1);
+ i = j + 1;
+ }
+ }
}
static void
@@ -291,16 +319,18 @@ reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
}
-static void
+static bool
reorder_myanmar (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
+ bool ret = false;
if (buffer->message (font, "start reordering myanmar"))
{
- hb_syllabic_insert_dotted_circles (font, buffer,
- myanmar_broken_cluster,
- M_Cat(DOTTEDCIRCLE));
+ if (hb_syllabic_insert_dotted_circles (font, buffer,
+ myanmar_broken_cluster,
+ M_Cat(DOTTEDCIRCLE)))
+ ret = true;
foreach_syllable (buffer, start, end)
reorder_syllable_myanmar (plan, font->face, buffer, start, end);
@@ -309,6 +339,8 @@ reorder_myanmar (const hb_ot_shape_plan_t *plan,
HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
+
+ return ret;
}
@@ -331,6 +363,7 @@ const hb_ot_shaper_t _hb_ot_shaper_myanmar =
};
+#ifndef HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
/* Ugly Zawgyi encoding.
* Disable all auto processing.
* https://github.com/harfbuzz/harfbuzz/issues/1162 */
@@ -351,6 +384,7 @@ const hb_ot_shaper_t _hb_ot_shaper_myanmar_zawgyi =
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};
+#endif
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc
index a8e0d8e8c1..89226ae4a1 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc
@@ -29,7 +29,7 @@
#include "hb-ot-shaper-syllabic.hh"
-void
+bool
hb_syllabic_insert_dotted_circles (hb_font_t *font,
hb_buffer_t *buffer,
unsigned int broken_syllable_type,
@@ -38,13 +38,13 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
int dottedcircle_position)
{
if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
- return;
+ return false;
if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE)))
- return;
+ return false;
hb_codepoint_t dottedcircle_glyph;
if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
- return;
+ return false;
hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CCu;
@@ -84,14 +84,16 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
(void) buffer->next_glyph ();
}
buffer->sync ();
+ return true;
}
-HB_INTERNAL void
+HB_INTERNAL bool
hb_syllabic_clear_var (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
+ return false;
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.hh
index e8a15bb48a..f240ad1c26 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.hh
@@ -30,7 +30,7 @@
#include "hb-ot-shaper.hh"
-HB_INTERNAL void
+HB_INTERNAL bool
hb_syllabic_insert_dotted_circles (hb_font_t *font,
hb_buffer_t *buffer,
unsigned int broken_syllable_type,
@@ -38,7 +38,7 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
int repha_category = -1,
int dottedcircle_position = -1);
-HB_INTERNAL void
+HB_INTERNAL bool
hb_syllabic_clear_var (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-thai.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-thai.cc
index 15349b1e64..6cd67cde35 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-thai.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-thai.cc
@@ -98,9 +98,9 @@ static hb_codepoint_t
thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
{
struct thai_pua_mapping_t {
- hb_codepoint_t u;
- hb_codepoint_t win_pua;
- hb_codepoint_t mac_pua;
+ uint16_t u;
+ uint16_t win_pua;
+ uint16_t mac_pua;
} const *pua_mappings = nullptr;
static const thai_pua_mapping_t SD_mappings[] = {
{0x0E48u, 0xF70Au, 0xF88Bu}, /* MAI EK */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh
index 41e8a34f3b..f2fbdb725b 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh
@@ -53,7 +53,7 @@ enum use_syllable_type_t {
};
-#line 57 "hb-ot-shaper-use-machine.hh"
+#line 54 "hb-ot-shaper-use-machine.hh"
#define use_syllable_machine_ex_B 1u
#define use_syllable_machine_ex_CGJ 6u
#define use_syllable_machine_ex_CMAbv 31u
@@ -97,7 +97,7 @@ enum use_syllable_type_t {
#define use_syllable_machine_ex_ZWNJ 14u
-#line 101 "hb-ot-shaper-use-machine.hh"
+#line 96 "hb-ot-shaper-use-machine.hh"
static const unsigned char _use_syllable_machine_trans_keys[] = {
0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u,
14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u,
@@ -839,7 +839,7 @@ static const int use_syllable_machine_en_main = 0;
for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ if (syllable_serial == 16) syllable_serial = 1; \
} HB_STMT_END
@@ -929,7 +929,7 @@ find_syllables_use (hb_buffer_t *buffer)
unsigned int act HB_UNUSED;
int cs;
-#line 933 "hb-ot-shaper-use-machine.hh"
+#line 922 "hb-ot-shaper-use-machine.hh"
{
cs = use_syllable_machine_start;
ts = 0;
@@ -942,7 +942,7 @@ find_syllables_use (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 946 "hb-ot-shaper-use-machine.hh"
+#line 931 "hb-ot-shaper-use-machine.hh"
{
int _slen;
int _trans;
@@ -956,7 +956,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 960 "hb-ot-shaper-use-machine.hh"
+#line 943 "hb-ot-shaper-use-machine.hh"
}
_keys = _use_syllable_machine_trans_keys + (cs<<1);
@@ -1046,7 +1046,7 @@ _eof_trans:
#line 178 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_non_cluster); }}
break;
-#line 1050 "hb-ot-shaper-use-machine.hh"
+#line 1014 "hb-ot-shaper-use-machine.hh"
}
_again:
@@ -1055,7 +1055,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 1059 "hb-ot-shaper-use-machine.hh"
+#line 1021 "hb-ot-shaper-use-machine.hh"
}
if ( ++p != pe )
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
index 9833fb55de..6b6b552ee5 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
@@ -91,6 +91,9 @@
#define VMPre USE(VMPre)
#pragma GCC diagnostic pop
+
+#ifndef HB_OPTIMIZE_SIZE
+
static const uint8_t
hb_use_u8[3141] =
{
@@ -357,6 +360,273 @@ hb_use_get_category (unsigned u)
return u<921600u?hb_use_u8[2777+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
}
+
+#else
+
+static const uint8_t
+hb_use_u8[3413] =
+{
+ 16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 14, 0, 1, 1, 2, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 1,
+ 11, 12, 1, 1, 1, 1, 1, 1, 13, 14, 15, 16, 17, 18, 19, 1,
+ 1, 20, 1, 1, 1, 1, 21, 1, 1, 1, 1, 1, 1, 1, 22, 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, 23, 24, 25, 26, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27,
+ 28, 1, 1, 1, 1, 1, 29, 1, 1, 1, 1, 30, 31, 1, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 1, 46, 47, 48,
+ 49, 50, 50, 50, 50, 51, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 52, 53, 1, 1, 1,
+ 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 50, 55, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 56, 1, 1,
+ 1, 1, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 58, 59, 1, 60, 1, 1, 1, 1, 61, 1, 1, 1, 1, 1,
+ 1, 62, 63, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 8, 0, 0, 0, 0,
+ 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 36, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 0, 55, 56, 57, 58, 59, 0, 0, 0, 60, 61, 62, 63, 55, 64, 65,
+ 66, 67, 55, 55, 68, 69, 70, 0, 0, 71, 72, 73, 74, 55, 75, 76,
+ 0, 77, 55, 78, 79, 80, 0, 0, 0, 81, 82, 83, 84, 85, 86, 55,
+ 87, 55, 88, 89, 0, 0, 0, 90, 91, 0, 0, 0, 0, 0, 0, 0,
+ 92, 93, 94, 0, 95, 96, 0, 0, 97, 0, 0, 0, 0, 0, 0, 98,
+ 0, 0, 99, 55, 100, 0, 0, 0, 0, 101, 102, 55, 103, 104, 105, 106,
+ 107, 55, 108, 109, 0, 110, 111, 112, 113, 55, 114, 115, 116, 55, 117, 118,
+ 119, 0, 0, 0, 0, 0, 0, 55, 120, 121, 0, 0, 0, 0, 0, 0,
+ 122, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 124, 125, 126, 0,
+ 0, 127, 128, 129, 0, 0, 0, 50, 130, 0, 0, 0, 0, 131, 132, 0,
+ 0, 55, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 134, 0,
+ 0, 0, 99, 135, 99, 136, 137, 138, 0, 139, 140, 141, 142, 143, 144, 145,
+ 0, 146, 147, 148, 149, 143, 150, 151, 152, 153, 154, 155, 0, 156, 157, 158,
+ 159, 160, 161, 162, 163, 0, 0, 0, 0, 55, 164, 165, 166, 167, 168, 169,
+ 0, 0, 0, 0, 0, 55, 170, 171, 0, 55, 172, 173, 0, 55, 174, 66,
+ 0, 175, 176, 177, 0, 0, 0, 0, 0, 55, 178, 0, 0, 0, 0, 0,
+ 0, 179, 180, 181, 0, 0, 182, 183, 184, 185, 186, 187, 55, 188, 0, 0,
+ 0, 189, 190, 191, 192, 193, 194, 0, 0, 195, 196, 197, 198, 199, 66, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 200, 201, 202, 203, 0, 0, 0, 0,
+ 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 204, 205, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 66, 0, 55, 206, 0, 0, 0, 0, 0,
+ 0, 55, 55, 207, 208, 209, 0, 0, 210, 55, 55, 55, 55, 55, 55, 211,
+ 0, 55, 55, 55, 212, 213, 0, 0, 0, 0, 0, 0, 214, 0, 0, 0,
+ 0, 55, 215, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 217, 55,
+ 218, 0, 0, 0, 0, 0, 0, 99, 219, 55, 55, 220, 0, 0, 0, 0,
+ 0, 221, 221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 222, 222, 222,
+ 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
+ 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 8, 9, 9, 9, 9, 0, 0, 0, 7, 10,
+ 0, 2, 2, 2, 2, 11, 12, 0, 0, 9, 13, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 14, 15, 16, 17, 18, 19, 20, 14, 21, 22,
+ 23, 10, 24, 25, 18, 2, 2, 2, 2, 2, 18, 0, 2, 2, 2, 2,
+ 2, 0, 2, 2, 2, 2, 2, 2, 2, 26, 27, 28, 2, 2, 2, 7,
+ 28, 7, 28, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 2, 2,
+ 2, 7, 7, 0, 2, 2, 0, 15, 16, 17, 18, 29, 30, 31, 30, 32,
+ 0, 0, 0, 0, 33, 0, 0, 2, 28, 2, 0, 0, 0, 0, 0, 7,
+ 34, 10, 13, 28, 2, 2, 7, 0, 28, 7, 2, 28, 7, 2, 0, 35,
+ 16, 17, 29, 0, 25, 36, 25, 37, 0, 38, 0, 0, 0, 28, 2, 7,
+ 7, 0, 0, 0, 2, 2, 2, 2, 2, 39, 40, 41, 0, 0, 0, 0,
+ 0, 10, 13, 28, 2, 2, 2, 2, 28, 2, 28, 2, 2, 2, 2, 2,
+ 2, 7, 2, 28, 2, 2, 0, 15, 16, 17, 18, 19, 25, 20, 33, 22,
+ 0, 0, 0, 0, 0, 28, 39, 39, 42, 10, 27, 28, 2, 2, 2, 7,
+ 28, 7, 2, 28, 2, 2, 0, 15, 43, 0, 0, 25, 20, 0, 0, 2,
+ 28, 28, 0, 0, 0, 0, 0, 0, 0, 0, 44, 28, 2, 2, 7, 0,
+ 2, 7, 2, 2, 0, 28, 7, 7, 2, 0, 28, 7, 0, 2, 7, 0,
+ 2, 2, 2, 2, 2, 2, 0, 0, 21, 14, 45, 0, 46, 31, 46, 32,
+ 0, 0, 0, 0, 33, 0, 0, 0, 0, 13, 27, 47, 2, 2, 2, 7,
+ 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 15,
+ 20, 14, 21, 45, 20, 36, 20, 37, 0, 0, 0, 25, 29, 2, 7, 0,
+ 0, 8, 27, 28, 2, 2, 2, 7, 2, 2, 2, 28, 2, 2, 0, 15,
+ 43, 0, 0, 33, 45, 0, 0, 0, 7, 48, 49, 0, 0, 0, 0, 0,
+ 0, 9, 27, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 50, 51,
+ 21, 21, 17, 29, 46, 31, 46, 32, 52, 0, 0, 0, 33, 0, 0, 0,
+ 28, 10, 27, 28, 2, 2, 2, 2, 2, 2, 2, 2, 7, 0, 2, 2,
+ 2, 2, 28, 2, 2, 2, 2, 28, 0, 2, 2, 2, 7, 0, 53, 0,
+ 33, 21, 20, 29, 29, 16, 46, 46, 23, 0, 21, 0, 0, 0, 0, 0,
+ 0, 2, 0, 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0,
+ 0, 2, 2, 54, 54, 55, 0, 0, 16, 2, 2, 2, 2, 28, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 7, 0, 56, 19, 57, 20, 20, 18, 18,
+ 44, 19, 9, 29, 9, 2, 2, 58, 59, 59, 59, 59, 59, 60, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61,
+ 0, 0, 0, 0, 62, 0, 0, 0, 0, 2, 2, 2, 2, 2, 63, 43,
+ 57, 64, 20, 20, 65, 66, 67, 68, 69, 2, 2, 2, 2, 2, 1, 0,
+ 3, 2, 2, 2, 21, 18, 2, 2, 70, 69, 71, 72, 63, 71, 27, 27,
+ 2, 50, 20, 51, 2, 2, 2, 2, 2, 2, 73, 74, 75, 27, 27, 76,
+ 77, 2, 2, 2, 2, 2, 27, 43, 0, 2, 57, 78, 0, 0, 0, 0,
+ 28, 2, 57, 45, 0, 0, 0, 0, 0, 2, 57, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 7, 2, 7, 57, 0, 0, 0, 0, 0,
+ 0, 2, 2, 79, 43, 20, 57, 18, 46, 46, 46, 46, 13, 80, 81, 82,
+ 83, 84, 85, 0, 0, 0, 0, 86, 0, 7, 0, 0, 28, 0, 87, 79,
+ 88, 2, 2, 2, 2, 7, 0, 0, 0, 40, 40, 89, 90, 2, 2, 2,
+ 2, 2, 2, 2, 2, 11, 7, 0, 0, 91, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 7, 20, 78, 43, 20, 92, 59, 0,
+ 0, 93, 94, 93, 93, 95, 96, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 0, 2, 2, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0,
+ 0, 2, 2, 2, 2, 27, 0, 0, 0, 2, 2, 2, 2, 2, 7, 0,
+ 0, 2, 2, 2, 50, 97, 43, 0, 0, 2, 2, 98, 99, 100, 101, 59,
+ 61, 102, 14, 43, 20, 57, 19, 78, 46, 46, 74, 9, 9, 9, 103, 44,
+ 38, 9, 104, 72, 2, 2, 2, 2, 2, 2, 2, 105, 20, 18, 18, 20,
+ 46, 46, 20, 106, 2, 2, 2, 7, 0, 0, 0, 0, 0, 0, 107, 108,
+ 109, 109, 109, 0, 0, 0, 0, 0, 0, 104, 72, 2, 2, 2, 2, 2,
+ 2, 58, 59, 57, 23, 20, 110, 59, 2, 2, 2, 2, 105, 20, 21, 43,
+ 43, 100, 12, 0, 0, 0, 0, 0, 0, 2, 2, 59, 16, 46, 21, 111,
+ 100, 100, 100, 112, 113, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 28,
+ 2, 9, 44, 114, 114, 114, 9, 114, 114, 13, 114, 114, 114, 24, 0, 38,
+ 0, 0, 0, 115, 49, 9, 3, 0, 0, 0, 0, 0, 0, 0, 116, 0,
+ 0, 0, 0, 0, 0, 0, 4, 117, 118, 40, 40, 3, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 118, 118, 119, 118, 118, 118, 118, 118, 118, 118,
+ 118, 0, 0, 120, 0, 0, 0, 0, 0, 0, 5, 120, 0, 0, 0, 0,
+ 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
+ 0, 2, 2, 2, 2, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0,
+ 121, 2, 51, 2, 106, 2, 8, 2, 2, 2, 63, 17, 14, 0, 0, 29,
+ 0, 2, 2, 0, 0, 0, 0, 0, 0, 27, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 122, 21, 21, 21, 21, 21, 21, 21, 123, 0, 0, 0, 0,
+ 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0,
+ 50, 2, 2, 2, 20, 20, 124, 114, 0, 2, 2, 2, 125, 18, 57, 18,
+ 111, 100, 126, 0, 0, 0, 0, 0, 0, 9, 127, 2, 2, 2, 2, 2,
+ 2, 2, 128, 21, 20, 18, 46, 129, 130, 131, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 50, 28, 2, 2, 2, 2, 2, 2, 2, 2, 8, 20, 57,
+ 97, 74, 132, 133, 134, 0, 0, 0, 0, 2, 135, 2, 2, 2, 2, 136,
+ 0, 28, 2, 40, 3, 0, 77, 13, 2, 51, 20, 137, 50, 51, 2, 2,
+ 103, 8, 7, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 138, 19,
+ 23, 0, 0, 139, 140, 0, 0, 0, 0, 2, 63, 43, 21, 78, 45, 141,
+ 0, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 0,
+ 4, 118, 118, 118, 118, 119, 0, 0, 0, 2, 2, 2, 2, 2, 7, 2,
+ 2, 2, 7, 2, 28, 2, 2, 2, 2, 2, 28, 2, 2, 2, 28, 7,
+ 0, 125, 18, 25, 29, 0, 0, 142, 143, 2, 2, 28, 2, 28, 2, 2,
+ 2, 2, 2, 2, 0, 12, 35, 0, 144, 2, 2, 11, 35, 0, 28, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 2, 2,
+ 7, 2, 2, 9, 39, 0, 0, 0, 0, 2, 2, 2, 2, 2, 25, 36,
+ 0, 2, 2, 2, 114, 114, 114, 114, 114, 145, 2, 7, 0, 0, 0, 0,
+ 0, 2, 12, 12, 0, 0, 0, 0, 0, 7, 2, 2, 7, 2, 2, 2,
+ 2, 28, 2, 7, 0, 28, 2, 0, 0, 146, 147, 148, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 20, 20, 18, 18, 18, 20, 20, 131, 0, 0, 0,
+ 0, 0, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 2, 2, 2, 2,
+ 2, 51, 50, 51, 0, 0, 0, 0, 150, 9, 72, 2, 2, 2, 2, 2,
+ 2, 16, 17, 19, 14, 22, 35, 0, 0, 0, 29, 0, 0, 0, 0, 0,
+ 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 18, 20, 151,
+ 20, 19, 152, 153, 2, 2, 2, 2, 2, 0, 0, 63, 154, 0, 0, 0,
+ 0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20,
+ 20, 106, 155, 0, 0, 54, 156, 29, 157, 28, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 158, 42, 0, 0, 0,
+ 47, 125, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 7, 7, 2, 2,
+ 28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
+ 8, 16, 17, 19, 20, 159, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7,
+ 28, 7, 2, 28, 2, 2, 56, 15, 21, 14, 21, 45, 30, 31, 30, 32,
+ 0, 0, 0, 0, 33, 0, 0, 0, 2, 2, 21, 0, 9, 9, 9, 44,
+ 0, 9, 9, 44, 0, 0, 0, 0, 0, 2, 2, 63, 23, 18, 18, 18,
+ 20, 21, 123, 13, 15, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0,
+ 160, 161, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 18, 64, 97, 23,
+ 157, 9, 162, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 63, 23, 18, 18, 0, 46, 46, 9, 163, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 18, 0, 21, 17, 18, 18, 19, 14, 80,
+ 163, 36, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 164,
+ 23, 18, 20, 20, 162, 7, 0, 0, 0, 2, 2, 2, 2, 2, 7, 41,
+ 133, 21, 20, 18, 74, 19, 20, 0, 0, 2, 2, 2, 7, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 163, 35, 0,
+ 0, 2, 2, 2, 7, 28, 0, 2, 2, 2, 2, 28, 7, 2, 2, 2,
+ 2, 21, 21, 16, 30, 31, 10, 165, 166, 167, 168, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 0, 2, 2, 2, 63, 23, 18, 18, 0, 20, 21,
+ 27, 106, 0, 31, 0, 0, 0, 0, 0, 50, 18, 20, 20, 20, 137, 2,
+ 2, 2, 169, 170, 9, 13, 171, 70, 172, 0, 0, 1, 144, 0, 0, 0,
+ 0, 50, 18, 20, 14, 17, 18, 2, 2, 2, 2, 155, 155, 155, 173, 173,
+ 173, 173, 173, 173, 13, 174, 0, 28, 0, 20, 18, 18, 29, 20, 20, 9,
+ 163, 0, 59, 59, 59, 59, 59, 59, 59, 64, 19, 80, 44, 0, 0, 0,
+ 0, 2, 2, 2, 7, 2, 28, 2, 2, 50, 20, 20, 29, 0, 36, 20,
+ 25, 9, 156, 175, 171, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2,
+ 2, 2, 2, 2, 2, 2, 21, 21, 45, 20, 33, 80, 66, 0, 0, 0,
+ 0, 2, 176, 64, 45, 0, 0, 0, 0, 9, 177, 2, 2, 2, 2, 2,
+ 2, 2, 2, 21, 20, 18, 29, 0, 46, 14, 140, 0, 0, 0, 0, 0,
+ 0, 178, 178, 178, 106, 179, 178, 0, 0, 145, 2, 2, 180, 114, 114, 114,
+ 114, 114, 114, 114, 0, 0, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 7, 0, 56, 181, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0,
+ 38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
+ 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56,
+ 35, 0, 4, 118, 118, 118, 119, 0, 0, 9, 9, 9, 47, 2, 2, 2,
+ 0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
+ 44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 2, 2, 2, 2, 20,
+ 20, 2, 2, 42, 42, 42, 90, 0, 0, O, O, O, GB, B, B, GB,
+ O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,
+ CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw,
+ VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,
+ VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O, VPst,FMAbv, O,CMBlw,
+ O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst,
+ VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS,VMPst, B, VAbv, VAbv,
+ B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB,
+ SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv,
+ MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,
+ VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,
+ VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB,
+ B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw,
+ SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,
+ SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,
+ CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, O, H, MPst, VPst, H,
+ VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H,
+ O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,
+ VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst,
+ CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R,
+ R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst,
+ H,VMPst, VAbv,VMAbv, VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R,
+ MBlw, MBlw, GB, FBlw, FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, R,VMPst, H, H, B,
+ H, B,VMBlw, O, VBlw,
+};
+static const uint16_t
+hb_use_u16[448] =
+{
+ 0, 0, 1, 2, 3, 4, 0, 5, 6, 0, 7, 0, 8, 9, 10, 11,
+ 9, 12, 13, 9, 9, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 17, 25, 26, 20, 21, 27, 28, 29, 30, 31, 32, 33, 21, 34, 35, 0,
+ 17, 36, 37, 20, 21, 38, 23, 39, 17, 40, 41, 42, 43, 44, 45, 46,
+ 30, 0, 47, 48, 21, 49, 50, 51, 17, 0, 52, 48, 21, 53, 50, 54,
+ 17, 55, 56, 48, 9, 57, 58, 59, 60, 61, 9, 62, 63, 64, 30, 65,
+ 66, 67, 9, 68, 69, 9, 70, 71, 72, 73, 74, 75, 76, 0, 9, 9,
+ 77, 78, 79, 80, 81, 82, 83, 84, 9, 85, 9, 86, 9, 87, 88, 89,
+ 9, 90, 91, 92, 2, 0, 93, 0, 9, 94, 95, 9, 96, 0, 97, 98,
+ 99,100, 30, 9,101,102,103, 9,104,105, 9,106, 9,107,108,109,
+ 2, 2,110, 9, 9,111,112, 2,113,114,115, 9,116, 9,117,118,
+ 119,120,121, 0, 0,122,123,124, 0,125,126,127,128, 0,129,130,
+ 131, 0, 0,132,133, 0, 0, 9,134,135,136, 9,137, 0, 9,138,
+ 139, 9, 9,140,141, 2,142,143,144, 9,145,146,147, 9, 9,148,
+ 149, 2,150, 98,151,152,153, 2, 9,154, 9,155,156, 0,157,158,
+ 159, 2,160, 0, 0,161, 0,162, 0,163,163,164, 33,165,166,167,
+ 9,168, 94, 0,169, 0, 9,170,171, 0,172, 2,173,170,174,175,
+ 176, 0, 0,177,178, 0,179, 9, 9,180,181,182,183,184,185, 9,
+ 9,186,187, 0,188, 9,189,190,191, 9, 9,192, 9,193,194,105,
+ 195,102, 9, 33,196,197,198, 0,199,200, 94, 9, 9,201,202, 2,
+ 203, 20, 21,204,205,206,207,208, 9,209,210,211,212, 0,195, 9,
+ 9,213,214, 2,215,216,217,218, 9,219,220, 2,221,222, 9,223,
+ 224,103,225, 0,226,227,228,229, 9,230,231, 2,232, 9, 9,233,
+ 234, 0,235, 9, 9,236,237,238,239,240, 21, 9,215,241, 7, 9,
+ 70, 18, 9,242, 73,243,244, 9, 9,245,246, 2,247, 9,248,249,
+ 9,250,251, 48, 9,252,253, 2, 9,254,255,256, 9,257,258,259,
+ 260,260,261,262,263, 0, 9,264,105, 70, 94,265, 0,266, 70,267,
+ 268, 0,269, 0,270, 2,271, 2,272, 2,129,129,160,160,160,129,
+};
+
+static inline unsigned
+hb_use_b4 (const uint8_t* a, unsigned i)
+{
+ return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline uint_fast8_t
+hb_use_get_category (unsigned u)
+{
+ return u<921600u?hb_use_u8[3049+(((hb_use_u8[865+(((hb_use_u16[((hb_use_u8[353+(((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>1>>3>>4))<<4)+((u>>1>>3>>1>>3)&15u))])<<3)+((u>>1>>3>>1)&7u))])<<1)+((u>>1>>3)&1u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+}
+
+#endif
+
#undef B
#undef CGJ
#undef CS
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-use.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-use.cc
index c40ec52f9c..342aba1235 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-use.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use.cc
@@ -89,19 +89,19 @@ use_other_features[] =
HB_TAG('p','s','t','s'),
};
-static void
+static bool
setup_syllables_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
record_rphf_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
record_pref_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
reorder_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
@@ -293,7 +293,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
}
}
-static void
+static bool
setup_syllables_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
@@ -304,9 +304,10 @@ setup_syllables_use (const hb_ot_shape_plan_t *plan,
buffer->unsafe_to_break (start, end);
setup_rphf_mask (plan, buffer);
setup_topographical_masks (plan, buffer);
+ return false;
}
-static void
+static bool
record_rphf_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
@@ -314,7 +315,7 @@ record_rphf_use (const hb_ot_shape_plan_t *plan,
const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
hb_mask_t mask = use_plan->rphf_mask;
- if (!mask) return;
+ if (!mask) return false;
hb_glyph_info_t *info = buffer->info;
foreach_syllable (buffer, start, end)
@@ -327,9 +328,10 @@ record_rphf_use (const hb_ot_shape_plan_t *plan,
break;
}
}
+ return false;
}
-static void
+static bool
record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
@@ -346,6 +348,7 @@ record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
break;
}
}
+ return false;
}
static inline bool
@@ -438,17 +441,19 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
}
}
-static void
+static bool
reorder_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
+ bool ret = false;
if (buffer->message (font, "start reordering USE"))
{
- hb_syllabic_insert_dotted_circles (font, buffer,
- use_broken_cluster,
- USE(B),
- USE(R));
+ if (hb_syllabic_insert_dotted_circles (font, buffer,
+ use_broken_cluster,
+ USE(B),
+ USE(R)))
+ ret = true;
foreach_syllable (buffer, start, end)
reorder_syllable_use (buffer, start, end);
@@ -457,6 +462,8 @@ reorder_use (const hb_ot_shape_plan_t *plan,
}
HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
+
+ return ret;
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper.hh b/thirdparty/harfbuzz/src/hb-ot-shaper.hh
index b2d1acb39b..0207b2bbe3 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper.hh
@@ -262,11 +262,13 @@ hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
return &_hb_ot_shaper_myanmar;
+#ifndef HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g'))
case HB_SCRIPT_MYANMAR_ZAWGYI:
/* https://github.com/harfbuzz/harfbuzz/issues/1162 */
return &_hb_ot_shaper_myanmar_zawgyi;
+#endif
/* Unicode-2.0 additions */
diff --git a/thirdparty/harfbuzz/src/hb-ot-stat-table.hh b/thirdparty/harfbuzz/src/hb-ot-stat-table.hh
index af6d550c0e..59bb2daccd 100644
--- a/thirdparty/harfbuzz/src/hb-ot-stat-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-stat-table.hh
@@ -320,7 +320,7 @@ struct AxisValueFormat4
unsigned total_size = min_size + axisCount * AxisValueRecord::static_size;
auto *out = c->serializer->allocate_size<AxisValueFormat4> (total_size);
if (unlikely (!out)) return_trace (false);
- memcpy (out, this, total_size);
+ hb_memcpy (out, this, total_size);
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-tag.cc b/thirdparty/harfbuzz/src/hb-ot-tag.cc
index 1b18270cca..f6ba3b0d47 100644
--- a/thirdparty/harfbuzz/src/hb-ot-tag.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-tag.cc
@@ -577,7 +577,7 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag,
else
{
int shift;
- memcpy (buf, lang_str, len);
+ hb_memcpy (buf, lang_str, len);
if (lang_str[0] != 'x' || lang_str[1] != '-') {
buf[len++] = '-';
buf[len++] = 'x';
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh
index f60bc4a3ce..cc5c5c0068 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh
@@ -143,7 +143,7 @@ struct avar
TRACE_SANITIZE (this);
if (!(version.sanitize (c) &&
(version.major == 1
-#ifndef HB_NO_VARIATIONS2
+#ifndef HB_NO_AVAR2
|| version.major == 2
#endif
) &&
@@ -159,7 +159,7 @@ struct avar
map = &StructAfter<SegmentMaps> (*map);
}
-#ifndef HB_NO_VARIATIONS2
+#ifndef HB_NO_AVAR2
if (version.major < 2)
return_trace (true);
@@ -182,7 +182,7 @@ struct avar
map = &StructAfter<SegmentMaps> (*map);
}
-#ifndef HB_NO_VARIATIONS2
+#ifndef HB_NO_AVAR2
if (version.major < 2)
return;
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-common.hh b/thirdparty/harfbuzz/src/hb-ot-var-common.hh
index 1d29e3e4f9..4997c2e2e8 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-common.hh
@@ -47,7 +47,7 @@ struct DeltaSetIndexMapFormat01
HBUINT8 *p = c->allocate_size<HBUINT8> (total_size);
if (unlikely (!p)) return_trace (nullptr);
- memcpy (p, this, HBUINT8::static_size * total_size);
+ hb_memcpy (p, this, HBUINT8::static_size * total_size);
return_trace (out);
}
@@ -219,6 +219,25 @@ struct DeltaSetIndexMap
DEFINE_SIZE_UNION (1, format);
};
+
+struct VarStoreInstancer
+{
+ VarStoreInstancer (const VariationStore &varStore,
+ const DeltaSetIndexMap &varIdxMap,
+ hb_array_t<int> coords) :
+ varStore (varStore), varIdxMap (varIdxMap), coords (coords) {}
+
+ operator bool () const { return bool (coords); }
+
+ float operator() (uint32_t varIdx, unsigned short offset = 0) const
+ { return varStore.get_delta (varIdxMap.map (VarIdx::add (varIdx, offset)), coords); }
+
+ const VariationStore &varStore;
+ const DeltaSetIndexMap &varIdxMap;
+ hb_array_t<int> coords;
+};
+
+
} /* namespace OT */
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
index af23862870..c1d57a002a 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
@@ -59,7 +59,7 @@ struct InstanceRecord
const hb_hashmap_t<hb_tag_t, float> *axes_location = c->plan->user_axes_location;
for (unsigned i = 0 ; i < axis_count; i++)
{
- unsigned *axis_tag;
+ uint32_t *axis_tag;
// only keep instances whose coordinates == pinned axis location
if (!c->plan->axes_old_index_tag_map->has (i, &axis_tag)) continue;
@@ -337,13 +337,13 @@ struct fvar
{
const InstanceRecord *instance = get_instance (i);
- if (hb_any (+ hb_zip (instance->get_coordinates (axisCount), hb_range ((unsigned)axisCount))
- | hb_filter (pinned_axes, hb_second)
- | hb_map ([&] (const hb_pair_t<const F16DOT16&, unsigned>& _)
+ if (hb_any (+ hb_enumerate (instance->get_coordinates (axisCount))
+ | hb_filter (pinned_axes, hb_first)
+ | hb_map ([&] (const hb_pair_t<unsigned, const F16DOT16&>& _)
{
- hb_tag_t axis_tag = pinned_axes.get (_.second);
+ hb_tag_t axis_tag = pinned_axes.get (_.first);
float location = user_axes_location->get (axis_tag);
- if (fabs ((double)location - (double)_.first.to_float ()) > 0.001) return true;
+ if (fabs ((double)location - (double)_.second.to_float ()) > 0.001) return true;
return false;
})
))
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
index bf1039d1d6..e02063ca43 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
@@ -56,12 +56,11 @@ struct contour_point_vector_t : hb_vector_t<contour_point_t>
void extend (const hb_array_t<contour_point_t> &a)
{
unsigned int old_len = length;
- if (unlikely (!resize (old_len + a.length)))
+ if (unlikely (!resize (old_len + a.length, false)))
return;
auto arrayZ = this->arrayZ + old_len;
unsigned count = a.length;
- for (unsigned int i = 0; i < count; i++)
- arrayZ[i] = a.arrayZ[i];
+ hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0]));
}
void transform (const float (&matrix)[4])
@@ -231,8 +230,8 @@ struct GlyphVariationData
{
return (index < var_data->tupleVarCount.get_count ()) &&
var_data_bytes.check_range (current_tuple, TupleVariationHeader::min_size) &&
- var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (), current_tuple->get_size (axis_count))) &&
- current_tuple->get_size (axis_count);
+ var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (),
+ current_tuple->get_size (axis_count)));
}
bool move_to_next ()
@@ -281,42 +280,42 @@ struct GlyphVariationData
if (unlikely (p + 1 > end)) return false;
- uint16_t count = *p++;
+ unsigned count = *p++;
if (count & POINTS_ARE_WORDS)
{
if (unlikely (p + 1 > end)) return false;
count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
}
- if (unlikely (!points.resize (count))) return false;
+ if (unlikely (!points.resize (count, false))) return false;
- unsigned int n = 0;
- uint16_t i = 0;
+ unsigned n = 0;
+ unsigned i = 0;
while (i < count)
{
if (unlikely (p + 1 > end)) return false;
- uint16_t j;
- uint8_t control = *p++;
- uint16_t run_count = (control & POINT_RUN_COUNT_MASK) + 1;
+ unsigned control = *p++;
+ unsigned run_count = (control & POINT_RUN_COUNT_MASK) + 1;
+ if (unlikely (i + run_count > count)) return false;
+ unsigned j;
if (control & POINTS_ARE_WORDS)
{
- for (j = 0; j < run_count && i < count; j++, i++)
+ if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
+ for (j = 0; j < run_count; j++, i++)
{
- if (unlikely (p + HBUINT16::static_size > end)) return false;
n += *(const HBUINT16 *)p;
- points[i] = n;
+ points.arrayZ[i] = n;
p += HBUINT16::static_size;
}
}
else
{
- for (j = 0; j < run_count && i < count; j++, i++)
+ if (unlikely (p + run_count > end)) return false;
+ for (j = 0; j < run_count; j++, i++)
{
- if (unlikely (p + 1 > end)) return false;
n += *p++;
- points[i] = n;
+ points.arrayZ[i] = n;
}
}
- if (j < run_count) return false;
}
return true;
}
@@ -332,32 +331,37 @@ struct GlyphVariationData
DELTA_RUN_COUNT_MASK = 0x3F
};
- unsigned int i = 0;
- unsigned int count = deltas.length;
+ unsigned i = 0;
+ unsigned count = deltas.length;
while (i < count)
{
if (unlikely (p + 1 > end)) return false;
- uint8_t control = *p++;
- unsigned int run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
- unsigned int j;
+ unsigned control = *p++;
+ unsigned run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
+ if (unlikely (i + run_count > count)) return false;
+ unsigned j;
if (control & DELTAS_ARE_ZERO)
- for (j = 0; j < run_count && i < count; j++, i++)
- deltas[i] = 0;
+ {
+ for (j = 0; j < run_count; j++, i++)
+ deltas.arrayZ[i] = 0;
+ }
else if (control & DELTAS_ARE_WORDS)
- for (j = 0; j < run_count && i < count; j++, i++)
+ {
+ if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
+ for (j = 0; j < run_count; j++, i++)
{
- if (unlikely (p + HBUINT16::static_size > end)) return false;
- deltas[i] = *(const HBINT16 *) p;
+ deltas.arrayZ[i] = * (const HBINT16 *) p;
p += HBUINT16::static_size;
}
+ }
else
- for (j = 0; j < run_count && i < count; j++, i++)
+ {
+ if (unlikely (p + run_count > end)) return false;
+ for (j = 0; j < run_count; j++, i++)
{
- if (unlikely (p + 1 > end)) return false;
- deltas[i] = *(const HBINT8 *) p++;
+ deltas.arrayZ[i] = * (const HBINT8 *) p++;
}
- if (j < run_count)
- return false;
+ }
}
return true;
}
@@ -450,7 +454,7 @@ struct gvar
F2DOT14 *tuples = c->serializer->allocate_size<F2DOT14> (shared_tuple_size);
if (!tuples) return_trace (false);
out->sharedTuples = (char *) tuples - (char *) out;
- memcpy (tuples, this+sharedTuples, shared_tuple_size);
+ hb_memcpy (tuples, this+sharedTuples, shared_tuple_size);
}
char *subset_data = c->serializer->allocate_size<char> (subset_data_size);
@@ -473,7 +477,7 @@ struct gvar
((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2;
if (var_data_bytes.length > 0)
- memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
+ hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
subset_data += var_data_bytes.length;
glyph_offset += var_data_bytes.length;
}
@@ -501,6 +505,7 @@ struct gvar
unsigned get_offset (unsigned i) const
{
if (unlikely (i > glyphCount)) return 0;
+ _hb_compiler_memory_r_barrier ();
return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2;
}
@@ -521,11 +526,11 @@ struct gvar
unsigned int target, unsigned int prev, unsigned int next,
float contour_point_t::*m)
{
- float target_val = points[target].*m;
- float prev_val = points[prev].*m;
- float next_val = points[next].*m;
- float prev_delta = deltas[prev].*m;
- float next_delta = deltas[next].*m;
+ float target_val = points.arrayZ[target].*m;
+ float prev_val = points.arrayZ[prev].*m;
+ float next_val = points.arrayZ[next].*m;
+ float prev_delta = deltas.arrayZ[prev].*m;
+ float next_delta = deltas.arrayZ[next].*m;
if (prev_val == next_val)
return (prev_delta == next_delta) ? prev_delta : 0.f;
@@ -543,10 +548,11 @@ struct gvar
{ return (i >= end) ? start : (i + 1); }
public:
- bool apply_deltas_to_points (hb_codepoint_t glyph, hb_font_t *font,
+ bool apply_deltas_to_points (hb_codepoint_t glyph,
+ hb_array_t<int> coords,
const hb_array_t<contour_point_t> points) const
{
- if (!font->num_coords) return true;
+ if (!coords) return true;
if (unlikely (glyph >= table->glyphCount)) return true;
@@ -559,20 +565,20 @@ struct gvar
return true; /* so isn't applied at all */
/* Save original points for inferred delta calculation */
- contour_point_vector_t orig_points;
- if (unlikely (!orig_points.resize (points.length))) return false;
- for (unsigned int i = 0; i < orig_points.length; i++)
- orig_points.arrayZ[i] = points.arrayZ[i];
+ contour_point_vector_t orig_points_vec;
+ orig_points_vec.extend (points);
+ if (unlikely (orig_points_vec.in_error ())) return false;
+ auto orig_points = orig_points_vec.as_array ();
- contour_point_vector_t deltas; /* flag is used to indicate referenced point */
- if (unlikely (!deltas.resize (points.length))) return false;
+ contour_point_vector_t deltas_vec; /* flag is used to indicate referenced point */
+ if (unlikely (!deltas_vec.resize (points.length, false))) return false;
+ auto deltas = deltas_vec.as_array ();
hb_vector_t<unsigned> end_points;
for (unsigned i = 0; i < points.length; ++i)
- if (points[i].is_end_point)
+ if (points.arrayZ[i].is_end_point)
end_points.push (i);
- auto coords = hb_array (font->coords, font->num_coords);
unsigned num_coords = table->axisCount;
hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
@@ -598,70 +604,89 @@ struct gvar
bool apply_to_all = (indices.length == 0);
unsigned int num_deltas = apply_to_all ? points.length : indices.length;
- if (unlikely (!x_deltas.resize (num_deltas))) return false;
+ if (unlikely (!x_deltas.resize (num_deltas, false))) return false;
if (unlikely (!GlyphVariationData::unpack_deltas (p, x_deltas, end))) return false;
- if (unlikely (!y_deltas.resize (num_deltas))) return false;
+ if (unlikely (!y_deltas.resize (num_deltas, false))) return false;
if (unlikely (!GlyphVariationData::unpack_deltas (p, y_deltas, end))) return false;
- for (unsigned int i = 0; i < deltas.length; i++)
- deltas[i].init ();
- for (unsigned int i = 0; i < num_deltas; i++)
- {
- unsigned int pt_index = apply_to_all ? i : indices[i];
- if (unlikely (pt_index >= deltas.length)) continue;
- deltas.arrayZ[pt_index].flag = 1; /* this point is referenced, i.e., explicit deltas specified */
- deltas.arrayZ[pt_index].x += x_deltas.arrayZ[i] * scalar;
- deltas.arrayZ[pt_index].y += y_deltas.arrayZ[i] * scalar;
- }
+ hb_memset (deltas.arrayZ, 0, deltas.get_size ());
+
+ unsigned ref_points = 0;
+ if (scalar != 1.0f)
+ for (unsigned int i = 0; i < num_deltas; i++)
+ {
+ unsigned int pt_index = apply_to_all ? i : indices[i];
+ if (unlikely (pt_index >= deltas.length)) continue;
+ auto &delta = deltas.arrayZ[pt_index];
+ ref_points += !delta.flag;
+ delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
+ delta.x += x_deltas.arrayZ[i] * scalar;
+ delta.y += y_deltas.arrayZ[i] * scalar;
+ }
+ else
+ for (unsigned int i = 0; i < num_deltas; i++)
+ {
+ unsigned int pt_index = apply_to_all ? i : indices[i];
+ if (unlikely (pt_index >= deltas.length)) continue;
+ auto &delta = deltas.arrayZ[pt_index];
+ ref_points += !delta.flag;
+ delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
+ delta.x += x_deltas.arrayZ[i];
+ delta.y += y_deltas.arrayZ[i];
+ }
/* infer deltas for unreferenced points */
- unsigned start_point = 0;
- for (unsigned c = 0; c < end_points.length; c++)
+ if (ref_points && ref_points < orig_points.length)
{
- unsigned end_point = end_points[c];
+ unsigned start_point = 0;
+ for (unsigned c = 0; c < end_points.length; c++)
+ {
+ unsigned end_point = end_points.arrayZ[c];
- /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
- unsigned unref_count = 0;
- for (unsigned i = start_point; i <= end_point; i++)
- if (!deltas[i].flag) unref_count++;
+ /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
+ unsigned unref_count = 0;
+ for (unsigned i = start_point; i < end_point + 1; i++)
+ unref_count += deltas.arrayZ[i].flag;
+ unref_count = (end_point - start_point + 1) - unref_count;
- unsigned j = start_point;
- if (unref_count == 0 || unref_count > end_point - start_point)
- goto no_more_gaps;
+ unsigned j = start_point;
+ if (unref_count == 0 || unref_count > end_point - start_point)
+ goto no_more_gaps;
- for (;;)
- {
- /* Locate the next gap of unreferenced points between two referenced points prev and next.
- * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
- */
- unsigned int prev, next, i;
- for (;;)
- {
- i = j;
- j = next_index (i, start_point, end_point);
- if (deltas[i].flag && !deltas[j].flag) break;
- }
- prev = j = i;
- for (;;)
- {
- i = j;
- j = next_index (i, start_point, end_point);
- if (!deltas[i].flag && deltas[j].flag) break;
- }
- next = j;
- /* Infer deltas for all unref points in the gap between prev and next */
- i = prev;
for (;;)
{
- i = next_index (i, start_point, end_point);
- if (i == next) break;
- deltas[i].x = infer_delta (orig_points.as_array (), deltas.as_array (), i, prev, next, &contour_point_t::x);
- deltas[i].y = infer_delta (orig_points.as_array (), deltas.as_array (), i, prev, next, &contour_point_t::y);
- if (--unref_count == 0) goto no_more_gaps;
+ /* Locate the next gap of unreferenced points between two referenced points prev and next.
+ * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
+ */
+ unsigned int prev, next, i;
+ for (;;)
+ {
+ i = j;
+ j = next_index (i, start_point, end_point);
+ if (deltas.arrayZ[i].flag && !deltas.arrayZ[j].flag) break;
+ }
+ prev = j = i;
+ for (;;)
+ {
+ i = j;
+ j = next_index (i, start_point, end_point);
+ if (!deltas.arrayZ[i].flag && deltas.arrayZ[j].flag) break;
+ }
+ next = j;
+ /* Infer deltas for all unref points in the gap between prev and next */
+ i = prev;
+ for (;;)
+ {
+ i = next_index (i, start_point, end_point);
+ if (i == next) break;
+ deltas.arrayZ[i].x = infer_delta (orig_points, deltas, i, prev, next, &contour_point_t::x);
+ deltas.arrayZ[i].y = infer_delta (orig_points, deltas, i, prev, next, &contour_point_t::y);
+ if (--unref_count == 0) goto no_more_gaps;
+ }
}
+ no_more_gaps:
+ start_point = end_point + 1;
}
- no_more_gaps:
- start_point = end_point + 1;
}
/* apply specified / inferred deltas to points */
diff --git a/thirdparty/harfbuzz/src/hb-pool.hh b/thirdparty/harfbuzz/src/hb-pool.hh
index dcf8f6627d..e4bb64f627 100644
--- a/thirdparty/harfbuzz/src/hb-pool.hh
+++ b/thirdparty/harfbuzz/src/hb-pool.hh
@@ -35,15 +35,13 @@ template <typename T, unsigned ChunkLen = 16>
struct hb_pool_t
{
hb_pool_t () : next (nullptr) {}
- ~hb_pool_t () { fini (); }
-
- void fini ()
+ ~hb_pool_t ()
{
next = nullptr;
- for (chunk_t *_ : chunks) hb_free (_);
-
- chunks.fini ();
+ + hb_iter (chunks)
+ | hb_apply (hb_free)
+ ;
}
T* alloc ()
@@ -60,7 +58,7 @@ struct hb_pool_t
T* obj = next;
next = * ((T**) next);
- memset (obj, 0, sizeof (T));
+ hb_memset (obj, 0, sizeof (T));
return obj;
}
diff --git a/thirdparty/harfbuzz/src/hb-priority-queue.hh b/thirdparty/harfbuzz/src/hb-priority-queue.hh
index ffb86e30ae..ac76b7d955 100644
--- a/thirdparty/harfbuzz/src/hb-priority-queue.hh
+++ b/thirdparty/harfbuzz/src/hb-priority-queue.hh
@@ -63,7 +63,9 @@ struct hb_priority_queue_t
heap.arrayZ[0] = heap.arrayZ[heap.length - 1];
heap.shrink (heap.length - 1);
- bubble_down (0);
+
+ if (!is_empty ())
+ bubble_down (0);
return result;
}
@@ -100,7 +102,7 @@ struct hb_priority_queue_t
void bubble_down (unsigned index)
{
- assert (index <= heap.length);
+ assert (index < heap.length);
unsigned left = left_child (index);
unsigned right = right_child (index);
@@ -112,7 +114,7 @@ struct hb_priority_queue_t
bool has_right = right < heap.length;
if (heap.arrayZ[index].first <= heap.arrayZ[left].first
- && (!has_right || heap[index].first <= heap.arrayZ[right].first))
+ && (!has_right || heap.arrayZ[index].first <= heap.arrayZ[right].first))
return;
if (!has_right || heap.arrayZ[left].first < heap.arrayZ[right].first)
@@ -128,7 +130,7 @@ struct hb_priority_queue_t
void bubble_up (unsigned index)
{
- assert (index <= heap.length);
+ assert (index < heap.length);
if (index == 0) return;
@@ -142,8 +144,8 @@ struct hb_priority_queue_t
void swap (unsigned a, unsigned b)
{
- assert (a <= heap.length);
- assert (b <= heap.length);
+ assert (a < heap.length);
+ assert (b < heap.length);
hb_swap (heap.arrayZ[a], heap.arrayZ[b]);
}
};
diff --git a/thirdparty/harfbuzz/src/hb-repacker.hh b/thirdparty/harfbuzz/src/hb-repacker.hh
index c97ce6cc2c..7a3143cec3 100644
--- a/thirdparty/harfbuzz/src/hb-repacker.hh
+++ b/thirdparty/harfbuzz/src/hb-repacker.hh
@@ -209,7 +209,7 @@ bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& over
// Only move at most half of the roots in a space at a time.
unsigned extra = roots_to_isolate.get_population () - maximum_to_move;
while (extra--) {
- unsigned root = HB_SET_VALUE_INVALID;
+ uint32_t root = HB_SET_VALUE_INVALID;
roots_to_isolate.previous (&root);
roots_to_isolate.del (root);
}
@@ -283,6 +283,11 @@ hb_resolve_graph_overflows (hb_tag_t table_tag,
graph_t& sorted_graph /* IN/OUT */)
{
sorted_graph.sort_shortest_distance ();
+ if (sorted_graph.in_error ())
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state after initial sort.");
+ return false;
+ }
bool will_overflow = graph::will_overflow (sorted_graph);
if (!will_overflow)
@@ -376,6 +381,26 @@ hb_resolve_overflows (const T& packed,
unsigned max_rounds = 20,
bool recalculate_extensions = false) {
graph_t sorted_graph (packed);
+ if (sorted_graph.in_error ())
+ {
+ // Invalid graph definition.
+ return nullptr;
+ }
+
+ if (!sorted_graph.is_fully_connected ())
+ {
+ sorted_graph.print_orphaned_nodes ();
+ return nullptr;
+ }
+
+ if (sorted_graph.in_error ())
+ {
+ // Allocations failed somewhere
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Graph is in error, likely due to a memory allocation error.");
+ return nullptr;
+ }
+
if (!hb_resolve_graph_overflows (table_tag, max_rounds, recalculate_extensions, sorted_graph))
return nullptr;
diff --git a/thirdparty/harfbuzz/src/hb-sanitize.hh b/thirdparty/harfbuzz/src/hb-sanitize.hh
index 65c2772201..bd3250e580 100644
--- a/thirdparty/harfbuzz/src/hb-sanitize.hh
+++ b/thirdparty/harfbuzz/src/hb-sanitize.hh
@@ -198,10 +198,11 @@ struct hb_sanitize_context_t :
void start_processing ()
{
reset_object ();
- if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR)))
+ unsigned m;
+ if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR, &m)))
this->max_ops = HB_SANITIZE_MAX_OPS_MAX;
else
- this->max_ops = hb_clamp ((unsigned) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR,
+ this->max_ops = hb_clamp (m,
(unsigned) HB_SANITIZE_MAX_OPS_MIN,
(unsigned) HB_SANITIZE_MAX_OPS_MAX);
this->edit_count = 0;
@@ -252,8 +253,9 @@ struct hb_sanitize_context_t :
unsigned int a,
unsigned int b) const
{
- return !hb_unsigned_mul_overflows (a, b) &&
- this->check_range (base, a * b);
+ unsigned m;
+ return !hb_unsigned_mul_overflows (a, b, &m) &&
+ this->check_range (base, m);
}
template <typename T>
@@ -262,8 +264,9 @@ struct hb_sanitize_context_t :
unsigned int b,
unsigned int c) const
{
- return !hb_unsigned_mul_overflows (a, b) &&
- this->check_range (base, a * b, c);
+ unsigned m;
+ return !hb_unsigned_mul_overflows (a, b, &m) &&
+ this->check_range (base, m, c);
}
template <typename T>
diff --git a/thirdparty/harfbuzz/src/hb-serialize.hh b/thirdparty/harfbuzz/src/hb-serialize.hh
index f47cde5eb5..d5573281f1 100644
--- a/thirdparty/harfbuzz/src/hb-serialize.hh
+++ b/thirdparty/harfbuzz/src/hb-serialize.hh
@@ -194,7 +194,6 @@ struct hb_serialize_context_t
current = current->next;
_->fini ();
}
- object_pool.fini ();
}
bool in_error () const { return bool (errors); }
@@ -224,6 +223,7 @@ struct hb_serialize_context_t
this->errors = HB_SERIALIZE_ERROR_NONE;
this->head = this->start;
this->tail = this->end;
+ this->zerocopy = nullptr;
this->debug_depth = 0;
fini ();
@@ -326,7 +326,8 @@ struct hb_serialize_context_t
if (unlikely (in_error() && !only_overflow ())) return;
current = current->next;
- revert (obj->head, obj->tail);
+ revert (zerocopy ? zerocopy : obj->head, obj->tail);
+ zerocopy = nullptr;
obj->fini ();
object_pool.release (obj);
}
@@ -344,8 +345,11 @@ struct hb_serialize_context_t
current = current->next;
obj->tail = head;
obj->next = nullptr;
+ assert (obj->head <= obj->tail);
unsigned len = obj->tail - obj->head;
- head = obj->head; /* Rewind head. */
+ head = zerocopy ? zerocopy : obj->head; /* Rewind head. */
+ bool was_zerocopy = zerocopy;
+ zerocopy = nullptr;
if (!len)
{
@@ -355,9 +359,11 @@ struct hb_serialize_context_t
}
objidx_t objidx;
+ uint32_t hash = 0;
if (share)
{
- objidx = packed_map.get (obj);
+ hash = hb_hash (obj);
+ objidx = packed_map.get_with_hash (obj, hash);
if (objidx)
{
merge_virtual_links (obj, objidx);
@@ -367,7 +373,10 @@ struct hb_serialize_context_t
}
tail -= len;
- memmove (tail, obj->head, len);
+ if (was_zerocopy)
+ assert (tail == obj->head);
+ else
+ memmove (tail, obj->head, len);
obj->head = tail;
obj->tail = tail + len;
@@ -385,7 +394,7 @@ struct hb_serialize_context_t
objidx = packed.length - 1;
- if (share) packed_map.set (obj, objidx);
+ if (share) packed_map.set_with_hash (obj, hash, objidx);
propagate_error (packed_map);
return objidx;
@@ -569,8 +578,26 @@ struct hb_serialize_context_t
return !bool ((errors = (errors | err_type)));
}
+ bool start_zerocopy (size_t size)
+ {
+ if (unlikely (in_error ())) return false;
+
+ if (unlikely (size > INT_MAX || this->tail - this->head < ptrdiff_t (size)))
+ {
+ err (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
+ return false;
+ }
+
+ assert (!this->zerocopy);
+ this->zerocopy = this->head;
+
+ assert (this->current->head == this->head);
+ this->current->head = this->current->tail = this->head = this->tail - size;
+ return true;
+ }
+
template <typename Type>
- Type *allocate_size (size_t size)
+ Type *allocate_size (size_t size, bool clear = true)
{
if (unlikely (in_error ())) return nullptr;
@@ -579,7 +606,8 @@ struct hb_serialize_context_t
err (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
return nullptr;
}
- hb_memset (this->head, 0, size);
+ if (clear)
+ hb_memset (this->head, 0, size);
char *ret = this->head;
this->head += size;
return reinterpret_cast<Type *> (ret);
@@ -593,9 +621,9 @@ struct hb_serialize_context_t
Type *embed (const Type *obj)
{
unsigned int size = obj->get_size ();
- Type *ret = this->allocate_size<Type> (size);
+ Type *ret = this->allocate_size<Type> (size, false);
if (unlikely (!ret)) return nullptr;
- memcpy (ret, obj, size);
+ hb_memcpy (ret, obj, size);
return ret;
}
template <typename Type>
@@ -616,7 +644,7 @@ struct hb_serialize_context_t
}
/* Like embed, but active: calls obj.operator=() or obj.copy() to transfer data
- * instead of memcpy(). */
+ * instead of hb_memcpy(). */
template <typename Type, typename ...Ts>
Type *copy (const Type &src, Ts&&... ds)
{ return _copy (src, hb_prioritize, std::forward<Ts> (ds)...); }
@@ -634,7 +662,7 @@ struct hb_serialize_context_t
hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
template <typename Type>
- Type *extend_size (Type *obj, size_t size)
+ Type *extend_size (Type *obj, size_t size, bool clear = true)
{
if (unlikely (in_error ())) return nullptr;
@@ -642,12 +670,12 @@ struct hb_serialize_context_t
assert ((char *) obj <= this->head);
assert ((size_t) (this->head - (char *) obj) <= size);
if (unlikely (((char *) obj + size < (char *) obj) ||
- !this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
+ !this->allocate_size<Type> (((char *) obj) + size - this->head, clear))) return nullptr;
return reinterpret_cast<Type *> (obj);
}
template <typename Type>
- Type *extend_size (Type &obj, size_t size)
- { return extend_size (std::addressof (obj), size); }
+ Type *extend_size (Type &obj, size_t size, bool clear = true)
+ { return extend_size (std::addressof (obj), size, clear); }
template <typename Type>
Type *extend_min (Type *obj) { return extend_size (obj, obj->min_size); }
@@ -676,8 +704,8 @@ struct hb_serialize_context_t
char *p = (char *) hb_malloc (len);
if (unlikely (!p)) return hb_bytes_t ();
- memcpy (p, this->start, this->head - this->start);
- memcpy (p + (this->head - this->start), this->tail, this->end - this->tail);
+ hb_memcpy (p, this->start, this->head - this->start);
+ hb_memcpy (p + (this->head - this->start), this->tail, this->end - this->tail);
return hb_bytes_t (p, len);
}
template <typename Type>
@@ -704,7 +732,7 @@ struct hb_serialize_context_t
}
public:
- char *start, *head, *tail, *end;
+ char *start, *head, *tail, *end, *zerocopy;
unsigned int debug_depth;
hb_serialize_error_t errors;
diff --git a/thirdparty/harfbuzz/src/hb-set-digest.hh b/thirdparty/harfbuzz/src/hb-set-digest.hh
index fab36216e4..e8409111f2 100644
--- a/thirdparty/harfbuzz/src/hb-set-digest.hh
+++ b/thirdparty/harfbuzz/src/hb-set-digest.hh
@@ -28,6 +28,7 @@
#define HB_SET_DIGEST_HH
#include "hb.hh"
+#include "hb-machinery.hh"
/*
* The set-digests here implement various "filters" that support
@@ -75,6 +76,8 @@ struct hb_set_digest_bits_pattern_t
void init () { mask = 0; }
+ void add (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
+
void add (hb_codepoint_t g) { mask |= mask_for (g); }
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
@@ -95,7 +98,7 @@ struct hb_set_digest_bits_pattern_t
for (unsigned int i = 0; i < count; i++)
{
add (*array);
- array = (const T *) (stride + (const char *) array);
+ array = &StructAtOffsetUnaligned<T> ((const void *) array, stride);
}
}
template <typename T>
@@ -103,16 +106,15 @@ struct hb_set_digest_bits_pattern_t
template <typename T>
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
- for (unsigned int i = 0; i < count; i++)
- {
- add (*array);
- array = (const T *) (stride + (const char *) array);
- }
+ add_array (array, count, stride);
return true;
}
template <typename T>
bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
+ bool may_have (const hb_set_digest_bits_pattern_t &o) const
+ { return mask & o.mask; }
+
bool may_have (hb_codepoint_t g) const
{ return mask & mask_for (g); }
@@ -132,6 +134,12 @@ struct hb_set_digest_combiner_t
tail.init ();
}
+ void add (const hb_set_digest_combiner_t &o)
+ {
+ head.add (o.head);
+ tail.add (o.tail);
+ }
+
void add (hb_codepoint_t g)
{
head.add (g);
@@ -140,9 +148,8 @@ struct hb_set_digest_combiner_t
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
{
- head.add_range (a, b);
- tail.add_range (a, b);
- return true;
+ return head.add_range (a, b) &&
+ tail.add_range (a, b);
}
template <typename T>
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
@@ -155,13 +162,17 @@ struct hb_set_digest_combiner_t
template <typename T>
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
- head.add_sorted_array (array, count, stride);
- tail.add_sorted_array (array, count, stride);
- return true;
+ return head.add_sorted_array (array, count, stride) &&
+ tail.add_sorted_array (array, count, stride);
}
template <typename T>
bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
+ bool may_have (const hb_set_digest_combiner_t &o) const
+ {
+ return head.may_have (o.head) && tail.may_have (o.tail);
+ }
+
bool may_have (hb_codepoint_t g) const
{
return head.may_have (g) && tail.may_have (g);
diff --git a/thirdparty/harfbuzz/src/hb-set.hh b/thirdparty/harfbuzz/src/hb-set.hh
index 5d5576cb9e..f958a081fb 100644
--- a/thirdparty/harfbuzz/src/hb-set.hh
+++ b/thirdparty/harfbuzz/src/hb-set.hh
@@ -105,10 +105,8 @@ struct hb_sparseset_t
bool get (hb_codepoint_t g) const { return s.get (g); }
/* Has interface. */
- static constexpr bool SENTINEL = false;
- typedef bool value_t;
- value_t operator [] (hb_codepoint_t k) const { return get (k); }
- bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ bool operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k]; }
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
diff --git a/thirdparty/harfbuzz/src/hb-shape-plan.cc b/thirdparty/harfbuzz/src/hb-shape-plan.cc
index 9e513c0458..cabcbd4e72 100644
--- a/thirdparty/harfbuzz/src/hb-shape-plan.cc
+++ b/thirdparty/harfbuzz/src/hb-shape-plan.cc
@@ -31,6 +31,8 @@
#include "hb-buffer.hh"
+#ifndef HB_NO_SHAPER
+
/**
* SECTION:hb-shape-plan
* @title: hb-shape-plan
@@ -74,7 +76,7 @@ hb_shape_plan_key_t::init (bool copy,
this->user_features = copy ? features : user_features;
if (copy && num_user_features)
{
- memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
+ hb_memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
/* Make start/end uniform to easier catch bugs. */
for (unsigned int i = 0; i < num_user_features; i++)
{
@@ -574,3 +576,6 @@ retry:
return hb_shape_plan_reference (shape_plan);
}
+
+
+#endif
diff --git a/thirdparty/harfbuzz/src/hb-shape.cc b/thirdparty/harfbuzz/src/hb-shape.cc
index 547d0afc47..7b5bf2c5ef 100644
--- a/thirdparty/harfbuzz/src/hb-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-shape.cc
@@ -35,6 +35,8 @@
#include "hb-machinery.hh"
+#ifndef HB_NO_SHAPER
+
/**
* SECTION:hb-shape
* @title: hb-shape
@@ -192,3 +194,6 @@ hb_shape (hb_font_t *font,
{
hb_shape_full (font, buffer, features, num_features, nullptr);
}
+
+
+#endif
diff --git a/thirdparty/harfbuzz/src/hb-shaper.cc b/thirdparty/harfbuzz/src/hb-shaper.cc
index a900ac6991..c4885cda94 100644
--- a/thirdparty/harfbuzz/src/hb-shaper.cc
+++ b/thirdparty/harfbuzz/src/hb-shaper.cc
@@ -53,7 +53,7 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<hb_shaper_entry_t,
if (unlikely (!shapers))
return nullptr;
- memcpy (shapers, _hb_all_shapers, sizeof (_hb_all_shapers));
+ hb_memcpy (shapers, _hb_all_shapers, sizeof (_hb_all_shapers));
/* Reorder shaper list to prefer requested shapers. */
unsigned int i = 0;
diff --git a/thirdparty/harfbuzz/src/hb-static.cc b/thirdparty/harfbuzz/src/hb-static.cc
index 5d4c7cda1b..eac50754c2 100644
--- a/thirdparty/harfbuzz/src/hb-static.cc
+++ b/thirdparty/harfbuzz/src/hb-static.cc
@@ -33,6 +33,7 @@
#include "hb-aat-layout-feat-table.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-cmap-table.hh"
+#include "hb-ot-color-colr-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"
@@ -47,6 +48,7 @@ DEFINE_NULL_NAMESPACE_BYTES (OT, Index) = {0xFF,0xFF};
DEFINE_NULL_NAMESPACE_BYTES (OT, VarIdx) = {0xFF,0xFF,0xFF,0xFF};
DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0x00,0x00, 0xFF,0xFF, 0x00,0x00};
DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x01};
+DEFINE_NULL_NAMESPACE_BYTES (OT, ClipRecord) = {0x01};
DEFINE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup) = {0x00,0x00,0x00,0x01, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00};
DEFINE_NULL_NAMESPACE_BYTES (AAT, SettingName) = {0xFF,0xFF, 0xFF,0xFF};
DEFINE_NULL_NAMESPACE_BYTES (AAT, Lookup) = {0xFF,0xFF};
diff --git a/thirdparty/harfbuzz/src/hb-subset-accelerator.hh b/thirdparty/harfbuzz/src/hb-subset-accelerator.hh
index 34bd0534fb..63ae6d77e2 100644
--- a/thirdparty/harfbuzz/src/hb-subset-accelerator.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-accelerator.hh
@@ -31,21 +31,34 @@
#include "hb.hh"
#include "hb-map.hh"
+#include "hb-multimap.hh"
#include "hb-set.hh"
+extern HB_INTERNAL hb_user_data_key_t _hb_subset_accelerator_user_data_key;
+
+namespace CFF {
+struct cff_subset_accelerator_t;
+}
+
+namespace OT {
+struct SubtableUnicodesCache;
+};
+
struct hb_subset_accelerator_t
{
static hb_user_data_key_t* user_data_key()
{
- static hb_user_data_key_t key;
- return &key;
+ return &_hb_subset_accelerator_user_data_key;
}
static hb_subset_accelerator_t* create(const hb_map_t& unicode_to_gid_,
- const hb_set_t& unicodes_) {
+ const hb_multimap_t gid_to_unicodes_,
+ const hb_set_t& unicodes_,
+ bool has_seac_) {
hb_subset_accelerator_t* accel =
(hb_subset_accelerator_t*) hb_malloc (sizeof(hb_subset_accelerator_t));
- new (accel) hb_subset_accelerator_t (unicode_to_gid_, unicodes_);
+ new (accel) hb_subset_accelerator_t (unicode_to_gid_, gid_to_unicodes_, unicodes_);
+ accel->has_seac = has_seac_;
return accel;
}
@@ -53,22 +66,54 @@ struct hb_subset_accelerator_t
if (!value) return;
hb_subset_accelerator_t* accel = (hb_subset_accelerator_t*) value;
+
+ if (accel->cff_accelerator && accel->destroy_cff_accelerator)
+ accel->destroy_cff_accelerator ((void*) accel->cff_accelerator);
+
+ if (accel->cmap_cache && accel->destroy_cmap_cache)
+ accel->destroy_cmap_cache ((void*) accel->cmap_cache);
+
accel->~hb_subset_accelerator_t ();
hb_free (accel);
}
- hb_subset_accelerator_t(const hb_map_t& unicode_to_gid_,
+ hb_subset_accelerator_t (const hb_map_t& unicode_to_gid_,
+ const hb_multimap_t& gid_to_unicodes_,
const hb_set_t& unicodes_)
- : unicode_to_gid(unicode_to_gid_), unicodes(unicodes_) {}
+ : unicode_to_gid(unicode_to_gid_), gid_to_unicodes (gid_to_unicodes_), unicodes(unicodes_),
+ cmap_cache(nullptr), destroy_cmap_cache(nullptr),
+ has_seac(false), cff_accelerator(nullptr), destroy_cff_accelerator(nullptr)
+ { sanitized_table_cache_lock.init (); }
+
+ ~hb_subset_accelerator_t ()
+ { sanitized_table_cache_lock.fini (); }
+
+ // Generic
+
+ mutable hb_mutex_t sanitized_table_cache_lock;
+ mutable hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>> sanitized_table_cache;
const hb_map_t unicode_to_gid;
+ const hb_multimap_t gid_to_unicodes;
const hb_set_t unicodes;
+
+ // cmap
+ const OT::SubtableUnicodesCache* cmap_cache;
+ hb_destroy_func_t destroy_cmap_cache;
+
+ // CFF
+ bool has_seac;
+ const CFF::cff_subset_accelerator_t* cff_accelerator;
+ hb_destroy_func_t destroy_cff_accelerator;
+
// TODO(garretrieger): cumulative glyf checksum map
- // TODO(garretrieger): sanitized table cache.
bool in_error () const
{
- return unicode_to_gid.in_error() || unicodes.in_error ();
+ return unicode_to_gid.in_error () ||
+ gid_to_unicodes.in_error () ||
+ unicodes.in_error () ||
+ sanitized_table_cache.in_error ();
}
};
diff --git a/thirdparty/harfbuzz/src/hb-subset-cff-common.cc b/thirdparty/harfbuzz/src/hb-subset-cff-common.cc
index 711b2236d6..6e1b6f713d 100644
--- a/thirdparty/harfbuzz/src/hb-subset-cff-common.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-cff-common.cc
@@ -66,8 +66,7 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
{
/* use hb_set to determine the subset of font dicts */
- hb_set_t *set = hb_set_create ();
- if (unlikely (set == &Null (hb_set_t))) return false;
+ hb_set_t set;
hb_codepoint_t prev_fd = CFF_UNDEF_CODE;
for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
{
@@ -79,7 +78,7 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
glyph = i;
}
fd = src.get_fd (glyph);
- set->add (fd);
+ set.add (fd);
if (fd != prev_fd)
{
@@ -90,12 +89,11 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
}
}
- subset_fd_count = set->get_population ();
+ subset_fd_count = set.get_population ();
if (subset_fd_count == fdCount)
{
/* all font dicts belong to the subset. no need to subset FDSelect & FDArray */
fdmap.identity (fdCount);
- hb_set_destroy (set);
}
else
{
@@ -103,9 +101,8 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
fdmap.reset ();
hb_codepoint_t fd = CFF_UNDEF_CODE;
- while (set->next (&fd))
+ while (set.next (&fd))
fdmap.add (fd);
- hb_set_destroy (set);
if (unlikely (fdmap.get_population () != subset_fd_count))
return false;
}
diff --git a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh
index bb9f27eec1..8bbc017656 100644
--- a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh
@@ -38,15 +38,16 @@ namespace CFF {
struct str_encoder_t
{
str_encoder_t (str_buff_t &buff_)
- : buff (buff_), error (false) {}
+ : buff (buff_) {}
void reset () { buff.reset (); }
void encode_byte (unsigned char b)
{
- buff.push (b);
- if (unlikely (buff.in_error ()))
- set_error ();
+ if (likely ((signed) buff.length < buff.allocated))
+ buff.arrayZ[buff.length++] = b;
+ else
+ buff.push (b);
}
void encode_int (int v)
@@ -108,27 +109,18 @@ struct str_encoder_t
encode_byte (op);
}
- void copy_str (const hb_ubytes_t &str)
+ void copy_str (const unsigned char *str, unsigned length)
{
- unsigned int offset = buff.length;
- /* Manually resize buffer since faster. */
- if ((signed) (buff.length + str.length) <= buff.allocated)
- buff.length += str.length;
- else if (unlikely (!buff.resize (offset + str.length)))
- {
- set_error ();
- return;
- }
- memcpy (buff.arrayZ + offset, &str[0], str.length);
+ assert ((signed) (buff.length + length) <= buff.allocated);
+ hb_memcpy (buff.arrayZ + buff.length, str, length);
+ buff.length += length;
}
- bool is_error () const { return error; }
+ bool in_error () const { return buff.in_error (); }
protected:
- void set_error () { error = true; }
str_buff_t &buff;
- bool error;
};
struct cff_sub_table_info_t {
@@ -187,9 +179,12 @@ struct cff_font_dict_op_serializer_t : op_serializer_t
}
else
{
- HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
+ unsigned char *d = c->allocate_size<unsigned char> (opstr.length);
if (unlikely (!d)) return_trace (false);
- memcpy (d, &opstr.str[0], opstr.str.length);
+ /* Faster than hb_memcpy for small strings. */
+ for (unsigned i = 0; i < opstr.length; i++)
+ d[i] = opstr.ptr[i];
+ //hb_memcpy (d, opstr.ptr, opstr.length);
}
return_trace (true);
}
@@ -239,11 +234,10 @@ struct subr_flattener_t
bool flatten (str_buff_vec_t &flat_charstrings)
{
- if (!flat_charstrings.resize (plan->num_output_glyphs ()))
+ unsigned count = plan->num_output_glyphs ();
+ if (!flat_charstrings.resize (count))
return false;
- for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
- flat_charstrings[i].init ();
- for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+ for (unsigned int i = 0; i < count; i++)
{
hb_codepoint_t glyph;
if (!plan->old_gid_for_new_gid (i, &glyph))
@@ -259,7 +253,7 @@ struct subr_flattener_t
ENV env (str, acc, fd);
cs_interpreter_t<ENV, OPSET, flatten_param_t> interp (env);
flatten_param_t param = {
- flat_charstrings[i],
+ flat_charstrings.arrayZ[i],
(bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
};
if (unlikely (!interp.interpret (param)))
@@ -274,11 +268,9 @@ struct subr_flattener_t
struct subr_closures_t
{
- subr_closures_t (unsigned int fd_count) : valid (false), global_closure (), local_closures ()
+ subr_closures_t (unsigned int fd_count) : global_closure (), local_closures ()
{
- valid = true;
- if (!local_closures.resize (fd_count))
- valid = false;
+ local_closures.resize (fd_count);
}
void reset ()
@@ -288,47 +280,38 @@ struct subr_closures_t
local_closures[i].clear();
}
- bool is_valid () const { return valid; }
- bool valid;
+ bool in_error () const { return local_closures.in_error (); }
hb_set_t global_closure;
hb_vector_t<hb_set_t> local_closures;
};
struct parsed_cs_op_t : op_str_t
{
- void init (unsigned int subr_num_ = 0)
- {
- subr_num = subr_num_;
- drop_flag = false;
- keep_flag = false;
- skip_flag = false;
- }
-
- bool for_drop () const { return drop_flag; }
- void set_drop () { if (!for_keep ()) drop_flag = true; }
+ parsed_cs_op_t (unsigned int subr_num_ = 0) :
+ subr_num (subr_num_) {}
- bool for_keep () const { return keep_flag; }
- void set_keep () { keep_flag = true; }
+ bool is_hinting () const { return hinting_flag; }
+ void set_hinting () { hinting_flag = true; }
- bool for_skip () const { return skip_flag; }
- void set_skip () { skip_flag = true; }
-
- unsigned int subr_num;
+ /* The layout of this struct is designed to fit within the
+ * padding of op_str_t! */
protected:
- bool drop_flag;
- bool keep_flag;
- bool skip_flag;
+ bool hinting_flag = false;
+
+ public:
+ uint16_t subr_num;
};
struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
{
- void init ()
+ parsed_cs_str_t () :
+ parsed (false),
+ hint_dropped (false),
+ has_prefix_ (false),
+ has_calls_ (false)
{
SUPER::init ();
- parsed = false;
- hint_dropped = false;
- has_prefix_ = false;
}
void add_op (op_code_t op, const byte_str_ref_t& str_ref)
@@ -341,13 +324,12 @@ struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
{
if (!is_parsed ())
{
- unsigned int parsed_len = get_count ();
- if (likely (parsed_len > 0))
- values[parsed_len-1].set_skip ();
+ has_calls_ = true;
- parsed_cs_op_t val;
- val.init (subr_num);
- SUPER::add_op (op, str_ref, val);
+ /* Pop the subroutine number. */
+ values.pop ();
+
+ SUPER::add_op (op, str_ref, {subr_num});
}
}
@@ -377,11 +359,14 @@ struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
op_code_t prefix_op () const { return prefix_op_; }
const number_t &prefix_num () const { return prefix_num_; }
+ bool has_calls () const { return has_calls_; }
+
protected:
- bool parsed;
- bool hint_dropped;
- bool vsindex_dropped;
- bool has_prefix_;
+ bool parsed : 1;
+ bool hint_dropped : 1;
+ bool vsindex_dropped : 1;
+ bool has_prefix_ : 1;
+ bool has_calls_ : 1;
op_code_t prefix_op_;
number_t prefix_num_;
@@ -395,6 +380,59 @@ struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t>
typedef hb_vector_t<parsed_cs_str_t> SUPER;
};
+struct cff_subset_accelerator_t
+{
+ static cff_subset_accelerator_t* create (
+ hb_blob_t* original_blob,
+ const parsed_cs_str_vec_t& parsed_charstrings,
+ const parsed_cs_str_vec_t& parsed_global_subrs,
+ const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs) {
+ cff_subset_accelerator_t* accel =
+ (cff_subset_accelerator_t*) hb_malloc (sizeof(cff_subset_accelerator_t));
+ new (accel) cff_subset_accelerator_t (original_blob,
+ parsed_charstrings,
+ parsed_global_subrs,
+ parsed_local_subrs);
+ return accel;
+ }
+
+ static void destroy (void* value) {
+ if (!value) return;
+
+ cff_subset_accelerator_t* accel = (cff_subset_accelerator_t*) value;
+ accel->~cff_subset_accelerator_t ();
+ hb_free (accel);
+ }
+
+ cff_subset_accelerator_t(
+ hb_blob_t* original_blob_,
+ const parsed_cs_str_vec_t& parsed_charstrings_,
+ const parsed_cs_str_vec_t& parsed_global_subrs_,
+ const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs_)
+ {
+ parsed_charstrings = parsed_charstrings_;
+ parsed_global_subrs = parsed_global_subrs_;
+ parsed_local_subrs = parsed_local_subrs_;
+
+ // the parsed charstrings point to memory in the original CFF table so we must hold a reference
+ // to it to keep the memory valid.
+ original_blob = hb_blob_reference (original_blob_);
+ }
+
+ ~cff_subset_accelerator_t() {
+ hb_blob_destroy (original_blob);
+ hb_map_destroy (glyph_to_sid_map.get_relaxed ());
+ }
+
+ parsed_cs_str_vec_t parsed_charstrings;
+ parsed_cs_str_vec_t parsed_global_subrs;
+ hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs;
+ mutable hb_atomic_ptr_t<hb_map_t> glyph_to_sid_map = nullptr;
+
+ private:
+ hb_blob_t* original_blob;
+};
+
struct subr_subset_param_t
{
subr_subset_param_t (parsed_cs_str_t *parsed_charstring_,
@@ -446,7 +484,11 @@ struct subr_subset_param_t
if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
env.set_error ();
else
+ {
+ if (!parsed_str->is_parsed ())
+ parsed_str->alloc (env.str_ref.total_size () / 2);
current_parsed_str = parsed_str;
+ }
}
parsed_cs_str_t *current_parsed_str;
@@ -506,7 +548,7 @@ struct subr_remaps_t
{
global_remap.create (&closures.global_closure);
for (unsigned int i = 0; i < local_remaps.length; i++)
- local_remaps[i].create (&closures.local_closures[i]);
+ local_remaps.arrayZ[i].create (&closures.local_closures[i]);
}
subr_remap_t global_remap;
@@ -517,7 +559,8 @@ template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typena
struct subr_subsetter_t
{
subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_)
- : acc (acc_), plan (plan_), closures(acc_.fdCount), remaps(acc_.fdCount)
+ : acc (acc_), plan (plan_), closures(acc_.fdCount),
+ remaps(acc_.fdCount)
{}
/* Subroutine subsetting with --no-desubroutinize runs in phases:
@@ -536,55 +579,96 @@ struct subr_subsetter_t
*/
bool subset (void)
{
- parsed_charstrings.resize (plan->num_output_glyphs ());
- parsed_global_subrs.resize (acc.globalSubrs->count);
-
- if (unlikely (remaps.in_error()
- || parsed_charstrings.in_error ()
- || parsed_global_subrs.in_error ())) {
- return false;
+ unsigned fd_count = acc.fdCount;
+ const cff_subset_accelerator_t* cff_accelerator = nullptr;
+ if (plan->accelerator && plan->accelerator->cff_accelerator) {
+ cff_accelerator = plan->accelerator->cff_accelerator;
+ fd_count = cff_accelerator->parsed_local_subrs.length;
}
- if (unlikely (!parsed_local_subrs.resize (acc.fdCount))) return false;
+ if (cff_accelerator) {
+ // If we are not dropping hinting then charstrings are not modified so we can
+ // just use a reference to the cached copies.
+ cached_charstrings.resize (plan->num_output_glyphs ());
+ parsed_global_subrs = &cff_accelerator->parsed_global_subrs;
+ parsed_local_subrs = &cff_accelerator->parsed_local_subrs;
+ } else {
+ parsed_charstrings.resize (plan->num_output_glyphs ());
+ parsed_global_subrs_storage.resize (acc.globalSubrs->count);
- for (unsigned int i = 0; i < acc.fdCount; i++)
- {
- parsed_local_subrs[i].resize (acc.privateDicts[i].localSubrs->count);
- if (unlikely (parsed_local_subrs[i].in_error ())) return false;
+ if (unlikely (!parsed_local_subrs_storage.resize (fd_count))) return false;
+
+ for (unsigned int i = 0; i < acc.fdCount; i++)
+ {
+ unsigned count = acc.privateDicts[i].localSubrs->count;
+ parsed_local_subrs_storage[i].resize (count);
+ if (unlikely (parsed_local_subrs_storage[i].in_error ())) return false;
+ }
+
+ parsed_global_subrs = &parsed_global_subrs_storage;
+ parsed_local_subrs = &parsed_local_subrs_storage;
}
- if (unlikely (!closures.valid))
+
+ if (unlikely (remaps.in_error()
+ || cached_charstrings.in_error ()
+ || parsed_charstrings.in_error ()
+ || parsed_global_subrs->in_error ()
+ || closures.in_error ())) {
return false;
+ }
/* phase 1 & 2 */
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
{
hb_codepoint_t glyph;
if (!plan->old_gid_for_new_gid (i, &glyph))
- continue;
+ continue;
+
const hb_ubytes_t str = (*acc.charStrings)[glyph];
unsigned int fd = acc.fdSelect->get_fd (glyph);
if (unlikely (fd >= acc.fdCount))
- return false;
+ return false;
+
+ if (cff_accelerator)
+ {
+ // parsed string already exists in accelerator, copy it and move
+ // on.
+ if (cached_charstrings)
+ cached_charstrings[i] = &cff_accelerator->parsed_charstrings[glyph];
+ else
+ parsed_charstrings[i] = cff_accelerator->parsed_charstrings[glyph];
+
+ continue;
+ }
ENV env (str, acc, fd);
cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env);
- parsed_charstrings[i].alloc (str.length);
+ parsed_charstrings[i].alloc (str.length / 2);
subr_subset_param_t param (&parsed_charstrings[i],
- &parsed_global_subrs,
- &parsed_local_subrs[fd],
- &closures.global_closure,
- &closures.local_closures[fd],
- plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
+ &parsed_global_subrs_storage,
+ &parsed_local_subrs_storage[fd],
+ &closures.global_closure,
+ &closures.local_closures[fd],
+ plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
if (unlikely (!interp.interpret (param)))
- return false;
+ return false;
/* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]);
}
- if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ // Since parsed strings were loaded from accelerator, we still need
+ // to compute the subroutine closures which would have normally happened during
+ // parsing.
+ if (cff_accelerator &&
+ !closure_subroutines(*parsed_global_subrs,
+ *parsed_local_subrs))
+ return false;
+
+ if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING && !cff_accelerator) ||
+ plan->inprogress_accelerator)
{
/* mark hint ops and arguments for drop */
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
@@ -596,8 +680,8 @@ struct subr_subsetter_t
if (unlikely (fd >= acc.fdCount))
return false;
subr_subset_param_t param (&parsed_charstrings[i],
- &parsed_global_subrs,
- &parsed_local_subrs[fd],
+ &parsed_global_subrs_storage,
+ &parsed_local_subrs_storage[fd],
&closures.global_closure,
&closures.local_closures[fd],
plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
@@ -612,27 +696,14 @@ struct subr_subsetter_t
}
/* after dropping hints recreate closures of actually used subrs */
- closures.reset ();
- for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
- {
- hb_codepoint_t glyph;
- if (!plan->old_gid_for_new_gid (i, &glyph))
- continue;
- unsigned int fd = acc.fdSelect->get_fd (glyph);
- if (unlikely (fd >= acc.fdCount))
- return false;
- subr_subset_param_t param (&parsed_charstrings[i],
- &parsed_global_subrs,
- &parsed_local_subrs[fd],
- &closures.global_closure,
- &closures.local_closures[fd],
- plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
- collect_subr_refs_in_str (parsed_charstrings[i], param);
- }
+ if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING &&
+ !cff_accelerator &&
+ !closure_subroutines(*parsed_global_subrs, *parsed_local_subrs)) return false;
}
remaps.create (closures);
+ populate_subset_accelerator ();
return true;
}
@@ -646,13 +717,13 @@ struct subr_subsetter_t
if (!plan->old_gid_for_new_gid (i, &glyph))
{
/* add an endchar only charstring for a missing glyph if CFF1 */
- if (endchar_op != OpCode_Invalid) buffArray[i].push (endchar_op);
+ if (endchar_op != OpCode_Invalid) buffArray.arrayZ[i].push (endchar_op);
continue;
}
unsigned int fd = acc.fdSelect->get_fd (glyph);
if (unlikely (fd >= acc.fdCount))
return false;
- if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i])))
+ if (unlikely (!encode_str (get_parsed_charstring (i), fd, buffArray.arrayZ[i])))
return false;
}
return true;
@@ -664,26 +735,25 @@ struct subr_subsetter_t
if (unlikely (!buffArray.resize (count)))
return false;
- for (unsigned int old_num = 0; old_num < subrs.length; old_num++)
+ for (unsigned int new_num = 0; new_num < count; new_num++)
{
- hb_codepoint_t new_num = remap[old_num];
- if (new_num != CFF_UNDEF_CODE)
- {
- if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num])))
- return false;
- }
+ hb_codepoint_t old_num = remap.backward (new_num);
+ assert (old_num != CFF_UNDEF_CODE);
+
+ if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num])))
+ return false;
}
return true;
}
bool encode_globalsubrs (str_buff_vec_t &buffArray)
{
- return encode_subrs (parsed_global_subrs, remaps.global_remap, 0, buffArray);
+ return encode_subrs (*parsed_global_subrs, remaps.global_remap, 0, buffArray);
}
bool encode_localsubrs (unsigned int fd, str_buff_vec_t &buffArray) const
{
- return encode_subrs (parsed_local_subrs[fd], remaps.local_remaps[fd], fd, buffArray);
+ return encode_subrs ((*parsed_local_subrs)[fd], remaps.local_remaps[fd], fd, buffArray);
}
protected:
@@ -712,7 +782,7 @@ struct subr_subsetter_t
* then this entire subroutine must be a hint. drop its call. */
if (drop.ends_in_hint)
{
- str.values[pos].set_drop ();
+ str.values[pos].set_hinting ();
/* if this subr call is at the end of the parent subr, propagate the flag
* otherwise reset the flag */
if (!str.at_end (pos))
@@ -720,7 +790,7 @@ struct subr_subsetter_t
}
else if (drop.all_dropped)
{
- str.values[pos].set_drop ();
+ str.values[pos].set_hinting ();
}
return has_hint;
@@ -731,20 +801,22 @@ struct subr_subsetter_t
{
bool seen_hint = false;
- for (unsigned int pos = 0; pos < str.values.length; pos++)
+ unsigned count = str.values.length;
+ auto *values = str.values.arrayZ;
+ for (unsigned int pos = 0; pos < count; pos++)
{
bool has_hint = false;
- switch (str.values[pos].op)
+ switch (values[pos].op)
{
case OpCode_callsubr:
has_hint = drop_hints_in_subr (str, pos,
- *param.parsed_local_subrs, str.values[pos].subr_num,
+ *param.parsed_local_subrs, values[pos].subr_num,
param, drop);
break;
case OpCode_callgsubr:
has_hint = drop_hints_in_subr (str, pos,
- *param.parsed_global_subrs, str.values[pos].subr_num,
+ *param.parsed_global_subrs, values[pos].subr_num,
param, drop);
break;
@@ -758,7 +830,7 @@ struct subr_subsetter_t
case OpCode_cntrmask:
if (drop.seen_moveto)
{
- str.values[pos].set_drop ();
+ values[pos].set_hinting ();
break;
}
HB_FALLTHROUGH;
@@ -768,13 +840,13 @@ struct subr_subsetter_t
case OpCode_hstem:
case OpCode_vstem:
has_hint = true;
- str.values[pos].set_drop ();
+ values[pos].set_hinting ();
if (str.at_end (pos))
drop.ends_in_hint = true;
break;
case OpCode_dotsection:
- str.values[pos].set_drop ();
+ values[pos].set_hinting ();
break;
default:
@@ -785,10 +857,10 @@ struct subr_subsetter_t
{
for (int i = pos - 1; i >= 0; i--)
{
- parsed_cs_op_t &csop = str.values[(unsigned)i];
- if (csop.for_drop ())
+ parsed_cs_op_t &csop = values[(unsigned)i];
+ if (csop.is_hinting ())
break;
- csop.set_drop ();
+ csop.set_hinting ();
if (csop.op == OpCode_vsindexcs)
drop.vsindex_dropped = true;
}
@@ -801,12 +873,12 @@ struct subr_subsetter_t
* only (usually one) hintmask operator, then calls to this subr can be dropped.
*/
drop.all_dropped = true;
- for (unsigned int pos = 0; pos < str.values.length; pos++)
+ for (unsigned int pos = 0; pos < count; pos++)
{
- parsed_cs_op_t &csop = str.values[pos];
+ parsed_cs_op_t &csop = values[pos];
if (csop.op == OpCode_return)
break;
- if (!csop.for_drop ())
+ if (!csop.is_hinting ())
{
drop.all_dropped = false;
break;
@@ -816,32 +888,62 @@ struct subr_subsetter_t
return seen_hint;
}
- void collect_subr_refs_in_subr (parsed_cs_str_t &str, unsigned int pos,
- unsigned int subr_num, parsed_cs_str_vec_t &subrs,
+ bool closure_subroutines (const parsed_cs_str_vec_t& global_subrs,
+ const hb_vector_t<parsed_cs_str_vec_t>& local_subrs)
+ {
+ closures.reset ();
+ for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+ {
+ hb_codepoint_t glyph;
+ if (!plan->old_gid_for_new_gid (i, &glyph))
+ continue;
+ unsigned int fd = acc.fdSelect->get_fd (glyph);
+ if (unlikely (fd >= acc.fdCount))
+ return false;
+
+ // Note: const cast is safe here because the collect_subr_refs_in_str only performs a
+ // closure and does not modify any of the charstrings.
+ subr_subset_param_t param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (i)),
+ const_cast<parsed_cs_str_vec_t*> (&global_subrs),
+ const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]),
+ &closures.global_closure,
+ &closures.local_closures[fd],
+ plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
+ collect_subr_refs_in_str (get_parsed_charstring (i), param);
+ }
+
+ return true;
+ }
+
+ void collect_subr_refs_in_subr (unsigned int subr_num, parsed_cs_str_vec_t &subrs,
hb_set_t *closure,
const subr_subset_param_t &param)
{
+ if (closure->has (subr_num))
+ return;
closure->add (subr_num);
collect_subr_refs_in_str (subrs[subr_num], param);
}
- void collect_subr_refs_in_str (parsed_cs_str_t &str, const subr_subset_param_t &param)
+ void collect_subr_refs_in_str (const parsed_cs_str_t &str,
+ const subr_subset_param_t &param)
{
- for (unsigned int pos = 0; pos < str.values.length; pos++)
+ if (!str.has_calls ())
+ return;
+
+ for (auto &opstr : str.values)
{
- if (!str.values[pos].for_drop ())
+ if (!param.drop_hints || !opstr.is_hinting ())
{
- switch (str.values[pos].op)
+ switch (opstr.op)
{
case OpCode_callsubr:
- collect_subr_refs_in_subr (str, pos,
- str.values[pos].subr_num, *param.parsed_local_subrs,
+ collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_local_subrs,
param.local_closure, param);
break;
case OpCode_callgsubr:
- collect_subr_refs_in_subr (str, pos,
- str.values[pos].subr_num, *param.parsed_global_subrs,
+ collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_global_subrs,
param.global_closure, param);
break;
@@ -853,42 +955,113 @@ struct subr_subsetter_t
bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff) const
{
- unsigned count = str.get_count ();
str_encoder_t encoder (buff);
encoder.reset ();
- buff.alloc (count * 3);
+ bool hinting = !(plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
/* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints,
* re-insert it at the beginning of charstreing */
- if (str.has_prefix () && str.is_hint_dropped ())
+ if (str.has_prefix () && !hinting && str.is_hint_dropped ())
{
encoder.encode_num (str.prefix_num ());
if (str.prefix_op () != OpCode_Invalid)
encoder.encode_op (str.prefix_op ());
}
- for (unsigned int i = 0; i < count; i++)
+
+ unsigned size = 0;
+ for (auto &opstr : str.values)
{
- const parsed_cs_op_t &opstr = str.values[i];
- if (!opstr.for_drop () && !opstr.for_skip ())
+ size += opstr.length;
+ if (opstr.op == OpCode_callsubr || opstr.op == OpCode_callgsubr)
+ size += 3;
+ }
+ if (!buff.alloc (buff.length + size))
+ return false;
+
+ for (auto &opstr : str.values)
+ {
+ if (hinting || !opstr.is_hinting ())
{
switch (opstr.op)
{
case OpCode_callsubr:
encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num));
- encoder.encode_op (OpCode_callsubr);
+ encoder.copy_str (opstr.ptr, opstr.length);
break;
case OpCode_callgsubr:
encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num));
- encoder.encode_op (OpCode_callgsubr);
+ encoder.copy_str (opstr.ptr, opstr.length);
break;
default:
- encoder.copy_str (opstr.str);
+ encoder.copy_str (opstr.ptr, opstr.length);
break;
}
}
}
- return !encoder.is_error ();
+ return !encoder.in_error ();
+ }
+
+ void compact_parsed_strings () const
+ {
+ for (auto &cs : parsed_charstrings)
+ compact_string (cs);
+ for (auto &cs : parsed_global_subrs_storage)
+ compact_string (cs);
+ for (auto &vec : parsed_local_subrs_storage)
+ for (auto &cs : vec)
+ compact_string (cs);
+ }
+
+ static void compact_string (parsed_cs_str_t &str)
+ {
+ unsigned count = str.values.length;
+ if (unlikely (!count)) return;
+ auto &opstr = str.values.arrayZ;
+ unsigned j = 0;
+ for (unsigned i = 1; i < count; i++)
+ {
+ /* See if we can combine op j and op i. */
+ bool combine =
+ (opstr[j].op != OpCode_callsubr && opstr[j].op != OpCode_callgsubr) &&
+ (opstr[i].op != OpCode_callsubr && opstr[i].op != OpCode_callgsubr) &&
+ (opstr[j].is_hinting () == opstr[i].is_hinting ()) &&
+ (opstr[j].ptr + opstr[j].length == opstr[i].ptr) &&
+ (opstr[j].length + opstr[i].length <= 255);
+
+ if (combine)
+ {
+ opstr[j].length += opstr[i].length;
+ opstr[j].op = OpCode_Invalid;
+ }
+ else
+ {
+ opstr[++j] = opstr[i];
+ }
+ }
+ str.values.shrink (j + 1);
+ }
+
+ void populate_subset_accelerator () const
+ {
+ if (!plan->inprogress_accelerator) return;
+
+ compact_parsed_strings ();
+
+ plan->inprogress_accelerator->cff_accelerator =
+ cff_subset_accelerator_t::create(acc.blob,
+ parsed_charstrings,
+ parsed_global_subrs_storage,
+ parsed_local_subrs_storage);
+ plan->inprogress_accelerator->destroy_cff_accelerator =
+ cff_subset_accelerator_t::destroy;
+
+ }
+
+ const parsed_cs_str_t& get_parsed_charstring (unsigned i) const
+ {
+ if (cached_charstrings) return *(cached_charstrings[i]);
+ return parsed_charstrings[i];
}
protected:
@@ -897,13 +1070,17 @@ struct subr_subsetter_t
subr_closures_t closures;
- parsed_cs_str_vec_t parsed_charstrings;
- parsed_cs_str_vec_t parsed_global_subrs;
- hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs;
+ hb_vector_t<const parsed_cs_str_t*> cached_charstrings;
+ const parsed_cs_str_vec_t* parsed_global_subrs;
+ const hb_vector_t<parsed_cs_str_vec_t>* parsed_local_subrs;
subr_remaps_t remaps;
private:
+
+ parsed_cs_str_vec_t parsed_charstrings;
+ parsed_cs_str_vec_t parsed_global_subrs_storage;
+ hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs_storage;
typedef typename SUBRS::count_type subr_count_type;
};
diff --git a/thirdparty/harfbuzz/src/hb-subset-cff1.cc b/thirdparty/harfbuzz/src/hb-subset-cff1.cc
index 52bb13d320..538f28f5aa 100644
--- a/thirdparty/harfbuzz/src/hb-subset-cff1.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-cff1.cc
@@ -167,9 +167,10 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dic
* for supplement, the original byte string is copied along with the op code */
op_str_t supp_op;
supp_op.op = op;
- if ( unlikely (!(opstr.str.length >= opstr.last_arg_offset + 3)))
+ if ( unlikely (!(opstr.length >= opstr.last_arg_offset + 3)))
return_trace (false);
- supp_op.str = hb_ubytes_t (&opstr.str + opstr.last_arg_offset, opstr.str.length - opstr.last_arg_offset);
+ supp_op.ptr = opstr.ptr + opstr.last_arg_offset;
+ supp_op.length = opstr.length - opstr.last_arg_offset;
return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::registry]) &&
UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) &&
copy_opstr (c, supp_op));
@@ -442,8 +443,17 @@ struct cff_subset_plan {
return;
}
- bool use_glyph_to_sid_map = plan->num_output_glyphs () > plan->source->get_num_glyphs () / 8.;
- hb_map_t *glyph_to_sid_map = use_glyph_to_sid_map ? acc.create_glyph_to_sid_map () : nullptr;
+ hb_map_t *glyph_to_sid_map = (plan->accelerator && plan->accelerator->cff_accelerator) ?
+ plan->accelerator->cff_accelerator->glyph_to_sid_map :
+ nullptr;
+ bool created_map = false;
+ if (!glyph_to_sid_map &&
+ ((plan->accelerator && plan->accelerator->cff_accelerator) ||
+ plan->num_output_glyphs () > plan->source->get_num_glyphs () / 8.))
+ {
+ created_map = true;
+ glyph_to_sid_map = acc.create_glyph_to_sid_map ();
+ }
unsigned int glyph;
for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
@@ -467,8 +477,12 @@ struct cff_subset_plan {
last_sid = sid;
}
- if (glyph_to_sid_map)
- hb_map_destroy (glyph_to_sid_map);
+ if (created_map)
+ {
+ if (!(plan->accelerator && plan->accelerator->cff_accelerator) ||
+ !plan->accelerator->cff_accelerator->glyph_to_sid_map.cmpexch (nullptr, glyph_to_sid_map))
+ hb_map_destroy (glyph_to_sid_map);
+ }
bool two_byte = subset_charset_ranges.complete (glyph);
@@ -728,11 +742,17 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
/* CharStrings */
{
+ c->push<CFF1CharStrings> ();
+
+ unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings);
+ if (unlikely (!c->start_zerocopy (total_size)))
+ return false;
+
CFF1CharStrings *cs = c->start_embed<CFF1CharStrings> ();
if (unlikely (!cs)) return false;
- c->push ();
+
if (likely (cs->serialize (c, plan.subset_charstrings)))
- plan.info.char_strings_link = c->pop_pack ();
+ plan.info.char_strings_link = c->pop_pack (false);
else
{
c->pop_discard ();
@@ -815,7 +835,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
if (unlikely (!dest)) return false;
if (likely (dest->serialize (c, plan.subset_globalsubrs)))
- c->pop_pack ();
+ c->pop_pack (false);
else
{
c->pop_discard ();
diff --git a/thirdparty/harfbuzz/src/hb-subset-cff2.cc b/thirdparty/harfbuzz/src/hb-subset-cff2.cc
index 08e820efcf..60946b0281 100644
--- a/thirdparty/harfbuzz/src/hb-subset-cff2.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-cff2.cc
@@ -334,7 +334,7 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
if (unlikely (!dest)) return false;
c->push ();
if (likely (dest->serialize (c, plan.subset_localsubrs[i])))
- subrs_link = c->pop_pack ();
+ subrs_link = c->pop_pack (false);
else
{
c->pop_discard ();
@@ -361,11 +361,17 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
/* CharStrings */
{
+ c->push ();
+
+ unsigned total_size = CFF2CharStrings::total_size (plan.subset_charstrings);
+ if (unlikely (!c->start_zerocopy (total_size)))
+ return false;
+
CFF2CharStrings *cs = c->start_embed<CFF2CharStrings> ();
if (unlikely (!cs)) return false;
- c->push ();
+
if (likely (cs->serialize (c, plan.subset_charstrings)))
- plan.info.char_strings_link = c->pop_pack ();
+ plan.info.char_strings_link = c->pop_pack (false);
else
{
c->pop_discard ();
@@ -377,9 +383,10 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
if (acc.fdSelect != &Null (CFF2FDSelect))
{
c->push ();
- if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect, plan.orig_fdcount,
- plan.subset_fdselect_format, plan.subset_fdselect_size,
- plan.subset_fdselect_ranges)))
+ if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect,
+ plan.orig_fdcount,
+ plan.subset_fdselect_format, plan.subset_fdselect_size,
+ plan.subset_fdselect_ranges)))
plan.info.fd_select.link = c->pop_pack ();
else
{
@@ -401,7 +408,7 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
hb_iter (private_dict_infos))
;
if (unlikely (!fda->serialize (c, it, fontSzr))) return false;
- plan.info.fd_array_link = c->pop_pack ();
+ plan.info.fd_array_link = c->pop_pack (false);
}
/* variation store */
@@ -410,7 +417,7 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
c->push ();
CFF2VariationStore *dest = c->start_embed<CFF2VariationStore> ();
if (unlikely (!dest || !dest->serialize (c, acc.varStore))) return false;
- plan.info.var_store_link = c->pop_pack ();
+ plan.info.var_store_link = c->pop_pack (false);
}
OT::cff2 *cff2 = c->allocate_min<OT::cff2> ();
diff --git a/thirdparty/harfbuzz/src/hb-subset-input.cc b/thirdparty/harfbuzz/src/hb-subset-input.cc
index fd250104bb..42434ae0ef 100644
--- a/thirdparty/harfbuzz/src/hb-subset-input.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-input.cc
@@ -26,7 +26,7 @@
#include "hb-subset.hh"
#include "hb-set.hh"
-
+#include "hb-utf.hh"
/**
* hb_subset_input_create_or_fail:
*
@@ -49,8 +49,15 @@ hb_subset_input_create_or_fail (void)
set = hb_set_create ();
input->axes_location = hb_hashmap_create<hb_tag_t, float> ();
+#ifdef HB_EXPERIMENTAL_API
+ input->name_table_overrides = hb_hashmap_create<hb_ot_name_record_ids_t, hb_bytes_t> ();
+#endif
- if (!input->axes_location || input->in_error ())
+ if (!input->axes_location ||
+#ifdef HB_EXPERIMENTAL_API
+ !input->name_table_overrides ||
+#endif
+ input->in_error ())
{
hb_subset_input_destroy (input);
return nullptr;
@@ -248,6 +255,15 @@ hb_subset_input_destroy (hb_subset_input_t *input)
hb_hashmap_destroy (input->axes_location);
+#ifdef HB_EXPERIMENTAL_API
+ if (input->name_table_overrides)
+ {
+ for (auto _ : *input->name_table_overrides)
+ _.second.fini ();
+ }
+ hb_hashmap_destroy (input->name_table_overrides);
+#endif
+
hb_free (input);
}
@@ -379,7 +395,6 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input,
return hb_object_get_user_data (input, key);
}
-#ifdef HB_EXPERIMENTAL_API
#ifndef HB_NO_VAR
/**
* hb_subset_input_pin_axis_to_default: (skip)
@@ -388,9 +403,12 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input,
*
* Pin an axis to its default location in the given subset input object.
*
+ * Currently only works for fonts with 'glyf' tables. CFF and CFF2 is not
+ * yet supported. Additionally all axes in a font must be pinned.
+ *
* Return value: `true` if success, `false` otherwise
*
- * Since: EXPERIMENTAL
+ * Since: 6.0.0
**/
HB_EXTERN hb_bool_t
hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
@@ -412,9 +430,12 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
*
* Pin an axis to a fixed location in the given subset input object.
*
+ * Currently only works for fonts with 'glyf' tables. CFF and CFF2 is not
+ * yet supported. Additionally all axes in a font must be pinned.
+ *
* Return value: `true` if success, `false` otherwise
*
- * Since: EXPERIMENTAL
+ * Since: 6.0.0
**/
HB_EXTERN hb_bool_t
hb_subset_input_pin_axis_location (hb_subset_input_t *input,
@@ -430,28 +451,41 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
return input->axes_location->set (axis_tag, val);
}
#endif
-#endif
-#ifdef HB_EXPERIMENTAL_API
/**
- * hb_subset_preprocess
- * @input: a #hb_face_t object.
+ * hb_subset_preprocess:
+ * @source: a #hb_face_t object.
*
* Preprocesses the face and attaches data that will be needed by the
* subsetter. Future subsetting operations can then use the precomputed data
* to speed up the subsetting operation.
*
- * Since: EXPERIMENTAL
+ * See [subset-preprocessing](https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md)
+ * for more information.
+ *
+ * Note: the preprocessed face may contain sub-blobs that reference the memory
+ * backing the source #hb_face_t. Therefore in the case that this memory is not
+ * owned by the source face you will need to ensure that memory lives
+ * as long as the returned #hb_face_t.
+ *
+ * Returns: a new #hb_face_t.
+ *
+ * Since: 6.0.0
**/
HB_EXTERN hb_face_t *
hb_subset_preprocess (hb_face_t *source)
{
hb_subset_input_t* input = hb_subset_input_create_or_fail ();
+ if (!input)
+ return source;
hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE));
hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE));
+ hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_GLYPH_INDEX));
+ hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_GLYPH_INDEX));
+
hb_set_clear (hb_subset_input_set(input,
HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
hb_set_invert (hb_subset_input_set(input,
@@ -467,15 +501,100 @@ hb_subset_preprocess (hb_face_t *source)
hb_set_invert (hb_subset_input_set(input,
HB_SUBSET_SETS_NAME_ID));
+ hb_set_clear (hb_subset_input_set(input,
+ HB_SUBSET_SETS_NAME_LANG_ID));
+ hb_set_invert (hb_subset_input_set(input,
+ HB_SUBSET_SETS_NAME_LANG_ID));
+
hb_subset_input_set_flags(input,
HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
HB_SUBSET_FLAGS_GLYPH_NAMES |
- HB_SUBSET_FLAGS_RETAIN_GIDS);
+ HB_SUBSET_FLAGS_RETAIN_GIDS |
+ HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES);
input->attach_accelerator_data = true;
+ // Always use long loca in the preprocessed version. This allows
+ // us to store the glyph bytes unpadded which allows the future subset
+ // operation to run faster by skipping the trim padding step.
+ input->force_long_loca = true;
+
hb_face_t* new_source = hb_subset_or_fail (source, input);
hb_subset_input_destroy (input);
+ if (!new_source) {
+ DEBUG_MSG (SUBSET, nullptr, "Preprocessing failed due to subset failure.");
+ return source;
+ }
+
return new_source;
}
+
+#ifdef HB_EXPERIMENTAL_API
+/**
+ * hb_subset_input_override_name_table:
+ * @input: a #hb_subset_input_t object.
+ * @name_id: name_id of a nameRecord
+ * @platform_id: platform ID of a nameRecord
+ * @encoding_id: encoding ID of a nameRecord
+ * @language_id: language ID of a nameRecord
+ * @name_str: pointer to name string new value or null to indicate should remove
+ * @str_len: the size of @name_str, or -1 if it is `NULL`-terminated
+ *
+ * Override the name string of the NameRecord identified by name_id,
+ * platform_id, encoding_id and language_id. If a record with that name_id
+ * doesn't exist, create it and insert to the name table.
+ *
+ * Note: for mac platform, we only support name_str with all ascii characters,
+ * name_str with non-ascii characters will be ignored.
+ *
+ * Since: EXPERIMENTAL
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_override_name_table (hb_subset_input_t *input,
+ hb_ot_name_id_t name_id,
+ unsigned platform_id,
+ unsigned encoding_id,
+ unsigned language_id,
+ const char *name_str,
+ int str_len /* -1 means nul-terminated */)
+{
+ if (!name_str)
+ {
+ str_len = 0;
+ }
+ else if (str_len == -1)
+ {
+ str_len = strlen (name_str);
+ }
+
+ hb_bytes_t name_bytes (nullptr, 0);
+ if (str_len)
+ {
+ if (platform_id == 1)
+ {
+ const uint8_t *src = reinterpret_cast<const uint8_t*> (name_str);
+ const uint8_t *src_end = src + str_len;
+
+ hb_codepoint_t unicode;
+ const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
+ while (src < src_end)
+ {
+ src = hb_utf8_t::next (src, src_end, &unicode, replacement);
+ if (unicode >= 0x0080u)
+ {
+ printf ("Non-ascii character detected, ignored...This API supports acsii characters only for mac platform\n");
+ return false;
+ }
+ }
+ }
+ char *override_name = (char *) hb_malloc (str_len);
+ if (unlikely (!override_name)) return false;
+
+ hb_memcpy (override_name, name_str, str_len);
+ name_bytes = hb_bytes_t (override_name, str_len);
+ }
+ input->name_table_overrides->set (hb_ot_name_record_ids_t (platform_id, encoding_id, language_id, name_id), name_bytes);
+ return true;
+}
+
#endif
diff --git a/thirdparty/harfbuzz/src/hb-subset-input.hh b/thirdparty/harfbuzz/src/hb-subset-input.hh
index dabb4918fe..ecd47b7abf 100644
--- a/thirdparty/harfbuzz/src/hb-subset-input.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-input.hh
@@ -36,6 +36,48 @@
#include "hb-font.hh"
+struct hb_ot_name_record_ids_t
+{
+ hb_ot_name_record_ids_t () = default;
+ hb_ot_name_record_ids_t (unsigned platform_id_,
+ unsigned encoding_id_,
+ unsigned language_id_,
+ unsigned name_id_)
+ :platform_id (platform_id_),
+ encoding_id (encoding_id_),
+ language_id (language_id_),
+ name_id (name_id_) {}
+
+ bool operator != (const hb_ot_name_record_ids_t o) const
+ { return !(*this == o); }
+
+ inline bool operator == (const hb_ot_name_record_ids_t& o) const
+ {
+ return platform_id == o.platform_id &&
+ encoding_id == o.encoding_id &&
+ language_id == o.language_id &&
+ name_id == o.name_id;
+ }
+
+ inline uint32_t hash () const
+ {
+ uint32_t current = 0;
+ current = current * 31 + hb_hash (platform_id);
+ current = current * 31 + hb_hash (encoding_id);
+ current = current * 31 + hb_hash (language_id);
+ current = current * 31 + hb_hash (name_id);
+ return current;
+ }
+
+ unsigned platform_id;
+ unsigned encoding_id;
+ unsigned language_id;
+ unsigned name_id;
+};
+
+typedef struct hb_ot_name_record_ids_t hb_ot_name_record_ids_t;
+
+
HB_MARK_AS_FLAG_T (hb_subset_flags_t);
struct hb_subset_input_t
@@ -60,7 +102,14 @@ struct hb_subset_input_t
unsigned flags;
bool attach_accelerator_data = false;
+
+ // If set loca format will always be the long version.
+ bool force_long_loca = false;
+
hb_hashmap_t<hb_tag_t, float> *axes_location;
+#ifdef HB_EXPERIMENTAL_API
+ hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides;
+#endif
inline unsigned num_sets () const
{
@@ -80,7 +129,11 @@ struct hb_subset_input_t
return true;
}
- return axes_location->in_error ();
+ return axes_location->in_error ()
+#ifdef HB_EXPERIMENTAL_API
+ || name_table_overrides->in_error ()
+#endif
+ ;
}
};
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc
index 9cf7c9e431..71bc908ffb 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc
@@ -27,6 +27,7 @@
#include "hb-subset-plan.hh"
#include "hb-subset-accelerator.hh"
#include "hb-map.hh"
+#include "hb-multimap.hh"
#include "hb-set.hh"
#include "hb-ot-cmap-table.hh"
@@ -47,7 +48,7 @@ using OT::Layout::GPOS;
typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map;
#ifndef HB_NO_SUBSET_CFF
-static inline void
+static inline bool
_add_cff_seac_components (const OT::cff1::accelerator_t &cff,
hb_codepoint_t gid,
hb_set_t *gids_to_retain)
@@ -57,7 +58,9 @@ _add_cff_seac_components (const OT::cff1::accelerator_t &cff,
{
gids_to_retain->add (base_gid);
gids_to_retain->add (accent_gid);
+ return true;
}
+ return false;
}
#endif
@@ -82,10 +85,8 @@ static void
_remap_indexes (const hb_set_t *indexes,
hb_map_t *mapping /* OUT */)
{
- unsigned count = indexes->get_population ();
-
- for (auto _ : + hb_zip (indexes->iter (), hb_range (count)))
- mapping->set (_.first, _.second);
+ for (auto _ : + hb_enumerate (indexes->iter ()))
+ mapping->set (_.second, _.first);
}
@@ -344,7 +345,9 @@ _get_hb_font_with_variations (const hb_subset_plan_t *plan)
vars.push (var);
}
+#ifndef HB_NO_VAR
hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ());
+#endif
return font;
}
@@ -521,14 +524,44 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
cmap_unicodes = &plan->accelerator->unicodes;
}
- for (hb_codepoint_t cp : *cmap_unicodes)
+ if (plan->accelerator &&
+ unicodes->get_population () < cmap_unicodes->get_population () &&
+ glyphs->get_population () < cmap_unicodes->get_population ())
+ {
+ auto &gid_to_unicodes = plan->accelerator->gid_to_unicodes;
+ for (hb_codepoint_t gid : *glyphs)
+ {
+ auto unicodes = gid_to_unicodes.get (gid);
+
+ for (hb_codepoint_t cp : unicodes)
+ {
+ plan->codepoint_to_glyph->set (cp, gid);
+ plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+ }
+ }
+ for (hb_codepoint_t cp : *unicodes)
+ {
+ /* Don't double-add entry. */
+ if (plan->codepoint_to_glyph->has (cp))
+ continue;
+
+ hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
+ plan->codepoint_to_glyph->set (cp, gid);
+ plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+ }
+ plan->unicode_to_new_gid_list.qsort ();
+ }
+ else
{
- hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
- if (!unicodes->has (cp) && !glyphs->has (gid))
- continue;
+ for (hb_codepoint_t cp : *cmap_unicodes)
+ {
+ hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
+ if (!unicodes->has (cp) && !glyphs->has (gid))
+ continue;
- plan->codepoint_to_glyph->set (cp, gid);
- plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+ plan->codepoint_to_glyph->set (cp, gid);
+ plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+ }
}
/* Add gids which where requested, but not mapped in cmap */
@@ -639,9 +672,15 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
else
plan->_glyphset->union_ (cur_glyphset);
#ifndef HB_NO_SUBSET_CFF
- if (cff.is_valid ())
- for (hb_codepoint_t gid : cur_glyphset)
- _add_cff_seac_components (cff, gid, plan->_glyphset);
+ if (!plan->accelerator || plan->accelerator->has_seac)
+ {
+ bool has_seac = false;
+ if (cff.is_valid ())
+ for (hb_codepoint_t gid : cur_glyphset)
+ if (_add_cff_seac_components (cff, gid, plan->_glyphset))
+ has_seac = true;
+ plan->has_seac = has_seac;
+ }
#endif
_remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ());
@@ -848,9 +887,28 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
plan->check_success (plan->vmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
plan->check_success (plan->hmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
+#ifdef HB_EXPERIMENTAL_API
+ plan->check_success (plan->name_table_overrides = hb_hashmap_create<hb_ot_name_record_ids_t, hb_bytes_t> ());
+ if (plan->name_table_overrides && input->name_table_overrides)
+ {
+ for (auto _ : *input->name_table_overrides)
+ {
+ hb_bytes_t name_bytes = _.second;
+ unsigned len = name_bytes.length;
+ char *name_str = (char *) hb_malloc (len);
+ if (unlikely (!plan->check_success (name_str)))
+ break;
+
+ hb_memcpy (name_str, name_bytes.arrayZ, len);
+ plan->name_table_overrides->set (_.first, hb_bytes_t (name_str, len));
+ }
+ }
+#endif
+
void* accel = hb_face_get_user_data(face, hb_subset_accelerator_t::user_data_key());
plan->attach_accelerator_data = input->attach_accelerator_data;
+ plan->force_long_loca = input->force_long_loca;
if (accel)
plan->accelerator = (hb_subset_accelerator_t*) accel;
@@ -893,6 +951,28 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
hb_subset_plan_destroy (plan);
return nullptr;
}
+
+
+ if (plan->attach_accelerator_data)
+ {
+ hb_multimap_t gid_to_unicodes;
+
+ hb_map_t &unicode_to_gid = *plan->codepoint_to_glyph;
+
+ for (auto unicode : *plan->unicodes)
+ {
+ auto gid = unicode_to_gid[unicode];
+ gid_to_unicodes.add (gid, unicode);
+ }
+
+ plan->inprogress_accelerator =
+ hb_subset_accelerator_t::create (*plan->codepoint_to_glyph,
+ gid_to_unicodes,
+ *plan->unicodes,
+ plan->has_seac);
+ }
+
+
return plan;
}
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.hh b/thirdparty/harfbuzz/src/hb-subset-plan.hh
index 15fabba9c3..1b2aee7825 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.hh
@@ -87,6 +87,18 @@ struct hb_subset_plan_t
hb_hashmap_destroy (vmtx_map);
hb_hashmap_destroy (layout_variation_idx_delta_map);
+#ifdef HB_EXPERIMENTAL_API
+ if (name_table_overrides)
+ {
+ for (auto _ : *name_table_overrides)
+ _.second.fini ();
+ }
+ hb_hashmap_destroy (name_table_overrides);
+#endif
+
+ if (inprogress_accelerator)
+ hb_subset_accelerator_t::destroy ((void*) inprogress_accelerator);
+
if (user_axes_location)
{
hb_object_destroy (user_axes_location);
@@ -99,10 +111,11 @@ struct hb_subset_plan_t
bool successful;
unsigned flags;
bool attach_accelerator_data = false;
+ bool force_long_loca = false;
// For each cp that we'd like to retain maps to the corresponding gid.
hb_set_t *unicodes;
- hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> unicode_to_new_gid_list;
+ hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> unicode_to_new_gid_list;
// name_ids we would like to retain
hb_set_t *name_ids;
@@ -185,31 +198,41 @@ struct hb_subset_plan_t
hb_map_t *axes_old_index_tag_map;
bool all_axes_pinned;
bool pinned_at_default;
+ bool has_seac;
//hmtx metrics map: new gid->(advance, lsb)
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *hmtx_map;
//vmtx metrics map: new gid->(advance, lsb)
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *vmtx_map;
+#ifdef HB_EXPERIMENTAL_API
+ // name table overrides map: hb_ot_name_record_ids_t-> name string new value or
+ // None to indicate should remove
+ hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides;
+#endif
+
const hb_subset_accelerator_t* accelerator;
+ hb_subset_accelerator_t* inprogress_accelerator;
public:
template<typename T>
hb_blob_ptr_t<T> source_table()
{
- if (sanitized_table_cache
- && !sanitized_table_cache->in_error ()
- && sanitized_table_cache->has (T::tableTag)) {
- return hb_blob_reference (sanitized_table_cache->get (T::tableTag).get ());
+ hb_lock_t (accelerator ? &accelerator->sanitized_table_cache_lock : nullptr);
+
+ auto *cache = accelerator ? &accelerator->sanitized_table_cache : sanitized_table_cache;
+ if (cache
+ && !cache->in_error ()
+ && cache->has (+T::tableTag)) {
+ return hb_blob_reference (cache->get (+T::tableTag).get ());
}
hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (source)};
hb_blob_t* ret = hb_blob_reference (table_blob.get ());
- if (likely (sanitized_table_cache))
- sanitized_table_cache->set (T::tableTag,
- std::move (table_blob));
+ if (likely (cache))
+ cache->set (+T::tableTag, std::move (table_blob));
return ret;
}
diff --git a/thirdparty/harfbuzz/src/hb-subset.cc b/thirdparty/harfbuzz/src/hb-subset.cc
index 6026aa6eff..186b12dbb8 100644
--- a/thirdparty/harfbuzz/src/hb-subset.cc
+++ b/thirdparty/harfbuzz/src/hb-subset.cc
@@ -82,6 +82,10 @@ using OT::Layout::GPOS;
* retain glyph ids option and configure the subset to pass through the layout tables untouched.
*/
+
+hb_user_data_key_t _hb_subset_accelerator_user_data_key = {};
+
+
/*
* The list of tables in the open type spec. Used to check for tables that may need handling
* if we are unable to list the tables in a face.
@@ -409,20 +413,14 @@ _passthrough (hb_subset_plan_t *plan, hb_tag_t tag)
static bool
_dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag,
- hb_set_t &visited_set, hb_set_t &revisit_set)
+ const hb_set_t &subsetted_tags,
+ const hb_set_t &pending_subset_tags)
{
switch (tag)
{
case HB_OT_TAG_hmtx:
case HB_OT_TAG_vmtx:
- if (!plan->pinned_at_default &&
- !visited_set.has (HB_OT_TAG_glyf))
- {
- revisit_set.add (tag);
- return false;
- }
- return true;
-
+ return plan->pinned_at_default || !pending_subset_tags.has (HB_OT_TAG_glyf);
default:
return true;
}
@@ -495,12 +493,14 @@ _subset_table (hb_subset_plan_t *plan,
}
}
-static void _attach_accelerator_data (const hb_subset_plan_t* plan,
+static void _attach_accelerator_data (hb_subset_plan_t* plan,
hb_face_t* face /* IN/OUT */)
{
- hb_subset_accelerator_t* accel =
- hb_subset_accelerator_t::create (*plan->codepoint_to_glyph,
- *plan->unicodes);
+ if (!plan->inprogress_accelerator) return;
+
+ // Transfer the accelerator from the plan to us.
+ hb_subset_accelerator_t* accel = plan->inprogress_accelerator;
+ plan->inprogress_accelerator = nullptr;
if (accel->in_error ())
{
@@ -508,6 +508,11 @@ static void _attach_accelerator_data (const hb_subset_plan_t* plan,
return;
}
+ // Populate caches that need access to the final tables.
+ hb_blob_ptr_t<OT::cmap> cmap_ptr (hb_sanitize_context_t ().reference_table<OT::cmap> (face));
+ accel->cmap_cache = OT::cmap::create_filled_cache (cmap_ptr);
+ accel->destroy_cmap_cache = OT::SubtableUnicodesCache::destroy;
+
if (!hb_face_set_user_data(face,
hb_subset_accelerator_t::user_data_key(),
accel,
@@ -561,41 +566,63 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
return nullptr;
}
- hb_set_t tags_set, revisit_set;
- bool success = true;
hb_tag_t table_tags[32];
unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags);
- hb_vector_t<char> buf;
- buf.alloc (4096 - 16);
+ hb_set_t subsetted_tags, pending_subset_tags;
while (((void) _get_table_tags (plan, offset, &num_tables, table_tags), num_tables))
{
for (unsigned i = 0; i < num_tables; ++i)
{
hb_tag_t tag = table_tags[i];
- if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue;
- if (!_dependencies_satisfied (plan, tag, tags_set, revisit_set)) continue;
- tags_set.add (tag);
- success = _subset_table (plan, buf, tag);
- if (unlikely (!success)) goto end;
+ if (_should_drop_table (plan, tag)) continue;
+ pending_subset_tags.add (tag);
+ }
+
+ offset += num_tables;
+ }
+
+ hb_vector_t<char> buf;
+ buf.alloc (4096 - 16);
+
+
+ bool success = true;
+
+ while (!pending_subset_tags.is_empty ())
+ {
+ if (subsetted_tags.in_error ()
+ || pending_subset_tags.in_error ()) {
+ success = false;
+ goto end;
}
- /*delayed subsetting for some tables since they might have dependency on other tables in some cases:
- e.g: during instantiating glyf tables, hmetrics/vmetrics are updated and saved in subset plan,
- hmtx/vmtx subsetting need to use these updated metrics values*/
- while (!revisit_set.is_empty ())
+ bool made_changes = false;
+ for (hb_tag_t tag : pending_subset_tags)
{
- hb_set_t revisit_temp;
- for (hb_tag_t tag : revisit_set)
+ if (!_dependencies_satisfied (plan, tag,
+ subsetted_tags,
+ pending_subset_tags))
{
- if (!_dependencies_satisfied (plan, tag, tags_set, revisit_temp)) continue;
- tags_set.add (tag);
- success = _subset_table (plan, buf, tag);
- if (unlikely (!success)) goto end;
+ // delayed subsetting for some tables since they might have dependency on other tables
+ // in some cases: e.g: during instantiating glyf tables, hmetrics/vmetrics are updated
+ // and saved in subset plan, hmtx/vmtx subsetting need to use these updated metrics values
+ continue;
}
- revisit_set = revisit_temp;
+
+ pending_subset_tags.del (tag);
+ subsetted_tags.add (tag);
+ made_changes = true;
+
+ success = _subset_table (plan, buf, tag);
+ if (unlikely (!success)) goto end;
+ }
+
+ if (!made_changes)
+ {
+ DEBUG_MSG (SUBSET, nullptr, "Table dependencies unable to be satisfied. Subset failed.");
+ success = false;
+ goto end;
}
- offset += num_tables;
}
if (success && plan->attach_accelerator_data) {
diff --git a/thirdparty/harfbuzz/src/hb-subset.h b/thirdparty/harfbuzz/src/hb-subset.h
index 6a2c5f6114..b83264ea5e 100644
--- a/thirdparty/harfbuzz/src/hb-subset.h
+++ b/thirdparty/harfbuzz/src/hb-subset.h
@@ -28,6 +28,7 @@
#define HB_SUBSET_H
#include "hb.h"
+#include "hb-ot.h"
HB_BEGIN_DECLS
@@ -164,8 +165,6 @@ HB_EXTERN void
hb_subset_input_set_flags (hb_subset_input_t *input,
unsigned value);
-#ifdef HB_EXPERIMENTAL_API
-#ifndef HB_NO_VAR
HB_EXTERN hb_bool_t
hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
hb_face_t *face,
@@ -176,16 +175,22 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
hb_face_t *face,
hb_tag_t axis_tag,
float axis_value);
-#endif
-#endif
#ifdef HB_EXPERIMENTAL_API
+HB_EXTERN hb_bool_t
+hb_subset_input_override_name_table (hb_subset_input_t *input,
+ hb_ot_name_id_t name_id,
+ unsigned platform_id,
+ unsigned encoding_id,
+ unsigned language_id,
+ const char *name_str,
+ int str_len);
+
+#endif
HB_EXTERN hb_face_t *
hb_subset_preprocess (hb_face_t *source);
-#endif
-
HB_EXTERN hb_face_t *
hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
diff --git a/thirdparty/harfbuzz/src/hb-ucd-table.hh b/thirdparty/harfbuzz/src/hb-ucd-table.hh
index a372a4afce..f7d76eee18 100644
--- a/thirdparty/harfbuzz/src/hb-ucd-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ucd-table.hh
@@ -1069,7 +1069,7 @@ _hb_ucd_dm2_u64_map[388] =
#ifndef HB_OPTIMIZE_SIZE
static const uint8_t
-_hb_ucd_u8[18260] =
+_hb_ucd_u8[17868] =
{
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 11, 12, 13, 13, 13, 14,
@@ -1535,191 +1535,166 @@ _hb_ucd_u8[18260] =
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0,
0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 40, 41, 42, 0, 43, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0,
- 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 0,
- 9, 0, 10, 11, 0, 0, 12, 13, 14, 15, 16, 0, 0, 0, 0, 17,
- 18, 19, 20, 0, 21, 0, 22, 23, 0, 24, 25, 0, 0, 24, 26, 27,
- 0, 24, 26, 0, 0, 24, 26, 0, 0, 24, 26, 0, 0, 0, 26, 0,
- 0, 24, 28, 0, 0, 24, 26, 0, 0, 29, 26, 0, 0, 0, 30, 0,
- 0, 31, 32, 0, 0, 33, 34, 0, 35, 36, 0, 37, 38, 0, 39, 0,
- 0, 40, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, 0, 0, 45, 0,
- 0, 0, 0, 0, 0, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0,
- 48, 0, 0, 49, 0, 50, 51, 0, 0, 52, 53, 54, 0, 55, 0, 56,
- 0, 57, 0, 0, 0, 0, 58, 59, 0, 0, 0, 0, 0, 0, 60, 61,
- 0, 0, 0, 0, 0, 0, 62, 63, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 66,
- 0, 67, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 69, 70, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0,
- 72, 73, 0, 0, 0, 0, 53, 74, 0, 75, 76, 0, 0, 77, 78, 0,
- 0, 0, 0, 0, 0, 79, 80, 81, 0, 0, 0, 0, 0, 0, 0, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0,
- 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84,
- 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 86, 0, 0, 0, 0,
- 87, 88, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 91, 0, 92, 0, 0, 93, 0, 94, 0, 0, 0,
- 0, 0, 72, 95, 0, 96, 0, 0, 97, 98, 0, 77, 0, 0, 99, 0,
- 0,100, 0, 0, 0, 0, 0,101, 0,102, 26,103, 0, 0, 0, 0,
- 0, 0,104, 0, 0, 0,105, 0, 0, 0, 0, 0, 0, 65,106, 0,
- 0, 65, 0, 0, 0,107, 0, 0, 0,108, 0, 0, 0, 0, 0, 0,
- 0, 96, 0, 0, 0, 0, 0, 0, 0,109,110, 0, 0, 0, 0, 78,
- 0, 44,111, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 65, 0, 0, 0, 0, 0, 0, 0, 0,113, 0,114, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,116, 0,117, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,
- 0, 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,121,122, 0, 0,
- 0, 0,123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 124,125, 0, 0,126, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,127, 0,128, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,129, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,130, 0, 0, 0,131, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4,
- 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17,
- 18, 1, 1, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28,
- 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 31, 0,
- 0, 0, 32, 33, 34, 35, 1, 36, 0, 0, 0, 0, 37, 0, 0, 0,
- 0, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, 0, 0, 0, 0,
- 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 43, 36, 44, 45,
- 21, 45, 46, 0, 0, 0, 0, 0, 0, 0, 19, 1, 21, 0, 0, 47,
- 0, 0, 0, 0, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 52, 1,
- 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1,
- 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0,
- 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59,
- 0, 0, 0, 56, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 61, 62,
- 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0,
- 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0,
- 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0,
- 0, 0, 0, 0, 0, 69, 70, 0, 0, 0, 0, 0, 71, 72, 73, 74,
- 75, 76, 0, 0, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 80, 0, 0,
- 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 63, 0, 0, 81,
- 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0,
- 0, 0, 0, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85,
- 0, 0, 0, 0, 1, 52, 15, 86, 36, 10, 21, 87, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 55, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0,
- 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0,
- 0, 89, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0,
- 0, 0, 0, 0, 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0,
- 21, 1, 21, 92, 93, 1, 1, 1, 1, 1, 1, 1, 1, 94, 95, 96,
- 0, 0, 0, 0, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0,
- 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61,
- 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,101,102, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,103, 0, 0, 0, 0, 19, 0, 1, 1, 50,
- 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 50, 0, 0, 0,
- 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0,
- 1, 1, 1, 1, 50, 0, 0, 0, 0, 0,104, 68, 0, 0, 0, 0,
- 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0,
- 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105,106, 58, 38,
- 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 47, 84, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,109, 61, 0,110, 0, 0, 0, 0, 0, 0,
- 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 19, 58, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 51, 0,111, 14, 52, 84, 0, 0, 0,
- 112, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 61,
- 0, 0, 0, 0, 0, 0,113, 0, 87, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 78, 55, 0, 38, 1, 58, 1, 58, 0, 0,
- 63, 89, 0, 0, 0, 0, 0, 59,115, 0, 0, 0, 0, 0, 0, 0,
- 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115, 0, 0,
- 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79,
- 78, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 61, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 8, 91, 0, 0, 0, 0, 0, 0, 1, 87, 0, 0,
- 0, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117,
- 0,118,119,120,121, 0,104, 4,122, 49, 23, 0, 0, 0, 0, 0,
- 0, 0, 38, 50, 0, 0, 0, 0, 38, 58, 0, 0, 0, 0, 0, 0,
- 1, 87, 1, 1, 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 0,
- 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0,
- 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,123, 0, 0, 0, 0,
- 0, 0, 0, 0, 4,122, 0, 0, 0, 1,124, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,230,230,230,230,230,232,220,220,220,220,232,216,
- 220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,
- 1, 1, 1, 1, 1,220,220,220,220,230,230,230,230,240,230,220,
- 220,220,230,230,230,220,220, 0,230,230,230,220,220,220,220,230,
- 232,220,220,230,233,234,234,233,234,234,233,230, 0, 0, 0,230,
- 0,220,230,230,230,230,220,230,230,230,222,220,230,230,220,220,
- 230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20,
- 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0,
- 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,
- 220,230,230,220, 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230,
- 230, 0,220,230,230,220, 0, 0, 0, 36, 0, 0,230,220,230,230,
- 220,220,230,220,220,230,220,230,220,230,230, 0, 0,220, 0, 0,
- 230,230, 0,230, 0,230,230,230,230,230, 0, 0, 0,220,220,220,
- 230,220,220,220,230,230, 0,220, 27, 28, 29,230, 7, 0, 0, 0,
- 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0,230, 0,
- 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 9, 0,
- 103,103, 9, 0,107,107,107,107,118,118, 9, 0,122,122,122,122,
- 220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0,
- 132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230,
- 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7, 0, 9, 9, 0,
- 9, 9, 0, 0, 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220,
- 220, 0, 0, 0,230, 0, 0,220,230,220, 0,220,230,230,230, 0,
- 0, 0, 9, 9, 0, 0, 7, 0,230, 0, 1, 1, 1, 0, 0, 0,
- 230,234,214,220,202,230,230,230,230,230,232,228,228,220,218,230,
- 233,220,230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,
- 220,230, 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0,
- 0, 0, 0,220,230, 0,230,230,220, 0, 0,230, 0, 0, 26, 0,
- 0,220, 0,230,230, 1,220, 0, 0,230,220, 0, 0, 0,220,220,
- 0, 0,230,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 9, 7,
- 6, 6, 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0,
- 0,226,216,216,216,216,216, 0,220,220,220, 0,232,232,220,230,
- 230,230, 7, 0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19,
- 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0,
+ 0, 0, 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, 0, 11,
+ 12, 13, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, 0, 19,
+ 16, 20, 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, 0, 0,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, 0, 48,
+ 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 52,
+ 53, 0, 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0,
+ 58, 0, 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, 0, 66,
+ 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 0,
+ 72, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0,
+ 0, 0, 75, 76, 0, 77, 78, 0, 0, 79, 80, 0, 81, 62, 0, 82,
+ 83, 0, 0, 84, 85, 86, 0, 0, 0, 87, 0, 88, 0, 0, 51, 89,
+ 51, 0, 90, 0, 91, 0, 0, 0, 80, 0, 0, 0, 92, 93, 0, 94,
+ 95, 96, 97, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 98, 99, 0,
+ 0, 0, 0, 0, 0,100, 0, 0, 0, 0, 0,101,102, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,103, 0, 0,104, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,105,106, 0, 0,107, 0, 0, 0, 0, 0, 0,
+ 108, 0,109, 0,102, 0, 0, 0, 0, 0,110,111, 0, 0, 0, 0,
+ 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0,113, 0,114, 0, 0,
+ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, 0, 0,
+ 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, 0, 16,
+ 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, 22, 23,
+ 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, 28, 29, 30, 31,
+ 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, 0, 0,
+ 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39,
+ 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, 0, 44,
+ 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48,
+ 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, 0, 0,
+ 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, 57, 58,
+ 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, 52, 0, 62, 63,
+ 0, 0, 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, 0, 68, 69, 70,
+ 71, 72, 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, 0, 0, 0, 79,
+ 0, 0, 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, 0, 0, 77, 82,
+ 0, 83, 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, 52, 0, 1, 78,
+ 0, 0, 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, 57, 0, 0, 0,
+ 0, 0, 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, 0, 91, 0, 0,
+ 0, 0, 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, 0, 0, 0, 94,
+ 95, 0, 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99, 0,
+ 0, 0, 0,100,101, 93, 0, 0,102, 0, 0, 0, 84, 0, 0,103,
+ 0, 0, 0,104,105, 0, 0,106,107, 0, 0, 0, 0, 0, 0,108,
+ 0, 0,109, 0, 0, 0, 0,110, 33, 0,111,112,113, 35, 0, 0,
+ 114, 0, 0, 0,115, 0, 0, 0, 0, 0, 0,116, 0, 0,117, 0,
+ 0, 0, 0,118, 88, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,
+ 119, 0, 0, 0, 0,120, 0, 0,121, 0, 0, 0, 0,119, 0, 0,
+ 122, 0, 0, 0, 0, 0, 0,123, 0, 0, 0,124, 0, 0, 0,125,
+ 0,126, 0, 0, 0, 0,127,128,129, 0,130, 0,131, 0, 0, 0,
+ 132,133,134, 0, 77, 0, 0, 0, 0, 0, 35, 0, 0, 0,135, 0,
+ 0, 0,136, 0, 0,137, 0, 0,138, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10,
+ 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 19, 1, 0, 0,
+ 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0,
+ 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, 37, 0, 0, 0,
+ 0, 38, 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, 43, 36, 44, 45,
+ 21, 45, 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, 0, 38, 48, 1,
+ 1, 49, 49, 50, 0, 0, 51, 0, 0, 0, 52, 1, 0, 0, 38, 14,
+ 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 55,
+ 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, 0, 60, 0, 0,
+ 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 65, 0,
+ 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 69, 70, 0,
+ 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, 0, 78, 79, 0,
+ 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, 0, 62, 0, 0,
+ 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0,
+ 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, 36, 10, 21, 87,
+ 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0,
+ 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 87, 9, 12, 4,
+ 90, 8, 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1,
+ 1, 94, 95, 96, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0,
+ 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,101,102,
+ 0, 0,103, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0,
+ 0, 0, 0, 62, 0, 0,104, 68, 61, 0, 0, 0, 78, 0, 0, 0,
+ 105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12,
+ 84, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0,109, 61,
+ 0,110, 0, 0, 0, 1, 0, 0, 0, 0, 19, 58, 0, 0, 0, 51,
+ 0,111, 14, 52,112, 41, 0, 0, 62, 0, 0, 61, 0, 0,113, 0,
+ 87, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0,113, 0, 0,
+ 0, 0,114, 0, 0, 0, 78, 55, 0, 38, 1, 58, 1, 58, 0, 0,
+ 63, 89, 0, 0,115, 0, 0, 0, 55, 0, 0, 0, 0,115, 0, 0,
+ 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, 0, 0, 0, 0, 56, 0,
+ 89, 80, 0, 0, 79, 0, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0,
+ 116, 0, 0, 0, 0, 0, 0,117, 0,118,119,120,121, 0,104, 4,
+ 122, 49, 23, 0, 0, 0, 38, 50, 38, 58, 0, 0, 1, 87, 1, 1,
+ 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 1, 0, 0, 0,123,
+ 4,122, 0, 0, 0, 1,124, 0, 0, 0, 0, 0,230,230,230,230,
+ 230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220,
+ 220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220,
+ 220,230,230,230,230,240,230,220,220,220,230,230,230,220,220, 0,
+ 230,230,230,220,220,220,220,230,232,220,220,230,233,234,234,233,
+ 234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230,220,230,
+ 230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,
+ 230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31,
+ 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0, 0, 0,
+ 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220, 0, 0,
+ 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230,220,230,
+ 220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,230,230,
+ 230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230, 0,220,
+ 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,
+ 230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9,
+ 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,107,107,
+ 118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220, 0,220,
+ 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,
+ 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,220, 0,
+ 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0,
+ 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, 0,220,
+ 230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0,
+ 230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,230,230,
+ 230,230,232,228,228,220,218,230,233,220,230,220,230,230, 1, 1,
+ 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228,
+ 232,222,224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230,
+ 220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0,
+ 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0,
+ 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0,
+ 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,
+ 220,220,220, 0,232,232,220,230,230,230, 7, 0, 16, 17, 17, 17,
+ 17, 17, 17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,
+ 129,169, 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17,237, 0, 1, 2, 2, 0, 3, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 5, 0, 0, 0, 0, 6, 7, 8, 9, 0, 0, 0, 10, 11, 12, 13,
- 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
- 0, 0, 21, 22, 0, 0, 0, 0, 23, 24, 25, 26, 0, 27, 0, 28,
- 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, 36, 0,
- 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39,
- 0, 0, 0, 0, 1, 2, 40, 41, 0, 1, 2, 2, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
- 0, 0, 3, 4, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0,
- 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0,
- 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 11, 12,
- 0, 13, 0, 14, 15, 16, 0, 0, 0, 0, 0, 1, 17, 18, 0, 19,
- 7, 1, 0, 0, 0, 20, 20, 7, 20, 20, 20, 20, 20, 20, 20, 8,
- 21, 0, 22, 0, 7, 23, 24, 0, 20, 20, 25, 0, 0, 0, 26, 27,
- 1, 7, 20, 20, 20, 20, 20, 1, 28, 29, 30, 31, 0, 0, 20, 0,
- 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 20, 20,
- 20, 1, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, 7, 20, 20, 20,
- 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, 38, 1, 20, 20,
- 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, 0, 0, 1, 0,
- 0, 40, 1, 1, 0, 0, 8, 21, 0, 1, 0, 1, 0, 1, 0, 0,
- 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 7, 20, 41,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, 43, 44, 0, 45,
- 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 46, 7, 1, 10, 1,
- 0, 0, 0, 1, 20, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 26, 34, 9, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0,
- 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 3, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3,
- 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24, 25, 26, 13, 13,
- 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42, 7, 7, 43, 7,
- 44, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2,
+ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8,
+ 9, 0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0,
+ 23, 24, 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0,
+ 0, 0, 0, 33, 34, 35, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 1, 2, 40, 41,
+ 0, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0,
+ 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0,
+ 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10,
+ 0, 0, 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0,
+ 0, 0, 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7,
+ 20, 20, 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0,
+ 20, 20, 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1,
+ 28, 29, 30, 31, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0,
+ 0, 0, 0, 0, 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4,
+ 0, 10, 0, 33, 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35,
+ 36, 34, 37, 0, 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8,
+ 21, 1, 20, 0, 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21,
+ 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 21, 0, 42, 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0,
+ 0, 0, 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 20, 20,
+ 1, 20, 20, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 12, 13,
+ 13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 13, 22, 13, 13, 13,
+ 13, 23, 24, 24, 25, 26, 13, 13, 13, 27, 28, 29, 13, 30, 31, 32,
+ 33, 34, 35, 36, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7,
+ 7, 41, 13, 42, 7, 7, 43, 7, 44, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
@@ -1740,420 +1715,420 @@ _hb_ucd_u8[18260] =
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45, 0, 0, 1,
- 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, 53, 54, 55, 56,
- 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61,
- 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
- 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 45, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 37,
+ 37, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 2, 2, 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59,
+ 59, 59, 59, 59, 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 80, 80,
- 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84, 85, 86, 87, 88,
- 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 79, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81,
+ 82, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 70, 70, 97, 98, 99,100,101,101,102,103,104,105,106,107,108,109,
- 110,111, 96,112,113,114,115,116,117,118,119,119,120,121,122,123,
- 124,125,126,127,128,129,130,131,132, 96,133,134,135,136,137,138,
- 139,140,141,142,143, 96,144,145, 96,146,147,148,149, 96,150,151,
- 152,153,154,155,156, 96,157,158,159,160, 96,161,162,163,164,164,
- 164,164,164,164,164,165,166,164,167, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,168,169,169,
- 169,169,169,169,169,169,170, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96,171,171,171,171,172, 96, 96, 96,173,173,
- 173,173,174,175,176,177, 96, 96, 96, 96,178,179,180,181,182,182,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, 97, 98, 99,100,101,101,
+ 102,103,104,105,106,107,108,109,110,111, 96,112,113,114,115,116,
+ 117,118,119,119,120,121,122,123,124,125,126,127,128,129,130,131,
+ 132, 96,133,134,135,136,137,138,139,140,141,142,143, 96,144,145,
+ 96,146,147,148,149, 96,150,151,152,153,154,155,156, 96,157,158,
+ 159,160, 96,161,162,163,164,164,164,164,164,164,164,165,166,164,
+ 167, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96,168,169,169,169,169,169,169,169,169,170, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,171,171,
+ 171,171,172, 96, 96, 96,173,173,173,173,174,175,176,177, 96, 96,
+ 96, 96,178,179,180,181,182,182,182,182,182,182,182,182,182,182,
182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
- 182,182,182,182,182,182,182,182,182,182,182,182,182,183,182,182,
- 182,182,182,182,184,184,184,185,186, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,187,188,189,
- 190,191,191,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96,193,194, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,195,196, 59,197,
- 198,199,200,201,202, 96,203,204,205, 59, 59,206, 59,207,208,208,
- 208,208,208,209, 96, 96, 96, 96, 96, 96, 96, 96,210, 96,211,212,
- 213, 96, 96,214, 96, 96, 96,215, 96, 96, 96, 96, 96,216,217,218,
- 219, 96, 96, 96, 96, 96,220,221,222, 96,223,224, 96, 96,225,226,
- 59,227,228, 96, 59, 59, 59, 59, 59, 59, 59,229,230,231,232,233,
- 59, 59,234,235, 59,236, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,237, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,238, 70,239, 70,
+ 182,182,182,182,182,183,182,182,182,182,182,182,184,184,184,185,
+ 186, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96,187,188,189,190,191,191,192, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,193,194,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96,195,196, 59,197,198,199,200,201,202, 96,203,204,
+ 205, 59, 59,206, 59,207,208,208,208,208,208,209, 96, 96, 96, 96,
+ 96, 96, 96, 96,210, 96,211,212,213, 96, 96,214, 96, 96, 96,215,
+ 96, 96, 96, 96, 96,216,217,218,219, 96, 96, 96, 96, 96,220,221,
+ 222, 96,223,224, 96, 96,225,226, 59,227,228, 96, 59, 59, 59, 59,
+ 59, 59, 59,229,230,231,232,233, 59, 59,234,235, 59,236, 96, 96,
+ 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70,237, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70,238, 70,239, 70, 70, 70, 70, 70, 70, 70, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,240, 70, 70, 70, 70,
- 70, 70, 70, 70, 70,241, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
- 70, 70,242, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
- 70, 70, 70, 70,243, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70,244, 96, 96, 96, 96, 96, 96, 96, 96,245, 96,
- 246,247, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0,
- 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 0, 19, 0,
- 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0,
- 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9,
- 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2,
- 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9,
- 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4, 4, 4, 2, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2,
- 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14,
- 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3,
- 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3,
- 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90,
- 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90,
- 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
- 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2, 2, 2, 3, 3,
- 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3,
- 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1,
- 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 5, 5,
- 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2,
- 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
- 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5,
- 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 2, 2, 2,
- 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 5, 5, 5,
- 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 11,
- 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2,
- 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2,
- 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11,
- 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11, 2, 2, 2, 11,
- 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, 11, 2, 2, 2,
- 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 10,
- 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10,
- 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2,
- 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10,
- 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 2, 2, 10, 2,
- 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10,
- 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 2, 21,
- 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2,
- 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2,
- 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21,
- 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 2, 2, 2, 2,
- 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21,
- 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22,
- 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22,
- 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 22, 22, 22, 2,
- 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22,
- 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23,
- 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 2,
- 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 23, 2, 2, 23, 23,
- 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16,
- 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2,
- 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 2, 16,
- 16, 16, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 2, 2,
- 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, 36,
- 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36,
- 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2,
- 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2,
- 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2, 2, 2, 2, 18,
- 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18,
- 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18,
- 18, 18, 18, 18, 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25,
- 25, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 2, 2, 2, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25,
- 25, 25, 25, 0, 0, 0, 0, 25, 25, 2, 2, 2, 2, 2, 33, 33,
- 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 2, 8, 2, 2, 2, 2, 2, 8, 2, 2, 8, 8,
- 8, 0, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30,
- 30, 30, 30, 30, 30, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30,
- 30, 30, 30, 2, 2, 2, 30, 30, 2, 2, 2, 2, 2, 2, 29, 29,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28,
- 28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 0, 0, 0, 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45,
- 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
- 44, 44, 44, 0, 0, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 2, 2, 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 2, 2, 31, 31,
- 2, 2, 2, 2, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, 2,
- 2, 2, 2, 2, 2, 2, 32, 32, 32, 2, 2, 2, 2, 2, 28, 28,
- 28, 28, 28, 28, 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 2, 48, 48, 48, 48, 2, 2, 2, 2, 48, 2,
- 2, 2, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 2, 2, 2, 2, 58, 58,
- 2, 2, 2, 2, 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54,
- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91,
- 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91,
- 91, 91, 91, 2, 2, 91, 91, 91, 2, 2, 2, 2, 2, 2, 91, 91,
- 91, 91, 91, 91, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 62, 62,
- 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 2, 2, 2, 62, 62,
- 62, 62, 62, 62, 62, 2, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93,
- 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2,
- 2, 2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2,
- 2, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 73, 73,
- 73, 73, 73, 73, 73, 73, 6, 2, 2, 2, 2, 2, 2, 2, 8, 8,
- 8, 2, 2, 8, 8, 8, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0,
- 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
- 0, 0, 1, 0, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 19, 19,
- 19, 19, 19, 19, 9, 9, 9, 9, 9, 6, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9,
- 9, 19, 19, 19, 19, 19, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 9, 9, 9, 9, 9, 9, 9, 2, 2, 2, 9,
- 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9,
- 9, 9, 2, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2,
- 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0,
- 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 19,
- 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0,
- 0, 0, 0, 0, 0, 2, 19, 19, 19, 19, 19, 2, 2, 2, 0, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0,
- 0, 0, 0, 0, 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 0, 0,
- 0, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0,
- 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 56, 56,
- 56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55,
- 55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2,
- 2, 2, 2, 2, 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 0, 0,
- 0, 0, 0, 0, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 13, 13,
- 13, 13, 13, 13, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0,
- 0, 0, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 1, 1, 1, 1, 12, 12, 13, 13, 13, 13, 0, 0, 0, 0, 2, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 0, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 12, 0, 17, 17,
- 17, 17, 17, 17, 17, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 86, 86,
- 86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
- 77, 77, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0,
- 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19,
- 19, 2, 2, 2, 2, 2, 19, 19, 2, 19, 2, 19, 19, 19, 19, 19,
- 2, 2, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 60, 60,
- 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 2, 2, 2, 0, 0,
- 2, 2, 2, 2, 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 75, 75,
- 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2,
- 2, 2, 2, 2, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 0, 69, 74, 74,
- 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84,
- 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84,
- 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 2, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68,
- 68, 68, 68, 68, 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92,
- 92, 92, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2,
- 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 2, 2, 30, 30, 30, 30, 30, 30, 2, 19, 19,
- 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19,
- 0, 0, 2, 2, 2, 2, 87, 87, 87, 87, 87, 87, 2, 2, 87, 87,
- 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2,
- 2, 12, 12, 12, 12, 12, 13, 13, 2, 2, 2, 2, 2, 2, 19, 19,
- 19, 19, 19, 19, 19, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2,
- 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14,
- 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, 3,
- 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 0, 0, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2,
- 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 6, 6, 0, 0,
- 0, 2, 0, 0, 0, 0, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3,
- 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, 2,
- 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 2, 2, 2, 2, 0,
- 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49,
- 49, 2, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 2, 2, 49, 49,
- 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0,
- 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 71, 71,
- 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67,
- 67, 67, 67, 67, 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 1, 0,
- 0, 0, 0, 0, 0, 0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
- 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 42, 42, 41, 41,
- 41, 41, 41, 41, 41, 41, 41, 41, 41, 2, 2, 2, 2, 2,118,118,
- 118,118,118,118,118,118,118,118,118, 2, 2, 2, 2, 2, 53, 53,
- 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, 59, 59,
- 59, 59, 59, 59, 2, 2, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51,
- 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50, 2, 2, 50, 50, 2, 2, 2, 2, 2, 2,135,135,
- 135,135,135,135,135,135,135,135,135,135, 2, 2, 2, 2,106,106,
- 106,106,106,106,106,106,104,104,104,104,104,104,104,104,104,104,
- 104,104, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,104,161,161,
- 161,161,161,161,161,161,161,161,161, 2,161,161,161,161,161,161,
- 161, 2,161,161, 2,161,161,161, 2,161,161,161,161,161,161,161,
- 2,161,161, 2, 2, 2,110,110,110,110,110,110,110,110,110,110,
- 110,110,110,110,110, 2,110,110,110,110,110,110, 2, 2, 19, 19,
- 19, 19, 19, 19, 2, 19, 19, 2, 19, 19, 19, 19, 19, 19, 47, 47,
- 47, 47, 47, 47, 2, 2, 47, 2, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2,
- 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
- 81, 81, 81, 81, 2, 81,120,120,120,120,120,120,120,120,116,116,
- 116,116,116,116,116,116,116,116,116,116,116,116,116, 2, 2, 2,
- 2, 2, 2, 2, 2,116,128,128,128,128,128,128,128,128,128,128,
- 128, 2,128,128, 2, 2, 2, 2, 2,128,128,128,128,128, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72,
- 72, 72, 72, 72, 72, 72, 72, 72, 2, 2, 2, 2, 2, 72, 98, 98,
- 98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 2, 2,
- 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 57, 57,
- 57, 57, 2, 57, 57, 2, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57,
- 57, 57, 2, 57, 57, 57, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57,
- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57,
- 57, 2, 2, 2, 2, 57, 57, 2, 2, 2, 2, 2, 2, 2, 88, 88,
- 88, 88, 88, 88, 88, 88,117,117,117,117,117,117,117,117,112,112,
- 112,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2,
- 2,112,112,112,112,112, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
- 78, 78, 78, 78, 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 83, 83,
- 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 2, 2, 82, 82,
- 82, 82, 82, 82, 82, 82, 82, 82, 82, 2, 2, 2, 2, 2,122,122,
- 122,122,122,122,122,122,122,122, 2, 2, 2, 2, 2, 2, 2,122,
- 122,122,122, 2, 2, 2, 2,122,122,122,122,122,122,122, 89, 89,
- 89, 89, 89, 89, 89, 89, 89, 2, 2, 2, 2, 2, 2, 2,130,130,
- 130,130,130,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2,
- 130,130,130,130,130,130,144,144,144,144,144,144,144,144,144,144,
- 2, 2, 2, 2, 2, 2,156,156,156,156,156,156,156,156,156,156,
- 2,156,156,156, 2, 2,156,156, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 3, 3, 3,147,147,147,147,147,147,147,147,148,148,
- 148,148,148,148,148,148,148,148, 2, 2, 2, 2, 2, 2,158,158,
- 158,158,158,158,158,158,158,158, 2, 2, 2, 2, 2, 2,153,153,
- 153,153,153,153,153,153,153,153,153,153, 2, 2, 2, 2,149,149,
- 149,149,149,149,149,149,149,149,149,149,149,149,149, 2, 94, 94,
- 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2,
- 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2, 2, 94, 85, 85,
- 85, 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,101,101,101, 2,
- 2, 2, 2, 2, 2, 2,101,101, 2, 2, 2, 2, 2, 2, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 96, 96,111,111,
- 111,111,111,111,111,111,111,111,111,111,111,111,111, 2,100,100,
- 100,100,100,100,100,100, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 2, 2, 2,108,108,108,108,108,108,108,108,108,108,
- 2,108,108,108,108,108,108,108, 2, 2, 2, 2, 2, 2,129,129,
- 129,129,129,129,129, 2,129, 2,129,129,129,129, 2,129,129,129,
- 129,129,129,129,129,129,129,129,129,129,129,129, 2,129,129,129,
- 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109,
- 109, 2, 2, 2, 2, 2,109,109, 2, 2, 2, 2, 2, 2,107,107,
- 107,107, 2,107,107,107,107,107,107,107,107, 2, 2,107,107, 2,
- 2,107,107,107,107,107,107,107,107,107,107,107,107,107,107, 2,
- 107,107,107,107,107,107,107, 2,107,107, 2,107,107,107,107,107,
- 2, 1,107,107,107,107,107, 2, 2,107,107,107, 2, 2,107, 2,
- 2, 2, 2, 2, 2,107, 2, 2, 2, 2, 2,107,107,107,107,107,
- 107,107, 2, 2,107,107,107,107,107,107,107, 2, 2, 2,137,137,
- 137,137,137,137,137,137,137,137,137,137, 2,137,137,137,137,137,
- 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124,
- 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,123,123,123,123,
- 123,123,123,123, 2, 2,114,114,114,114,114,114,114,114,114,114,
- 114,114,114, 2, 2, 2,114,114, 2, 2, 2, 2, 2, 2, 32, 32,
- 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,102,102,102,102,
- 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,126,126,126,126,
- 126, 2, 2,126,126,126,126,126,126,126, 2, 2, 2, 2,126,126,
- 126,126,126,126,126, 2,142,142,142,142,142,142,142,142,142,142,
- 142,142, 2, 2, 2, 2,125,125,125,125,125,125,125,125,125,125,
- 125, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,125,154,154,
- 154,154,154,154,154, 2, 2,154, 2, 2,154,154,154,154,154,154,
- 154,154, 2,154,154, 2,154,154,154,154,154,154,154,154,154,154,
- 154,154,154,154, 2,154,154, 2, 2,154,154,154,154,154,154,154,
- 2, 2, 2, 2, 2, 2,150,150,150,150,150,150,150,150, 2, 2,
- 150,150,150,150,150,150,150,150,150,150,150, 2, 2, 2,141,141,
- 141,141,141,141,141,141,140,140,140,140,140,140,140,140,140,140,
- 140, 2, 2, 2, 2, 2,121,121,121,121,121,121,121,121,121, 2,
- 2, 2, 2, 2, 2, 2, 7, 7, 2, 2, 2, 2, 2, 2,133,133,
- 133,133,133,133,133,133,133, 2,133,133,133,133,133,133,133,133,
- 133,133,133,133,133, 2,133,133,133,133,133,133, 2, 2,133,133,
- 133,133,133, 2, 2, 2,134,134,134,134,134,134,134,134, 2, 2,
- 134,134,134,134,134,134, 2,134,134,134,134,134,134,134,134,134,
- 134,134,134,134,134, 2,138,138,138,138,138,138,138, 2,138,138,
- 2,138,138,138,138,138,138,138,138,138,138,138,138,138, 2, 2,
- 138, 2,138,138, 2,138,138,138, 2, 2, 2, 2, 2, 2,143,143,
- 143,143,143,143, 2,143,143, 2,143,143,143,143,143,143,143,143,
- 143,143,143,143,143,143,143,143,143,143,143,143,143, 2,143,143,
- 2,143,143,143,143,143,143, 2, 2, 2, 2, 2, 2, 2,143,143,
- 2, 2, 2, 2, 2, 2,145,145,145,145,145,145,145,145,145, 2,
- 2, 2, 2, 2, 2, 2,163,163,163,163,163,163,163,163,163, 2,
- 163,163,163,163,163,163,163,163,163, 2, 2, 2,163,163,163,163,
- 2, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 22, 22,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63,
- 63, 63, 63, 63, 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 63, 63,
- 63, 63, 2, 2, 2, 2,157,157,157,157,157,157,157,157,157,157,
- 157, 2, 2, 2, 2, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
- 80, 80, 80, 80, 2, 2,127,127,127,127,127,127,127,127,127,127,
- 127,127,127,127,127, 2, 79, 2, 2, 2, 2, 2, 2, 2,115,115,
- 115,115,115,115,115,115,115,115,115,115,115,115,115, 2,115,115,
- 2, 2, 2, 2,115,115,159,159,159,159,159,159,159,159,159,159,
- 159,159,159,159,159, 2,159,159, 2, 2, 2, 2, 2, 2,103,103,
- 103,103,103,103,103,103,103,103,103,103,103,103, 2, 2,119,119,
- 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2,119,119,
- 2,119,119,119,119,119, 2, 2, 2, 2, 2,119,119,119,146,146,
- 146,146,146,146,146,146,146,146,146, 2, 2, 2, 2, 2, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 99, 2, 2,
- 2, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, 2, 2,136,136,
- 136,136,136,136,136,136,155,155,155,155,155,155,155,155,155,155,
- 155,155,155,155, 2, 2,136, 2, 2, 2, 2, 2, 2, 2, 17, 17,
- 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17, 17, 2, 17, 15,
- 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, 2, 2, 2, 2,
- 15, 2, 2, 2, 2, 2, 15, 15, 15, 2, 2, 17, 2, 2, 2, 2,
- 2, 2, 17, 17, 17, 17,139,139,139,139,139,139,139,139,139,139,
- 139,139, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105,
- 105, 2, 2, 2, 2, 2,105,105,105,105,105, 2, 2, 2,105, 2,
- 2, 2, 2, 2, 2, 2,105,105, 2, 2,105,105,105,105, 1, 1,
- 1, 1, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
- 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 0, 0, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0,
- 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0,
- 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2,
- 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,131,131,
- 131,131,131,131,131,131,131,131,131,131, 2, 2, 2, 2, 2, 2,
- 2,131,131,131,131,131, 2,131,131,131,131,131,131,131, 2, 2,
- 2, 2, 2, 19, 19, 19, 56, 56, 56, 56, 56, 56, 56, 2, 56, 2,
- 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, 56, 56, 56, 56,
- 56, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 6,151,151,151,151,151,151,151,151,151,151,
- 151,151,151, 2, 2, 2,151,151,151,151,151,151, 2, 2,151,151,
- 2, 2, 2, 2,151,151,160,160,160,160,160,160,160,160,160,160,
- 160,160,160,160,160, 2,152,152,152,152,152,152,152,152,152,152,
- 2, 2, 2, 2, 2,152,164,164,164,164,164,164,164,164,164,164,
- 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 2, 30, 30, 2,113,113,
- 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113,
- 113,113,113,113,113, 2,132,132,132,132,132,132,132,132,132,132,
- 132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,132,132, 3, 3,
- 3, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3,
- 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3,
- 2, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
- 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2,
- 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 13, 2,
- 2, 2, 2, 2, 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, 0,
- 2, 2, 2, 2, 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
- 9, 9, 9, 10, 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 70, 70, 70,240, 70, 70, 70, 70, 70, 70, 70, 70, 70,241, 96, 96,
+ 96, 96, 96, 96, 96, 96, 70, 70, 70, 70,242, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70,243, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,244, 96, 96,
+ 96, 96, 96, 96, 96, 96,245, 96,246,247, 0, 1, 2, 2, 0, 1,
+ 2, 2, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 19, 19,
+ 19, 19, 19, 19, 19, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19,
+ 19, 19, 19, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2,
+ 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9,
+ 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 2, 9, 9, 9, 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 1, 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4,
+ 4, 2, 2, 4, 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 14, 14,
+ 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 0, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37,
+ 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+ 2, 2, 2, 2, 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, 2, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37,
+ 37, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3,
+ 2, 2, 2, 2, 2, 2, 3, 3, 0, 3, 3, 3, 3, 3, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7,
+ 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5,
+ 5, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2,
+ 5, 2, 2, 2, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2,
+ 2, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2,
+ 2, 2, 5, 5, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11,
+ 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2,
+ 11, 11, 2, 11, 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 2,
+ 2, 11, 11, 11, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11,
+ 11, 11, 11, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2,
+ 10, 10, 2, 10, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10,
+ 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10,
+ 10, 10, 2, 2, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10,
+ 10, 10, 10, 10, 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21,
+ 21, 21, 21, 2, 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2,
+ 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2,
+ 2, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2,
+ 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2,
+ 22, 22, 2, 22, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2,
+ 22, 22, 22, 22, 2, 2, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2,
+ 2, 22, 22, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 2, 2, 2, 2, 22, 22, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2,
+ 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2,
+ 23, 23, 23, 23, 23, 23, 23, 23, 2, 2, 23, 23, 23, 23, 23, 2,
+ 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23,
+ 23, 2, 2, 23, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, 2,
+ 2, 2, 2, 2, 2, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 2, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 2, 16, 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, 16, 2,
+ 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 16, 16,
+ 16, 16, 2, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, 2, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2,
+ 20, 20, 20, 20, 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20,
+ 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,
+ 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 36,
+ 36, 36, 36, 2, 36, 2, 2, 2, 2, 2, 2, 2, 36, 36, 2, 2,
+ 36, 36, 36, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24,
+ 24, 24, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18,
+ 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18,
+ 18, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 18, 18,
+ 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 2, 2, 25, 25,
+ 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25,
+ 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33, 33, 33, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 8, 2, 2,
+ 2, 2, 2, 8, 2, 2, 8, 8, 8, 0, 8, 8, 8, 8, 12, 12,
+ 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2,
+ 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30,
+ 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2, 30, 30,
+ 2, 2, 2, 2, 2, 2, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28, 28, 28, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 2, 2, 2, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, 35, 35, 35, 2,
+ 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 2, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2, 2, 2, 46, 46,
+ 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 2, 46, 46, 46, 2,
+ 46, 46, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 2, 2, 31, 31, 2, 2, 2, 2, 2, 2, 32, 32,
+ 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 32, 32,
+ 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, 2, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 2, 48, 48,
+ 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, 48, 48, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 2, 2, 52, 52,
+ 52, 52, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, 2, 2, 2, 58, 58,
+ 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2, 2, 91, 91, 91,
+ 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 2, 2, 1, 1,
+ 1, 1, 1, 1, 1, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 62, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 2, 76, 76,
+ 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 70, 70,
+ 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 70, 70, 70, 70,
+ 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 6, 2,
+ 2, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8, 8, 8, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1,
+ 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9,
+ 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, 9,
+ 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 19, 6, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9,
+ 9, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, 2, 9, 9, 9,
+ 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9,
+ 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 2, 19, 19,
+ 19, 19, 19, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2,
+ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0,
+ 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 19, 0,
+ 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 27, 27,
+ 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 0, 56, 56, 56, 56, 56, 56, 56, 56, 55, 55,
+ 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, 61,
+ 61, 61, 61, 61, 61, 61, 2, 2, 2, 2, 2, 2, 2, 61, 61, 2,
+ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 2, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 0, 0,
+ 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 13, 13,
+ 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 1,
+ 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17, 17, 17, 2, 2,
+ 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 12, 12,
+ 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 0, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2, 39, 39,
+ 39, 39, 39, 39, 39, 2, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2, 2, 2, 2, 79, 79,
+ 79, 79, 79, 79, 79, 79, 0, 0, 19, 19, 19, 19, 19, 19, 0, 0,
+ 0, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, 2, 2, 19, 19,
+ 2, 19, 2, 19, 19, 19, 19, 19, 2, 2, 2, 2, 2, 2, 2, 2,
+ 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 65, 65,
+ 65, 65, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 2, 2, 75, 75, 75, 75,
+ 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 12, 12,
+ 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2, 84, 84, 33, 33,
+ 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 2, 68, 68, 68, 68, 68, 68, 2, 2, 68, 68,
+ 2, 2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 2, 2, 2, 2, 2, 2, 2, 2, 92, 92, 92, 92, 92, 87, 87,
+ 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 2, 2, 30,
+ 30, 30, 30, 30, 30, 2, 19, 19, 19, 0, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 9, 19, 19, 19, 19, 0, 0, 2, 2, 2, 2, 87, 87,
+ 87, 87, 87, 87, 2, 2, 87, 87, 2, 2, 2, 2, 2, 2, 12, 12,
+ 12, 12, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 13, 13,
+ 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2,
+ 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 2, 14, 14, 14, 14, 14, 2, 14, 2, 14, 14,
+ 2, 14, 14, 2, 14, 14, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2,
+ 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 1, 1,
+ 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0, 0, 0, 3, 3,
+ 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 2, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17,
+ 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2,
+ 12, 12, 12, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 2, 49, 49, 49, 2, 49, 49, 2, 49, 49, 49,
+ 49, 49, 49, 49, 2, 2, 49, 49, 49, 2, 2, 2, 2, 2, 0, 0,
+ 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0,
+ 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+ 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 2,
+ 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 2, 2, 2, 2, 2,118,118,118,118,118,118,118,118,118,118,
+ 118, 2, 2, 2, 2, 2, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 2, 2, 2, 2, 59, 59, 59, 59, 59, 59, 2, 2, 40, 40,
+ 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 2, 2, 50, 50,
+ 2, 2, 2, 2, 2, 2,135,135,135,135,135,135,135,135,135,135,
+ 135,135, 2, 2, 2, 2,106,106,106,106,106,106,106,106,104,104,
+ 104,104,104,104,104,104,104,104,104,104, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2,104,161,161,161,161,161,161,161,161,161,161,
+ 161, 2,161,161,161,161,161,161,161, 2,161,161, 2,161,161,161,
+ 2,161,161,161,161,161,161,161, 2,161,161, 2, 2, 2,110,110,
+ 110,110,110,110,110,110,110,110,110,110,110,110,110, 2,110,110,
+ 110,110,110,110, 2, 2, 19, 19, 19, 19, 19, 19, 2, 19, 19, 2,
+ 19, 19, 19, 19, 19, 19, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2, 81,120,120,
+ 120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116,
+ 116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2, 2,116,128,128,
+ 128,128,128,128,128,128,128,128,128, 2,128,128, 2, 2, 2, 2,
+ 2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97,
+ 97, 97, 97, 97, 97, 97, 2, 2, 2, 2, 97, 97, 97, 97, 2, 2,
+ 97, 97, 97, 97, 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 2,
+ 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 2, 57, 57, 57, 2, 57,
+ 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+ 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 57, 2,
+ 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88, 88, 88,117,117,
+ 117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112,
+ 112,112,112,112,112, 2, 2, 2, 2,112,112,112,112,112, 78, 78,
+ 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 2, 2, 2, 78,
+ 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+ 83, 83, 83, 83, 2, 2, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+ 82, 2, 2, 2, 2, 2,122,122,122,122,122,122,122,122,122,122,
+ 2, 2, 2, 2, 2, 2, 2,122,122,122,122, 2, 2, 2, 2,122,
+ 122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89, 2,
+ 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,130,130,130,130,
+ 130, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,144,144,
+ 144,144,144,144,144,144,144,144, 2, 2, 2, 2, 2, 2,156,156,
+ 156,156,156,156,156,156,156,156, 2,156,156,156, 2, 2,156,156,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,147,147,
+ 147,147,147,147,147,147,148,148,148,148,148,148,148,148,148,148,
+ 2, 2, 2, 2, 2, 2,158,158,158,158,158,158,158,158,158,158,
+ 2, 2, 2, 2, 2, 2,153,153,153,153,153,153,153,153,153,153,
+ 153,153, 2, 2, 2, 2,149,149,149,149,149,149,149,149,149,149,
+ 149,149,149,149,149, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2,
+ 2, 2, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+ 85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 85, 2, 2,101,101,
+ 101,101,101,101,101,101,101, 2, 2, 2, 2, 2, 2, 2,101,101,
+ 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 2, 96, 96,111,111,111,111,111,111,111,111,111,111,
+ 111,111,111,111,111, 2,100,100,100,100,100,100,100,100, 2, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,108,108,
+ 108,108,108,108,108,108,108,108, 2,108,108,108,108,108,108,108,
+ 2, 2, 2, 2, 2, 2,129,129,129,129,129,129,129, 2,129, 2,
+ 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129,
+ 129,129,129,129, 2,129,129,129, 2, 2, 2, 2, 2, 2,109,109,
+ 109,109,109,109,109,109,109,109,109, 2, 2, 2, 2, 2,109,109,
+ 2, 2, 2, 2, 2, 2,107,107,107,107, 2,107,107,107,107,107,
+ 107,107,107, 2, 2,107,107, 2, 2,107,107,107,107,107,107,107,
+ 107,107,107,107,107,107,107, 2,107,107,107,107,107,107,107, 2,
+ 107,107, 2,107,107,107,107,107, 2, 1,107,107,107,107,107, 2,
+ 2,107,107,107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2,
+ 2, 2, 2,107,107,107,107,107,107,107, 2, 2,107,107,107,107,
+ 107,107,107, 2, 2, 2,137,137,137,137,137,137,137,137,137,137,
+ 137,137, 2,137,137,137,137,137, 2, 2, 2, 2, 2, 2,124,124,
+ 124,124,124,124,124,124,124,124, 2, 2, 2, 2, 2, 2,123,123,
+ 123,123,123,123,123,123,123,123,123,123,123,123, 2, 2,114,114,
+ 114,114,114,114,114,114,114,114,114,114,114, 2, 2, 2,114,114,
+ 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 2, 2, 2,102,102,
+ 102,102,102,102,102,102,102,102, 2, 2, 2, 2, 2, 2,126,126,
+ 126,126,126,126,126,126,126,126,126, 2, 2,126,126,126,126,126,
+ 126,126, 2, 2, 2, 2,126,126,126,126,126,126,126, 2,142,142,
+ 142,142,142,142,142,142,142,142,142,142, 2, 2, 2, 2,125,125,
+ 125,125,125,125,125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154,
+ 2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,154,154,
+ 154,154,154,154,154,154,154,154,154,154,154,154, 2,154,154, 2,
+ 2,154,154,154,154,154,154,154, 2, 2, 2, 2, 2, 2,150,150,
+ 150,150,150,150,150,150, 2, 2,150,150,150,150,150,150,150,150,
+ 150,150,150, 2, 2, 2,141,141,141,141,141,141,141,141,140,140,
+ 140,140,140,140,140,140,140,140,140, 2, 2, 2, 2, 2,121,121,
+ 121,121,121,121,121,121,121, 2, 2, 2, 2, 2, 2, 2, 7, 7,
+ 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133, 2,
+ 133,133,133,133,133,133,133,133,133,133,133,133,133, 2,133,133,
+ 133,133,133,133, 2, 2,133,133,133,133,133, 2, 2, 2,134,134,
+ 134,134,134,134,134,134, 2, 2,134,134,134,134,134,134, 2,134,
+ 134,134,134,134,134,134,134,134,134,134,134,134,134, 2,138,138,
+ 138,138,138,138,138, 2,138,138, 2,138,138,138,138,138,138,138,
+ 138,138,138,138,138,138, 2, 2,138, 2,138,138, 2,138,138,138,
+ 2, 2, 2, 2, 2, 2,143,143,143,143,143,143, 2,143,143, 2,
+ 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
+ 143,143,143,143,143, 2,143,143, 2,143,143,143,143,143,143, 2,
+ 2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, 2, 2, 2,145,145,
+ 145,145,145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2,163,163,
+ 163,163,163,163,163,163,163, 2,163,163,163,163,163,163,163,163,
+ 163, 2, 2, 2,163,163,163,163, 2, 2, 2, 2, 2, 2, 86, 2,
+ 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 2, 63, 63,
+ 63, 63, 63, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2,157,157,
+ 157,157,157,157,157,157,157,157,157, 2, 2, 2, 2, 2, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, 2,127,127,
+ 127,127,127,127,127,127,127,127,127,127,127,127,127, 2, 79, 2,
+ 2, 2, 2, 2, 2, 2,115,115,115,115,115,115,115,115,115,115,
+ 115,115,115,115,115, 2,115,115, 2, 2, 2, 2,115,115,159,159,
+ 159,159,159,159,159,159,159,159,159,159,159,159,159, 2,159,159,
+ 2, 2, 2, 2, 2, 2,103,103,103,103,103,103,103,103,103,103,
+ 103,103,103,103, 2, 2,119,119,119,119,119,119,119,119,119,119,
+ 119,119,119,119, 2, 2,119,119, 2,119,119,119,119,119, 2, 2,
+ 2, 2, 2,119,119,119,146,146,146,146,146,146,146,146,146,146,
+ 146, 2, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, 99,136,139,
+ 13, 13,155, 2, 2, 2,136,136,136,136,136,136,136,136,155,155,
+ 155,155,155,155,155,155,155,155,155,155,155,155, 2, 2,136, 2,
+ 2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 17, 17, 17, 17, 17,
+ 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17,
+ 17, 2, 2, 2, 2, 2, 2, 2, 15, 2, 2, 2, 2, 2, 15, 15,
+ 15, 2, 2, 17, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17,139,139,
+ 139,139,139,139,139,139,139,139,139,139, 2, 2, 2, 2,105,105,
+ 105,105,105,105,105,105,105,105,105, 2, 2, 2, 2, 2,105,105,
+ 105,105,105, 2, 2, 2,105, 2, 2, 2, 2, 2, 2, 2,105,105,
+ 2, 2,105,105,105,105, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 2, 2,
+ 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0,
+ 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
+ 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0,131,131,131,131,131,131,131,131,131,131,
+ 131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2,131,
+ 131,131,131,131,131,131, 2, 2, 2, 2, 2, 19, 19, 19, 56, 56,
+ 56, 56, 56, 56, 56, 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56,
+ 2, 56, 56, 2, 56, 56, 56, 56, 56, 2, 2, 2, 2, 2, 6, 6,
+ 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,151,151,
+ 151,151,151,151,151,151,151,151,151,151,151, 2, 2, 2,151,151,
+ 151,151,151,151, 2, 2,151,151, 2, 2, 2, 2,151,151,160,160,
+ 160,160,160,160,160,160,160,160,160,160,160,160,160, 2,152,152,
+ 152,152,152,152,152,152,152,152, 2, 2, 2, 2, 2,152,164,164,
+ 164,164,164,164,164,164,164,164, 2, 2, 2, 2, 2, 2, 30, 30,
+ 30, 30, 2, 30, 30, 2,113,113,113,113,113,113,113,113,113,113,
+ 113,113,113, 2, 2,113,113,113,113,113,113,113,113, 2,132,132,
+ 132,132,132,132,132,132,132,132,132,132, 2, 2, 2, 2,132,132,
+ 2, 2, 2, 2,132,132, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3,
+ 3, 2, 3, 2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2,
+ 3, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, 3,
+ 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 3,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3,
+ 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2,
+ 2, 0, 0, 0, 0, 0, 13, 2, 2, 2, 2, 2, 2, 2, 13, 13,
+ 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 0, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13,
+ 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 16, 17, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19,
- 20, 9, 21, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 22, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
@@ -2162,57 +2137,57 @@ _hb_ucd_u8[18260] =
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28,
- 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0,
- 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 23, 24, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33,
+ 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0,
- 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0,
- 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0,
- 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0,
- 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65,
- 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44,
+ 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48,
+ 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0,
+ 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0,
+ 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
- 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
- 99,100,101,102,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,
- 107, 0, 0, 0,108, 0,109, 0,110, 0,111,112,113, 0,114, 0,
- 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121, 0,122,123,124,
- 125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69,
+ 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0,
+ 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0,108, 0,109, 0,
+ 110, 0,111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,128,129,130,131,132,133,134,135,136,137,138,139,
- 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,
- 156,157, 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162,163, 0,
- 0, 0, 0, 0, 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167,
+ 118,119,120,121, 0,122,123,124,125,126, 0,127, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129,130,131,
+ 132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,
+ 148,149,150,151,152,153,154,155,156,157, 0, 0, 0,158,159,160,
+ 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0, 0, 0,164, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,169,170, 0, 0, 0, 0,171,
- 172, 0, 0, 0,173,174,175,176,177,178,179,180,181,182,183,184,
- 185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,
- 201,202,203,204,205,206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 2, 3, 4,
+ 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,169,170, 0, 0, 0, 0,171,172, 0, 0, 0,173,174,175,176,
+ 177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,
+ 193,194,195,196,197,198,199,200,201,202,203,204,205,206, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
};
static const uint16_t
_hb_ucd_u16[9320] =
@@ -2827,7 +2802,7 @@ _hb_ucd_gc (unsigned u)
static inline uint_fast8_t
_hb_ucd_ccc (unsigned u)
{
- return u<125259u?_hb_ucd_u8[9184+(((_hb_ucd_u8[8128+(((_hb_ucd_u8[7424+(((_hb_ucd_u8[7178+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0;
+ return u<125259u?_hb_ucd_u8[8792+(((_hb_ucd_u8[8236+(((_hb_ucd_u8[7776+(((_hb_ucd_u8[7424+(((_hb_ucd_u8[7178+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
}
static inline unsigned
_hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -2837,24 +2812,24 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
static inline int_fast16_t
_hb_ucd_bmg (unsigned u)
{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9932+(((_hb_ucd_u8[9812+(((_hb_ucd_b4(9684+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9540+(((_hb_ucd_u8[9420+(((_hb_ucd_b4(9292+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
}
static inline uint_fast8_t
_hb_ucd_sc (unsigned u)
{
- return u<918000u?_hb_ucd_u8[11454+(((_hb_ucd_u16[2040+(((_hb_ucd_u8[10718+(((_hb_ucd_u8[10268+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
+ return u<918000u?_hb_ucd_u8[11062+(((_hb_ucd_u16[2040+(((_hb_ucd_u8[10326+(((_hb_ucd_u8[9876+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
}
static inline uint_fast16_t
_hb_ucd_dm (unsigned u)
{
- return u<195102u?_hb_ucd_u16[6008+(((_hb_ucd_u8[17460+(((_hb_ucd_u8[17078+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+ return u<195102u?_hb_ucd_u16[6008+(((_hb_ucd_u8[17068+(((_hb_ucd_u8[16686+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
}
#elif !defined(HB_NO_UCD_UNASSIGNED)
static const uint8_t
-_hb_ucd_u8[17868] =
+_hb_ucd_u8[14744] =
{
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 11, 12, 13, 13, 13, 14,
@@ -3436,51 +3411,54 @@ _hb_ucd_u8[17868] =
0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0,
0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0,
0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,
- 220,220,220, 0,232,232,220,230,230,230, 7, 0, 16, 17, 17, 17,
- 17, 17, 17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,
- 129,169, 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 220,220,220, 0,232,232,220,230,230,230, 7, 0, 16, 17, 17, 33,
+ 17, 49, 17, 17, 84, 97,135,145, 26, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2,
- 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8,
- 9, 0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0,
- 23, 24, 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0,
- 0, 0, 0, 33, 34, 35, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 1, 2, 40, 41,
- 0, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0,
- 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0,
- 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10,
- 0, 0, 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0,
- 0, 0, 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7,
- 20, 20, 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0,
- 20, 20, 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1,
- 28, 29, 30, 31, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0,
- 0, 0, 0, 0, 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4,
- 0, 10, 0, 33, 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35,
- 36, 34, 37, 0, 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8,
- 21, 1, 20, 0, 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21,
- 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 21, 0, 42, 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0,
- 0, 0, 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 20, 20,
- 1, 20, 20, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 12, 13,
- 13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 13, 22, 13, 13, 13,
- 13, 23, 24, 24, 25, 26, 13, 13, 13, 27, 28, 29, 13, 30, 31, 32,
- 33, 34, 35, 36, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7,
- 7, 41, 13, 42, 7, 7, 43, 7, 44, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,177, 0, 1, 2, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 6, 7, 8, 3,
+ 3, 3, 3, 3, 9, 10, 11, 12, 13, 3, 3, 3, 3, 3, 3, 3,
+ 3, 14, 3, 15, 3, 3, 3, 3, 3, 3, 16, 17, 18, 19, 20, 21,
+ 3, 3, 3, 22, 23, 24, 3, 3, 3, 3, 3, 3, 25, 3, 3, 3,
+ 3, 3, 3, 3, 3, 26, 3, 3, 27, 28, 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0,
+ 0, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 0,
+ 0, 0, 0, 0, 0, 10, 11, 12, 13, 0, 0, 14, 15, 16, 6, 0,
+ 17, 18, 19, 19, 19, 20, 21, 22, 23, 24, 19, 25, 0, 26, 27, 19,
+ 19, 28, 29, 30, 0, 31, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0,
+ 0, 19, 28, 0, 32, 33, 9, 34, 35, 19, 0, 0, 36, 37, 38, 39,
+ 40, 19, 0, 41, 42, 43, 44, 31, 0, 1, 45, 42, 0, 0, 0, 0,
+ 0, 32, 14, 14, 0, 0, 0, 0, 14, 0, 0, 46, 47, 47, 47, 47,
+ 48, 49, 47, 47, 47, 47, 50, 51, 52, 53, 43, 21, 0, 0, 0, 0,
+ 0, 0, 0, 54, 6, 55, 0, 14, 19, 1, 0, 0, 0, 0, 56, 57,
+ 0, 0, 0, 0, 0, 19, 58, 31, 0, 0, 0, 0, 0, 0, 0, 59,
+ 14, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 60,
+ 61, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 3,
+ 0, 4, 5, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 1, 1, 0,
+ 0, 8, 9, 0, 8, 9, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0,
+ 0, 0, 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, 1, 0,
+ 0, 18, 19, 0, 0, 0, 20, 0, 0, 0, 1, 1, 1, 1, 0, 1,
+ 1, 1, 1, 1, 1, 1, 0, 8, 21, 9, 0, 0, 22, 0, 0, 0,
+ 0, 1, 0, 23, 24, 25, 0, 0, 26, 0, 0, 0, 8, 21, 27, 0,
+ 1, 0, 0, 1, 1, 1, 1, 0, 1, 28, 29, 30, 0, 31, 32, 20,
+ 1, 1, 0, 0, 0, 8, 21, 9, 1, 4, 5, 0, 0, 0, 33, 9,
+ 0, 1, 1, 1, 0, 8, 21, 21, 21, 21, 34, 1, 35, 21, 21, 21,
+ 9, 36, 0, 0, 37, 38, 1, 0, 39, 0, 0, 0, 1, 0, 1, 0,
+ 0, 0, 0, 8, 21, 9, 1, 0, 0, 0, 40, 0, 8, 21, 21, 21,
+ 21, 21, 21, 21, 21, 9, 0, 1, 1, 1, 1, 8, 21, 21, 21, 9,
+ 0, 0, 0, 41, 0, 42, 43, 0, 0, 0, 1, 44, 0, 0, 0, 45,
+ 8, 9, 1, 0, 0, 0, 8, 21, 21, 21, 9, 0, 1, 0, 1, 1,
+ 8, 21, 21, 9, 0, 4, 5, 8, 9, 1, 0, 0, 0, 1, 2, 3,
+ 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24, 25, 26, 13, 13,
+ 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42, 7, 7, 43, 7,
+ 44, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
@@ -3501,419 +3479,221 @@ _hb_ucd_u8[17868] =
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 45, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 37,
- 37, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
- 51, 52, 2, 2, 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59,
- 59, 59, 59, 59, 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65,
- 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45, 0, 0, 1,
+ 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, 53, 54, 55, 56,
+ 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61,
+ 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 79, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81,
- 82, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, 97, 98, 99,100,101,101,
- 102,103,104,105,106,107,108,109,110,111, 96,112,113,114,115,116,
- 117,118,119,119,120,121,122,123,124,125,126,127,128,129,130,131,
- 132, 96,133,134,135,136,137,138,139,140,141,142,143, 96,144,145,
- 96,146,147,148,149, 96,150,151,152,153,154,155,156, 96,157,158,
- 159,160, 96,161,162,163,164,164,164,164,164,164,164,165,166,164,
- 167, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96,168,169,169,169,169,169,169,169,169,170, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,171,171,
- 171,171,172, 96, 96, 96,173,173,173,173,174,175,176,177, 96, 96,
- 96, 96,178,179,180,181,182,182,182,182,182,182,182,182,182,182,
- 182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
- 182,182,182,182,182,183,182,182,182,182,182,182,184,184,184,185,
- 186, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96,187,188,189,190,191,191,192, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,193,194,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96,195,196, 59,197,198,199,200,201,202, 96,203,204,
- 205, 59, 59,206, 59,207,208,208,208,208,208,209, 96, 96, 96, 96,
- 96, 96, 96, 96,210, 96,211,212,213, 96, 96,214, 96, 96, 96,215,
- 96, 96, 96, 96, 96,216,217,218,219, 96, 96, 96, 96, 96,220,221,
- 222, 96,223,224, 96, 96,225,226, 59,227,228, 96, 59, 59, 59, 59,
- 59, 59, 59,229,230,231,232,233, 59, 59,234,235, 59,236, 96, 96,
- 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70,237, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70,238, 70,239, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 97, 98, 99,100,101,101,102,103,104,105,106,107,108,109,
+ 110,111, 96,112,113,114,115,116,117,118,119,119,120,121,122,123,
+ 124,125,126,127,128,129,130,131,132, 96,133,134,135,136,137,138,
+ 139,140,141,142,143, 96,144,145, 96,146,147,148,149, 96,150,151,
+ 152,153,154,155,156, 96,157,158,159,160, 96,161,162,163,164,164,
+ 164,164,164,164,164,165,166,164,167, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,168,169,169,
+ 169,169,169,169,169,169,170, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96,171,171,171,171,172, 96, 96, 96,173,173,
+ 173,173,174,175,176,177, 96, 96, 96, 96,178,179,180,181,182,182,
+ 182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+ 182,182,182,182,182,182,182,182,182,182,182,182,182,183,182,182,
+ 182,182,182,182,184,184,184,185,186, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,187,188,189,
+ 190,191,191,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96,193,194, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,195,196, 59,197,
+ 198,199,200,201,202, 96,203,204,205, 59, 59,206, 59,207,208,208,
+ 208,208,208,209, 96, 96, 96, 96, 96, 96, 96, 96,210, 96,211,212,
+ 213, 96, 96,214, 96, 96, 96,215, 96, 96, 96, 96, 96,216,217,218,
+ 219, 96, 96, 96, 96, 96,220,221,222, 96,223,224, 96, 96,225,226,
+ 59,227,228, 96, 59, 59, 59, 59, 59, 59, 59,229,230,231,232,233,
+ 59, 59,234,235, 59,236, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,237, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,238, 70,239, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70,240, 70, 70, 70, 70, 70, 70, 70, 70, 70,241, 96, 96,
- 96, 96, 96, 96, 96, 96, 70, 70, 70, 70,242, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70,243, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,244, 96, 96,
- 96, 96, 96, 96, 96, 96,245, 96,246,247, 0, 1, 2, 2, 0, 1,
- 2, 2, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 19, 19,
- 19, 19, 19, 19, 19, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19,
- 19, 19, 19, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 1, 1,
- 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2,
- 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9,
- 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 2, 9, 9, 9, 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55,
- 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 1, 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4,
- 4, 2, 2, 4, 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 14, 14,
- 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 0, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37,
- 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 2, 2, 2, 2, 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
- 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, 2, 95, 95,
- 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37,
- 37, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3,
- 2, 2, 2, 2, 2, 2, 3, 3, 0, 3, 3, 3, 3, 3, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7,
- 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5,
- 5, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2,
- 5, 2, 2, 2, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2,
- 2, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2,
- 2, 2, 5, 5, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11,
- 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11,
- 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2,
- 11, 11, 2, 11, 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 2,
- 2, 11, 11, 11, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11,
- 11, 11, 11, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11,
- 11, 11, 11, 11, 11, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2,
- 10, 10, 2, 10, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10,
- 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10,
- 10, 10, 2, 2, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10,
- 10, 10, 10, 10, 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21,
- 21, 21, 21, 2, 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2,
- 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2,
- 2, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2,
- 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2,
- 22, 22, 2, 22, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2,
- 22, 22, 22, 22, 2, 2, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2,
- 2, 22, 22, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 2, 2, 2, 2, 22, 22, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2,
- 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2,
- 23, 23, 23, 23, 23, 23, 23, 23, 2, 2, 23, 23, 23, 23, 23, 2,
- 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23,
- 23, 2, 2, 23, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, 2,
- 2, 2, 2, 2, 2, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 2, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 2, 16, 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, 16, 2,
- 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 16, 16,
- 16, 16, 2, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, 2, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2,
- 20, 20, 20, 20, 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20,
- 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,
- 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 36,
- 36, 36, 36, 2, 36, 2, 2, 2, 2, 2, 2, 2, 36, 36, 2, 2,
- 36, 36, 36, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24,
- 24, 24, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18,
- 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18,
- 18, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 18, 18,
- 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 2, 2, 25, 25,
- 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25,
- 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33, 33, 33, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 8, 2, 2,
- 2, 2, 2, 8, 2, 2, 8, 8, 8, 0, 8, 8, 8, 8, 12, 12,
- 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2,
- 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30,
- 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2, 30, 30,
- 2, 2, 2, 2, 2, 2, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28, 28, 28, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 2, 2, 2, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, 35, 35, 35, 2,
- 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 44, 44,
- 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 2, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2, 2, 2, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 2, 46, 46, 46, 2,
- 46, 46, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 2, 2, 31, 31, 2, 2, 2, 2, 2, 2, 32, 32,
- 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 32, 32,
- 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, 2, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 2, 48, 48,
- 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, 48, 48, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 2, 2, 52, 52,
- 52, 52, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, 2, 2, 2, 58, 58,
- 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
- 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2, 2, 91, 91, 91,
- 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 2, 2, 1, 1,
- 1, 1, 1, 1, 1, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 2, 76, 76,
- 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
- 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 70, 70,
- 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 70, 70, 70, 70,
- 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 6, 2,
- 2, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8, 8, 8, 1, 1,
- 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
- 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1,
- 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9,
- 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, 9,
- 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 19, 6, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9,
- 9, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, 2, 9, 9, 9,
- 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9,
- 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
- 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 2, 19, 19,
- 19, 19, 19, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0,
- 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 19, 0,
- 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 27, 27,
- 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0,
- 0, 0, 0, 0, 2, 0, 56, 56, 56, 56, 56, 56, 56, 56, 55, 55,
- 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, 61,
- 61, 61, 61, 61, 61, 61, 2, 2, 2, 2, 2, 2, 2, 61, 61, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 2, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 0, 0,
- 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 13, 13,
- 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 1,
- 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17, 17, 17, 2, 2,
- 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 12, 12,
- 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 0, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2, 39, 39,
- 39, 39, 39, 39, 39, 2, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77,
- 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2, 2, 2, 2, 79, 79,
- 79, 79, 79, 79, 79, 79, 0, 0, 19, 19, 19, 19, 19, 19, 0, 0,
- 0, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, 2, 2, 19, 19,
- 2, 19, 2, 19, 19, 19, 19, 19, 2, 2, 2, 2, 2, 2, 2, 2,
- 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
- 60, 60, 60, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 65, 65,
- 65, 65, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
- 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 2, 2, 75, 75, 75, 75,
- 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
- 74, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 12, 12,
- 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
- 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2, 84, 84, 33, 33,
- 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 2, 68, 68, 68, 68, 68, 68, 2, 2, 68, 68,
- 2, 2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
- 92, 2, 2, 2, 2, 2, 2, 2, 2, 92, 92, 92, 92, 92, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 2, 2, 30,
- 30, 30, 30, 30, 30, 2, 19, 19, 19, 0, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 9, 19, 19, 19, 19, 0, 0, 2, 2, 2, 2, 87, 87,
- 87, 87, 87, 87, 2, 2, 87, 87, 2, 2, 2, 2, 2, 2, 12, 12,
- 12, 12, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 13, 13,
- 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2,
- 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 2, 14, 14, 14, 14, 14, 2, 14, 2, 14, 14,
- 2, 14, 14, 2, 14, 14, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
- 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2,
- 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 1, 1,
- 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0, 0, 0, 3, 3,
- 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 2, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17,
- 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2,
- 12, 12, 12, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 2, 49, 49, 49, 2, 49, 49, 2, 49, 49, 49,
- 49, 49, 49, 49, 2, 2, 49, 49, 49, 2, 2, 2, 2, 2, 0, 0,
- 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0,
- 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 2, 0, 0,
- 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
- 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 2,
- 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 42, 42,
- 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
- 41, 2, 2, 2, 2, 2,118,118,118,118,118,118,118,118,118,118,
- 118, 2, 2, 2, 2, 2, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
- 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
- 59, 59, 2, 2, 2, 2, 59, 59, 59, 59, 59, 59, 2, 2, 40, 40,
- 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 50, 50,
- 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 2, 2, 50, 50,
- 2, 2, 2, 2, 2, 2,135,135,135,135,135,135,135,135,135,135,
- 135,135, 2, 2, 2, 2,106,106,106,106,106,106,106,106,104,104,
- 104,104,104,104,104,104,104,104,104,104, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2,104,161,161,161,161,161,161,161,161,161,161,
- 161, 2,161,161,161,161,161,161,161, 2,161,161, 2,161,161,161,
- 2,161,161,161,161,161,161,161, 2,161,161, 2, 2, 2,110,110,
- 110,110,110,110,110,110,110,110,110,110,110,110,110, 2,110,110,
- 110,110,110,110, 2, 2, 19, 19, 19, 19, 19, 19, 2, 19, 19, 2,
- 19, 19, 19, 19, 19, 19, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, 81,
- 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2, 81,120,120,
- 120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116,
- 116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2, 2,116,128,128,
- 128,128,128,128,128,128,128,128,128, 2,128,128, 2, 2, 2, 2,
- 2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
- 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97,
- 97, 97, 97, 97, 97, 97, 2, 2, 2, 2, 97, 97, 97, 97, 2, 2,
- 97, 97, 97, 97, 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 2,
- 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 2, 57, 57, 57, 2, 57,
- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
- 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 57, 2,
- 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88, 88, 88,117,117,
- 117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112,
- 112,112,112,112,112, 2, 2, 2, 2,112,112,112,112,112, 78, 78,
- 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 2, 2, 2, 78,
- 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
- 83, 83, 83, 83, 2, 2, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
- 82, 2, 2, 2, 2, 2,122,122,122,122,122,122,122,122,122,122,
- 2, 2, 2, 2, 2, 2, 2,122,122,122,122, 2, 2, 2, 2,122,
- 122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89, 2,
- 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,130,130,130,130,
- 130, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,144,144,
- 144,144,144,144,144,144,144,144, 2, 2, 2, 2, 2, 2,156,156,
- 156,156,156,156,156,156,156,156, 2,156,156,156, 2, 2,156,156,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,147,147,
- 147,147,147,147,147,147,148,148,148,148,148,148,148,148,148,148,
- 2, 2, 2, 2, 2, 2,158,158,158,158,158,158,158,158,158,158,
- 2, 2, 2, 2, 2, 2,153,153,153,153,153,153,153,153,153,153,
- 153,153, 2, 2, 2, 2,149,149,149,149,149,149,149,149,149,149,
- 149,149,149,149,149, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
- 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2,
- 2, 2, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
- 85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 85, 2, 2,101,101,
- 101,101,101,101,101,101,101, 2, 2, 2, 2, 2, 2, 2,101,101,
- 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 2, 96, 96,111,111,111,111,111,111,111,111,111,111,
- 111,111,111,111,111, 2,100,100,100,100,100,100,100,100, 2, 36,
- 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,108,108,
- 108,108,108,108,108,108,108,108, 2,108,108,108,108,108,108,108,
- 2, 2, 2, 2, 2, 2,129,129,129,129,129,129,129, 2,129, 2,
- 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129,
- 129,129,129,129, 2,129,129,129, 2, 2, 2, 2, 2, 2,109,109,
- 109,109,109,109,109,109,109,109,109, 2, 2, 2, 2, 2,109,109,
- 2, 2, 2, 2, 2, 2,107,107,107,107, 2,107,107,107,107,107,
- 107,107,107, 2, 2,107,107, 2, 2,107,107,107,107,107,107,107,
- 107,107,107,107,107,107,107, 2,107,107,107,107,107,107,107, 2,
- 107,107, 2,107,107,107,107,107, 2, 1,107,107,107,107,107, 2,
- 2,107,107,107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2,
- 2, 2, 2,107,107,107,107,107,107,107, 2, 2,107,107,107,107,
- 107,107,107, 2, 2, 2,137,137,137,137,137,137,137,137,137,137,
- 137,137, 2,137,137,137,137,137, 2, 2, 2, 2, 2, 2,124,124,
- 124,124,124,124,124,124,124,124, 2, 2, 2, 2, 2, 2,123,123,
- 123,123,123,123,123,123,123,123,123,123,123,123, 2, 2,114,114,
- 114,114,114,114,114,114,114,114,114,114,114, 2, 2, 2,114,114,
- 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 2, 2, 2,102,102,
- 102,102,102,102,102,102,102,102, 2, 2, 2, 2, 2, 2,126,126,
- 126,126,126,126,126,126,126,126,126, 2, 2,126,126,126,126,126,
- 126,126, 2, 2, 2, 2,126,126,126,126,126,126,126, 2,142,142,
- 142,142,142,142,142,142,142,142,142,142, 2, 2, 2, 2,125,125,
- 125,125,125,125,125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154,
- 2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,154,154,
- 154,154,154,154,154,154,154,154,154,154,154,154, 2,154,154, 2,
- 2,154,154,154,154,154,154,154, 2, 2, 2, 2, 2, 2,150,150,
- 150,150,150,150,150,150, 2, 2,150,150,150,150,150,150,150,150,
- 150,150,150, 2, 2, 2,141,141,141,141,141,141,141,141,140,140,
- 140,140,140,140,140,140,140,140,140, 2, 2, 2, 2, 2,121,121,
- 121,121,121,121,121,121,121, 2, 2, 2, 2, 2, 2, 2, 7, 7,
- 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133, 2,
- 133,133,133,133,133,133,133,133,133,133,133,133,133, 2,133,133,
- 133,133,133,133, 2, 2,133,133,133,133,133, 2, 2, 2,134,134,
- 134,134,134,134,134,134, 2, 2,134,134,134,134,134,134, 2,134,
- 134,134,134,134,134,134,134,134,134,134,134,134,134, 2,138,138,
- 138,138,138,138,138, 2,138,138, 2,138,138,138,138,138,138,138,
- 138,138,138,138,138,138, 2, 2,138, 2,138,138, 2,138,138,138,
- 2, 2, 2, 2, 2, 2,143,143,143,143,143,143, 2,143,143, 2,
- 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
- 143,143,143,143,143, 2,143,143, 2,143,143,143,143,143,143, 2,
- 2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, 2, 2, 2,145,145,
- 145,145,145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2,163,163,
- 163,163,163,163,163,163,163, 2,163,163,163,163,163,163,163,163,
- 163, 2, 2, 2,163,163,163,163, 2, 2, 2, 2, 2, 2, 86, 2,
- 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 2, 63, 63,
- 63, 63, 63, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2,157,157,
- 157,157,157,157,157,157,157,157,157, 2, 2, 2, 2, 2, 80, 80,
- 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, 2,127,127,
- 127,127,127,127,127,127,127,127,127,127,127,127,127, 2, 79, 2,
- 2, 2, 2, 2, 2, 2,115,115,115,115,115,115,115,115,115,115,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,240, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70,241, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70,242, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70, 70, 70,243, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70,244, 96, 96, 96, 96, 96, 96, 96, 96,245, 96,
+ 246,247, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0,
+ 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0,
+ 19, 0, 19, 0, 0, 0, 0, 0, 26, 26, 1, 1, 1, 1, 9, 9,
+ 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2,
+ 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9,
+ 2, 9, 9, 9, 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 1,
+ 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 14, 14, 2,
+ 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3,
+ 3, 0, 3, 3, 3, 1, 1, 1, 3, 3, 1, 3, 3, 3, 37, 37,
+ 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38,
+ 38, 38, 38, 38, 2, 2, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64,
+ 64, 64, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90, 90, 2, 95, 95,
+ 95, 95, 2, 2, 95, 2, 3, 3, 3, 2, 3, 3, 2, 2, 3, 3,
+ 0, 3, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 0, 0,
+ 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 2, 2, 5, 5, 2,
+ 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5, 2, 2, 5, 5,
+ 5, 2, 2, 2, 2, 5, 5, 5, 2, 5, 2, 11, 11, 11, 11, 11,
+ 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 2,
+ 11, 11, 2, 11, 11, 2, 11, 11, 2, 2, 2, 11, 2, 2, 11, 2,
+ 11, 2, 2, 2, 11, 11, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 2, 10, 10, 2, 10, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2,
+ 10, 10, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2,
+ 21, 21, 21, 21, 2, 2, 21, 21, 2, 21, 2, 2, 21, 21, 2, 2,
+ 22, 22, 2, 22, 22, 22, 22, 22, 22, 2, 22, 2, 22, 22, 22, 22,
+ 2, 2, 2, 22, 22, 2, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22,
+ 22, 22, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 23,
+ 23, 2, 23, 23, 23, 2, 2, 23, 2, 2, 2, 2, 23, 23, 2, 2,
+ 2, 23, 16, 16, 16, 16, 16, 2, 16, 16, 2, 16, 16, 16, 16, 16,
+ 2, 2, 2, 16, 16, 2, 2, 2, 16, 16, 20, 20, 20, 20, 20, 2,
+ 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 2, 2, 2, 36, 36, 36, 36, 2, 36, 2, 36, 2, 2, 2, 2,
+ 36, 2, 2, 2, 2, 36, 36, 2, 36, 2, 36, 2, 2, 2, 2, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 2, 18,
+ 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 2, 18,
+ 2, 18, 18, 18, 2, 2, 18, 2, 18, 2, 25, 25, 25, 25, 2, 25,
+ 25, 25, 25, 2, 2, 2, 25, 2, 25, 25, 25, 0, 0, 0, 0, 25,
+ 25, 2, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 2, 8, 2, 8,
+ 2, 2, 8, 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30, 30, 2,
+ 30, 30, 30, 30, 2, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 2,
+ 2, 2, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 34, 34,
+ 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0,
+ 35, 35, 35, 2, 2, 2, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2,
+ 2, 45, 44, 44, 44, 44, 44, 0, 0, 2, 43, 43, 43, 43, 46, 46,
+ 46, 46, 46, 2, 46, 46, 31, 31, 31, 31, 31, 31, 2, 2, 32, 32,
+ 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 2, 2, 32, 2,
+ 2, 2, 32, 32, 32, 2, 28, 28, 2, 2, 48, 48, 48, 48, 48, 48,
+ 48, 2, 48, 2, 2, 2, 52, 52, 52, 52, 52, 52, 2, 2, 52, 2,
+ 2, 2, 58, 58, 58, 58, 58, 58, 2, 2, 58, 58, 58, 2, 2, 2,
+ 58, 58, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91,
+ 91, 2, 91, 2, 2, 91, 91, 91, 2, 2, 1, 1, 1, 2, 62, 62,
+ 62, 62, 62, 2, 2, 2, 62, 62, 62, 2, 76, 76, 76, 76, 93, 93,
+ 93, 93, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 2, 2, 2, 70,
+ 70, 70, 73, 73, 73, 73, 6, 2, 2, 2, 8, 8, 8, 2, 2, 8,
+ 8, 8, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1,
+ 0, 0, 1, 1, 0, 2, 19, 19, 9, 9, 9, 9, 9, 6, 19, 9,
+ 9, 9, 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19, 19, 19,
+ 19, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, 9, 9, 1, 1,
+ 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, 0, 19, 0, 0,
+ 0, 2, 19, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2, 0, 0,
+ 9, 0, 0, 0, 19, 19, 27, 27, 27, 27, 2, 2, 0, 0, 0, 0,
+ 2, 0, 56, 56, 56, 56, 2, 55, 55, 55, 61, 61, 61, 61, 2, 2,
+ 2, 61, 61, 2, 2, 2, 0, 0, 2, 2, 13, 13, 13, 13, 13, 13,
+ 2, 13, 13, 13, 2, 2, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13,
+ 1, 1, 1, 1, 12, 12, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 0, 2, 26, 26, 26, 26, 26, 26, 26, 2, 12,
+ 12, 12, 12, 12, 12, 2, 12, 12, 12, 0, 39, 39, 39, 39, 39, 2,
+ 2, 2, 39, 39, 39, 2, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79,
+ 79, 79, 19, 19, 19, 2, 19, 19, 2, 19, 2, 19, 19, 19, 19, 19,
+ 2, 2, 2, 2, 19, 19, 60, 60, 60, 60, 60, 2, 2, 2, 65, 65,
+ 65, 65, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, 75, 75, 69, 69,
+ 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 2, 2, 2, 74, 12, 2,
+ 2, 2, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2,
+ 84, 84, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68,
+ 2, 2, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 92, 87, 87,
+ 87, 87, 87, 87, 87, 2, 19, 9, 19, 19, 19, 19, 0, 0, 87, 87,
+ 2, 2, 2, 2, 2, 12, 2, 2, 2, 4, 14, 2, 14, 2, 14, 14,
+ 2, 14, 14, 2, 14, 14, 2, 2, 2, 3, 3, 3, 0, 0, 2, 2,
+ 3, 3, 1, 1, 6, 6, 3, 2, 3, 3, 3, 2, 2, 0, 2, 0,
+ 0, 0, 0, 0, 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 49, 49,
+ 49, 49, 2, 49, 49, 49, 49, 49, 49, 2, 49, 49, 2, 49, 49, 49,
+ 2, 2, 9, 2, 2, 2, 0, 1, 2, 2, 71, 71, 71, 71, 71, 2,
+ 2, 2, 67, 67, 67, 67, 67, 2, 2, 2, 42, 42, 42, 42, 2, 42,
+ 42, 42, 41, 41, 41, 41, 41, 41, 41, 2,118,118,118,118,118,118,
+ 118, 2, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59,
+ 2, 2, 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50,
+ 2, 2,135,135,135,135,106,106,106,106,104,104,104,104, 2, 2,
+ 2,104,161,161,161,161,161,161,161, 2,161,161, 2,161,161, 2,
+ 2, 2,110,110,110,110,110,110,110, 2,110,110, 2, 2, 19, 2,
+ 19, 19, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2, 47, 47, 47, 47,
+ 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, 81, 81,
+ 2, 81,120,120,120,120,116,116,116,116,116,116,116, 2, 2, 2,
+ 2,116,128,128,128,128,128,128,128, 2,128,128, 2, 2, 2, 2,
+ 2,128, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72,
+ 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 97, 97, 97, 97, 2, 2,
+ 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 57, 57, 57, 57, 57,
+ 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 57, 2, 2, 2, 88, 88,
+ 88, 88,117,117,117,117,112,112,112,112,112,112,112, 2, 2, 2,
+ 2,112, 78, 78, 78, 78, 78, 78, 2, 2, 2, 78, 78, 78, 83, 83,
+ 83, 83, 83, 83, 2, 2, 82, 82, 82, 82, 82, 82, 82, 2,122,122,
+ 122,122,122,122, 2, 2, 2,122,122,122,122, 2, 2, 2, 89, 89,
+ 89, 89, 89, 2, 2, 2,130,130,130,130,130,130,130, 2, 2, 2,
+ 130,130,144,144,144,144,144,144, 2, 2,156,156,156,156,156,156,
+ 2,156,156,156, 2, 2, 2, 3, 3, 3,147,147,147,147,148,148,
+ 148,148,148,148, 2, 2,158,158,158,158,158,158, 2, 2,153,153,
+ 153,153,149,149,149,149,149,149,149, 2, 94, 94, 94, 94, 94, 94,
+ 2, 2, 2, 2, 94, 94, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85,
+ 85, 2, 2, 85, 2, 2,101,101,101,101,101, 2, 2, 2,101,101,
+ 2, 2, 96, 96, 96, 96, 96, 2, 96, 96,111,111,111,111,111,111,
+ 111, 2,100,100,100,100,108,108,108,108,108,108, 2,108,108,108,
+ 2, 2,129,129,129,129,129,129,129, 2,129, 2,129,129,129,129,
+ 2,129,129,129, 2, 2,109,109,109,109,109,109,109, 2,109,109,
+ 2, 2,107,107,107,107, 2,107,107,107,107, 2, 2,107,107, 2,
+ 107,107,107,107, 2, 1,107,107, 2, 2,107, 2, 2, 2, 2, 2,
+ 2,107, 2, 2,107,107,137,137,137,137, 2,137,137,137,137,137,
+ 2, 2,124,124,124,124,124,124, 2, 2,123,123,123,123,123,123,
+ 2, 2,114,114,114,114,114, 2, 2, 2,114,114, 2, 2,102,102,
+ 102,102,102,102, 2, 2,126,126,126,126,126,126,126, 2, 2,126,
+ 126,126,142,142,142,142,125,125,125,125,125,125,125, 2, 2, 2,
+ 2,125,154,154,154,154,154,154,154, 2, 2,154, 2, 2, 2,154,
+ 154, 2,154,154, 2,154,154, 2, 2,154,154,154, 2, 2,150,150,
+ 150,150, 2, 2,150,150,150, 2, 2, 2,141,141,141,141,140,140,
+ 140,140,140,140,140, 2,121,121,121,121,121, 2, 2, 2, 7, 7,
+ 2, 2,133,133,133,133,133, 2,133,133,133,133,133, 2,133,133,
+ 2, 2,133, 2, 2, 2,134,134,134,134, 2, 2,134,134, 2,134,
+ 134,134,134,134,134, 2,138,138,138,138,138,138,138, 2,138,138,
+ 2,138, 2, 2,138, 2,138,138, 2, 2,143,143,143,143,143,143,
+ 2,143,143, 2,143,143,143,143,143, 2,143, 2, 2, 2,143,143,
+ 2, 2,145,145,145,145,145, 2, 2, 2,163,163,163,163,163, 2,
+ 163,163,163,163,163, 2, 2, 2,163,163,163,163, 2, 2, 86, 2,
+ 2, 2, 63, 63, 63, 63, 63, 63, 2, 2, 63, 63, 63, 2, 63, 2,
+ 2, 2,157,157,157,157,157,157,157, 2, 80, 80, 80, 80, 80, 80,
+ 2, 2,127,127,127,127,127,127,127, 2, 79, 2, 2, 2,115,115,
115,115,115,115,115, 2,115,115, 2, 2, 2, 2,115,115,159,159,
- 159,159,159,159,159,159,159,159,159,159,159,159,159, 2,159,159,
- 2, 2, 2, 2, 2, 2,103,103,103,103,103,103,103,103,103,103,
- 103,103,103,103, 2, 2,119,119,119,119,119,119,119,119,119,119,
- 119,119,119,119, 2, 2,119,119, 2,119,119,119,119,119, 2, 2,
- 2, 2, 2,119,119,119,146,146,146,146,146,146,146,146,146,146,
- 146, 2, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, 99,136,139,
- 13, 13,155, 2, 2, 2,136,136,136,136,136,136,136,136,155,155,
- 155,155,155,155,155,155,155,155,155,155,155,155, 2, 2,136, 2,
- 2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 17, 17, 17, 17, 17,
- 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17,
- 17, 2, 2, 2, 2, 2, 2, 2, 15, 2, 2, 2, 2, 2, 15, 15,
- 15, 2, 2, 17, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17,139,139,
- 139,139,139,139,139,139,139,139,139,139, 2, 2, 2, 2,105,105,
- 105,105,105,105,105,105,105,105,105, 2, 2, 2, 2, 2,105,105,
- 105,105,105, 2, 2, 2,105, 2, 2, 2, 2, 2, 2, 2,105,105,
- 2, 2,105,105,105,105, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0,
- 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1,
- 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 2, 2,
- 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0,
- 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
- 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0,
- 0, 0, 0, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2,
- 0, 0, 0, 0, 0, 0,131,131,131,131,131,131,131,131,131,131,
- 131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2,131,
- 131,131,131,131,131,131, 2, 2, 2, 2, 2, 19, 19, 19, 56, 56,
- 56, 56, 56, 56, 56, 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56,
- 2, 56, 56, 2, 56, 56, 56, 56, 56, 2, 2, 2, 2, 2, 6, 6,
- 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,151,151,
- 151,151,151,151,151,151,151,151,151,151,151, 2, 2, 2,151,151,
- 151,151,151,151, 2, 2,151,151, 2, 2, 2, 2,151,151,160,160,
- 160,160,160,160,160,160,160,160,160,160,160,160,160, 2,152,152,
- 152,152,152,152,152,152,152,152, 2, 2, 2, 2, 2,152,164,164,
- 164,164,164,164,164,164,164,164, 2, 2, 2, 2, 2, 2, 30, 30,
- 30, 30, 2, 30, 30, 2,113,113,113,113,113,113,113,113,113,113,
- 113,113,113, 2, 2,113,113,113,113,113,113,113,113, 2,132,132,
- 132,132,132,132,132,132,132,132,132,132, 2, 2, 2, 2,132,132,
- 2, 2, 2, 2,132,132, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3,
- 3, 2, 3, 2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2,
- 3, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, 3,
- 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 3,
- 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3,
- 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0,
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2,
- 2, 0, 0, 0, 0, 0, 13, 2, 2, 2, 2, 2, 2, 2, 13, 13,
- 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 0, 1,
- 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13,
- 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 159,159,159,159,159, 2,159,159, 2, 2,103,103,103,103,103,103,
+ 2, 2,119,119,119,119,119,119, 2, 2,119,119, 2,119, 2,119,
+ 119,119,146,146,146,146,146,146,146, 2, 99, 99, 99, 99, 99, 99,
+ 99, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, 2, 2,136,136,
+ 136,136,155,155,155,155,155,155, 2, 2,136, 2, 2, 2, 2, 17,
+ 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 17, 17, 17, 2, 2, 2,
+ 15, 2, 2, 17, 2, 2,139,139,139,139,105,105,105,105,105,105,
+ 105, 2,105, 2, 2, 2,105,105, 2, 2, 1, 1, 2, 2, 0, 0,
+ 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 2, 2, 0, 2, 2, 0,
+ 0, 2, 0, 2, 0, 2,131,131,131,131, 2, 2, 2,131, 2,131,
+ 131,131, 56, 56, 56, 2, 56, 2, 2, 56, 56, 56, 2, 56, 56, 2,
+ 56, 56, 6, 6, 2, 2, 2, 2, 2, 6,151,151,151,151,151, 2,
+ 2, 2,151,151, 2, 2, 2, 2,151,151,160,160,160,160,160,160,
+ 160, 2,152,152,152,152,152,152, 2, 2, 2, 2, 2,152,164,164,
+ 164,164,164,164, 2, 2, 2, 30, 30, 2,113,113,113,113,113, 2,
+ 2,113,113,113,113, 2,132,132,132,132,132,132, 2, 2, 2, 2,
+ 132,132, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3, 2, 3, 2, 2,
+ 3, 2, 3, 2, 3, 2, 3, 3, 2, 3, 15, 0, 0, 2, 13, 2,
+ 2, 2, 13, 13, 13, 2, 2, 0, 2, 2, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13, 9, 9, 9, 14,
+ 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 16, 17, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 18, 19, 20, 9, 21, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 22, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 22, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
@@ -3922,60 +3702,60 @@ _hb_ucd_u8[17868] =
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 23, 24, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
- 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33,
- 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44,
- 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48,
- 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0,
- 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0,
- 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0,
+ 9, 9, 9, 9, 9, 9, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 24,
+ 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, 35,
+ 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, 0,
+ 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 0,
+ 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0,
+ 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0,
+ 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, 61,
+ 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69,
- 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 72, 73, 74,
- 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
- 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0,
- 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0,108, 0,109, 0,
- 110, 0,111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 71, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99,100,101,102,103, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0,
+ 0,105,106, 0,107, 0, 0, 0,108, 0,109, 0,110, 0,111,112,
+ 113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 118,119,120,121, 0,122,123,124,125,126, 0,127, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121,
+ 0,122,123,124,125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129,130,131,
- 132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,
- 148,149,150,151,152,153,154,155,156,157, 0, 0, 0,158,159,160,
- 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0, 0, 0,164, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,128,129,130,131,132,133,134,135,
+ 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,
+ 152,153,154,155,156,157, 0, 0, 0,158,159,160,161, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,162,163, 0, 0, 0, 0, 0, 0, 0,164, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,165, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,169,170, 0, 0, 0, 0,171,172, 0, 0, 0,173,174,175,176,
- 177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,
- 193,194,195,196,197,198,199,200,201,202,203,204,205,206, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,169,170, 0,
+ 0, 0, 0,171,172, 0, 0, 0,173,174,175,176,177,178,179,180,
+ 181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,
+ 197,198,199,200,201,202,203,204,205,206, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
+ 0, 0, 0, 0, 1, 2, 3, 4,
};
static const uint16_t
-_hb_ucd_u16[9320] =
+_hb_ucd_u16[10040] =
{
0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12,
13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23,
@@ -4104,255 +3884,300 @@ _hb_ucd_u16[9320] =
48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 140, 140, 140, 140, 140,
683, 140, 570, 570, 570, 570, 570, 570, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 140, 391, 391, 391, 391, 391, 391, 391, 684,
- 391, 391, 391, 391, 391, 391, 391, 685, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 2, 2, 3, 1, 2, 2, 3, 0, 0, 0, 0, 0, 4, 0, 4,
- 2, 2, 5, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,
- 0, 0, 0, 0, 7, 8, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 10, 11, 12, 13, 14, 14, 15, 14, 14, 14,
- 14, 14, 14, 14, 16, 17, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 19, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 20, 21,
- 21, 21, 22, 20, 21, 21, 21, 21, 21, 23, 24, 25, 25, 25, 25, 25,
- 25, 26, 25, 25, 25, 27, 28, 26, 29, 30, 31, 32, 31, 31, 31, 31,
- 33, 34, 35, 31, 31, 31, 36, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 29, 31, 31, 31, 31, 37, 38, 37, 37, 37, 37, 37, 37,
- 37, 39, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 41, 26,
- 42, 42, 42, 42, 42, 42, 42, 43, 44, 44, 44, 44, 44, 45, 44, 46,
- 47, 47, 47, 48, 37, 49, 31, 31, 31, 50, 51, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 52, 31, 31, 31, 53, 53, 53, 53, 53, 53, 53, 53,
- 53, 53, 54, 53, 55, 53, 53, 53, 56, 57, 58, 59, 59, 60, 61, 62,
- 57, 63, 64, 65, 66, 59, 59, 67, 68, 69, 70, 71, 71, 72, 73, 74,
- 69, 75, 76, 77, 78, 71, 79, 26, 80, 81, 82, 83, 83, 84, 85, 86,
- 81, 87, 88, 26, 89, 83, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98,
- 93, 99, 100, 101, 102, 95, 95, 26, 103, 104, 105, 106, 107, 104, 108, 109,
- 104, 105, 110, 26, 111, 108, 108, 112, 113, 114, 115, 113, 113, 115, 113, 116,
- 114, 117, 118, 119, 120, 113, 121, 113, 122, 123, 124, 122, 122, 124, 125, 126,
- 123, 127, 128, 128, 129, 122, 130, 26, 131, 132, 133, 131, 131, 131, 131, 131,
- 132, 133, 134, 131, 135, 131, 131, 131, 136, 137, 138, 139, 137, 137, 140, 141,
- 138, 142, 143, 137, 144, 137, 145, 26, 146, 147, 147, 147, 147, 147, 147, 148,
- 147, 147, 147, 149, 26, 26, 26, 26, 150, 151, 152, 152, 153, 152, 152, 154,
- 155, 156, 152, 157, 26, 26, 26, 26, 158, 158, 158, 158, 158, 158, 158, 158,
- 158, 159, 158, 158, 158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161,
- 158, 161, 162, 163, 26, 26, 26, 26, 164, 164, 164, 164, 164, 164, 164, 164,
- 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165,
- 166, 167, 165, 165, 165, 165, 165, 168, 169, 169, 169, 169, 169, 169, 169, 169,
- 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170,
- 170, 171, 172, 171, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 171, 172,
- 171, 170, 172, 170, 170, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 170,
- 170, 170, 170, 173, 170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176,
- 176, 176, 176, 176, 176, 176, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178,
- 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181,
- 181, 181, 181, 181, 181, 182, 181, 183, 184, 184, 185, 186, 187, 187, 188, 26,
- 189, 189, 190, 26, 191, 192, 193, 26, 194, 194, 194, 194, 194, 194, 194, 194,
- 194, 194, 194, 195, 194, 196, 194, 196, 197, 198, 198, 199, 198, 198, 198, 198,
- 198, 198, 198, 198, 198, 198, 198, 200, 198, 198, 198, 198, 198, 201, 178, 178,
- 178, 178, 178, 178, 178, 178, 202, 26, 203, 203, 203, 204, 203, 205, 203, 205,
- 206, 203, 207, 207, 207, 208, 209, 26, 210, 210, 210, 210, 210, 211, 210, 210,
- 210, 212, 210, 213, 194, 194, 194, 194, 214, 214, 214, 215, 216, 216, 216, 216,
- 216, 216, 216, 217, 216, 216, 216, 218, 216, 219, 216, 219, 216, 220, 9, 9,
- 9, 221, 26, 26, 26, 26, 26, 26, 222, 222, 222, 222, 222, 222, 222, 222,
- 222, 223, 222, 222, 222, 222, 222, 224, 225, 225, 225, 225, 225, 225, 225, 225,
- 226, 226, 226, 226, 226, 226, 227, 228, 229, 229, 229, 229, 229, 229, 229, 230,
- 229, 231, 232, 232, 232, 232, 232, 232, 18, 233, 165, 165, 165, 165, 165, 234,
- 225, 26, 235, 9, 236, 237, 238, 239, 2, 2, 2, 2, 240, 241, 2, 2,
- 2, 2, 2, 242, 243, 244, 2, 245, 2, 2, 2, 2, 2, 2, 2, 246,
- 9, 9, 9, 9, 9, 9, 9, 9, 14, 14, 247, 247, 14, 14, 14, 14,
- 247, 247, 14, 248, 14, 14, 14, 247, 14, 14, 14, 14, 14, 14, 249, 14,
- 249, 14, 250, 251, 14, 14, 252, 253, 0, 254, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 255, 0, 256, 257, 0, 258, 2, 259, 0, 0, 0, 0,
- 260, 26, 9, 9, 9, 9, 261, 26, 0, 0, 0, 0, 262, 263, 4, 0,
- 0, 264, 0, 0, 2, 2, 2, 2, 2, 265, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 26, 26, 26,
- 0, 266, 26, 26, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267,
- 267, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 269, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270,
- 270, 270, 270, 270, 2, 2, 2, 2, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 271, 272, 165, 165, 165, 165, 166, 167, 273, 273,
- 273, 273, 273, 273, 273, 274, 275, 274, 170, 170, 172, 26, 172, 172, 172, 172,
- 172, 172, 172, 172, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 276, 26, 26, 26, 26, 277, 277, 277, 278, 277, 277, 277, 277,
- 277, 277, 277, 277, 277, 277, 279, 26, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 277, 280, 26, 26, 26, 0, 281, 282, 0, 0, 0, 283, 284, 0, 285,
- 286, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288, 289, 290, 291, 291, 291,
- 291, 291, 291, 291, 291, 291, 291, 292, 293, 294, 294, 294, 294, 294, 295, 169,
- 169, 169, 169, 169, 169, 169, 169, 169, 169, 296, 0, 0, 294, 294, 294, 294,
- 0, 0, 0, 0, 281, 26, 291, 291, 169, 169, 169, 296, 0, 0, 0, 0,
- 0, 0, 0, 0, 169, 169, 169, 297, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 291, 291, 291, 291, 291, 298, 291, 291, 291, 291, 291, 291, 291, 291,
- 291, 291, 291, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277,
- 0, 0, 0, 0, 0, 0, 0, 0, 299, 299, 299, 299, 299, 299, 299, 299,
- 299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 299, 299, 299, 299, 299, 299,
- 301, 26, 302, 302, 302, 302, 302, 302, 303, 303, 303, 303, 303, 303, 303, 303,
- 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 304, 26, 26,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 305, 305, 305, 305,
- 305, 305, 305, 305, 305, 305, 305, 26, 0, 0, 0, 0, 306, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 307, 2, 2, 2, 2, 2, 2,
- 2, 308, 309, 310, 26, 26, 311, 2, 312, 312, 312, 312, 312, 313, 0, 314,
- 315, 315, 315, 315, 315, 315, 315, 26, 316, 316, 316, 316, 316, 316, 316, 316,
- 317, 318, 316, 319, 53, 53, 53, 53, 320, 320, 320, 320, 320, 321, 322, 322,
- 322, 322, 323, 324, 169, 169, 169, 325, 326, 326, 326, 326, 326, 326, 326, 326,
- 326, 327, 326, 328, 164, 164, 164, 329, 330, 330, 330, 330, 330, 330, 331, 26,
- 330, 332, 330, 333, 164, 164, 164, 164, 334, 334, 334, 334, 334, 334, 334, 334,
- 335, 26, 26, 336, 337, 337, 338, 26, 339, 339, 339, 26, 172, 172, 2, 2,
- 2, 2, 2, 340, 341, 342, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176,
- 337, 337, 337, 337, 337, 343, 337, 344, 169, 169, 169, 169, 345, 26, 169, 169,
- 296, 346, 169, 169, 169, 169, 169, 345, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 277, 277, 347, 26, 26, 26, 26, 348, 26, 349, 350, 25, 25, 351, 352,
- 353, 25, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 354, 26, 355, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 356,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 357, 31, 31, 31, 31, 31,
- 31, 358, 26, 26, 26, 26, 31, 31, 9, 9, 0, 314, 9, 359, 0, 0,
- 0, 0, 360, 0, 258, 281, 361, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 362, 363, 0, 0, 0, 1, 2, 2, 3,
- 1, 2, 2, 3, 364, 291, 290, 291, 291, 291, 291, 365, 169, 169, 169, 296,
- 366, 366, 366, 367, 258, 258, 26, 368, 369, 370, 369, 369, 371, 369, 369, 372,
- 369, 373, 369, 373, 26, 26, 26, 26, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 374, 375, 0, 0, 0, 0, 0, 376, 0,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 253, 0, 377, 378, 26, 26, 26,
- 26, 26, 0, 0, 0, 0, 0, 379, 380, 380, 380, 381, 382, 382, 382, 382,
- 382, 382, 383, 26, 384, 0, 0, 281, 385, 385, 385, 385, 386, 387, 388, 388,
- 388, 389, 390, 390, 390, 390, 390, 391, 392, 392, 392, 393, 394, 394, 394, 394,
- 395, 394, 396, 26, 26, 26, 26, 26, 397, 397, 397, 397, 397, 397, 397, 397,
- 397, 397, 398, 398, 398, 398, 398, 398, 399, 399, 399, 400, 399, 401, 402, 402,
- 402, 402, 403, 402, 402, 402, 402, 403, 404, 404, 404, 404, 404, 26, 405, 405,
- 405, 405, 405, 405, 406, 407, 408, 409, 408, 409, 410, 408, 411, 408, 411, 412,
- 26, 26, 26, 26, 26, 26, 26, 26, 413, 413, 413, 413, 413, 413, 413, 413,
- 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 414, 26,
- 413, 413, 415, 26, 413, 26, 26, 26, 416, 2, 2, 2, 2, 2, 417, 308,
- 26, 26, 26, 26, 26, 26, 26, 26, 418, 419, 420, 420, 420, 420, 421, 422,
- 423, 423, 424, 423, 425, 425, 425, 425, 426, 426, 426, 427, 428, 426, 26, 26,
- 26, 26, 26, 26, 429, 429, 430, 431, 432, 432, 432, 433, 434, 434, 434, 435,
- 26, 26, 26, 26, 26, 26, 26, 26, 436, 436, 436, 436, 437, 437, 437, 438,
- 437, 437, 439, 437, 437, 437, 437, 437, 440, 441, 442, 443, 444, 444, 445, 446,
- 444, 447, 444, 447, 448, 448, 448, 448, 449, 449, 449, 449, 26, 26, 26, 26,
- 450, 450, 450, 450, 451, 452, 451, 26, 453, 453, 453, 453, 453, 453, 454, 455,
- 456, 456, 457, 456, 458, 458, 459, 458, 460, 460, 461, 462, 26, 463, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 464, 464, 464, 464, 464, 464, 464, 464,
- 464, 465, 26, 26, 26, 26, 26, 26, 466, 466, 466, 466, 466, 466, 467, 26,
- 466, 466, 466, 466, 466, 466, 467, 468, 469, 469, 469, 469, 469, 26, 469, 470,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 31, 31, 31, 50, 471, 471, 471, 471, 471, 472, 473, 26,
- 26, 26, 26, 26, 26, 26, 26, 474, 475, 475, 475, 475, 475, 26, 476, 476,
- 476, 476, 476, 477, 26, 26, 478, 478, 478, 479, 26, 26, 26, 26, 480, 480,
- 480, 481, 26, 26, 482, 482, 483, 26, 484, 484, 484, 484, 484, 484, 484, 484,
- 484, 485, 486, 484, 484, 484, 485, 487, 488, 488, 488, 488, 488, 488, 488, 488,
- 489, 490, 491, 491, 491, 492, 491, 493, 494, 494, 494, 494, 494, 494, 495, 494,
- 494, 26, 496, 496, 496, 496, 497, 26, 498, 498, 498, 498, 498, 498, 498, 498,
- 498, 498, 498, 498, 499, 137, 500, 26, 501, 501, 502, 501, 501, 501, 501, 501,
- 503, 26, 26, 26, 26, 26, 26, 26, 504, 505, 506, 507, 506, 508, 509, 509,
- 509, 509, 509, 509, 509, 510, 509, 511, 512, 513, 514, 515, 515, 516, 517, 518,
- 513, 519, 520, 521, 522, 523, 523, 26, 524, 524, 524, 524, 524, 524, 524, 524,
- 524, 524, 524, 525, 526, 26, 26, 26, 527, 527, 527, 527, 527, 527, 527, 527,
- 527, 26, 527, 528, 26, 26, 26, 26, 529, 529, 529, 529, 529, 529, 530, 529,
- 529, 529, 529, 530, 26, 26, 26, 26, 531, 531, 531, 531, 531, 531, 531, 531,
- 532, 26, 531, 533, 198, 534, 26, 26, 535, 535, 535, 535, 535, 535, 535, 536,
- 535, 536, 26, 26, 26, 26, 26, 26, 537, 537, 537, 538, 537, 539, 537, 537,
- 540, 26, 26, 26, 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 542,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 543, 543, 543, 543,
- 543, 543, 543, 543, 543, 543, 544, 545, 546, 547, 548, 549, 549, 549, 550, 551,
- 546, 26, 549, 552, 26, 26, 26, 26, 26, 26, 26, 26, 553, 554, 553, 553,
- 553, 553, 553, 554, 555, 26, 26, 26, 556, 556, 556, 556, 556, 556, 556, 556,
- 556, 26, 557, 557, 557, 557, 557, 557, 557, 557, 557, 557, 558, 26, 178, 178,
- 559, 559, 559, 559, 559, 559, 559, 560, 53, 561, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 562, 563, 562, 562, 562, 562, 564, 562,
- 565, 26, 562, 562, 562, 566, 567, 567, 567, 567, 568, 567, 567, 569, 570, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 571, 572, 573, 573, 573, 573, 571, 574,
- 573, 26, 573, 575, 576, 577, 578, 578, 578, 579, 580, 581, 578, 582, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 583, 583, 583, 584, 585, 585, 586, 585, 585, 585, 585, 587,
- 585, 585, 585, 588, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 589, 26,
- 108, 108, 108, 108, 108, 108, 590, 591, 592, 592, 592, 592, 592, 592, 592, 592,
- 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 593, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 592, 592, 592, 592, 592, 592, 592, 592,
- 592, 592, 592, 592, 592, 594, 595, 26, 592, 592, 592, 592, 592, 592, 592, 592,
- 596, 26, 26, 26, 26, 26, 26, 26, 26, 26, 597, 597, 597, 597, 597, 597,
- 597, 597, 597, 597, 597, 597, 598, 26, 599, 599, 599, 599, 599, 599, 599, 599,
- 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599,
- 599, 599, 600, 26, 26, 26, 26, 26, 601, 601, 601, 601, 601, 601, 601, 601,
- 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601,
- 602, 26, 26, 26, 26, 26, 26, 26, 305, 305, 305, 305, 305, 305, 305, 305,
- 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 603,
- 604, 604, 604, 605, 604, 606, 607, 607, 607, 607, 607, 607, 607, 607, 607, 608,
- 607, 609, 610, 610, 610, 611, 611, 26, 612, 612, 612, 612, 612, 612, 612, 612,
- 613, 26, 612, 614, 614, 612, 612, 615, 612, 612, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 617, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 618, 618, 618, 618, 618, 618, 618, 618,
- 618, 619, 618, 618, 618, 618, 618, 618, 618, 620, 618, 618, 26, 26, 26, 26,
- 26, 26, 26, 26, 621, 26, 347, 26, 622, 622, 622, 622, 622, 622, 622, 622,
- 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622,
- 622, 622, 622, 622, 622, 622, 622, 26, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 624, 26, 26, 26, 26, 26, 622, 625, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 626, 627, 628, 287, 287, 287, 287, 287, 287, 287,
- 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287,
- 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 629, 26, 630, 26,
- 26, 26, 631, 26, 632, 26, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633,
- 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633,
- 633, 633, 633, 633, 633, 633, 633, 634, 635, 635, 635, 635, 635, 635, 635, 635,
- 635, 635, 635, 635, 635, 636, 635, 637, 635, 638, 635, 639, 281, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 9, 9, 9, 9, 9, 640, 9, 9,
- 221, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 281, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 276, 26, 0, 0, 0, 0, 258, 363, 0, 0,
- 0, 0, 0, 0, 641, 642, 0, 643, 644, 645, 0, 0, 0, 646, 0, 0,
- 0, 0, 0, 0, 0, 266, 26, 26, 14, 14, 14, 14, 14, 14, 14, 14,
- 247, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 0, 0, 281, 26, 0, 0, 281, 26, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 258, 26, 0, 0, 0, 260, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 647, 648, 0, 649,
- 650, 0, 0, 0, 0, 0, 0, 0, 269, 651, 255, 255, 0, 0, 0, 652,
- 653, 654, 655, 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 268, 0, 0, 0, 0, 0, 0, 656, 656, 656, 656, 656, 656, 656, 656,
- 656, 656, 656, 656, 656, 656, 656, 656, 656, 657, 26, 658, 659, 656, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 348, 660, 308, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 661, 270, 270, 662, 663, 664, 18, 18,
- 18, 18, 18, 18, 18, 665, 26, 26, 26, 666, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 667, 667, 667, 667, 667, 668, 667, 669,
- 667, 670, 26, 26, 26, 26, 26, 26, 26, 26, 671, 671, 671, 672, 26, 26,
- 673, 673, 673, 673, 673, 673, 673, 674, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 675, 675, 675, 675, 675, 676, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 172, 677, 170, 172, 678, 678, 678, 678, 678, 678, 678, 678,
- 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678,
- 679, 678, 680, 26, 26, 26, 26, 26, 681, 681, 681, 681, 681, 681, 681, 681,
- 681, 682, 681, 683, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 0, 377, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 276,
- 26, 26, 26, 26, 26, 26, 26, 26, 684, 31, 31, 31, 685, 686, 687, 688,
- 689, 690, 685, 691, 685, 687, 687, 692, 31, 693, 31, 694, 695, 693, 31, 694,
- 26, 26, 26, 26, 26, 26, 51, 26, 0, 0, 0, 0, 0, 281, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 281, 26, 0, 258, 363, 0,
- 363, 0, 363, 0, 0, 0, 276, 26, 0, 0, 0, 0, 0, 276, 26, 26,
- 26, 26, 26, 26, 696, 0, 0, 0, 697, 26, 0, 0, 0, 0, 0, 281,
- 0, 260, 314, 26, 276, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 698, 0, 377, 0, 377, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 258, 699, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 314, 0, 281, 260, 26, 0, 281, 0, 0, 0, 0, 0, 0,
- 0, 26, 0, 314, 0, 0, 0, 0, 0, 26, 0, 0, 0, 276, 314, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 281, 26, 0, 276, 0, 377, 0, 260, 0, 0, 0, 0, 0, 269,
- 276, 696, 0, 281, 0, 260, 0, 260, 0, 0, 360, 0, 0, 0, 0, 0,
- 0, 266, 26, 26, 26, 26, 0, 314, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 277, 277, 277, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 347,
- 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 277, 277, 277, 277,
- 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 347, 26, 277, 277,
- 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 277, 277, 277, 700, 26, 26, 26, 277, 277, 277, 280, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 701, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 702, 26, 26, 26, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 391, 391, 391, 391, 391, 391, 391, 685, 0, 0, 0, 0, 1, 2, 1, 2,
+ 0, 0, 3, 3, 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 6, 0, 0, 7, 0, 8, 8, 8, 8, 8, 8, 8, 9,
+ 10, 11, 12, 11, 11, 11, 13, 11, 14, 14, 14, 14, 14, 14, 14, 14,
+ 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 16, 17, 18, 17, 17,
+ 19, 20, 21, 21, 22, 21, 23, 24, 25, 26, 27, 27, 28, 29, 27, 30,
+ 27, 27, 27, 27, 27, 31, 27, 27, 32, 33, 33, 33, 34, 27, 27, 27,
+ 35, 35, 35, 36, 37, 37, 37, 38, 39, 39, 40, 41, 42, 43, 44, 27,
+ 45, 46, 27, 27, 27, 27, 47, 27, 48, 48, 48, 48, 48, 49, 50, 48,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 109, 110, 111, 112, 109,
+ 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 122, 123, 122, 124, 125, 125,
+ 126, 127, 128, 129, 130, 131, 125, 125, 132, 132, 132, 132, 133, 132, 134, 135,
+ 132, 133, 132, 136, 136, 137, 125, 125, 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 139, 139, 140, 139, 139, 141, 142, 142, 142, 142, 142, 142, 142, 142,
+ 143, 143, 143, 143, 144, 145, 143, 143, 144, 143, 143, 146, 147, 148, 143, 143,
+ 143, 147, 143, 143, 143, 149, 143, 150, 143, 151, 152, 152, 152, 152, 152, 153,
+ 154, 154, 154, 154, 154, 154, 154, 154, 155, 156, 157, 157, 157, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 168, 168, 168, 169, 170, 170,
+ 171, 172, 173, 173, 173, 173, 173, 174, 173, 173, 175, 154, 154, 154, 154, 176,
+ 177, 178, 179, 179, 180, 181, 182, 183, 184, 184, 185, 184, 186, 187, 168, 168,
+ 188, 189, 190, 190, 190, 191, 190, 192, 193, 193, 194, 8, 195, 125, 125, 125,
+ 196, 196, 196, 196, 197, 196, 196, 198, 199, 199, 199, 199, 200, 200, 200, 201,
+ 202, 202, 202, 203, 204, 205, 205, 205, 206, 139, 139, 207, 208, 209, 210, 211,
+ 4, 4, 212, 4, 4, 213, 214, 215, 4, 4, 4, 216, 8, 8, 8, 8,
+ 11, 217, 11, 11, 217, 218, 11, 219, 11, 11, 11, 220, 220, 221, 11, 222,
+ 223, 0, 0, 0, 0, 0, 224, 225, 226, 227, 0, 0, 228, 8, 8, 229,
+ 0, 0, 230, 231, 232, 0, 4, 4, 233, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 125, 235, 125, 0, 0,
+ 236, 236, 236, 236, 236, 236, 236, 236, 0, 0, 0, 0, 0, 0, 0, 237,
+ 0, 238, 0, 0, 0, 0, 0, 0, 239, 239, 239, 239, 239, 239, 4, 4,
+ 240, 240, 240, 240, 240, 240, 240, 241, 139, 139, 140, 242, 242, 242, 243, 244,
+ 143, 245, 246, 246, 246, 246, 14, 14, 0, 0, 0, 0, 0, 247, 125, 125,
+ 248, 249, 248, 248, 248, 248, 248, 250, 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 251, 125, 252, 253, 0, 254, 255, 256, 257, 257, 257,
+ 257, 258, 259, 260, 260, 260, 260, 261, 262, 263, 263, 264, 142, 142, 142, 142,
+ 265, 0, 263, 263, 0, 0, 266, 260, 142, 265, 0, 0, 0, 0, 142, 267,
+ 0, 0, 0, 0, 0, 260, 260, 268, 260, 260, 260, 260, 260, 269, 0, 0,
+ 248, 248, 248, 248, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270,
+ 271, 270, 270, 270, 272, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274,
+ 274, 274, 275, 125, 14, 14, 14, 14, 14, 14, 276, 276, 276, 276, 276, 277,
+ 0, 0, 278, 4, 4, 4, 4, 4, 279, 4, 4, 4, 280, 281, 125, 282,
+ 283, 283, 284, 285, 286, 286, 286, 287, 288, 288, 288, 288, 289, 290, 48, 48,
+ 291, 291, 292, 293, 293, 294, 142, 295, 296, 296, 296, 296, 297, 298, 138, 299,
+ 300, 300, 300, 301, 302, 303, 138, 138, 304, 304, 304, 304, 305, 306, 307, 308,
+ 309, 310, 246, 4, 4, 311, 312, 152, 152, 152, 152, 152, 307, 307, 313, 314,
+ 142, 142, 315, 142, 316, 142, 142, 317, 125, 125, 125, 125, 125, 125, 125, 125,
+ 248, 248, 248, 248, 248, 248, 318, 248, 248, 248, 248, 248, 248, 319, 125, 125,
+ 320, 321, 21, 322, 323, 27, 27, 27, 27, 27, 27, 27, 324, 325, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 326, 27, 27, 27, 27,
+ 27, 327, 27, 27, 328, 125, 125, 27, 8, 285, 329, 0, 0, 330, 331, 332,
+ 27, 27, 27, 27, 27, 27, 27, 333, 334, 0, 1, 2, 1, 2, 335, 259,
+ 260, 336, 142, 265, 337, 338, 339, 340, 341, 342, 343, 344, 345, 345, 125, 125,
+ 342, 342, 342, 342, 342, 342, 342, 346, 347, 0, 0, 348, 11, 11, 11, 11,
+ 349, 350, 351, 125, 125, 0, 0, 352, 353, 354, 355, 355, 355, 356, 357, 252,
+ 358, 358, 359, 360, 361, 362, 362, 363, 364, 365, 366, 366, 367, 368, 125, 125,
+ 369, 369, 369, 369, 369, 370, 370, 370, 371, 372, 373, 374, 374, 375, 374, 376,
+ 377, 377, 378, 379, 379, 379, 380, 381, 381, 382, 383, 384, 125, 125, 125, 125,
+ 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 386, 385, 387, 388, 125,
+ 389, 4, 4, 390, 125, 125, 125, 125, 391, 392, 392, 393, 394, 395, 396, 396,
+ 397, 398, 399, 125, 125, 125, 400, 401, 402, 403, 404, 405, 125, 125, 125, 125,
+ 406, 406, 407, 408, 407, 409, 407, 407, 410, 411, 412, 413, 414, 414, 415, 415,
+ 416, 416, 125, 125, 417, 417, 418, 419, 420, 420, 420, 421, 422, 423, 424, 425,
+ 426, 427, 428, 125, 125, 125, 125, 125, 429, 429, 429, 429, 430, 125, 125, 125,
+ 431, 431, 431, 432, 431, 431, 431, 433, 434, 434, 435, 436, 125, 125, 125, 125,
+ 125, 125, 125, 125, 125, 125, 27, 45, 437, 437, 438, 439, 125, 125, 125, 440,
+ 441, 441, 442, 443, 443, 444, 125, 445, 446, 125, 125, 447, 448, 125, 449, 450,
+ 451, 451, 451, 451, 452, 453, 451, 454, 455, 455, 455, 455, 456, 457, 458, 459,
+ 460, 460, 460, 461, 462, 463, 463, 464, 465, 465, 465, 465, 465, 465, 466, 467,
+ 468, 469, 468, 468, 470, 125, 125, 125, 471, 472, 473, 474, 474, 474, 475, 476,
+ 477, 478, 479, 480, 481, 482, 483, 484, 485, 485, 485, 485, 485, 486, 487, 125,
+ 488, 488, 488, 488, 489, 490, 125, 125, 491, 491, 491, 492, 491, 493, 125, 125,
+ 494, 494, 494, 494, 495, 496, 497, 125, 498, 498, 498, 499, 499, 125, 125, 125,
+ 500, 501, 502, 500, 503, 125, 125, 125, 504, 504, 504, 505, 125, 125, 125, 125,
+ 125, 125, 506, 506, 506, 506, 506, 507, 508, 509, 510, 511, 512, 513, 125, 125,
+ 125, 125, 514, 515, 515, 514, 516, 125, 517, 517, 517, 517, 518, 519, 519, 519,
+ 519, 519, 520, 154, 521, 521, 521, 522, 523, 125, 125, 125, 125, 125, 125, 125,
+ 524, 525, 525, 526, 527, 525, 528, 529, 529, 530, 531, 532, 125, 125, 125, 125,
+ 533, 534, 534, 535, 536, 537, 538, 539, 540, 541, 542, 125, 125, 125, 125, 125,
+ 125, 125, 125, 125, 125, 125, 543, 544, 545, 546, 545, 547, 545, 548, 125, 125,
+ 125, 125, 125, 549, 550, 550, 550, 551, 552, 552, 552, 552, 552, 552, 552, 552,
+ 552, 553, 125, 125, 125, 125, 125, 125, 552, 552, 552, 552, 552, 552, 554, 555,
+ 552, 552, 552, 552, 556, 125, 125, 125, 125, 557, 557, 557, 557, 557, 557, 558,
+ 559, 559, 559, 559, 559, 559, 559, 559, 559, 559, 559, 559, 559, 560, 125, 125,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 562, 125, 125, 125,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 563, 564, 565, 566, 567,
+ 567, 567, 567, 568, 569, 570, 571, 572, 573, 573, 573, 573, 574, 575, 576, 577,
+ 573, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 578, 578, 578, 578,
+ 578, 579, 125, 125, 125, 125, 125, 125, 580, 580, 580, 580, 581, 580, 580, 580,
+ 582, 580, 125, 125, 125, 125, 583, 584, 585, 585, 585, 585, 585, 585, 585, 585,
+ 585, 585, 585, 585, 585, 585, 585, 586, 587, 587, 587, 587, 587, 587, 587, 587,
+ 587, 587, 587, 587, 587, 588, 125, 125, 589, 125, 125, 125, 125, 125, 125, 125,
+ 125, 125, 125, 125, 125, 125, 125, 590, 591, 257, 257, 257, 257, 257, 257, 257,
+ 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 592, 593, 125, 594, 595, 596,
+ 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 597,
+ 598, 598, 598, 598, 598, 598, 599, 600, 601, 602, 266, 125, 125, 125, 125, 125,
+ 8, 8, 603, 8, 604, 0, 0, 0, 0, 0, 0, 0, 266, 125, 125, 125,
+ 0, 0, 0, 0, 0, 0, 0, 605, 0, 0, 606, 0, 0, 0, 607, 608,
+ 609, 0, 610, 0, 0, 0, 235, 125, 11, 11, 11, 11, 611, 125, 125, 125,
+ 125, 125, 125, 125, 0, 266, 0, 266, 0, 0, 0, 0, 0, 234, 0, 612,
+ 0, 0, 0, 0, 0, 224, 0, 0, 0, 613, 614, 615, 616, 0, 0, 0,
+ 617, 618, 0, 619, 620, 621, 0, 0, 0, 0, 622, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 623, 0, 0, 0, 624, 624, 624, 624, 624, 624, 624, 624,
+ 625, 626, 627, 125, 125, 125, 125, 125, 4, 628, 629, 125, 125, 125, 125, 125,
+ 630, 631, 632, 14, 14, 14, 633, 125, 634, 125, 125, 125, 125, 125, 125, 125,
+ 635, 635, 636, 637, 638, 125, 125, 125, 125, 639, 640, 125, 641, 641, 641, 642,
+ 125, 125, 125, 125, 125, 643, 643, 644, 125, 125, 125, 125, 125, 125, 645, 646,
+ 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 648, 649, 125, 125,
+ 650, 650, 650, 650, 651, 652, 125, 125, 125, 125, 125, 125, 125, 125, 125, 334,
+ 0, 0, 0, 653, 125, 125, 125, 125, 334, 0, 0, 247, 125, 125, 125, 125,
+ 654, 27, 655, 656, 657, 658, 659, 660, 661, 662, 663, 662, 125, 125, 125, 664,
+ 0, 0, 252, 0, 0, 0, 0, 0, 0, 266, 226, 334, 334, 334, 0, 605,
+ 0, 0, 247, 125, 125, 125, 665, 0, 666, 0, 0, 252, 612, 667, 605, 125,
+ 0, 0, 0, 0, 0, 668, 350, 350, 0, 0, 0, 0, 0, 0, 0, 669,
+ 0, 0, 0, 0, 0, 285, 252, 228, 252, 0, 0, 0, 670, 285, 0, 0,
+ 670, 0, 247, 667, 125, 125, 125, 125, 0, 0, 0, 0, 0, 266, 247, 350,
+ 612, 0, 0, 671, 672, 252, 612, 612, 0, 330, 0, 0, 235, 125, 125, 285,
+ 248, 248, 248, 248, 248, 248, 125, 125, 248, 248, 248, 319, 248, 248, 248, 248,
+ 248, 318, 248, 248, 248, 248, 248, 248, 248, 248, 584, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 673, 125, 248, 318, 125, 125, 125, 125, 125, 125,
+ 248, 248, 248, 248, 674, 248, 248, 248, 248, 248, 248, 125, 125, 125, 125, 125,
+ 675, 125, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 1, 2, 2, 2,
+ 2, 2, 3, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, 2, 2,
+ 2, 2, 5, 0, 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 8, 8, 8, 8, 16, 8, 8, 8, 17, 18, 18, 18,
+ 19, 19, 19, 19, 19, 20, 19, 19, 21, 22, 22, 22, 22, 22, 22, 22,
+ 22, 23, 21, 22, 22, 22, 23, 21, 24, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 12, 12, 25, 25, 26, 27, 25, 28, 12, 12, 29, 30, 29, 31,
+ 29, 29, 32, 32, 29, 29, 29, 29, 31, 29, 33, 7, 7, 34, 29, 29,
+ 35, 29, 29, 29, 29, 29, 29, 30, 36, 36, 36, 37, 36, 36, 36, 36,
+ 36, 36, 38, 39, 40, 40, 40, 40, 41, 12, 12, 12, 42, 42, 42, 42,
+ 42, 42, 43, 44, 45, 45, 45, 45, 45, 45, 45, 46, 45, 45, 45, 47,
+ 48, 48, 48, 48, 48, 48, 48, 49, 36, 36, 38, 12, 29, 29, 29, 50,
+ 51, 12, 29, 29, 52, 29, 29, 29, 53, 53, 53, 53, 54, 55, 53, 53,
+ 53, 56, 53, 53, 57, 58, 57, 59, 59, 57, 57, 57, 57, 57, 60, 57,
+ 61, 62, 63, 57, 57, 59, 59, 64, 12, 65, 12, 66, 57, 62, 57, 57,
+ 57, 57, 57, 64, 67, 67, 68, 69, 70, 71, 71, 71, 71, 71, 72, 71,
+ 72, 73, 74, 72, 68, 69, 70, 74, 75, 12, 67, 76, 12, 77, 71, 71,
+ 71, 68, 12, 12, 78, 78, 79, 80, 80, 79, 79, 79, 79, 79, 81, 79,
+ 81, 78, 82, 79, 79, 80, 80, 82, 83, 12, 12, 12, 79, 84, 79, 79,
+ 82, 12, 78, 79, 85, 85, 86, 87, 87, 86, 86, 86, 86, 86, 88, 86,
+ 88, 85, 89, 86, 86, 87, 87, 89, 12, 85, 12, 90, 86, 91, 86, 86,
+ 86, 86, 12, 12, 92, 93, 94, 92, 95, 96, 97, 95, 98, 99, 94, 92,
+ 100, 100, 96, 92, 94, 92, 95, 96, 99, 98, 12, 12, 12, 92, 100, 100,
+ 100, 100, 94, 12, 101, 101, 101, 102, 102, 101, 101, 101, 101, 101, 102, 101,
+ 101, 101, 103, 101, 101, 102, 102, 103, 12, 104, 105, 106, 101, 107, 101, 101,
+ 12, 108, 101, 101, 109, 109, 109, 110, 110, 109, 109, 109, 109, 109, 110, 109,
+ 109, 111, 112, 109, 109, 110, 110, 112, 12, 113, 12, 113, 109, 114, 109, 109,
+ 111, 12, 12, 12, 115, 115, 115, 116, 116, 115, 115, 115, 115, 115, 115, 115,
+ 115, 116, 116, 115, 12, 115, 115, 115, 115, 117, 115, 115, 118, 118, 119, 119,
+ 119, 120, 121, 119, 119, 119, 119, 119, 122, 119, 119, 123, 119, 120, 124, 125,
+ 119, 126, 119, 119, 12, 121, 119, 119, 121, 127, 12, 12, 128, 129, 129, 129,
+ 129, 129, 129, 129, 129, 129, 130, 131, 129, 129, 129, 12, 12, 12, 12, 12,
+ 132, 133, 134, 135, 135, 135, 135, 135, 135, 136, 135, 135, 135, 135, 135, 137,
+ 135, 138, 135, 134, 135, 135, 137, 135, 139, 139, 139, 139, 139, 139, 140, 139,
+ 139, 139, 139, 141, 140, 139, 139, 139, 139, 139, 139, 142, 139, 143, 144, 12,
+ 145, 145, 145, 145, 146, 146, 146, 146, 146, 147, 12, 148, 146, 146, 149, 146,
+ 150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 152, 153, 151, 154, 152, 153,
+ 152, 153, 151, 154, 152, 153, 151, 151, 151, 154, 151, 151, 151, 151, 154, 155,
+ 151, 151, 151, 156, 151, 151, 153, 12, 157, 157, 157, 157, 157, 158, 157, 158,
+ 159, 159, 159, 159, 160, 160, 160, 160, 160, 160, 160, 161, 162, 162, 162, 162,
+ 162, 162, 163, 164, 162, 162, 165, 12, 166, 166, 166, 166, 166, 167, 12, 168,
+ 169, 169, 169, 169, 169, 170, 12, 12, 171, 171, 171, 171, 171, 12, 12, 12,
+ 172, 172, 172, 173, 173, 12, 12, 12, 174, 174, 174, 174, 174, 174, 174, 175,
+ 174, 174, 175, 12, 176, 177, 178, 178, 178, 178, 179, 12, 178, 178, 178, 178,
+ 178, 178, 180, 12, 178, 178, 181, 12, 159, 182, 12, 12, 183, 183, 183, 183,
+ 183, 183, 183, 184, 183, 183, 183, 12, 185, 183, 183, 183, 186, 186, 186, 186,
+ 186, 186, 186, 187, 186, 188, 12, 12, 189, 189, 189, 189, 189, 189, 189, 12,
+ 189, 189, 190, 12, 189, 189, 191, 192, 193, 193, 193, 193, 193, 193, 193, 194,
+ 195, 195, 195, 195, 195, 195, 195, 196, 195, 195, 195, 197, 195, 195, 198, 12,
+ 195, 195, 195, 198, 7, 7, 7, 199, 200, 200, 200, 200, 200, 200, 200, 201,
+ 200, 200, 200, 202, 203, 203, 203, 203, 204, 204, 204, 204, 204, 12, 12, 204,
+ 205, 205, 205, 205, 205, 205, 206, 205, 205, 205, 207, 208, 209, 209, 209, 209,
+ 19, 19, 210, 12, 146, 146, 211, 212, 203, 203, 12, 12, 213, 7, 7, 7,
+ 214, 7, 215, 216, 0, 215, 217, 12, 2, 218, 219, 2, 2, 2, 2, 220,
+ 221, 218, 222, 2, 2, 2, 223, 2, 2, 2, 2, 224, 8, 225, 8, 225,
+ 8, 8, 226, 226, 8, 8, 8, 225, 8, 15, 8, 8, 8, 10, 8, 227,
+ 10, 15, 8, 14, 0, 0, 0, 228, 0, 229, 0, 0, 230, 0, 0, 231,
+ 0, 0, 0, 232, 2, 2, 2, 233, 234, 12, 12, 12, 235, 12, 12, 12,
+ 0, 236, 237, 0, 4, 0, 0, 0, 0, 0, 0, 4, 2, 2, 5, 12,
+ 0, 232, 12, 12, 0, 0, 232, 12, 238, 238, 238, 238, 0, 239, 0, 0,
+ 0, 240, 0, 0, 241, 241, 241, 241, 18, 18, 18, 18, 18, 12, 242, 18,
+ 243, 243, 243, 243, 243, 243, 12, 244, 245, 12, 12, 244, 151, 154, 12, 12,
+ 151, 154, 151, 154, 0, 0, 0, 246, 247, 247, 247, 247, 247, 247, 248, 247,
+ 247, 12, 12, 12, 247, 249, 12, 12, 0, 0, 0, 12, 0, 250, 0, 0,
+ 251, 247, 252, 253, 0, 0, 247, 0, 254, 255, 255, 255, 255, 255, 255, 255,
+ 255, 256, 257, 258, 259, 260, 260, 260, 260, 260, 260, 260, 260, 260, 261, 259,
+ 12, 262, 263, 263, 263, 263, 263, 263, 264, 150, 150, 150, 150, 150, 150, 265,
+ 0, 12, 12, 12, 150, 150, 150, 266, 260, 260, 260, 261, 260, 260, 0, 0,
+ 267, 267, 267, 267, 267, 267, 267, 268, 267, 269, 12, 12, 270, 270, 270, 270,
+ 271, 271, 271, 271, 271, 271, 271, 12, 272, 272, 272, 272, 272, 272, 12, 12,
+ 237, 2, 2, 2, 2, 2, 231, 2, 2, 2, 273, 12, 274, 275, 276, 12,
+ 277, 2, 2, 2, 278, 278, 278, 278, 278, 278, 278, 279, 0, 0, 246, 12,
+ 280, 280, 280, 280, 280, 280, 12, 12, 281, 281, 281, 281, 281, 282, 12, 283,
+ 281, 281, 282, 12, 284, 284, 284, 284, 284, 284, 284, 285, 286, 286, 286, 286,
+ 286, 12, 12, 287, 150, 150, 150, 288, 289, 289, 289, 289, 289, 289, 289, 290,
+ 289, 289, 291, 292, 145, 145, 145, 293, 294, 294, 294, 294, 294, 295, 12, 12,
+ 294, 294, 294, 296, 294, 294, 296, 294, 297, 297, 297, 297, 298, 12, 12, 12,
+ 12, 12, 299, 297, 300, 300, 300, 300, 300, 301, 12, 12, 155, 154, 155, 154,
+ 155, 154, 12, 12, 2, 2, 3, 2, 2, 302, 303, 12, 300, 300, 300, 304,
+ 300, 300, 304, 12, 150, 12, 12, 12, 150, 265, 305, 150, 150, 150, 150, 12,
+ 247, 247, 247, 249, 247, 247, 249, 12, 2, 273, 12, 12, 306, 22, 12, 24,
+ 25, 26, 25, 307, 308, 309, 25, 25, 50, 12, 12, 12, 310, 29, 29, 29,
+ 29, 29, 29, 311, 312, 29, 29, 29, 29, 29, 12, 310, 7, 7, 7, 313,
+ 232, 0, 0, 0, 0, 232, 0, 12, 29, 314, 29, 29, 29, 29, 29, 315,
+ 316, 0, 0, 0, 0, 317, 260, 260, 260, 260, 260, 318, 319, 150, 319, 150,
+ 319, 150, 319, 288, 0, 232, 0, 232, 12, 12, 316, 246, 320, 320, 320, 321,
+ 320, 320, 320, 320, 320, 322, 320, 320, 320, 320, 322, 323, 320, 320, 320, 324,
+ 320, 320, 322, 12, 232, 131, 0, 0, 0, 131, 0, 0, 8, 8, 8, 14,
+ 0, 0, 0, 234, 325, 12, 12, 12, 0, 0, 0, 326, 327, 327, 327, 327,
+ 327, 327, 327, 328, 329, 329, 329, 329, 330, 12, 12, 12, 215, 0, 0, 0,
+ 331, 331, 331, 331, 331, 12, 12, 332, 333, 333, 333, 333, 333, 333, 334, 12,
+ 335, 335, 335, 335, 335, 335, 336, 12, 337, 337, 337, 337, 337, 337, 337, 338,
+ 339, 339, 339, 339, 339, 12, 339, 339, 339, 340, 12, 12, 341, 341, 341, 341,
+ 342, 342, 342, 342, 343, 343, 343, 343, 343, 343, 343, 344, 343, 343, 344, 12,
+ 345, 345, 345, 345, 345, 12, 345, 345, 345, 345, 345, 12, 346, 346, 346, 346,
+ 346, 346, 12, 12, 347, 347, 347, 347, 347, 12, 12, 348, 349, 349, 350, 349,
+ 350, 351, 349, 349, 351, 349, 349, 349, 351, 349, 351, 352, 353, 353, 353, 353,
+ 353, 354, 12, 12, 353, 355, 12, 12, 353, 353, 12, 12, 2, 274, 2, 2,
+ 356, 2, 273, 12, 357, 358, 359, 357, 357, 357, 357, 357, 357, 360, 361, 362,
+ 363, 363, 363, 363, 363, 364, 363, 363, 365, 365, 365, 365, 366, 366, 366, 366,
+ 366, 366, 366, 367, 12, 368, 366, 366, 369, 369, 369, 369, 370, 371, 372, 369,
+ 373, 373, 373, 373, 373, 373, 373, 374, 375, 375, 375, 375, 375, 375, 376, 377,
+ 378, 378, 378, 378, 379, 379, 379, 379, 379, 379, 12, 379, 380, 379, 379, 379,
+ 381, 382, 12, 381, 381, 383, 383, 381, 381, 381, 381, 381, 381, 384, 385, 386,
+ 381, 381, 387, 12, 388, 388, 388, 388, 389, 389, 389, 389, 390, 390, 390, 390,
+ 390, 391, 392, 390, 390, 391, 12, 12, 393, 393, 393, 393, 393, 394, 395, 393,
+ 396, 396, 396, 396, 396, 397, 396, 396, 398, 398, 398, 398, 399, 12, 398, 398,
+ 400, 400, 400, 400, 401, 12, 402, 403, 12, 12, 402, 400, 404, 404, 404, 404,
+ 404, 404, 405, 12, 406, 406, 406, 406, 407, 12, 12, 12, 407, 12, 408, 406,
+ 409, 409, 409, 409, 409, 409, 12, 12, 409, 409, 410, 12, 411, 411, 411, 411,
+ 411, 411, 412, 413, 413, 12, 12, 12, 12, 12, 12, 414, 415, 415, 415, 415,
+ 415, 415, 12, 12, 416, 416, 416, 416, 416, 416, 417, 12, 418, 418, 418, 418,
+ 418, 418, 419, 12, 420, 420, 420, 420, 420, 420, 420, 12, 421, 421, 421, 421,
+ 421, 422, 12, 12, 423, 423, 423, 423, 423, 423, 423, 424, 425, 423, 423, 423,
+ 423, 424, 12, 426, 427, 427, 427, 427, 428, 12, 12, 429, 430, 430, 430, 430,
+ 430, 430, 431, 12, 430, 430, 432, 12, 433, 433, 433, 433, 433, 434, 433, 433,
+ 433, 433, 12, 12, 435, 435, 435, 435, 435, 436, 12, 12, 437, 437, 437, 437,
+ 118, 119, 119, 119, 119, 127, 12, 12, 438, 438, 438, 438, 439, 438, 438, 438,
+ 440, 12, 12, 12, 441, 442, 443, 444, 441, 441, 441, 444, 441, 441, 445, 12,
+ 446, 446, 446, 446, 446, 446, 447, 12, 446, 446, 448, 12, 449, 450, 449, 451,
+ 451, 449, 449, 449, 449, 449, 452, 449, 452, 450, 453, 449, 449, 451, 451, 454,
+ 455, 456, 12, 450, 449, 457, 449, 455, 449, 455, 12, 12, 458, 458, 458, 458,
+ 458, 458, 458, 459, 460, 12, 12, 12, 461, 461, 461, 461, 461, 461, 12, 12,
+ 461, 461, 462, 12, 463, 463, 463, 463, 463, 464, 463, 463, 463, 463, 463, 464,
+ 465, 465, 465, 465, 465, 466, 12, 12, 465, 465, 467, 12, 178, 178, 178, 180,
+ 468, 468, 468, 468, 468, 468, 469, 12, 470, 470, 470, 470, 470, 470, 471, 472,
+ 470, 470, 470, 12, 470, 471, 12, 12, 473, 473, 473, 473, 473, 473, 473, 12,
+ 474, 474, 474, 474, 475, 12, 12, 476, 477, 478, 479, 477, 477, 480, 477, 477,
+ 477, 477, 477, 477, 477, 481, 482, 477, 477, 478, 12, 12, 477, 477, 483, 12,
+ 484, 484, 485, 484, 484, 484, 484, 484, 484, 486, 12, 12, 487, 487, 487, 487,
+ 487, 487, 12, 12, 488, 488, 488, 488, 489, 12, 12, 12, 490, 490, 490, 490,
+ 490, 490, 491, 12, 53, 53, 492, 12, 493, 493, 494, 493, 493, 493, 493, 493,
+ 493, 495, 493, 493, 493, 496, 12, 12, 493, 493, 493, 497, 498, 498, 498, 498,
+ 499, 498, 498, 498, 498, 498, 500, 498, 498, 501, 12, 12, 502, 503, 504, 502,
+ 502, 502, 502, 502, 502, 503, 505, 504, 502, 502, 12, 12, 502, 502, 506, 12,
+ 507, 508, 509, 507, 507, 507, 507, 507, 507, 507, 507, 510, 508, 507, 511, 12,
+ 507, 507, 512, 12, 513, 513, 513, 513, 513, 513, 514, 12, 515, 515, 515, 515,
+ 516, 515, 515, 515, 515, 515, 517, 518, 515, 515, 519, 12, 520, 12, 12, 12,
+ 100, 100, 100, 100, 96, 12, 12, 98, 521, 521, 521, 521, 521, 521, 522, 12,
+ 521, 521, 521, 523, 521, 524, 12, 12, 521, 12, 12, 12, 525, 525, 525, 525,
+ 526, 12, 12, 12, 527, 527, 527, 527, 527, 528, 12, 12, 529, 529, 529, 529,
+ 529, 530, 12, 12, 272, 272, 531, 12, 532, 532, 532, 532, 532, 532, 532, 533,
+ 532, 532, 534, 535, 536, 536, 536, 536, 536, 536, 536, 537, 536, 536, 538, 12,
+ 539, 539, 539, 539, 539, 539, 539, 540, 539, 540, 12, 12, 541, 541, 541, 541,
+ 541, 542, 12, 12, 541, 541, 543, 541, 543, 541, 541, 541, 541, 541, 12, 544,
+ 545, 545, 545, 545, 545, 545, 546, 12, 547, 547, 547, 547, 547, 547, 548, 549,
+ 547, 547, 12, 549, 550, 551, 12, 12, 249, 12, 12, 12, 552, 552, 552, 552,
+ 552, 552, 12, 12, 553, 553, 553, 553, 553, 554, 12, 12, 552, 552, 555, 12,
+ 260, 556, 260, 557, 558, 255, 255, 255, 559, 12, 12, 12, 560, 12, 12, 12,
+ 256, 561, 12, 12, 12, 260, 12, 12, 562, 562, 562, 562, 562, 562, 562, 12,
+ 563, 563, 563, 563, 563, 563, 564, 12, 563, 563, 563, 565, 563, 563, 565, 12,
+ 563, 563, 566, 563, 7, 7, 7, 567, 7, 199, 12, 12, 0, 246, 12, 12,
+ 0, 232, 316, 0, 0, 568, 228, 0, 0, 0, 568, 7, 213, 569, 7, 0,
+ 0, 0, 570, 228, 8, 225, 12, 12, 0, 0, 234, 12, 0, 0, 0, 229,
+ 571, 572, 316, 229, 0, 0, 240, 316, 0, 316, 0, 0, 0, 240, 232, 316,
+ 0, 229, 0, 229, 0, 0, 240, 232, 0, 573, 239, 0, 229, 0, 0, 0,
+ 0, 246, 0, 0, 0, 0, 0, 239, 574, 574, 574, 574, 574, 574, 574, 12,
+ 12, 12, 575, 574, 576, 574, 574, 574, 2, 2, 2, 273, 12, 275, 273, 12,
+ 241, 577, 241, 241, 241, 241, 578, 241, 579, 580, 577, 12, 19, 19, 19, 581,
+ 12, 12, 12, 582, 583, 583, 583, 583, 583, 583, 583, 584, 583, 583, 583, 585,
+ 583, 583, 585, 586, 587, 587, 587, 587, 587, 587, 587, 588, 589, 589, 589, 589,
+ 589, 589, 590, 591, 592, 592, 592, 592, 592, 592, 593, 12, 151, 154, 151, 594,
+ 151, 151, 151, 154, 595, 595, 595, 595, 595, 596, 595, 595, 595, 597, 12, 12,
+ 598, 598, 598, 598, 598, 598, 598, 12, 598, 598, 599, 600, 0, 234, 12, 12,
+ 29, 414, 29, 29, 601, 602, 414, 29, 50, 29, 603, 12, 604, 310, 603, 414,
+ 601, 602, 603, 603, 601, 602, 50, 29, 50, 29, 414, 605, 29, 29, 606, 29,
+ 29, 29, 29, 12, 414, 414, 606, 29, 51, 12, 12, 12, 12, 239, 0, 0,
+ 607, 12, 12, 12, 246, 12, 12, 12, 0, 0, 12, 0, 0, 232, 131, 0,
+ 0, 0, 12, 12, 0, 0, 0, 240, 0, 246, 12, 239, 608, 12, 12, 12,
+ 247, 247, 609, 12, 610, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962,
969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0,
0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147,
@@ -4562,21 +4387,14 @@ _hb_ucd_u16[9320] =
817, 818, 819, 820, 821, 935, 0, 0,
};
static const int16_t
-_hb_ucd_i16[196] =
+_hb_ucd_i16[92] =
{
- 0, 0, 0, 0, 1, -1, 0, 0, 2, 0, -2, 0, 0, 0, 0, 2,
- 0, -2, 0, 0, 0, 0, 0, 16, 0, 0, 0, -16, 0, 0, 1, -1,
- 0, 0, 0, 1, -1, 0, 0, 0, 0, 1, -1, 0, 3, 3, 3, -3,
- -3, -3, 0, 0, 0, 2016, 0, 0, 0, 0, 0, 2527, 1923, 1914, 1918, 0,
- 2250, 0, 0, 0, 0, 0, 0, 138, 0, 7, 0, 0, -7, 0, 0, 0,
- 1, -1, 1, -1, -1, 1, -1, 0, 1824, 0, 0, 0, 0, 0, 2104, 0,
- 2108, 2106, 0, 2106, 1316, 0, 0, 0, 0, 1, -1, 1, -1, -138, 0, 0,
- 1, -1, 8, 8, 8, 0, 7, 7, 0, 0, -8, -8, -8, -7, -7, 0,
- 1, -1, 0, 2,-1316, 1, -1, 0, -1, 1, -1, 1, -1, 3, 1, -1,
- -3, 1, -1, 1, -1, 0, 0,-1914,-1918, 0, 0,-1923,-1824, 0, 0, 0,
- 0,-2016, 0, 0, 1, -1, 0, 1, 0, 0,-2104, 0, 0, 0, 0,-2106,
- -2108,-2106, 0, 0, 1, -1,-2250, 0, 0, 0,-2527, 0, 0, -2, 0, 1,
- -1, 0, 1, -1,
+ 0, 0, 1, -1, 2, 0, -2, 0, 0, 2, 0, -2, 0, 16, 0, -16,
+ 0, 1, -1, 0, 3, 3, 3, -3, -3, -3, 0, 2016, 0, 2527, 1923, 1914,
+ 1918, 0, 2250, 0, 0, 138, 0, 7, -7, 0, -1, 1, 1824, 0, 2104, 0,
+ 2108, 2106, 0, 2106, 1316, 0, -1, -138, 8, 8, 8, 0, 7, 7, -8, -8,
+ -8, -7,-1316, 1, -1, 3, -3, 1, 0,-1914,-1918, 0, 0,-1923,-1824, 0,
+ 0,-2016,-2104, 0, 0,-2106,-2108,-2106,-2250, 0,-2527, 0,
};
static inline uint_fast8_t
@@ -4597,17 +4415,17 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
static inline int_fast16_t
_hb_ucd_bmg (unsigned u)
{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9540+(((_hb_ucd_u8[9420+(((_hb_ucd_b4(9292+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9684+(((_hb_ucd_u8[9452+(((_hb_ucd_u8[9356+(((_hb_ucd_b4(9292+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
}
static inline uint_fast8_t
_hb_ucd_sc (unsigned u)
{
- return u<918000u?_hb_ucd_u8[11062+(((_hb_ucd_u16[2040+(((_hb_ucd_u8[10326+(((_hb_ucd_u8[9876+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
+ return u<918000u?_hb_ucd_u8[11118+(((_hb_ucd_u16[4024+(((_hb_ucd_u16[2040+(((_hb_ucd_u8[10382+(((_hb_ucd_u8[9932+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
}
static inline uint_fast16_t
_hb_ucd_dm (unsigned u)
{
- return u<195102u?_hb_ucd_u16[6008+(((_hb_ucd_u8[17068+(((_hb_ucd_u8[16686+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+ return u<195102u?_hb_ucd_u16[6728+(((_hb_ucd_u8[13944+(((_hb_ucd_u8[13562+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
}
diff --git a/thirdparty/harfbuzz/src/hb-ucd.cc b/thirdparty/harfbuzz/src/hb-ucd.cc
index baea224a25..4c8b1ee5e6 100644
--- a/thirdparty/harfbuzz/src/hb-ucd.cc
+++ b/thirdparty/harfbuzz/src/hb-ucd.cc
@@ -129,12 +129,16 @@ hb_ucd_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab,
void *user_data HB_UNUSED)
{
+ // Hangul is handled algorithmically.
if (_hb_ucd_compose_hangul (a, b, ab)) return true;
hb_codepoint_t u = 0;
if ((a & 0xFFFFF800u) == 0x0000u && (b & 0xFFFFFF80) == 0x0300u)
{
+ /* If "a" is small enough and "b" is in the U+0300 range,
+ * the composition data is encoded in a 32bit array sorted
+ * by "a,b" pair. */
uint32_t k = HB_CODEPOINT_ENCODE3_11_7_14 (a, b, 0);
const uint32_t *v = hb_bsearch (k,
_hb_ucd_dm2_u32_map,
@@ -146,6 +150,8 @@ hb_ucd_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
}
else
{
+ /* Otherwise it is stored in a 64bit array sorted by
+ * "a,b" pair. */
uint64_t k = HB_CODEPOINT_ENCODE3 (a, b, 0);
const uint64_t *v = hb_bsearch (k,
_hb_ucd_dm2_u64_map,
@@ -170,15 +176,22 @@ hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
unsigned i = _hb_ucd_dm (ab);
+ /* If no data, there's no decomposition. */
if (likely (!i)) return false;
i--;
+ /* Check if it's a single-character decomposition. */
if (i < ARRAY_LENGTH (_hb_ucd_dm1_p0_map) + ARRAY_LENGTH (_hb_ucd_dm1_p2_map))
{
+ /* Single-character decompositions currently are only in plane 0 or plane 2. */
if (i < ARRAY_LENGTH (_hb_ucd_dm1_p0_map))
+ {
+ /* Plane 0. */
*a = _hb_ucd_dm1_p0_map[i];
+ }
else
{
+ /* Plane 2. */
i -= ARRAY_LENGTH (_hb_ucd_dm1_p0_map);
*a = 0x20000 | _hb_ucd_dm1_p2_map[i];
}
@@ -187,8 +200,10 @@ hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
}
i -= ARRAY_LENGTH (_hb_ucd_dm1_p0_map) + ARRAY_LENGTH (_hb_ucd_dm1_p2_map);
+ /* Otherwise they are encoded either in a 32bit array or a 64bit array. */
if (i < ARRAY_LENGTH (_hb_ucd_dm2_u32_map))
{
+ /* 32bit array. */
uint32_t v = _hb_ucd_dm2_u32_map[i];
*a = HB_CODEPOINT_DECODE3_11_7_14_1 (v);
*b = HB_CODEPOINT_DECODE3_11_7_14_2 (v);
@@ -196,6 +211,7 @@ hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
}
i -= ARRAY_LENGTH (_hb_ucd_dm2_u32_map);
+ /* 64bit array. */
uint64_t v = _hb_ucd_dm2_u64_map[i];
*a = HB_CODEPOINT_DECODE3_1 (v);
*b = HB_CODEPOINT_DECODE3_2 (v);
diff --git a/thirdparty/harfbuzz/src/hb-unicode.cc b/thirdparty/harfbuzz/src/hb-unicode.cc
index c1795dc7f2..9a6471e52c 100644
--- a/thirdparty/harfbuzz/src/hb-unicode.cc
+++ b/thirdparty/harfbuzz/src/hb-unicode.cc
@@ -377,20 +377,30 @@ hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t *ufuncs, \
hb_destroy_func_t destroy) \
{ \
if (hb_object_is_immutable (ufuncs)) \
- return; \
+ goto fail; \
+ \
+ if (!func) \
+ { \
+ if (destroy) \
+ destroy (user_data); \
+ destroy = nullptr; \
+ user_data = ufuncs->parent->user_data.name; \
+ } \
\
if (ufuncs->destroy.name) \
ufuncs->destroy.name (ufuncs->user_data.name); \
\
- if (func) { \
+ if (func) \
ufuncs->func.name = func; \
- ufuncs->user_data.name = user_data; \
- ufuncs->destroy.name = destroy; \
- } else { \
+ else \
ufuncs->func.name = ufuncs->parent->func.name; \
- ufuncs->user_data.name = ufuncs->parent->user_data.name; \
- ufuncs->destroy.name = nullptr; \
- } \
+ ufuncs->user_data.name = user_data; \
+ ufuncs->destroy.name = destroy; \
+ return; \
+ \
+fail: \
+ if (destroy) \
+ destroy (user_data); \
}
HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
diff --git a/thirdparty/harfbuzz/src/hb-uniscribe.cc b/thirdparty/harfbuzz/src/hb-uniscribe.cc
index 50f71ce9ce..9648e02663 100644
--- a/thirdparty/harfbuzz/src/hb-uniscribe.cc
+++ b/thirdparty/harfbuzz/src/hb-uniscribe.cc
@@ -355,7 +355,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
return nullptr;
}
- memcpy(new_sfnt_data, orig_sfnt_data, length);
+ hb_memcpy(new_sfnt_data, orig_sfnt_data, length);
OT::name &name = StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
name.format = 0;
@@ -478,11 +478,11 @@ populate_log_font (LOGFONTW *lf,
hb_font_t *font,
unsigned int font_size)
{
- memset (lf, 0, sizeof (*lf));
+ hb_memset (lf, 0, sizeof (*lf));
lf->lfHeight = - (int) font_size;
lf->lfCharSet = DEFAULT_CHARSET;
- memcpy (lf->lfFaceName, font->face->data.uniscribe->face_name, sizeof (lf->lfFaceName));
+ hb_memcpy (lf->lfFaceName, font->face->data.uniscribe->face_name, sizeof (lf->lfFaceName));
return true;
}
diff --git a/thirdparty/harfbuzz/src/hb-vector.hh b/thirdparty/harfbuzz/src/hb-vector.hh
index a6d9f6b3fb..9b52f5ca95 100644
--- a/thirdparty/harfbuzz/src/hb-vector.hh
+++ b/thirdparty/harfbuzz/src/hb-vector.hh
@@ -35,7 +35,7 @@
template <typename Type,
bool sorted=false>
-struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty_t>::type
+struct hb_vector_t
{
typedef Type item_t;
static constexpr unsigned item_size = hb_static_size (Type);
@@ -53,9 +53,10 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
hb_requires (hb_is_iterable (Iterable))>
hb_vector_t (const Iterable &o) : hb_vector_t ()
{
- if (hb_iter (o).is_random_access_iterator)
- alloc (hb_len (hb_iter (o)));
- hb_copy (o, *this);
+ auto iter = hb_iter (o);
+ if (iter.is_random_access_iterator)
+ alloc (hb_len (iter));
+ hb_copy (iter, *this);
}
hb_vector_t (const hb_vector_t &o) : hb_vector_t ()
{
@@ -83,6 +84,9 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
allocated = length = 0;
arrayZ = nullptr;
}
+ void init0 ()
+ {
+ }
void fini ()
{
@@ -94,7 +98,11 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
void reset ()
{
if (unlikely (in_error ()))
- allocated = length; // Big hack!
+ /* Big Hack! We don't know the true allocated size before
+ * an allocation failure happened. But we know it was at
+ * least as big as length. Restore it to that and continue
+ * as if error did not happen. */
+ allocated = length;
resize (0);
}
@@ -122,7 +130,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
}
hb_bytes_t as_bytes () const
- { return hb_bytes_t ((const char *) arrayZ, length * item_size); }
+ { return hb_bytes_t ((const char *) arrayZ, get_size ()); }
bool operator == (const hb_vector_t &o) const { return as_array () == o.as_array (); }
bool operator != (const hb_vector_t &o) const { return !(*this == o); }
@@ -164,14 +172,10 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
operator iter_t () const { return iter (); }
operator writer_t () { return writer (); }
- c_array_t sub_array (unsigned int start_offset, unsigned int count) const
- { return as_array ().sub_array (start_offset, count); }
- c_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
- { return as_array ().sub_array (start_offset, count); }
- array_t sub_array (unsigned int start_offset, unsigned int count)
- { return as_array ().sub_array (start_offset, count); }
- array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
- { return as_array ().sub_array (start_offset, count); }
+ /* Faster range-based for loop. */
+ Type *begin () const { return arrayZ; }
+ Type *end () const { return arrayZ + length; }
+
hb_sorted_array_t<Type> as_sorted_array ()
{ return hb_sorted_array (arrayZ, length); }
@@ -240,12 +244,11 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
if (likely (new_array))
{
for (unsigned i = 0; i < length; i++)
+ {
new (std::addressof (new_array[i])) Type ();
- for (unsigned i = 0; i < (unsigned) length; i++)
new_array[i] = std::move (arrayZ[i]);
- unsigned old_length = length;
- shrink_vector (0);
- length = old_length;
+ arrayZ[i].~Type ();
+ }
hb_free (arrayZ);
}
return new_array;
@@ -277,7 +280,14 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
copy_vector (const hb_vector_t &other)
{
length = other.length;
- hb_memcpy ((void *) arrayZ, (const void *) other.arrayZ, length * item_size);
+#ifndef HB_OPTIMIZE_SIZE
+ if (sizeof (T) >= sizeof (long long))
+ /* This runs faster because of alignment. */
+ for (unsigned i = 0; i < length; i++)
+ arrayZ[i] = other.arrayZ[i];
+ else
+#endif
+ hb_memcpy ((void *) arrayZ, (const void *) other.arrayZ, length * item_size);
}
template <typename T = Type,
hb_enable_if (!hb_is_trivially_copyable (T) &&
@@ -309,15 +319,6 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
}
}
- template <typename T = Type,
- hb_enable_if (hb_is_trivially_destructible(T))>
- void
- shrink_vector (unsigned size)
- {
- length = size;
- }
- template <typename T = Type,
- hb_enable_if (!hb_is_trivially_destructible(T))>
void
shrink_vector (unsigned size)
{
@@ -328,17 +329,6 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
}
}
- template <typename T = Type,
- hb_enable_if (hb_is_trivially_copy_assignable(T))>
- void
- shift_down_vector (unsigned i)
- {
- memmove (static_cast<void *> (&arrayZ[i - 1]),
- static_cast<void *> (&arrayZ[i]),
- (length - i) * sizeof (Type));
- }
- template <typename T = Type,
- hb_enable_if (!hb_is_trivially_copy_assignable(T))>
void
shift_down_vector (unsigned i)
{
@@ -381,16 +371,22 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
return true;
}
- bool resize (int size_)
+ bool resize (int size_, bool initialize = true)
{
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
if (!alloc (size))
return false;
if (size > length)
- grow_vector (size);
+ {
+ if (initialize)
+ grow_vector (size);
+ }
else if (size < length)
- shrink_vector (size);
+ {
+ if (initialize)
+ shrink_vector (size);
+ }
length = size;
return true;
@@ -399,13 +395,13 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
Type pop ()
{
if (!length) return Null (Type);
- Type v = arrayZ[length - 1];
+ Type v {std::move (arrayZ[length - 1])};
arrayZ[length - 1].~Type ();
length--;
return v;
}
- void remove (unsigned int i)
+ void remove_ordered (unsigned int i)
{
if (unlikely (i >= length))
return;
@@ -414,6 +410,18 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
length--;
}
+ template <bool Sorted = sorted,
+ hb_enable_if (!Sorted)>
+ void remove_unordered (unsigned int i)
+ {
+ if (unlikely (i >= length))
+ return;
+ if (i != length - 1)
+ arrayZ[i] = std::move (arrayZ[length - 1]);
+ arrayZ[length - 1].~Type ();
+ length--;
+ }
+
void shrink (int size_)
{
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
@@ -425,10 +433,8 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
/* Sorting API. */
- void qsort (int (*cmp)(const void*, const void*))
+ void qsort (int (*cmp)(const void*, const void*) = Type::cmp)
{ as_array ().qsort (cmp); }
- void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
- { as_array ().qsort (start, end); }
/* Unsorted search API. */
template <typename T>
diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h
index 8d6ec66e13..1070262a3b 100644
--- a/thirdparty/harfbuzz/src/hb-version.h
+++ b/thirdparty/harfbuzz/src/hb-version.h
@@ -41,26 +41,26 @@ HB_BEGIN_DECLS
*
* The major component of the library version available at compile-time.
*/
-#define HB_VERSION_MAJOR 5
+#define HB_VERSION_MAJOR 6
/**
* HB_VERSION_MINOR:
*
* The minor component of the library version available at compile-time.
*/
-#define HB_VERSION_MINOR 3
+#define HB_VERSION_MINOR 0
/**
* HB_VERSION_MICRO:
*
* The micro component of the library version available at compile-time.
*/
-#define HB_VERSION_MICRO 1
+#define HB_VERSION_MICRO 0
/**
* HB_VERSION_STRING:
*
* A string literal containing the library version available at compile-time.
*/
-#define HB_VERSION_STRING "5.3.1"
+#define HB_VERSION_STRING "6.0.0"
/**
* HB_VERSION_ATLEAST:
diff --git a/thirdparty/harfbuzz/src/hb.hh b/thirdparty/harfbuzz/src/hb.hh
index 8ec638a2b4..410d090d36 100644
--- a/thirdparty/harfbuzz/src/hb.hh
+++ b/thirdparty/harfbuzz/src/hb.hh
@@ -126,6 +126,7 @@
/* Ignored intentionally. */
#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED
#pragma GCC diagnostic ignored "-Wclass-memaccess"
+#pragma GCC diagnostic ignored "-Wcast-function-type-strict" // https://github.com/harfbuzz/harfbuzz/pull/3859#issuecomment-1295409126
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#pragma GCC diagnostic ignored "-Wformat-zero-length"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
diff --git a/thirdparty/libpng/arm/arm_init.c b/thirdparty/libpng/arm/arm_init.c
index ab22525b38..84d05556f8 100644
--- a/thirdparty/libpng/arm/arm_init.c
+++ b/thirdparty/libpng/arm/arm_init.c
@@ -36,7 +36,10 @@
#ifndef PNG_ARM_NEON_FILE
# if defined(__aarch64__) || defined(_M_ARM64)
/* ARM Neon is expected to be unconditionally available on ARM64. */
-# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on this platform"
+# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on ARM64"
+# elif defined(__ARM_NEON__) || defined(__ARM_NEON)
+ /* ARM Neon is expected to be available on the target CPU architecture. */
+# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on this CPU arch"
# elif defined(__linux__)
# define PNG_ARM_NEON_FILE "contrib/arm-neon/linux.c"
# else
diff --git a/thirdparty/libpng/png.c b/thirdparty/libpng/png.c
index fc09564262..4f3e8bbd31 100644
--- a/thirdparty/libpng/png.c
+++ b/thirdparty/libpng/png.c
@@ -14,7 +14,7 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_38 Your_png_h_is_not_version_1_6_38;
+typedef png_libpng_version_1_6_39 Your_png_h_is_not_version_1_6_39;
#ifdef __GNUC__
/* The version tests may need to be added to, but the problem warning has
@@ -815,7 +815,7 @@ png_get_copyright(png_const_structrp png_ptr)
return PNG_STRING_COPYRIGHT
#else
return PNG_STRING_NEWLINE \
- "libpng version 1.6.38" PNG_STRING_NEWLINE \
+ "libpng version 1.6.39" PNG_STRING_NEWLINE \
"Copyright (c) 2018-2022 Cosmin Truta" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
PNG_STRING_NEWLINE \
@@ -2710,7 +2710,7 @@ png_check_IHDR(png_const_structrp png_ptr,
int /* PRIVATE */
png_check_fp_number(png_const_charp string, size_t size, int *statep,
- png_size_tp whereami)
+ size_t *whereami)
{
int state = *statep;
size_t i = *whereami;
diff --git a/thirdparty/libpng/png.h b/thirdparty/libpng/png.h
index 5fb494fb1a..f109cdf336 100644
--- a/thirdparty/libpng/png.h
+++ b/thirdparty/libpng/png.h
@@ -1,7 +1,7 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.6.38 - September 14, 2022
+ * libpng version 1.6.39 - November 20, 2022
*
* Copyright (c) 2018-2022 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
@@ -15,7 +15,7 @@
* libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
* libpng versions 0.97, January 1998, through 1.6.35, July 2018:
* Glenn Randers-Pehrson
- * libpng versions 1.6.36, December 2018, through 1.6.38, September 2022:
+ * libpng versions 1.6.36, December 2018, through 1.6.39, November 2022:
* Cosmin Truta
* See also "Contributing Authors", below.
*/
@@ -239,7 +239,7 @@
* ...
* 1.5.30 15 10530 15.so.15.30[.0]
* ...
- * 1.6.38 16 10638 16.so.16.38[.0]
+ * 1.6.39 16 10639 16.so.16.39[.0]
*
* Henceforth the source version will match the shared-library major and
* minor numbers; the shared-library major version number will be used for
@@ -278,8 +278,8 @@
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.38"
-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.38 - September 14, 2022\n"
+#define PNG_LIBPNG_VER_STRING "1.6.39"
+#define PNG_HEADER_VERSION_STRING " libpng version 1.6.39 - November 20, 2022\n"
#define PNG_LIBPNG_VER_SONUM 16
#define PNG_LIBPNG_VER_DLLNUM 16
@@ -287,7 +287,7 @@
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
#define PNG_LIBPNG_VER_MINOR 6
-#define PNG_LIBPNG_VER_RELEASE 38
+#define PNG_LIBPNG_VER_RELEASE 39
/* This should be zero for a public release, or non-zero for a
* development version. [Deprecated]
@@ -318,7 +318,7 @@
* From version 1.0.1 it is:
* XXYYZZ, where XX=major, YY=minor, ZZ=release
*/
-#define PNG_LIBPNG_VER 10638 /* 1.6.38 */
+#define PNG_LIBPNG_VER 10639 /* 1.6.39 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -428,7 +428,7 @@ extern "C" {
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
*/
-typedef char* png_libpng_version_1_6_38;
+typedef char* png_libpng_version_1_6_39;
/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
*
diff --git a/thirdparty/libpng/pngconf.h b/thirdparty/libpng/pngconf.h
index 89d28f83a0..fcb4b43069 100644
--- a/thirdparty/libpng/pngconf.h
+++ b/thirdparty/libpng/pngconf.h
@@ -1,7 +1,7 @@
/* pngconf.h - machine-configurable file for libpng
*
- * libpng version 1.6.38
+ * libpng version 1.6.39
*
* Copyright (c) 2018-2022 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
diff --git a/thirdparty/libpng/pnglibconf.h b/thirdparty/libpng/pnglibconf.h
index 89d5b4c8ad..e5948c8ce1 100644
--- a/thirdparty/libpng/pnglibconf.h
+++ b/thirdparty/libpng/pnglibconf.h
@@ -1,6 +1,6 @@
/* pnglibconf.h - library build configuration */
-/* libpng version 1.6.38 */
+/* libpng version 1.6.39 */
/* Copyright (c) 2018-2022 Cosmin Truta */
/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
diff --git a/thirdparty/libpng/pngpriv.h b/thirdparty/libpng/pngpriv.h
index 2e426cf47d..b8a73b685d 100644
--- a/thirdparty/libpng/pngpriv.h
+++ b/thirdparty/libpng/pngpriv.h
@@ -1946,7 +1946,7 @@ PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr,
* the problem character.) This has not been tested within libpng.
*/
PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string,
- size_t size, int *statep, png_size_tp whereami),PNG_EMPTY);
+ size_t size, int *statep, size_t *whereami),PNG_EMPTY);
/* This is the same but it checks a complete string and returns true
* only if it just contains a floating point number. As of 1.5.4 this
diff --git a/thirdparty/libpng/pngread.c b/thirdparty/libpng/pngread.c
index 5ab9224038..96996ced5b 100644
--- a/thirdparty/libpng/pngread.c
+++ b/thirdparty/libpng/pngread.c
@@ -3762,13 +3762,13 @@ png_image_read_direct(png_voidp argument)
mode = PNG_ALPHA_PNG;
output_gamma = PNG_DEFAULT_sRGB;
}
-
+
if ((change & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0)
{
mode = PNG_ALPHA_OPTIMIZED;
change &= ~PNG_FORMAT_FLAG_ASSOCIATED_ALPHA;
}
-
+
/* If 'do_local_background' is set check for the presence of gamma
* correction; this is part of the work-round for the libpng bug
* described above.
diff --git a/thirdparty/libpng/pngrutil.c b/thirdparty/libpng/pngrutil.c
index ca060dd15f..068ab193a3 100644
--- a/thirdparty/libpng/pngrutil.c
+++ b/thirdparty/libpng/pngrutil.c
@@ -3186,7 +3186,7 @@ png_check_chunk_length(png_const_structrp png_ptr, png_uint_32 length)
{
png_debug2(0," length = %lu, limit = %lu",
(unsigned long)length,(unsigned long)limit);
- png_chunk_error(png_ptr, "chunk data is too large");
+ png_benign_error(png_ptr, "chunk data is too large");
}
}
diff --git a/thirdparty/libpng/pngwrite.c b/thirdparty/libpng/pngwrite.c
index 06c45d16ab..4e58d776a9 100644
--- a/thirdparty/libpng/pngwrite.c
+++ b/thirdparty/libpng/pngwrite.c
@@ -75,10 +75,10 @@ write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr,
* library. If you have a new chunk to add, make a function to write it,
* and put it in the correct location here. If you want the chunk written
* after the image data, put it in png_write_end(). I strongly encourage
- * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
- * the chunk, as that will keep the code from breaking if you want to just
- * write a plain PNG file. If you have long comments, I suggest writing
- * them in png_write_end(), and compressing them.
+ * you to supply a PNG_INFO_<chunk> flag, and check info_ptr->valid before
+ * writing the chunk, as that will keep the code from breaking if you want
+ * to just write a plain PNG file. If you have long comments, I suggest
+ * writing them in png_write_end(), and compressing them.
*/
void PNGAPI
png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
diff --git a/thirdparty/libpng/pngwutil.c b/thirdparty/libpng/pngwutil.c
index 16345e4c0b..01f0607c70 100644
--- a/thirdparty/libpng/pngwutil.c
+++ b/thirdparty/libpng/pngwutil.c
@@ -1,7 +1,7 @@
/* pngwutil.c - utilities to write a PNG file
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2022 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -1747,7 +1747,7 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0,
{
png_uint_32 purpose_len;
size_t units_len, total_len;
- png_size_tp params_len;
+ size_t *params_len;
png_byte buf[10];
png_byte new_purpose[80];
int i;
@@ -1769,7 +1769,7 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0,
png_debug1(3, "pCAL units length = %d", (int)units_len);
total_len = purpose_len + units_len + 10;
- params_len = (png_size_tp)png_malloc(png_ptr,
+ params_len = (size_t *)png_malloc(png_ptr,
(png_alloc_size_t)((png_alloc_size_t)nparams * (sizeof (size_t))));
/* Find the length of each parameter, making sure we don't count the
diff --git a/thirdparty/mbedtls/include/mbedtls/asn1write.h b/thirdparty/mbedtls/include/mbedtls/asn1write.h
index 44afae0e56..5da7654bb4 100644
--- a/thirdparty/mbedtls/include/mbedtls/asn1write.h
+++ b/thirdparty/mbedtls/include/mbedtls/asn1write.h
@@ -90,7 +90,7 @@ int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start,
#if defined(MBEDTLS_BIGNUM_C)
/**
- * \brief Write a arbitrary-precision number (#MBEDTLS_ASN1_INTEGER)
+ * \brief Write an arbitrary-precision number (#MBEDTLS_ASN1_INTEGER)
* in ASN.1 format.
*
* \note This function works backwards in data buffer.
diff --git a/thirdparty/mbedtls/include/mbedtls/bignum.h b/thirdparty/mbedtls/include/mbedtls/bignum.h
index dd594c512d..c61db82c6d 100644
--- a/thirdparty/mbedtls/include/mbedtls/bignum.h
+++ b/thirdparty/mbedtls/include/mbedtls/bignum.h
@@ -182,6 +182,20 @@
#endif /* !MBEDTLS_NO_UDBL_DIVISION */
#endif /* !MBEDTLS_HAVE_INT64 */
+/** \typedef mbedtls_mpi_uint
+ * \brief The type of machine digits in a bignum, called _limbs_.
+ *
+ * This is always an unsigned integer type with no padding bits. The size
+ * is platform-dependent.
+ */
+
+/** \typedef mbedtls_mpi_sint
+ * \brief The signed type corresponding to #mbedtls_mpi_uint.
+ *
+ * This is always a signed integer type with no padding bits. The size
+ * is platform-dependent.
+ */
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -191,9 +205,27 @@ extern "C" {
*/
typedef struct mbedtls_mpi
{
- int s; /*!< Sign: -1 if the mpi is negative, 1 otherwise */
- size_t n; /*!< total # of limbs */
- mbedtls_mpi_uint *p; /*!< pointer to limbs */
+ /** Sign: -1 if the mpi is negative, 1 otherwise.
+ *
+ * The number 0 must be represented with `s = +1`. Although many library
+ * functions treat all-limbs-zero as equivalent to a valid representation
+ * of 0 regardless of the sign bit, there are exceptions, so bignum
+ * functions and external callers must always set \c s to +1 for the
+ * number zero.
+ *
+ * Note that this implies that calloc() or `... = {0}` does not create
+ * a valid MPI representation. You must call mbedtls_mpi_init().
+ */
+ int s;
+
+ /** Total number of limbs in \c p. */
+ size_t n;
+
+ /** Pointer to limbs.
+ *
+ * This may be \c NULL if \c n is 0.
+ */
+ mbedtls_mpi_uint *p;
}
mbedtls_mpi;
@@ -280,7 +312,7 @@ void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y );
* \param Y The MPI to be assigned from. This must point to an
* initialized MPI.
* \param assign The condition deciding whether to perform the
- * assignment or not. Possible values:
+ * assignment or not. Must be either 0 or 1:
* * \c 1: Perform the assignment `X = Y`.
* * \c 0: Keep the original value of \p X.
*
@@ -291,6 +323,10 @@ void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y );
* information through branch prediction and/or memory access
* patterns analysis).
*
+ * \warning If \p assign is neither 0 nor 1, the result of this function
+ * is indeterminate, and the resulting value in \p X might be
+ * neither its original value nor the value in \p Y.
+ *
* \return \c 0 if successful.
* \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed.
* \return Another negative error code on other kinds of failure.
@@ -303,24 +339,28 @@ int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned
*
* \param X The first MPI. This must be initialized.
* \param Y The second MPI. This must be initialized.
- * \param assign The condition deciding whether to perform
- * the swap or not. Possible values:
+ * \param swap The condition deciding whether to perform
+ * the swap or not. Must be either 0 or 1:
* * \c 1: Swap the values of \p X and \p Y.
* * \c 0: Keep the original values of \p X and \p Y.
*
* \note This function is equivalent to
- * if( assign ) mbedtls_mpi_swap( X, Y );
+ * if( swap ) mbedtls_mpi_swap( X, Y );
* except that it avoids leaking any information about whether
- * the assignment was done or not (the above code may leak
+ * the swap was done or not (the above code may leak
* information through branch prediction and/or memory access
* patterns analysis).
*
+ * \warning If \p swap is neither 0 nor 1, the result of this function
+ * is indeterminate, and both \p X and \p Y might end up with
+ * values different to either of the original ones.
+ *
* \return \c 0 if successful.
* \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed.
* \return Another negative error code on other kinds of failure.
*
*/
-int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char assign );
+int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap );
/**
* \brief Store integer value in MPI.
@@ -753,11 +793,11 @@ int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A,
*
* \param Q The destination MPI for the quotient.
* This may be \c NULL if the value of the
- * quotient is not needed.
+ * quotient is not needed. This must not alias A or B.
* \param R The destination MPI for the remainder value.
* This may be \c NULL if the value of the
- * remainder is not needed.
- * \param A The dividend. This must point to an initialized MPi.
+ * remainder is not needed. This must not alias A or B.
+ * \param A The dividend. This must point to an initialized MPI.
* \param B The divisor. This must point to an initialized MPI.
*
* \return \c 0 if successful.
@@ -774,10 +814,10 @@ int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A,
*
* \param Q The destination MPI for the quotient.
* This may be \c NULL if the value of the
- * quotient is not needed.
+ * quotient is not needed. This must not alias A.
* \param R The destination MPI for the remainder value.
* This may be \c NULL if the value of the
- * remainder is not needed.
+ * remainder is not needed. This must not alias A.
* \param A The dividend. This must point to an initialized MPi.
* \param b The divisor.
*
@@ -832,6 +872,7 @@ int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A,
* \brief Perform a sliding-window exponentiation: X = A^E mod N
*
* \param X The destination MPI. This must point to an initialized MPI.
+ * This must not alias E or N.
* \param A The base of the exponentiation.
* This must point to an initialized MPI.
* \param E The exponent MPI. This must point to an initialized MPI.
diff --git a/thirdparty/mbedtls/include/mbedtls/bn_mul.h b/thirdparty/mbedtls/include/mbedtls/bn_mul.h
index 31137cd4c2..a3fc363815 100644
--- a/thirdparty/mbedtls/include/mbedtls/bn_mul.h
+++ b/thirdparty/mbedtls/include/mbedtls/bn_mul.h
@@ -95,12 +95,28 @@
( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 )
/*
+ * GCC < 5.0 treated the x86 ebx (which is used for the GOT) as a
+ * fixed reserved register when building as PIC, leading to errors
+ * like: bn_mul.h:46:13: error: PIC register clobbered by 'ebx' in 'asm'
+ *
+ * This is fixed by an improved register allocator in GCC 5+. From the
+ * release notes:
+ * Register allocation improvements: Reuse of the PIC hard register,
+ * instead of using a fixed register, was implemented on x86/x86-64
+ * targets. This improves generated PIC code performance as more hard
+ * registers can be used.
+ */
+#if defined(__GNUC__) && __GNUC__ < 5 && defined(__PIC__)
+#define MULADDC_CANNOT_USE_EBX
+#endif
+
+/*
* Disable use of the i386 assembly code below if option -O0, to disable all
* compiler optimisations, is passed, detected with __OPTIMIZE__
* This is done as the number of registers used in the assembly code doesn't
* work with the -O0 option.
*/
-#if defined(__i386__) && defined(__OPTIMIZE__)
+#if defined(__i386__) && defined(__OPTIMIZE__) && !defined(MULADDC_CANNOT_USE_EBX)
#define MULADDC_INIT \
asm( \
@@ -563,10 +579,20 @@
"andi r7, r6, 0xffff \n\t" \
"bsrli r6, r6, 16 \n\t"
-#define MULADDC_CORE \
+#if(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define MULADDC_LHUI \
+ "lhui r9, r3, 0 \n\t" \
+ "addi r3, r3, 2 \n\t" \
+ "lhui r8, r3, 0 \n\t"
+#else
+#define MULADDC_LHUI \
"lhui r8, r3, 0 \n\t" \
"addi r3, r3, 2 \n\t" \
- "lhui r9, r3, 0 \n\t" \
+ "lhui r9, r3, 0 \n\t"
+#endif
+
+#define MULADDC_CORE \
+ MULADDC_LHUI \
"addi r3, r3, 2 \n\t" \
"mul r10, r9, r6 \n\t" \
"mul r11, r8, r7 \n\t" \
diff --git a/thirdparty/mbedtls/include/mbedtls/check_config.h b/thirdparty/mbedtls/include/mbedtls/check_config.h
index be5c548e56..7ae1ff94db 100644
--- a/thirdparty/mbedtls/include/mbedtls/check_config.h
+++ b/thirdparty/mbedtls/include/mbedtls/check_config.h
@@ -525,6 +525,20 @@
#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously"
#endif
+#if defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_VSNPRINTF_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_VSNPRINTF_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO) &&\
+ ( defined(MBEDTLS_PLATFORM_STD_VSNPRINTF) ||\
+ defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) )
+#error "MBEDTLS_PLATFORM_VSNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_VSNPRINTF/MBEDTLS_PLATFORM_VSNPRINTF_ALT cannot be defined simultaneously"
+#endif
+
#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\
!defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
#error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites"
@@ -650,10 +664,9 @@
MBEDTLS_ECDSA_C requires MBEDTLS_PK_WRITE_C to be defined."
#endif
-#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_PKCS1_V15) && \
- !defined(MBEDTLS_PK_WRITE_C) && defined(MBEDTLS_PSA_CRYPTO_C)
-#error "MBEDTLS_PSA_CRYPTO_C, MBEDTLS_RSA_C and MBEDTLS_PKCS1_V15 defined, \
- but not all prerequisites"
+#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_RSA_C) && \
+ !( defined(MBEDTLS_PK_PARSE_C) && defined(MBEDTLS_PK_WRITE_C) )
+#error "MBEDTLS_PSA_CRYPTO_C with MBEDTLS_RSA_C requires MBEDTLS_PK_PARSE_C and MBEDTLS_PK_WRITE_C"
#endif
#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
@@ -812,6 +825,11 @@
#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites"
#endif
+#if defined(MBEDTLS_SSL_TICKET_C) && \
+ !( defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) || defined(MBEDTLS_CHACHAPOLY_C) )
+#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites"
+#endif
+
#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) && \
!defined(MBEDTLS_SSL_PROTO_SSL3) && !defined(MBEDTLS_SSL_PROTO_TLS1)
#error "MBEDTLS_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites"
@@ -926,6 +944,10 @@
#error "MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH defined, but not all prerequisites"
#endif
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) && !( defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) || defined(MBEDTLS_CHACHAPOLY_C) )
+#error "MBEDTLS_SSL_CONTEXT_SERIALIZATION defined, but not all prerequisites"
+#endif
+
/*
* Avoid warning from -pedantic. This is a convenient place for this
* workaround since this is included by every single file before the
diff --git a/thirdparty/mbedtls/include/mbedtls/config.h b/thirdparty/mbedtls/include/mbedtls/config.h
index 1cd6eb6634..61db79362f 100644
--- a/thirdparty/mbedtls/include/mbedtls/config.h
+++ b/thirdparty/mbedtls/include/mbedtls/config.h
@@ -1329,7 +1329,7 @@
* Include backtrace information with each allocated block.
*
* Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C
- * GLIBC-compatible backtrace() an backtrace_symbols() support
+ * GLIBC-compatible backtrace() and backtrace_symbols() support
*
* Uncomment this macro to include backtrace information
*/
@@ -1620,6 +1620,8 @@
* saved after the handshake to allow for more efficient serialization, so if
* you don't need this feature you'll save RAM by disabling it.
*
+ * Requires: MBEDTLS_GCM_C or MBEDTLS_CCM_C or MBEDTLS_CHACHAPOLY_C
+ *
* Comment to disable the context serialization APIs.
*/
#define MBEDTLS_SSL_CONTEXT_SERIALIZATION
@@ -2425,7 +2427,7 @@
* MBEDTLS_TLS_PSK_WITH_RC4_128_SHA
*
* \warning ARC4 is considered a weak cipher and its use constitutes a
- * security risk. If possible, we recommend avoidng dependencies on
+ * security risk. If possible, we recommend avoiding dependencies on
* it, and considering stronger ciphers instead.
*
*/
@@ -3030,7 +3032,7 @@
*
* \note See also our Knowledge Base article about porting to a new
* environment:
- * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS
+ * https://mbed-tls.readthedocs.io/en/latest/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS
*
* Module: library/net_sockets.c
*
@@ -3400,7 +3402,8 @@
* Module: library/ssl_ticket.c
* Caller:
*
- * Requires: MBEDTLS_CIPHER_C
+ * Requires: MBEDTLS_CIPHER_C &&
+ * ( MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_C )
*/
#define MBEDTLS_SSL_TICKET_C
@@ -3456,7 +3459,7 @@
* contexts are not shared between threads. If you do intend to use contexts
* between threads, you will need to enable this layer to prevent race
* conditions. See also our Knowledge Base article about threading:
- * https://tls.mbed.org/kb/development/thread-safety-and-multi-threading
+ * https://mbed-tls.readthedocs.io/en/latest/kb/development/thread-safety-and-multi-threading
*
* Module: library/threading.c
*
@@ -3488,7 +3491,7 @@
*
* \note See also our Knowledge Base article about porting to a new
* environment:
- * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS
+ * https://mbed-tls.readthedocs.io/en/latest/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS
*
* Module: library/timing.c
* Caller: library/havege.c
diff --git a/thirdparty/mbedtls/include/mbedtls/ecdsa.h b/thirdparty/mbedtls/include/mbedtls/ecdsa.h
index 264a638bb5..118f7cedb1 100644
--- a/thirdparty/mbedtls/include/mbedtls/ecdsa.h
+++ b/thirdparty/mbedtls/include/mbedtls/ecdsa.h
@@ -309,10 +309,8 @@ int mbedtls_ecdsa_sign_det_ext( mbedtls_ecp_group *grp, mbedtls_mpi *r,
* This must be initialized.
*
* \return \c 0 on success.
- * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the signature
- * is invalid.
* \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX
- * error code on failure for any other reason.
+ * error code on failure.
*/
int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
const unsigned char *buf, size_t blen,
diff --git a/thirdparty/mbedtls/include/mbedtls/md.h b/thirdparty/mbedtls/include/mbedtls/md.h
index 84fafd2ac7..9cea40a89c 100644
--- a/thirdparty/mbedtls/include/mbedtls/md.h
+++ b/thirdparty/mbedtls/include/mbedtls/md.h
@@ -215,7 +215,7 @@ MBEDTLS_CHECK_RETURN_TYPICAL
int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac );
/**
- * \brief This function clones the state of an message-digest
+ * \brief This function clones the state of a message-digest
* context.
*
* \note You must call mbedtls_md_setup() on \c dst before calling
diff --git a/thirdparty/mbedtls/include/mbedtls/platform.h b/thirdparty/mbedtls/include/mbedtls/platform.h
index 06dd192eab..eaf5122bec 100644
--- a/thirdparty/mbedtls/include/mbedtls/platform.h
+++ b/thirdparty/mbedtls/include/mbedtls/platform.h
@@ -11,6 +11,13 @@
* implementations of these functions, or implementations specific to
* their platform, which can be statically linked to the library or
* dynamically configured at runtime.
+ *
+ * When all compilation options related to platform abstraction are
+ * disabled, this header just defines `mbedtls_xxx` function names
+ * as aliases to the standard `xxx` function.
+ *
+ * Most modules in the library and example programs are expected to
+ * include this header.
*/
/*
* Copyright The Mbed TLS Contributors
diff --git a/thirdparty/mbedtls/include/mbedtls/ripemd160.h b/thirdparty/mbedtls/include/mbedtls/ripemd160.h
index 63270d1239..f890aefaee 100644
--- a/thirdparty/mbedtls/include/mbedtls/ripemd160.h
+++ b/thirdparty/mbedtls/include/mbedtls/ripemd160.h
@@ -74,7 +74,7 @@ void mbedtls_ripemd160_init( mbedtls_ripemd160_context *ctx );
void mbedtls_ripemd160_free( mbedtls_ripemd160_context *ctx );
/**
- * \brief Clone (the state of) an RIPEMD-160 context
+ * \brief Clone (the state of) a RIPEMD-160 context
*
* \param dst The destination context
* \param src The context to be cloned
diff --git a/thirdparty/mbedtls/include/mbedtls/rsa.h b/thirdparty/mbedtls/include/mbedtls/rsa.h
index 062df73aa0..8559f67bb9 100644
--- a/thirdparty/mbedtls/include/mbedtls/rsa.h
+++ b/thirdparty/mbedtls/include/mbedtls/rsa.h
@@ -491,7 +491,7 @@ int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx );
* the current function does not have access to them,
* and therefore cannot check them. See mbedtls_rsa_complete().
* If you want to check the consistency of the entire
- * content of an PKCS1-encoded RSA private key, for example, you
+ * content of a PKCS1-encoded RSA private key, for example, you
* should use mbedtls_rsa_validate_params() before setting
* up the RSA context.
* Additionally, if the implementation performs empirical checks,
diff --git a/thirdparty/mbedtls/include/mbedtls/ssl.h b/thirdparty/mbedtls/include/mbedtls/ssl.h
index 5064ec5689..aecac93f33 100644
--- a/thirdparty/mbedtls/include/mbedtls/ssl.h
+++ b/thirdparty/mbedtls/include/mbedtls/ssl.h
@@ -624,7 +624,7 @@ typedef int mbedtls_ssl_recv_t( void *ctx,
* \param ctx Context for the receive callback (typically a file descriptor)
* \param buf Buffer to write the received data to
* \param len Length of the receive buffer
- * \param timeout Maximum nomber of millisecondes to wait for data
+ * \param timeout Maximum number of milliseconds to wait for data
* 0 means no timeout (potentially waiting forever)
*
* \return The callback must return the number of bytes received,
@@ -652,7 +652,7 @@ typedef int mbedtls_ssl_recv_timeout_t( void *ctx,
* for the associated \c mbedtls_ssl_get_timer_t callback to
* return correct information.
*
- * \note If using a event-driven style of programming, an event must
+ * \note If using an event-driven style of programming, an event must
* be generated when the final delay is passed. The event must
* cause a call to \c mbedtls_ssl_handshake() with the proper
* SSL context to be scheduled. Care must be taken to ensure
@@ -2000,7 +2000,7 @@ int mbedtls_ssl_check_record( mbedtls_ssl_context const *ssl,
* here, except if using an event-driven style.
*
* \note See also the "DTLS tutorial" article in our knowledge base.
- * https://tls.mbed.org/kb/how-to/dtls-tutorial
+ * https://mbed-tls.readthedocs.io/en/latest/kb/how-to/dtls-tutorial
*/
void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl,
void *p_timer,
diff --git a/thirdparty/mbedtls/include/mbedtls/ssl_internal.h b/thirdparty/mbedtls/include/mbedtls/ssl_internal.h
index 46ade67b9c..77ad755477 100644
--- a/thirdparty/mbedtls/include/mbedtls/ssl_internal.h
+++ b/thirdparty/mbedtls/include/mbedtls/ssl_internal.h
@@ -782,7 +782,7 @@ struct mbedtls_ssl_transform
#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
uint8_t in_cid_len;
uint8_t out_cid_len;
- unsigned char in_cid [ MBEDTLS_SSL_CID_OUT_LEN_MAX ];
+ unsigned char in_cid [ MBEDTLS_SSL_CID_IN_LEN_MAX ];
unsigned char out_cid[ MBEDTLS_SSL_CID_OUT_LEN_MAX ];
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
diff --git a/thirdparty/mbedtls/include/mbedtls/version.h b/thirdparty/mbedtls/include/mbedtls/version.h
index 44adcbfe03..b3b441d46b 100644
--- a/thirdparty/mbedtls/include/mbedtls/version.h
+++ b/thirdparty/mbedtls/include/mbedtls/version.h
@@ -38,16 +38,16 @@
*/
#define MBEDTLS_VERSION_MAJOR 2
#define MBEDTLS_VERSION_MINOR 28
-#define MBEDTLS_VERSION_PATCH 1
+#define MBEDTLS_VERSION_PATCH 2
/**
* The single version number has the following structure:
* MMNNPP00
* Major version | Minor version | Patch version
*/
-#define MBEDTLS_VERSION_NUMBER 0x021C0100
-#define MBEDTLS_VERSION_STRING "2.28.1"
-#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.28.1"
+#define MBEDTLS_VERSION_NUMBER 0x021C0200
+#define MBEDTLS_VERSION_STRING "2.28.2"
+#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.28.2"
#if defined(MBEDTLS_VERSION_C)
diff --git a/thirdparty/mbedtls/library/aes.c b/thirdparty/mbedtls/library/aes.c
index 03d8b7ea61..74ea2672b0 100644
--- a/thirdparty/mbedtls/library/aes.c
+++ b/thirdparty/mbedtls/library/aes.c
@@ -40,14 +40,7 @@
#include "mbedtls/aesni.h"
#endif
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_AES_ALT)
@@ -1170,7 +1163,7 @@ int mbedtls_aes_crypt_xts( mbedtls_aes_xts_context *ctx,
{
/* We are on the last block in a decrypt operation that has
* leftover bytes, so we need to use the next tweak for this block,
- * and this tweak for the lefover bytes. Save the current tweak for
+ * and this tweak for the leftover bytes. Save the current tweak for
* the leftovers and then update the current tweak for use on this,
* the last full block. */
memcpy( prev_tweak, tweak, sizeof( tweak ) );
@@ -1770,7 +1763,8 @@ int mbedtls_aes_self_test( int verbose )
unsigned char key[32];
unsigned char buf[64];
const unsigned char *aes_tests;
-#if defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB)
+#if defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB) || \
+ defined(MBEDTLS_CIPHER_MODE_OFB)
unsigned char iv[16];
#endif
#if defined(MBEDTLS_CIPHER_MODE_CBC)
diff --git a/thirdparty/mbedtls/library/arc4.c b/thirdparty/mbedtls/library/arc4.c
index b34dc5e754..dcc13d539a 100644
--- a/thirdparty/mbedtls/library/arc4.c
+++ b/thirdparty/mbedtls/library/arc4.c
@@ -31,14 +31,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_ARC4_ALT)
diff --git a/thirdparty/mbedtls/library/aria.c b/thirdparty/mbedtls/library/aria.c
index bc05c4a319..5e52eea91e 100644
--- a/thirdparty/mbedtls/library/aria.c
+++ b/thirdparty/mbedtls/library/aria.c
@@ -31,24 +31,12 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_ARIA_ALT)
#include "mbedtls/platform_util.h"
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
- !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
/* Parameter validation macros */
#define ARIA_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ARIA_BAD_INPUT_DATA )
@@ -895,15 +883,17 @@ static const uint8_t aria_test2_ctr_ct[3][48] = // CTR ciphertext
};
#endif /* MBEDTLS_CIPHER_MODE_CFB */
-#define ARIA_SELF_TEST_IF_FAIL \
- { \
- if( verbose ) \
- mbedtls_printf( "failed\n" ); \
- goto exit; \
- } else { \
- if( verbose ) \
- mbedtls_printf( "passed\n" ); \
- }
+#define ARIA_SELF_TEST_ASSERT( cond ) \
+ do { \
+ if( cond ) { \
+ if( verbose ) \
+ mbedtls_printf( "failed\n" ); \
+ goto exit; \
+ } else { \
+ if( verbose ) \
+ mbedtls_printf( "passed\n" ); \
+ } \
+ } while( 0 )
/*
* Checkup routine
@@ -937,16 +927,18 @@ int mbedtls_aria_self_test( int verbose )
mbedtls_printf( " ARIA-ECB-%d (enc): ", 128 + 64 * i );
mbedtls_aria_setkey_enc( &ctx, aria_test1_ecb_key, 128 + 64 * i );
mbedtls_aria_crypt_ecb( &ctx, aria_test1_ecb_pt, blk );
- if( memcmp( blk, aria_test1_ecb_ct[i], MBEDTLS_ARIA_BLOCKSIZE ) != 0 )
- ARIA_SELF_TEST_IF_FAIL;
+ ARIA_SELF_TEST_ASSERT(
+ memcmp( blk, aria_test1_ecb_ct[i], MBEDTLS_ARIA_BLOCKSIZE )
+ != 0 );
/* test ECB decryption */
if( verbose )
mbedtls_printf( " ARIA-ECB-%d (dec): ", 128 + 64 * i );
mbedtls_aria_setkey_dec( &ctx, aria_test1_ecb_key, 128 + 64 * i );
mbedtls_aria_crypt_ecb( &ctx, aria_test1_ecb_ct[i], blk );
- if( memcmp( blk, aria_test1_ecb_pt, MBEDTLS_ARIA_BLOCKSIZE ) != 0 )
- ARIA_SELF_TEST_IF_FAIL;
+ ARIA_SELF_TEST_ASSERT(
+ memcmp( blk, aria_test1_ecb_pt, MBEDTLS_ARIA_BLOCKSIZE )
+ != 0 );
}
if( verbose )
mbedtls_printf( "\n" );
@@ -965,8 +957,8 @@ int mbedtls_aria_self_test( int verbose )
memset( buf, 0x55, sizeof( buf ) );
mbedtls_aria_crypt_cbc( &ctx, MBEDTLS_ARIA_ENCRYPT, 48, iv,
aria_test2_pt, buf );
- if( memcmp( buf, aria_test2_cbc_ct[i], 48 ) != 0 )
- ARIA_SELF_TEST_IF_FAIL;
+ ARIA_SELF_TEST_ASSERT( memcmp( buf, aria_test2_cbc_ct[i], 48 )
+ != 0 );
/* Test CBC decryption */
if( verbose )
@@ -976,8 +968,7 @@ int mbedtls_aria_self_test( int verbose )
memset( buf, 0xAA, sizeof( buf ) );
mbedtls_aria_crypt_cbc( &ctx, MBEDTLS_ARIA_DECRYPT, 48, iv,
aria_test2_cbc_ct[i], buf );
- if( memcmp( buf, aria_test2_pt, 48 ) != 0 )
- ARIA_SELF_TEST_IF_FAIL;
+ ARIA_SELF_TEST_ASSERT( memcmp( buf, aria_test2_pt, 48 ) != 0 );
}
if( verbose )
mbedtls_printf( "\n" );
@@ -996,8 +987,7 @@ int mbedtls_aria_self_test( int verbose )
j = 0;
mbedtls_aria_crypt_cfb128( &ctx, MBEDTLS_ARIA_ENCRYPT, 48, &j, iv,
aria_test2_pt, buf );
- if( memcmp( buf, aria_test2_cfb_ct[i], 48 ) != 0 )
- ARIA_SELF_TEST_IF_FAIL;
+ ARIA_SELF_TEST_ASSERT( memcmp( buf, aria_test2_cfb_ct[i], 48 ) != 0 );
/* Test CFB decryption */
if( verbose )
@@ -1008,8 +998,7 @@ int mbedtls_aria_self_test( int verbose )
j = 0;
mbedtls_aria_crypt_cfb128( &ctx, MBEDTLS_ARIA_DECRYPT, 48, &j,
iv, aria_test2_cfb_ct[i], buf );
- if( memcmp( buf, aria_test2_pt, 48 ) != 0 )
- ARIA_SELF_TEST_IF_FAIL;
+ ARIA_SELF_TEST_ASSERT( memcmp( buf, aria_test2_pt, 48 ) != 0 );
}
if( verbose )
mbedtls_printf( "\n" );
@@ -1027,8 +1016,7 @@ int mbedtls_aria_self_test( int verbose )
j = 0;
mbedtls_aria_crypt_ctr( &ctx, 48, &j, iv, blk,
aria_test2_pt, buf );
- if( memcmp( buf, aria_test2_ctr_ct[i], 48 ) != 0 )
- ARIA_SELF_TEST_IF_FAIL;
+ ARIA_SELF_TEST_ASSERT( memcmp( buf, aria_test2_ctr_ct[i], 48 ) != 0 );
/* Test CTR decryption */
if( verbose )
@@ -1039,8 +1027,7 @@ int mbedtls_aria_self_test( int verbose )
j = 0;
mbedtls_aria_crypt_ctr( &ctx, 48, &j, iv, blk,
aria_test2_ctr_ct[i], buf );
- if( memcmp( buf, aria_test2_pt, 48 ) != 0 )
- ARIA_SELF_TEST_IF_FAIL;
+ ARIA_SELF_TEST_ASSERT( memcmp( buf, aria_test2_pt, 48 ) != 0 );
}
if( verbose )
mbedtls_printf( "\n" );
diff --git a/thirdparty/mbedtls/library/asn1parse.c b/thirdparty/mbedtls/library/asn1parse.c
index 22747d3ba4..bf97585289 100644
--- a/thirdparty/mbedtls/library/asn1parse.c
+++ b/thirdparty/mbedtls/library/asn1parse.c
@@ -31,13 +31,7 @@
#include "mbedtls/bignum.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
/*
* ASN.1 DER decoding routines
diff --git a/thirdparty/mbedtls/library/asn1write.c b/thirdparty/mbedtls/library/asn1write.c
index afa26a6be9..4b59927cbb 100644
--- a/thirdparty/mbedtls/library/asn1write.c
+++ b/thirdparty/mbedtls/library/asn1write.c
@@ -26,13 +26,7 @@
#include <string.h>
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len )
{
@@ -78,9 +72,11 @@ int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len
return( 4 );
}
+ int len_is_valid = 1;
#if SIZE_MAX > 0xFFFFFFFF
- if( len <= 0xFFFFFFFF )
+ len_is_valid = ( len <= 0xFFFFFFFF );
#endif
+ if( len_is_valid )
{
if( *p - start < 5 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
@@ -93,9 +89,7 @@ int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len
return( 5 );
}
-#if SIZE_MAX > 0xFFFFFFFF
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
-#endif
}
int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag )
diff --git a/thirdparty/mbedtls/library/base64.c b/thirdparty/mbedtls/library/base64.c
index 83daa0bcc6..9021a041bb 100644
--- a/thirdparty/mbedtls/library/base64.c
+++ b/thirdparty/mbedtls/library/base64.c
@@ -28,12 +28,7 @@
#if defined(MBEDTLS_SELF_TEST)
#include <string.h>
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
diff --git a/thirdparty/mbedtls/library/bignum.c b/thirdparty/mbedtls/library/bignum.c
index 32578e2c68..37193f55a8 100644
--- a/thirdparty/mbedtls/library/bignum.c
+++ b/thirdparty/mbedtls/library/bignum.c
@@ -46,15 +46,7 @@
#include <limits.h>
#include <string.h>
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#define mbedtls_printf printf
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#define MPI_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA )
@@ -270,6 +262,17 @@ void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y )
memcpy( Y, &T, sizeof( mbedtls_mpi ) );
}
+static inline mbedtls_mpi_uint mpi_sint_abs( mbedtls_mpi_sint z )
+{
+ if( z >= 0 )
+ return( z );
+ /* Take care to handle the most negative value (-2^(biL-1)) correctly.
+ * A naive -z would have undefined behavior.
+ * Write this in a way that makes popular compilers happy (GCC, Clang,
+ * MSVC). */
+ return( (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z );
+}
+
/*
* Set value from integer
*/
@@ -281,7 +284,7 @@ int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z )
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) );
memset( X->p, 0, X->n * ciL );
- X->p[0] = ( z < 0 ) ? -z : z;
+ X->p[0] = mpi_sint_abs( z );
X->s = ( z < 0 ) ? -1 : 1;
cleanup:
@@ -1101,7 +1104,7 @@ int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z )
mbedtls_mpi_uint p[1];
MPI_VALIDATE_RET( X != NULL );
- *p = ( z < 0 ) ? -z : z;
+ *p = mpi_sint_abs( z );
Y.s = ( z < 0 ) ? -1 : 1;
Y.n = 1;
Y.p = p;
@@ -1138,6 +1141,11 @@ int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi
if( B->p[j - 1] != 0 )
break;
+ /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0
+ * and B is 0 (of any size). */
+ if( j == 0 )
+ return( 0 );
+
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
o = B->p; p = X->p; c = 0;
@@ -1257,10 +1265,12 @@ cleanup:
return( ret );
}
-/*
- * Signed addition: X = A + B
+/* Common function for signed addition and subtraction.
+ * Calculate A + B * flip_B where flip_B is 1 or -1.
*/
-int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
+static int add_sub_mpi( mbedtls_mpi *X,
+ const mbedtls_mpi *A, const mbedtls_mpi *B,
+ int flip_B )
{
int ret, s;
MPI_VALIDATE_RET( X != NULL );
@@ -1268,16 +1278,21 @@ int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi
MPI_VALIDATE_RET( B != NULL );
s = A->s;
- if( A->s * B->s < 0 )
+ if( A->s * B->s * flip_B < 0 )
{
- if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
+ int cmp = mbedtls_mpi_cmp_abs( A, B );
+ if( cmp >= 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
- X->s = s;
+ /* If |A| = |B|, the result is 0 and we must set the sign bit
+ * to +1 regardless of which of A or B was negative. Otherwise,
+ * since |A| > |B|, the sign is the sign of A. */
+ X->s = cmp == 0 ? 1 : s;
}
else
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
+ /* Since |A| < |B|, the sign is the opposite of A. */
X->s = -s;
}
}
@@ -1293,38 +1308,19 @@ cleanup:
}
/*
+ * Signed addition: X = A + B
+ */
+int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
+{
+ return( add_sub_mpi( X, A, B, 1 ) );
+}
+
+/*
* Signed subtraction: X = A - B
*/
int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
{
- int ret, s;
- MPI_VALIDATE_RET( X != NULL );
- MPI_VALIDATE_RET( A != NULL );
- MPI_VALIDATE_RET( B != NULL );
-
- s = A->s;
- if( A->s * B->s > 0 )
- {
- if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
- {
- MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
- X->s = s;
- }
- else
- {
- MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
- X->s = -s;
- }
- }
- else
- {
- MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
- X->s = s;
- }
-
-cleanup:
-
- return( ret );
+ return( add_sub_mpi( X, A, B, -1 ) );
}
/*
@@ -1337,7 +1333,7 @@ int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint
MPI_VALIDATE_RET( X != NULL );
MPI_VALIDATE_RET( A != NULL );
- p[0] = ( b < 0 ) ? -b : b;
+ p[0] = mpi_sint_abs( b );
B.s = ( b < 0 ) ? -1 : 1;
B.n = 1;
B.p = p;
@@ -1355,7 +1351,7 @@ int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint
MPI_VALIDATE_RET( X != NULL );
MPI_VALIDATE_RET( A != NULL );
- p[0] = ( b < 0 ) ? -b : b;
+ p[0] = mpi_sint_abs( b );
B.s = ( b < 0 ) ? -1 : 1;
B.n = 1;
B.p = p;
@@ -1776,7 +1772,7 @@ int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R,
mbedtls_mpi_uint p[1];
MPI_VALIDATE_RET( A != NULL );
- p[0] = ( b < 0 ) ? -b : b;
+ p[0] = mpi_sint_abs( b );
B.s = ( b < 0 ) ? -1 : 1;
B.n = 1;
B.p = p;
@@ -2009,11 +2005,11 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A,
mbedtls_mpi *prec_RR )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- size_t wbits, wsize, one = 1;
+ size_t window_bitsize;
size_t i, j, nblimbs;
size_t bufsize, nbits;
mbedtls_mpi_uint ei, mm, state;
- mbedtls_mpi RR, T, W[ 1 << MBEDTLS_MPI_WINDOW_SIZE ], WW, Apos;
+ mbedtls_mpi RR, T, W[ (size_t) 1 << MBEDTLS_MPI_WINDOW_SIZE ], WW, Apos;
int neg;
MPI_VALIDATE_RET( X != NULL );
@@ -2042,21 +2038,59 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A,
i = mbedtls_mpi_bitlen( E );
- wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
+ window_bitsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1;
#if( MBEDTLS_MPI_WINDOW_SIZE < 6 )
- if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
- wsize = MBEDTLS_MPI_WINDOW_SIZE;
+ if( window_bitsize > MBEDTLS_MPI_WINDOW_SIZE )
+ window_bitsize = MBEDTLS_MPI_WINDOW_SIZE;
#endif
+ const size_t w_table_used_size = (size_t) 1 << window_bitsize;
+
+ /*
+ * This function is not constant-trace: its memory accesses depend on the
+ * exponent value. To defend against timing attacks, callers (such as RSA
+ * and DHM) should use exponent blinding. However this is not enough if the
+ * adversary can find the exponent in a single trace, so this function
+ * takes extra precautions against adversaries who can observe memory
+ * access patterns.
+ *
+ * This function performs a series of multiplications by table elements and
+ * squarings, and we want the prevent the adversary from finding out which
+ * table element was used, and from distinguishing between multiplications
+ * and squarings. Firstly, when multiplying by an element of the window
+ * W[i], we do a constant-trace table lookup to obfuscate i. This leaves
+ * squarings as having a different memory access patterns from other
+ * multiplications. So secondly, we put the accumulator X in the table as
+ * well, and also do a constant-trace table lookup to multiply by X.
+ *
+ * This way, all multiplications take the form of a lookup-and-multiply.
+ * The number of lookup-and-multiply operations inside each iteration of
+ * the main loop still depends on the bits of the exponent, but since the
+ * other operations in the loop don't have an easily recognizable memory
+ * trace, an adversary is unlikely to be able to observe the exact
+ * patterns.
+ *
+ * An adversary may still be able to recover the exponent if they can
+ * observe both memory accesses and branches. However, branch prediction
+ * exploitation typically requires many traces of execution over the same
+ * data, which is defeated by randomized blinding.
+ *
+ * To achieve this, we make a copy of X and we use the table entry in each
+ * calculation from this point on.
+ */
+ const size_t x_index = 0;
+ mbedtls_mpi_init( &W[x_index] );
+ mbedtls_mpi_copy( &W[x_index], X );
+
j = N->n + 1;
/* All W[i] and X must have at least N->n limbs for the mpi_montmul()
* and mpi_montred() calls later. Here we ensure that W[1] and X are
* large enough, and later we'll grow other W[i] to the same length.
* They must not be shrunk midway through this function!
*/
- MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[x_index], j ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1], j ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) );
@@ -2105,28 +2139,36 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A,
mpi_montmul( &W[1], &RR, N, mm, &T );
/*
- * X = R^2 * R^-1 mod N = R mod N
+ * W[x_index] = R^2 * R^-1 mod N = R mod N
*/
- MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) );
- mpi_montred( X, N, mm, &T );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[x_index], &RR ) );
+ mpi_montred( &W[x_index], N, mm, &T );
+
- if( wsize > 1 )
+ if( window_bitsize > 1 )
{
/*
- * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
+ * W[i] = W[1] ^ i
+ *
+ * The first bit of the sliding window is always 1 and therefore we
+ * only need to store the second half of the table.
+ *
+ * (There are two special elements in the table: W[0] for the
+ * accumulator/result and W[1] for A in Montgomery form. Both of these
+ * are already set at this point.)
*/
- j = one << ( wsize - 1 );
+ j = w_table_used_size / 2;
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1] ) );
- for( i = 0; i < wsize - 1; i++ )
+ for( i = 0; i < window_bitsize - 1; i++ )
mpi_montmul( &W[j], &W[j], N, mm, &T );
/*
* W[i] = W[i - 1] * W[1]
*/
- for( i = j + 1; i < ( one << wsize ); i++ )
+ for( i = j + 1; i < w_table_used_size; i++ )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) );
@@ -2138,7 +2180,7 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A,
nblimbs = E->n;
bufsize = 0;
nbits = 0;
- wbits = 0;
+ size_t exponent_bits_in_window = 0;
state = 0;
while( 1 )
@@ -2166,9 +2208,10 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A,
if( ei == 0 && state == 1 )
{
/*
- * out of window, square X
+ * out of window, square W[x_index]
*/
- mpi_montmul( X, X, N, mm, &T );
+ MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size, x_index ) );
+ mpi_montmul( &W[x_index], &WW, N, mm, &T );
continue;
}
@@ -2178,25 +2221,30 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A,
state = 2;
nbits++;
- wbits |= ( ei << ( wsize - nbits ) );
+ exponent_bits_in_window |= ( ei << ( window_bitsize - nbits ) );
- if( nbits == wsize )
+ if( nbits == window_bitsize )
{
/*
- * X = X^wsize R^-1 mod N
+ * W[x_index] = W[x_index]^window_bitsize R^-1 mod N
*/
- for( i = 0; i < wsize; i++ )
- mpi_montmul( X, X, N, mm, &T );
+ for( i = 0; i < window_bitsize; i++ )
+ {
+ MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size,
+ x_index ) );
+ mpi_montmul( &W[x_index], &WW, N, mm, &T );
+ }
/*
- * X = X * W[wbits] R^-1 mod N
+ * W[x_index] = W[x_index] * W[exponent_bits_in_window] R^-1 mod N
*/
- MBEDTLS_MPI_CHK( mpi_select( &WW, W, (size_t) 1 << wsize, wbits ) );
- mpi_montmul( X, &WW, N, mm, &T );
+ MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size,
+ exponent_bits_in_window ) );
+ mpi_montmul( &W[x_index], &WW, N, mm, &T );
state--;
nbits = 0;
- wbits = 0;
+ exponent_bits_in_window = 0;
}
}
@@ -2205,31 +2253,45 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A,
*/
for( i = 0; i < nbits; i++ )
{
- mpi_montmul( X, X, N, mm, &T );
+ MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size, x_index ) );
+ mpi_montmul( &W[x_index], &WW, N, mm, &T );
- wbits <<= 1;
+ exponent_bits_in_window <<= 1;
- if( ( wbits & ( one << wsize ) ) != 0 )
- mpi_montmul( X, &W[1], N, mm, &T );
+ if( ( exponent_bits_in_window & ( (size_t) 1 << window_bitsize ) ) != 0 )
+ {
+ MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size, 1 ) );
+ mpi_montmul( &W[x_index], &WW, N, mm, &T );
+ }
}
/*
- * X = A^E * R * R^-1 mod N = A^E mod N
+ * W[x_index] = A^E * R * R^-1 mod N = A^E mod N
*/
- mpi_montred( X, N, mm, &T );
+ mpi_montred( &W[x_index], N, mm, &T );
if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 )
{
- X->s = -1;
- MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) );
+ W[x_index].s = -1;
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &W[x_index], N, &W[x_index] ) );
}
+ /*
+ * Load the result in the output variable.
+ */
+ mbedtls_mpi_copy( X, &W[x_index] );
+
cleanup:
- for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ )
+ /* The first bit of the sliding window is always 1 and therefore the first
+ * half of the table was unused. */
+ for( i = w_table_used_size/2; i < w_table_used_size; i++ )
mbedtls_mpi_free( &W[i] );
- mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos );
+ mbedtls_mpi_free( &W[x_index] );
+ mbedtls_mpi_free( &W[1] );
+ mbedtls_mpi_free( &T );
+ mbedtls_mpi_free( &Apos );
mbedtls_mpi_free( &WW );
if( prec_RR == NULL || prec_RR->p == NULL )
@@ -2862,7 +2924,7 @@ int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags,
else
{
/*
- * An necessary condition for Y and X = 2Y + 1 to be prime
+ * A necessary condition for Y and X = 2Y + 1 to be prime
* is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
* Make sure it is satisfied, while keeping X = 3 mod 4
*/
diff --git a/thirdparty/mbedtls/library/camellia.c b/thirdparty/mbedtls/library/camellia.c
index 29d730ab53..e90cd7f134 100644
--- a/thirdparty/mbedtls/library/camellia.c
+++ b/thirdparty/mbedtls/library/camellia.c
@@ -32,14 +32,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_CAMELLIA_ALT)
diff --git a/thirdparty/mbedtls/library/ccm.c b/thirdparty/mbedtls/library/ccm.c
index a21a37f55f..e0d43334f9 100644
--- a/thirdparty/mbedtls/library/ccm.c
+++ b/thirdparty/mbedtls/library/ccm.c
@@ -36,14 +36,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#if !defined(MBEDTLS_CCM_ALT)
diff --git a/thirdparty/mbedtls/library/chacha20.c b/thirdparty/mbedtls/library/chacha20.c
index 658f046901..bd0701482c 100644
--- a/thirdparty/mbedtls/library/chacha20.c
+++ b/thirdparty/mbedtls/library/chacha20.c
@@ -32,22 +32,10 @@
#include <stddef.h>
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_CHACHA20_ALT)
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
- !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
/* Parameter validation macros */
#define CHACHA20_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA )
diff --git a/thirdparty/mbedtls/library/chachapoly.c b/thirdparty/mbedtls/library/chachapoly.c
index dc75b2030a..4adf846857 100644
--- a/thirdparty/mbedtls/library/chachapoly.c
+++ b/thirdparty/mbedtls/library/chachapoly.c
@@ -28,14 +28,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_CHACHAPOLY_ALT)
diff --git a/thirdparty/mbedtls/library/cipher.c b/thirdparty/mbedtls/library/cipher.c
index f3b4bd29ce..67e3274587 100644
--- a/thirdparty/mbedtls/library/cipher.c
+++ b/thirdparty/mbedtls/library/cipher.c
@@ -63,12 +63,7 @@
#include "mbedtls/nist_kw.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#define CIPHER_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA )
diff --git a/thirdparty/mbedtls/library/cipher_wrap.c b/thirdparty/mbedtls/library/cipher_wrap.c
index 57eb3cb67f..c76bdcc0f8 100644
--- a/thirdparty/mbedtls/library/cipher_wrap.c
+++ b/thirdparty/mbedtls/library/cipher_wrap.c
@@ -76,13 +76,7 @@
#include <string.h>
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#if defined(MBEDTLS_GCM_C)
/* shared by all GCM ciphers */
diff --git a/thirdparty/mbedtls/library/common.h b/thirdparty/mbedtls/library/common.h
index c06472418d..1663d50226 100644
--- a/thirdparty/mbedtls/library/common.h
+++ b/thirdparty/mbedtls/library/common.h
@@ -29,8 +29,15 @@
#include "mbedtls/config.h"
#endif
+#include <stddef.h>
#include <stdint.h>
+/* Define `inline` on some non-C99-compliant compilers. */
+#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
+ !defined(inline) && !defined(__cplusplus)
+#define inline __inline
+#endif
+
/** Helper to define a function as static except when building invasive tests.
*
* If a function is only used inside its own source file and should be
@@ -52,6 +59,44 @@
#define MBEDTLS_STATIC_TESTABLE static
#endif
+/** Return an offset into a buffer.
+ *
+ * This is just the addition of an offset to a pointer, except that this
+ * function also accepts an offset of 0 into a buffer whose pointer is null.
+ * (`p + n` has undefined behavior when `p` is null, even when `n == 0`.
+ * A null pointer is a valid buffer pointer when the size is 0, for example
+ * as the result of `malloc(0)` on some platforms.)
+ *
+ * \param p Pointer to a buffer of at least n bytes.
+ * This may be \p NULL if \p n is zero.
+ * \param n An offset in bytes.
+ * \return Pointer to offset \p n in the buffer \p p.
+ * Note that this is only a valid pointer if the size of the
+ * buffer is at least \p n + 1.
+ */
+static inline unsigned char *mbedtls_buffer_offset(
+ unsigned char *p, size_t n )
+{
+ return( p == NULL ? NULL : p + n );
+}
+
+/** Return an offset into a read-only buffer.
+ *
+ * Similar to mbedtls_buffer_offset(), but for const pointers.
+ *
+ * \param p Pointer to a buffer of at least n bytes.
+ * This may be \p NULL if \p n is zero.
+ * \param n An offset in bytes.
+ * \return Pointer to offset \p n in the buffer \p p.
+ * Note that this is only a valid pointer if the size of the
+ * buffer is at least \p n + 1.
+ */
+static inline const unsigned char *mbedtls_buffer_offset_const(
+ const unsigned char *p, size_t n )
+{
+ return( p == NULL ? NULL : p + n );
+}
+
/** Byte Reading Macros
*
* Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th
diff --git a/thirdparty/mbedtls/library/constant_time.c b/thirdparty/mbedtls/library/constant_time.c
index e276d23ca0..2401b0434a 100644
--- a/thirdparty/mbedtls/library/constant_time.c
+++ b/thirdparty/mbedtls/library/constant_time.c
@@ -81,7 +81,7 @@ unsigned mbedtls_ct_uint_mask( unsigned value )
#endif
}
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
+#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
size_t mbedtls_ct_size_mask( size_t value )
{
@@ -97,7 +97,7 @@ size_t mbedtls_ct_size_mask( size_t value )
#endif
}
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
+#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
#if defined(MBEDTLS_BIGNUM_C)
@@ -272,7 +272,7 @@ unsigned mbedtls_ct_uint_if( unsigned condition,
* \note if1 and if0 must be either 1 or -1, otherwise the result
* is undefined.
*
- * \param condition Condition to test.
+ * \param condition Condition to test; must be either 0 or 1.
* \param if1 The first sign; must be either +1 or -1.
* \param if0 The second sign; must be either +1 or -1.
*
@@ -404,8 +404,7 @@ static void mbedtls_ct_mem_move_to_left( void *start,
#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
-
+#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
void mbedtls_ct_memcpy_if_eq( unsigned char *dest,
const unsigned char *src,
size_t len,
@@ -527,7 +526,7 @@ cleanup:
return( ret );
}
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
+#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
#if defined(MBEDTLS_BIGNUM_C)
diff --git a/thirdparty/mbedtls/library/constant_time_internal.h b/thirdparty/mbedtls/library/constant_time_internal.h
index a550b38fa5..ff2d0ff92c 100644
--- a/thirdparty/mbedtls/library/constant_time_internal.h
+++ b/thirdparty/mbedtls/library/constant_time_internal.h
@@ -32,7 +32,6 @@
#include <stddef.h>
-
/** Turn a value into a mask:
* - if \p value == 0, return the all-bits 0 mask, aka 0
* - otherwise, return the all-bits 1 mask, aka (unsigned) -1
@@ -46,7 +45,7 @@
*/
unsigned mbedtls_ct_uint_mask( unsigned value );
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
+#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
/** Turn a value into a mask:
* - if \p value == 0, return the all-bits 0 mask, aka 0
@@ -61,7 +60,7 @@ unsigned mbedtls_ct_uint_mask( unsigned value );
*/
size_t mbedtls_ct_size_mask( size_t value );
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
+#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
#if defined(MBEDTLS_BIGNUM_C)
@@ -196,7 +195,7 @@ signed char mbedtls_ct_base64_dec_value( unsigned char c );
#endif /* MBEDTLS_BASE64_C */
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
+#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
/** Conditional memcpy without branches.
*
@@ -292,7 +291,7 @@ int mbedtls_ct_hmac( mbedtls_md_context_t *ctx,
size_t max_data_len,
unsigned char *output );
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
+#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
diff --git a/thirdparty/mbedtls/library/ctr_drbg.c b/thirdparty/mbedtls/library/ctr_drbg.c
index a00d66ce87..ed31576a7b 100644
--- a/thirdparty/mbedtls/library/ctr_drbg.c
+++ b/thirdparty/mbedtls/library/ctr_drbg.c
@@ -36,14 +36,7 @@
#include <stdio.h>
#endif
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
/*
* CTR_DRBG context initialization
diff --git a/thirdparty/mbedtls/library/debug.c b/thirdparty/mbedtls/library/debug.c
index e1086008af..353b4bf07b 100644
--- a/thirdparty/mbedtls/library/debug.c
+++ b/thirdparty/mbedtls/library/debug.c
@@ -21,16 +21,7 @@
#if defined(MBEDTLS_DEBUG_C)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#define mbedtls_time_t time_t
-#define mbedtls_snprintf snprintf
-#define mbedtls_vsnprintf vsnprintf
-#endif
#include "mbedtls/debug.h"
#include "mbedtls/error.h"
@@ -39,11 +30,6 @@
#include <stdio.h>
#include <string.h>
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
- !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
#define DEBUG_BUF_SIZE 512
static int debug_threshold = 0;
diff --git a/thirdparty/mbedtls/library/des.c b/thirdparty/mbedtls/library/des.c
index 91d22b5d90..65f5681cf1 100644
--- a/thirdparty/mbedtls/library/des.c
+++ b/thirdparty/mbedtls/library/des.c
@@ -33,14 +33,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_DES_ALT)
diff --git a/thirdparty/mbedtls/library/dhm.c b/thirdparty/mbedtls/library/dhm.c
index 88e148bb80..4d2e33e689 100644
--- a/thirdparty/mbedtls/library/dhm.c
+++ b/thirdparty/mbedtls/library/dhm.c
@@ -43,15 +43,7 @@
#include "mbedtls/asn1.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#include <stdio.h>
-#define mbedtls_printf printf
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#if !defined(MBEDTLS_DHM_ALT)
diff --git a/thirdparty/mbedtls/library/ecdh.c b/thirdparty/mbedtls/library/ecdh.c
index 60c6e429de..724c938a71 100644
--- a/thirdparty/mbedtls/library/ecdh.c
+++ b/thirdparty/mbedtls/library/ecdh.c
@@ -77,10 +77,12 @@ static int ecdh_gen_public_restartable( mbedtls_ecp_group *grp,
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- /* If multiplication is in progress, we already generated a privkey */
+ int restarting = 0;
#if defined(MBEDTLS_ECP_RESTARTABLE)
- if( rs_ctx == NULL || rs_ctx->rsm == NULL )
+ restarting = ( rs_ctx != NULL && rs_ctx->rsm != NULL );
#endif
+ /* If multiplication is in progress, we already generated a privkey */
+ if( !restarting )
MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) );
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, Q, d, &grp->G,
diff --git a/thirdparty/mbedtls/library/ecdsa.c b/thirdparty/mbedtls/library/ecdsa.c
index 640eb24a26..4bae6a93fd 100644
--- a/thirdparty/mbedtls/library/ecdsa.c
+++ b/thirdparty/mbedtls/library/ecdsa.c
@@ -36,13 +36,7 @@
#include "mbedtls/hmac_drbg.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
diff --git a/thirdparty/mbedtls/library/ecjpake.c b/thirdparty/mbedtls/library/ecjpake.c
index 0b9bffb93e..fe0b9d93e9 100644
--- a/thirdparty/mbedtls/library/ecjpake.c
+++ b/thirdparty/mbedtls/library/ecjpake.c
@@ -794,12 +794,7 @@ cleanup:
#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif
#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
!defined(MBEDTLS_SHA256_C)
diff --git a/thirdparty/mbedtls/library/ecp.c b/thirdparty/mbedtls/library/ecp.c
index 890f364a08..ad19e05fb2 100644
--- a/thirdparty/mbedtls/library/ecp.c
+++ b/thirdparty/mbedtls/library/ecp.c
@@ -90,15 +90,7 @@
#define ECP_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#include <stdio.h>
-#define mbedtls_printf printf
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#include "mbedtls/ecp_internal.h"
@@ -112,11 +104,6 @@
#endif
#endif /* MBEDTLS_ECP_NO_INTERNAL_RNG */
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
- !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
#if defined(MBEDTLS_SELF_TEST)
/*
* Counts of point addition and doubling, and field multiplications.
@@ -2056,9 +2043,13 @@ static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R
i = d;
MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, T_size, x[i] ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) );
+
+ int have_rng = 1;
#if defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- if( f_rng != 0 )
+ if( f_rng == NULL )
+ have_rng = 0;
#endif
+ if( have_rng )
MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) );
}
@@ -2192,9 +2183,12 @@ final_norm:
*
* Avoid the leak by randomizing coordinates before we normalize them.
*/
+ int have_rng = 1;
#if defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- if( f_rng != 0 )
+ if( f_rng == NULL )
+ have_rng = 0;
#endif
+ if( have_rng )
MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, RR, f_rng, p_rng ) );
MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, RR ) );
@@ -2403,12 +2397,14 @@ cleanup:
mbedtls_free( T );
}
- /* don't free R while in progress in case R == P */
+ /* prevent caller from using invalid value */
+ int should_free_R = ( ret != 0 );
#if defined(MBEDTLS_ECP_RESTARTABLE)
- if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
+ /* don't free R while in progress in case R == P */
+ if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+ should_free_R = 0;
#endif
- /* prevent caller from using invalid value */
- if( ret != 0 )
+ if( should_free_R )
mbedtls_ecp_point_free( R );
ECP_RS_LEAVE( rsm );
@@ -2596,13 +2592,16 @@ static int ecp_mul_mxz( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
MOD_ADD( RP.X );
/* Randomize coordinates of the starting point */
+ int have_rng = 1;
#if defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- if( f_rng != NULL )
+ if( f_rng == NULL )
+ have_rng = 0;
#endif
+ if( have_rng )
MBEDTLS_MPI_CHK( ecp_randomize_mxz( grp, &RP, f_rng, p_rng ) );
/* Loop invariant: R = result so far, RP = R + P */
- i = mbedtls_mpi_bitlen( m ); /* one past the (zero-based) most significant bit */
+ i = grp->nbits + 1; /* one past the (zero-based) required msb for private keys */
while( i-- > 0 )
{
b = mbedtls_mpi_get_bit( m, i );
@@ -2631,9 +2630,12 @@ static int ecp_mul_mxz( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
*
* Avoid the leak by randomizing coordinates before we normalize them.
*/
+ have_rng = 1;
#if defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- if( f_rng != NULL )
+ if( f_rng == NULL )
+ have_rng = 0;
#endif
+ if( have_rng )
MBEDTLS_MPI_CHK( ecp_randomize_mxz( grp, R, f_rng, p_rng ) );
MBEDTLS_MPI_CHK( ecp_normalize_mxz( grp, R ) );
@@ -2680,10 +2682,12 @@ int mbedtls_ecp_mul_restartable( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) );
#endif /* MBEDTLS_ECP_INTERNAL_ALT */
+ int restarting = 0;
#if defined(MBEDTLS_ECP_RESTARTABLE)
- /* skip argument check when restarting */
- if( rs_ctx == NULL || rs_ctx->rsm == NULL )
+ restarting = ( rs_ctx != NULL && rs_ctx->rsm != NULL );
#endif
+ /* skip argument check when restarting */
+ if( !restarting )
{
/* check_privkey is free */
MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_CHK );
@@ -2797,14 +2801,17 @@ static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp,
if( mbedtls_mpi_cmp_int( m, 0 ) == 0 )
{
+ MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) );
MBEDTLS_MPI_CHK( mbedtls_ecp_set_zero( R ) );
}
else if( mbedtls_mpi_cmp_int( m, 1 ) == 0 )
{
+ MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) );
MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) );
}
else if( mbedtls_mpi_cmp_int( m, -1 ) == 0 )
{
+ MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) );
MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) );
if( mbedtls_mpi_cmp_int( &R->Y, 0 ) != 0 )
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &R->Y, &grp->P, &R->Y ) );
diff --git a/thirdparty/mbedtls/library/ecp_curves.c b/thirdparty/mbedtls/library/ecp_curves.c
index 2199be6461..47761eef4e 100644
--- a/thirdparty/mbedtls/library/ecp_curves.c
+++ b/thirdparty/mbedtls/library/ecp_curves.c
@@ -38,11 +38,6 @@
#define ECP_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
- !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
#define ECP_MPI_INIT(s, n, p) {s, (n), (mbedtls_mpi_uint *)(p)}
#define ECP_MPI_INIT_ARRAY(x) \
diff --git a/thirdparty/mbedtls/library/entropy.c b/thirdparty/mbedtls/library/entropy.c
index 12fd3b9b5f..e3b337ff35 100644
--- a/thirdparty/mbedtls/library/entropy.c
+++ b/thirdparty/mbedtls/library/entropy.c
@@ -38,18 +38,9 @@
#include <stdio.h>
#endif
-#if defined(MBEDTLS_ENTROPY_NV_SEED)
#include "mbedtls/platform.h"
-#endif
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if defined(MBEDTLS_HAVEGE_C)
#include "mbedtls/havege.h"
diff --git a/thirdparty/mbedtls/library/entropy_poll.c b/thirdparty/mbedtls/library/entropy_poll.c
index 40f23fd2a6..69ac29e4f7 100644
--- a/thirdparty/mbedtls/library/entropy_poll.c
+++ b/thirdparty/mbedtls/library/entropy_poll.c
@@ -38,9 +38,7 @@
#if defined(MBEDTLS_HAVEGE_C)
#include "mbedtls/havege.h"
#endif
-#if defined(MBEDTLS_ENTROPY_NV_SEED)
#include "mbedtls/platform.h"
-#endif
#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
diff --git a/thirdparty/mbedtls/library/error.c b/thirdparty/mbedtls/library/error.c
index afad38904f..8573369a32 100644
--- a/thirdparty/mbedtls/library/error.c
+++ b/thirdparty/mbedtls/library/error.c
@@ -25,11 +25,7 @@
#if defined(MBEDTLS_ERROR_C)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#define mbedtls_snprintf snprintf
-#endif
#include <stdio.h>
#include <string.h>
@@ -961,7 +957,7 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
#else /* MBEDTLS_ERROR_C */
/*
- * Provide an non-function in case MBEDTLS_ERROR_C is not defined
+ * Provide a dummy implementation when MBEDTLS_ERROR_C is not defined
*/
void mbedtls_strerror( int ret, char *buf, size_t buflen )
{
diff --git a/thirdparty/mbedtls/library/gcm.c b/thirdparty/mbedtls/library/gcm.c
index 43a5e1bec6..d0b73379a6 100644
--- a/thirdparty/mbedtls/library/gcm.c
+++ b/thirdparty/mbedtls/library/gcm.c
@@ -32,6 +32,7 @@
#if defined(MBEDTLS_GCM_C)
#include "mbedtls/gcm.h"
+#include "mbedtls/platform.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
@@ -41,15 +42,6 @@
#include "mbedtls/aesni.h"
#endif
-#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
-#include "mbedtls/aes.h"
-#include "mbedtls/platform.h"
-#if !defined(MBEDTLS_PLATFORM_C)
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
-
#if !defined(MBEDTLS_GCM_ALT)
/* Parameter validation macros */
diff --git a/thirdparty/mbedtls/library/hmac_drbg.c b/thirdparty/mbedtls/library/hmac_drbg.c
index de9706885c..69272fa73d 100644
--- a/thirdparty/mbedtls/library/hmac_drbg.c
+++ b/thirdparty/mbedtls/library/hmac_drbg.c
@@ -37,14 +37,7 @@
#include <stdio.h>
#endif
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_SELF_TEST */
-#endif /* MBEDTLS_PLATFORM_C */
/*
* HMAC_DRBG context initialization
diff --git a/thirdparty/mbedtls/library/md.c b/thirdparty/mbedtls/library/md.c
index a10a835634..53a84b01c6 100644
--- a/thirdparty/mbedtls/library/md.c
+++ b/thirdparty/mbedtls/library/md.c
@@ -38,13 +38,7 @@
#include "mbedtls/sha256.h"
#include "mbedtls/sha512.h"
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#include <string.h>
diff --git a/thirdparty/mbedtls/library/md2.c b/thirdparty/mbedtls/library/md2.c
index 7264e30313..f8293a1df3 100644
--- a/thirdparty/mbedtls/library/md2.c
+++ b/thirdparty/mbedtls/library/md2.c
@@ -33,14 +33,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_MD2_ALT)
diff --git a/thirdparty/mbedtls/library/md4.c b/thirdparty/mbedtls/library/md4.c
index eaa679a0a6..a412213480 100644
--- a/thirdparty/mbedtls/library/md4.c
+++ b/thirdparty/mbedtls/library/md4.c
@@ -33,14 +33,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_MD4_ALT)
diff --git a/thirdparty/mbedtls/library/md5.c b/thirdparty/mbedtls/library/md5.c
index 4b53fcf367..e53bfe6306 100644
--- a/thirdparty/mbedtls/library/md5.c
+++ b/thirdparty/mbedtls/library/md5.c
@@ -32,14 +32,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_MD5_ALT)
diff --git a/thirdparty/mbedtls/library/mps_reader.c b/thirdparty/mbedtls/library/mps_reader.c
index 9af5073cc9..0c30a75d05 100644
--- a/thirdparty/mbedtls/library/mps_reader.c
+++ b/thirdparty/mbedtls/library/mps_reader.c
@@ -29,11 +29,6 @@
#include <string.h>
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
- !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
#if defined(MBEDTLS_MPS_ENABLE_TRACE)
static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_READER;
#endif /* MBEDTLS_MPS_ENABLE_TRACE */
@@ -535,7 +530,7 @@ int mbedtls_mps_reader_reclaim( mbedtls_mps_reader *rd,
* of the accumulator. */
memmove( acc, acc + acc_backup_offset, acc_backup_len );
- /* Copy uncmmitted parts of the current fragment to the
+ /* Copy uncommitted parts of the current fragment to the
* accumulator. */
memcpy( acc + acc_backup_len,
frag + frag_backup_offset, frag_backup_len );
diff --git a/thirdparty/mbedtls/library/mps_trace.h b/thirdparty/mbedtls/library/mps_trace.h
index 7c2360118a..820a1b66c2 100644
--- a/thirdparty/mbedtls/library/mps_trace.h
+++ b/thirdparty/mbedtls/library/mps_trace.h
@@ -30,13 +30,7 @@
#include "mps_common.h"
#include "mps_trace.h"
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#define mbedtls_vsnprintf vsnprintf
-#endif /* MBEDTLS_PLATFORM_C */
#if defined(MBEDTLS_MPS_ENABLE_TRACE)
diff --git a/thirdparty/mbedtls/library/net_sockets.c b/thirdparty/mbedtls/library/net_sockets.c
index 8c765e1c8c..b2cab503f2 100644
--- a/thirdparty/mbedtls/library/net_sockets.c
+++ b/thirdparty/mbedtls/library/net_sockets.c
@@ -37,11 +37,7 @@
#error "This module only works on Unix and Windows, see MBEDTLS_NET_C in config.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#endif
#include "mbedtls/net_sockets.h"
#include "mbedtls/error.h"
diff --git a/thirdparty/mbedtls/library/nist_kw.c b/thirdparty/mbedtls/library/nist_kw.c
index 1aea0b6345..495c23d06a 100644
--- a/thirdparty/mbedtls/library/nist_kw.c
+++ b/thirdparty/mbedtls/library/nist_kw.c
@@ -39,14 +39,7 @@
#include <stdint.h>
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#if !defined(MBEDTLS_NIST_KW_ALT)
diff --git a/thirdparty/mbedtls/library/oid.c b/thirdparty/mbedtls/library/oid.c
index 19c8ac207c..53e5350eb3 100644
--- a/thirdparty/mbedtls/library/oid.c
+++ b/thirdparty/mbedtls/library/oid.c
@@ -30,11 +30,7 @@
#include <stdio.h>
#include <string.h>
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#define mbedtls_snprintf snprintf
-#endif
/*
* Macro to automatically add the size of #define'd OIDs
diff --git a/thirdparty/mbedtls/library/pem.c b/thirdparty/mbedtls/library/pem.c
index fcfde94799..cb1c82b3e4 100644
--- a/thirdparty/mbedtls/library/pem.c
+++ b/thirdparty/mbedtls/library/pem.c
@@ -32,13 +32,7 @@
#include <string.h>
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#if defined(MBEDTLS_PEM_PARSE_C)
void mbedtls_pem_init( mbedtls_pem_context *ctx )
diff --git a/thirdparty/mbedtls/library/pk_wrap.c b/thirdparty/mbedtls/library/pk_wrap.c
index 107e912ace..f35abf21a4 100644
--- a/thirdparty/mbedtls/library/pk_wrap.c
+++ b/thirdparty/mbedtls/library/pk_wrap.c
@@ -50,13 +50,7 @@
#include "mbedtls/asn1.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#include <limits.h>
#include <stdint.h>
@@ -872,7 +866,7 @@ static void *pk_opaque_alloc_wrap( void )
{
void *ctx = mbedtls_calloc( 1, sizeof( psa_key_id_t ) );
- /* no _init() function to call, an calloc() already zeroized */
+ /* no _init() function to call, as calloc() already zeroized */
return( ctx );
}
diff --git a/thirdparty/mbedtls/library/pkcs11.c b/thirdparty/mbedtls/library/pkcs11.c
index 4deccf3f60..a7207cfc93 100644
--- a/thirdparty/mbedtls/library/pkcs11.c
+++ b/thirdparty/mbedtls/library/pkcs11.c
@@ -29,13 +29,7 @@
#include "mbedtls/oid.h"
#include "mbedtls/x509_crt.h"
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#include <string.h>
diff --git a/thirdparty/mbedtls/library/pkcs5.c b/thirdparty/mbedtls/library/pkcs5.c
index 2b014d91c8..f9d01371a7 100644
--- a/thirdparty/mbedtls/library/pkcs5.c
+++ b/thirdparty/mbedtls/library/pkcs5.c
@@ -42,12 +42,7 @@
#include <string.h>
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif
#if defined(MBEDTLS_ASN1_PARSE_C)
static int pkcs5_parse_pbkdf2_params( const mbedtls_asn1_buf *params,
diff --git a/thirdparty/mbedtls/library/pkparse.c b/thirdparty/mbedtls/library/pkparse.c
index ea5c6b69cb..6170d6d012 100644
--- a/thirdparty/mbedtls/library/pkparse.c
+++ b/thirdparty/mbedtls/library/pkparse.c
@@ -48,13 +48,7 @@
#include "mbedtls/pkcs12.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
/* Parameter validation macros based on platform_util.h */
#define PK_VALIDATE_RET( cond ) \
diff --git a/thirdparty/mbedtls/library/pkwrite.c b/thirdparty/mbedtls/library/pkwrite.c
index 566153dd93..c1ce0e3f02 100644
--- a/thirdparty/mbedtls/library/pkwrite.c
+++ b/thirdparty/mbedtls/library/pkwrite.c
@@ -48,13 +48,7 @@
#include "psa/crypto.h"
#include "mbedtls/psa_util.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
/* Parameter validation macros based on platform_util.h */
#define PK_VALIDATE_RET( cond ) \
diff --git a/thirdparty/mbedtls/library/poly1305.c b/thirdparty/mbedtls/library/poly1305.c
index 7375a0c572..a1c5b19d8e 100644
--- a/thirdparty/mbedtls/library/poly1305.c
+++ b/thirdparty/mbedtls/library/poly1305.c
@@ -28,22 +28,10 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_POLY1305_ALT)
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
- !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
/* Parameter validation macros */
#define POLY1305_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA )
diff --git a/thirdparty/mbedtls/library/ripemd160.c b/thirdparty/mbedtls/library/ripemd160.c
index aed7322cff..55e259e192 100644
--- a/thirdparty/mbedtls/library/ripemd160.c
+++ b/thirdparty/mbedtls/library/ripemd160.c
@@ -33,14 +33,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_RIPEMD160_ALT)
diff --git a/thirdparty/mbedtls/library/rsa.c b/thirdparty/mbedtls/library/rsa.c
index d1f6ddb177..9c39fa5d91 100644
--- a/thirdparty/mbedtls/library/rsa.c
+++ b/thirdparty/mbedtls/library/rsa.c
@@ -57,14 +57,7 @@
#include <stdlib.h>
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#if !defined(MBEDTLS_RSA_ALT)
diff --git a/thirdparty/mbedtls/library/sha1.c b/thirdparty/mbedtls/library/sha1.c
index 0a5edafaff..7f0c8757db 100644
--- a/thirdparty/mbedtls/library/sha1.c
+++ b/thirdparty/mbedtls/library/sha1.c
@@ -32,14 +32,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#define SHA1_VALIDATE_RET(cond) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA1_BAD_INPUT_DATA )
diff --git a/thirdparty/mbedtls/library/sha256.c b/thirdparty/mbedtls/library/sha256.c
index db675efd1b..6f1306ee66 100644
--- a/thirdparty/mbedtls/library/sha256.c
+++ b/thirdparty/mbedtls/library/sha256.c
@@ -32,17 +32,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#define mbedtls_printf printf
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#define SHA256_VALIDATE_RET(cond) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA256_BAD_INPUT_DATA )
diff --git a/thirdparty/mbedtls/library/sha512.c b/thirdparty/mbedtls/library/sha512.c
index 02a135ca92..1a6872c8aa 100644
--- a/thirdparty/mbedtls/library/sha512.c
+++ b/thirdparty/mbedtls/library/sha512.c
@@ -38,17 +38,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#define mbedtls_printf printf
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#define SHA512_VALIDATE_RET(cond) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA512_BAD_INPUT_DATA )
@@ -428,9 +418,11 @@ int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx,
sha512_put_uint64_be( ctx->state[4], output, 32 );
sha512_put_uint64_be( ctx->state[5], output, 40 );
+ int truncated = 0;
#if !defined(MBEDTLS_SHA512_NO_SHA384)
- if( ctx->is384 == 0 )
+ truncated = ctx->is384;
#endif
+ if( !truncated )
{
sha512_put_uint64_be( ctx->state[6], output, 48 );
sha512_put_uint64_be( ctx->state[7], output, 56 );
diff --git a/thirdparty/mbedtls/library/ssl_cache.c b/thirdparty/mbedtls/library/ssl_cache.c
index 32188cf3f6..7a600cad18 100644
--- a/thirdparty/mbedtls/library/ssl_cache.c
+++ b/thirdparty/mbedtls/library/ssl_cache.c
@@ -25,13 +25,7 @@
#if defined(MBEDTLS_SSL_CACHE_C)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#include "mbedtls/ssl_cache.h"
#include "mbedtls/ssl_internal.h"
diff --git a/thirdparty/mbedtls/library/ssl_ciphersuites.c b/thirdparty/mbedtls/library/ssl_ciphersuites.c
index ceec77efb0..2bc8a9bba0 100644
--- a/thirdparty/mbedtls/library/ssl_ciphersuites.c
+++ b/thirdparty/mbedtls/library/ssl_ciphersuites.c
@@ -23,11 +23,7 @@
#if defined(MBEDTLS_SSL_TLS_C)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#endif
#include "mbedtls/ssl_ciphersuites.h"
#include "mbedtls/ssl.h"
diff --git a/thirdparty/mbedtls/library/ssl_cli.c b/thirdparty/mbedtls/library/ssl_cli.c
index 72351c9757..b40ddb70b4 100644
--- a/thirdparty/mbedtls/library/ssl_cli.c
+++ b/thirdparty/mbedtls/library/ssl_cli.c
@@ -21,13 +21,7 @@
#if defined(MBEDTLS_SSL_CLI_C)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#include "mbedtls/ssl.h"
#include "mbedtls/ssl_internal.h"
@@ -174,7 +168,7 @@ static int ssl_write_renegotiation_ext( mbedtls_ssl_context *ssl,
*olen = 0;
- /* We're always including an TLS_EMPTY_RENEGOTIATION_INFO_SCSV in the
+ /* We're always including a TLS_EMPTY_RENEGOTIATION_INFO_SCSV in the
* initial ClientHello, in which case also adding the renegotiation
* info extension is NOT RECOMMENDED as per RFC 5746 Section 3.4. */
if( ssl->renego_status != MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS )
@@ -1004,9 +998,12 @@ static int ssl_write_client_hello( mbedtls_ssl_context *ssl )
return( MBEDTLS_ERR_SSL_NO_RNG );
}
+ int renegotiating = 0;
#if defined(MBEDTLS_SSL_RENEGOTIATION)
- if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE )
+ if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE )
+ renegotiating = 1;
#endif
+ if( !renegotiating )
{
ssl->major_ver = ssl->conf->min_major_ver;
ssl->minor_ver = ssl->conf->min_minor_ver;
@@ -1092,9 +1089,7 @@ static int ssl_write_client_hello( mbedtls_ssl_context *ssl )
* RFC 5077 section 3.4: "When presenting a ticket, the client MAY
* generate and include a Session ID in the TLS ClientHello."
*/
-#if defined(MBEDTLS_SSL_RENEGOTIATION)
- if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE )
-#endif
+ if( !renegotiating )
{
if( ssl->session_negotiate->ticket != NULL &&
ssl->session_negotiate->ticket_len != 0 )
@@ -1209,9 +1204,7 @@ static int ssl_write_client_hello( mbedtls_ssl_context *ssl )
/*
* Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV
*/
-#if defined(MBEDTLS_SSL_RENEGOTIATION)
- if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE )
-#endif
+ if( !renegotiating )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding EMPTY_RENEGOTIATION_INFO_SCSV" ) );
MBEDTLS_SSL_CHK_BUF_PTR( p, end, 2 );
@@ -2062,6 +2055,30 @@ static int ssl_parse_hello_verify_request( mbedtls_ssl_context *ssl )
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
+static int is_compression_bad( mbedtls_ssl_context *ssl, unsigned char comp )
+{
+ int bad_comp = 0;
+
+ /* Suppress warnings in some configurations */
+ (void) ssl;
+#if defined(MBEDTLS_ZLIB_SUPPORT)
+ /* See comments in ssl_write_client_hello() */
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+ comp != MBEDTLS_SSL_COMPRESS_NULL )
+ bad_comp = 1;
+#endif
+
+ if( comp != MBEDTLS_SSL_COMPRESS_NULL &&
+ comp != MBEDTLS_SSL_COMPRESS_DEFLATE )
+ bad_comp = 1;
+#else /* MBEDTLS_ZLIB_SUPPORT */
+ if( comp != MBEDTLS_SSL_COMPRESS_NULL )
+ bad_comp = 1;
+#endif/* MBEDTLS_ZLIB_SUPPORT */
+ return bad_comp;
+}
+
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_server_hello( mbedtls_ssl_context *ssl )
{
@@ -2070,9 +2087,6 @@ static int ssl_parse_server_hello( mbedtls_ssl_context *ssl )
size_t ext_len;
unsigned char *buf, *ext;
unsigned char comp;
-#if defined(MBEDTLS_ZLIB_SUPPORT)
- int accept_comp;
-#endif
#if defined(MBEDTLS_SSL_RENEGOTIATION)
int renegotiation_info_seen = 0;
#endif
@@ -2241,20 +2255,7 @@ static int ssl_parse_server_hello( mbedtls_ssl_context *ssl )
*/
comp = buf[37 + n];
-#if defined(MBEDTLS_ZLIB_SUPPORT)
- /* See comments in ssl_write_client_hello() */
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
- if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
- accept_comp = 0;
- else
-#endif
- accept_comp = 1;
-
- if( comp != MBEDTLS_SSL_COMPRESS_NULL &&
- ( comp != MBEDTLS_SSL_COMPRESS_DEFLATE || accept_comp == 0 ) )
-#else /* MBEDTLS_ZLIB_SUPPORT */
- if( comp != MBEDTLS_SSL_COMPRESS_NULL )
-#endif/* MBEDTLS_ZLIB_SUPPORT */
+ if( is_compression_bad( ssl, comp ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1,
( "server hello, bad compression: %d", comp ) );
@@ -2687,7 +2688,7 @@ static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl )
grp_id = ssl->handshake->ecdh_ctx.grp.id;
#else
grp_id = ssl->handshake->ecdh_ctx.grp_id;
-#endif
+#endif /* MBEDTLS_ECDH_LEGACY_CONTEXT */
curve_info = mbedtls_ecp_curve_info_from_grp_id( grp_id );
if( curve_info == NULL )
@@ -2700,11 +2701,12 @@ static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl )
#if defined(MBEDTLS_ECP_C)
if( mbedtls_ssl_check_curve( ssl, grp_id ) != 0 )
+ return( -1 );
#else
if( ssl->handshake->ecdh_ctx.grp.nbits < 163 ||
ssl->handshake->ecdh_ctx.grp.nbits > 521 )
-#endif
return( -1 );
+#endif /* MBEDTLS_ECP_C */
MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx,
MBEDTLS_DEBUG_ECDH_QP );
@@ -2858,8 +2860,8 @@ static int ssl_parse_server_psk_hint( mbedtls_ssl_context *ssl,
}
/*
- * Note: we currently ignore the PKS identity hint, as we only allow one
- * PSK to be provisionned on the client. This could be changed later if
+ * Note: we currently ignore the PSK identity hint, as we only allow one
+ * PSK to be provisioned on the client. This could be changed later if
* someone needs that feature.
*/
*p += len;
@@ -3452,23 +3454,23 @@ start_processing:
#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED)
if( ssl->handshake->ecrs_enabled )
rs_ctx = &ssl->handshake->ecrs_ctx.pk;
-#endif
+#endif /* MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED */
if( ( ret = mbedtls_pk_verify_restartable( peer_pk,
md_alg, hash, hashlen, p, sig_len, rs_ctx ) ) != 0 )
{
#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED)
- if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
-#endif
- mbedtls_ssl_send_alert_message(
- ssl,
- MBEDTLS_SSL_ALERT_LEVEL_FATAL,
- MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
- MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret );
-#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED)
if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
- ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
-#endif
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret );
+ return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS );
+ }
+#endif /* MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED */
+ mbedtls_ssl_send_alert_message(
+ ssl,
+ MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+ MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret );
return( ret );
}
diff --git a/thirdparty/mbedtls/library/ssl_cookie.c b/thirdparty/mbedtls/library/ssl_cookie.c
index 3781796b72..f12f28e849 100644
--- a/thirdparty/mbedtls/library/ssl_cookie.c
+++ b/thirdparty/mbedtls/library/ssl_cookie.c
@@ -25,12 +25,7 @@
#if defined(MBEDTLS_SSL_COOKIE_C)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#include "mbedtls/ssl_cookie.h"
#include "mbedtls/ssl_internal.h"
diff --git a/thirdparty/mbedtls/library/ssl_msg.c b/thirdparty/mbedtls/library/ssl_msg.c
index e47c538888..d7bebe04d6 100644
--- a/thirdparty/mbedtls/library/ssl_msg.c
+++ b/thirdparty/mbedtls/library/ssl_msg.c
@@ -30,13 +30,7 @@
#if defined(MBEDTLS_SSL_TLS_C)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#include "mbedtls/ssl.h"
#include "mbedtls/ssl_internal.h"
@@ -441,9 +435,12 @@ static void ssl_extract_add_data_from_record( unsigned char* add_data,
unsigned char *cur = add_data;
+ int is_tls13 = 0;
#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)
- if( minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 )
+ if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 )
+ is_tls13 = 1;
#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
+ if( !is_tls13 )
{
((void) minor_ver);
memcpy( cur, rec->ctr, sizeof( rec->ctr ) );
@@ -1887,8 +1884,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want )
if( ssl->f_recv == NULL && ssl->f_recv_timeout == NULL )
{
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() "
- "or mbedtls_ssl_set_bio()" ) );
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " ) );
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
@@ -2103,8 +2099,7 @@ int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl )
if( ssl->f_send == NULL )
{
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() "
- "or mbedtls_ssl_set_bio()" ) );
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " ) );
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
@@ -3950,8 +3945,8 @@ int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl,
if( ssl_record_is_in_progress( ssl ) == 0 )
{
+ int dtls_have_buffered = 0;
#if defined(MBEDTLS_SSL_PROTO_DTLS)
- int have_buffered = 0;
/* We only check for buffered messages if the
* current datagram is fully consumed. */
@@ -3959,11 +3954,11 @@ int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl,
ssl_next_record_is_in_datagram( ssl ) == 0 )
{
if( ssl_load_buffered_message( ssl ) == 0 )
- have_buffered = 1;
+ dtls_have_buffered = 1;
}
- if( have_buffered == 0 )
#endif /* MBEDTLS_SSL_PROTO_DTLS */
+ if( dtls_have_buffered == 0 )
{
ret = ssl_get_next_record( ssl );
if( ret == MBEDTLS_ERR_SSL_CONTINUE_PROCESSING )
@@ -4037,7 +4032,7 @@ static int ssl_load_buffered_message( mbedtls_ssl_context *ssl )
if( hs == NULL )
return( -1 );
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_messsage" ) );
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_message" ) );
if( ssl->state == MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC ||
ssl->state == MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC )
diff --git a/thirdparty/mbedtls/library/ssl_srv.c b/thirdparty/mbedtls/library/ssl_srv.c
index 2efb13cc33..0563c0b590 100644
--- a/thirdparty/mbedtls/library/ssl_srv.c
+++ b/thirdparty/mbedtls/library/ssl_srv.c
@@ -21,13 +21,7 @@
#if defined(MBEDTLS_SSL_SRV_C)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#include "mbedtls/ssl.h"
#include "mbedtls/ssl_internal.h"
@@ -1460,6 +1454,7 @@ static int ssl_parse_client_hello( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) );
+ int renegotiating = 0;
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
read_record_header:
#endif
@@ -1469,8 +1464,10 @@ read_record_header:
* ClientHello, which doesn't use the same record layer format.
*/
#if defined(MBEDTLS_SSL_RENEGOTIATION)
- if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE )
+ if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE )
+ renegotiating = 1;
#endif
+ if( !renegotiating )
{
if( ( ret = mbedtls_ssl_fetch_input( ssl, 5 ) ) != 0 )
{
@@ -1483,9 +1480,12 @@ read_record_header:
buf = ssl->in_hdr;
#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
+ int is_dtls = 0;
#if defined(MBEDTLS_SSL_PROTO_DTLS)
- if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_STREAM )
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+ is_dtls = 1;
#endif
+ if( !is_dtls )
if( ( buf[0] & 0x80 ) != 0 )
return( ssl_parse_client_hello_v2( ssl ) );
#endif
@@ -3903,8 +3903,14 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl,
size_t peer_pmssize )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+ mbedtls_x509_crt *own_cert = mbedtls_ssl_own_cert( ssl );
+ if( own_cert == NULL ) {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no local certificate" ) );
+ return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
+ }
+ mbedtls_pk_context *public_key = &own_cert->pk;
mbedtls_pk_context *private_key = mbedtls_ssl_own_key( ssl );
- mbedtls_pk_context *public_key = &mbedtls_ssl_own_cert( ssl )->pk;
size_t len = mbedtls_pk_get_len( public_key );
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
diff --git a/thirdparty/mbedtls/library/ssl_ticket.c b/thirdparty/mbedtls/library/ssl_ticket.c
index e0126cc9d1..8a57789f10 100644
--- a/thirdparty/mbedtls/library/ssl_ticket.c
+++ b/thirdparty/mbedtls/library/ssl_ticket.c
@@ -21,13 +21,7 @@
#if defined(MBEDTLS_SSL_TICKET_C)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#include "mbedtls/ssl_internal.h"
#include "mbedtls/ssl_ticket.h"
@@ -152,27 +146,45 @@ int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,
if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ int do_mbedtls_cipher_setup = 1;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
ret = mbedtls_cipher_setup_psa( &ctx->keys[0].ctx,
cipher_info, TICKET_AUTH_TAG_BYTES );
- if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
- return( ret );
- /* We don't yet expect to support all ciphers through PSA,
- * so allow fallback to ordinary mbedtls_cipher_setup(). */
- if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
+
+ switch( ret )
+ {
+ case 0:
+ do_mbedtls_cipher_setup = 0;
+ break;
+ case MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE:
+ /* We don't yet expect to support all ciphers through PSA,
+ * so allow fallback to ordinary mbedtls_cipher_setup(). */
+ do_mbedtls_cipher_setup = 1;
+ break;
+ default:
+ return( ret );
+ }
#endif /* MBEDTLS_USE_PSA_CRYPTO */
- if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) != 0 )
- return( ret );
+ if( do_mbedtls_cipher_setup )
+ if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) )
+ != 0 )
+ return( ret );
+ do_mbedtls_cipher_setup = 1;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ do_mbedtls_cipher_setup = 0;
+
ret = mbedtls_cipher_setup_psa( &ctx->keys[1].ctx,
cipher_info, TICKET_AUTH_TAG_BYTES );
if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
return( ret );
if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
+ do_mbedtls_cipher_setup = 1;
#endif /* MBEDTLS_USE_PSA_CRYPTO */
- if( ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) ) != 0 )
- return( ret );
+ if( do_mbedtls_cipher_setup )
+ if( ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) )
+ != 0 )
+ return( ret );
if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 ||
( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 )
diff --git a/thirdparty/mbedtls/library/ssl_tls.c b/thirdparty/mbedtls/library/ssl_tls.c
index 7badec51ae..70196a4861 100644
--- a/thirdparty/mbedtls/library/ssl_tls.c
+++ b/thirdparty/mbedtls/library/ssl_tls.c
@@ -29,13 +29,7 @@
#if defined(MBEDTLS_SSL_TLS_C)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
#include "mbedtls/ssl.h"
#include "mbedtls/ssl_internal.h"
@@ -766,7 +760,9 @@ static int tls_prf_generic( mbedtls_md_type_t md_type,
exit:
mbedtls_md_free( &md_ctx );
- mbedtls_platform_zeroize( tmp, tmp_len );
+ if ( tmp != NULL )
+ mbedtls_platform_zeroize( tmp, tmp_len );
+
mbedtls_platform_zeroize( h_i, sizeof( h_i ) );
mbedtls_free( tmp );
@@ -985,6 +981,7 @@ static int ssl_populate_transform( mbedtls_ssl_transform *transform,
#if defined(MBEDTLS_USE_PSA_CRYPTO)
int psa_fallthrough;
#endif /* MBEDTLS_USE_PSA_CRYPTO */
+ int do_mbedtls_cipher_setup;
unsigned char keyblk[256];
unsigned char *key1;
unsigned char *key2;
@@ -1363,6 +1360,7 @@ static int ssl_populate_transform( mbedtls_ssl_transform *transform,
}
#endif
+ do_mbedtls_cipher_setup = 1;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
/* Only use PSA-based ciphers for TLS-1.2.
@@ -1398,15 +1396,18 @@ static int ssl_populate_transform( mbedtls_ssl_transform *transform,
psa_fallthrough = 1;
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
- if( psa_fallthrough == 1 )
+ if( psa_fallthrough == 0 )
+ do_mbedtls_cipher_setup = 0;
#endif /* MBEDTLS_USE_PSA_CRYPTO */
- if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc,
- cipher_info ) ) != 0 )
+ if( do_mbedtls_cipher_setup &&
+ ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc,
+ cipher_info ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret );
goto end;
}
+ do_mbedtls_cipher_setup = 1;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
/* Only use PSA-based ciphers for TLS-1.2.
* That's relevant at least for TLS-1.0, where
@@ -1441,10 +1442,12 @@ static int ssl_populate_transform( mbedtls_ssl_transform *transform,
psa_fallthrough = 1;
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
- if( psa_fallthrough == 1 )
+ if( psa_fallthrough == 0 )
+ do_mbedtls_cipher_setup = 0;
#endif /* MBEDTLS_USE_PSA_CRYPTO */
- if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec,
- cipher_info ) ) != 0 )
+ if( do_mbedtls_cipher_setup &&
+ ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec,
+ cipher_info ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret );
goto end;
@@ -3411,7 +3414,7 @@ static void ssl_calc_finished_tls_sha384(
sha512.state, sizeof( sha512.state ) );
#endif
/* mbedtls_sha512_finish_ret's output parameter is declared as a
- * 64-byte buffer, but sice we're using SHA-384, we know that the
+ * 64-byte buffer, but since we're using SHA-384, we know that the
* output fits in 48 bytes. This is correct C, but GCC 11.1 warns
* about it.
*/
@@ -4089,9 +4092,12 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial )
memset( ssl->out_buf, 0, out_buf_len );
+ int clear_in_buf = 1;
#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C)
- if( partial == 0 )
+ if( partial != 0 )
+ clear_in_buf = 0;
#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */
+ if( clear_in_buf )
{
ssl->in_left = 0;
memset( ssl->in_buf, 0, in_buf_len );
@@ -4128,9 +4134,12 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial )
#endif
#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C)
+ int free_cli_id = 1;
#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE)
- if( partial == 0 )
+ if( partial != 0 )
+ free_cli_id = 0;
#endif
+ if( free_cli_id )
{
mbedtls_free( ssl->cli_id );
ssl->cli_id = NULL;
@@ -4471,7 +4480,7 @@ static void ssl_conf_remove_psk( mbedtls_ssl_config *conf )
conf->psk_opaque = MBEDTLS_SVC_KEY_ID_INIT;
}
/* This and the following branch should never
- * be taken simultaenously as we maintain the
+ * be taken simultaneously as we maintain the
* invariant that raw and opaque PSKs are never
* configured simultaneously. As a safeguard,
* though, `else` is omitted here. */
@@ -6335,7 +6344,7 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
MBEDTLS_SSL_DEBUG_MSG( 1, ( "There is pending outgoing data" ) );
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
- /* Protocol must be DLTS, not TLS */
+ /* Protocol must be DTLS, not TLS */
if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "Only DTLS is supported" ) );
@@ -6510,24 +6519,41 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
* Helper to get TLS 1.2 PRF from ciphersuite
* (Duplicates bits of logic from ssl_set_handshake_prfs().)
*/
+#if defined(MBEDTLS_SHA256_C) || \
+ (defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384))
typedef int (*tls_prf_fn)( const unsigned char *secret, size_t slen,
const char *label,
const unsigned char *random, size_t rlen,
unsigned char *dstbuf, size_t dlen );
static tls_prf_fn ssl_tls12prf_from_cs( int ciphersuite_id )
{
-#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384)
const mbedtls_ssl_ciphersuite_t * const ciphersuite_info =
mbedtls_ssl_ciphersuite_from_id( ciphersuite_id );
+ if( ciphersuite_info == NULL )
+ return( NULL );
+
+#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384)
if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 )
return( tls_prf_sha384 );
-#else
- (void) ciphersuite_id;
+ else
+#endif
+#if defined(MBEDTLS_SHA256_C)
+ {
+ if( ciphersuite_info->mac == MBEDTLS_MD_SHA256 )
+ return( tls_prf_sha256 );
+ }
#endif
- return( tls_prf_sha256 );
+#if !defined(MBEDTLS_SHA256_C) && \
+ (!defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_SHA512_NO_SHA384))
+ (void) ciphersuite_info;
+#endif
+ return( NULL );
}
+#endif /* MBEDTLS_SHA256_C ||
+ (MBEDTLS_SHA512_C && !MBEDTLS_SHA512_NO_SHA384) */
+
/*
* Deserialize context, see mbedtls_ssl_context_save() for format.
*
@@ -6543,6 +6569,7 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
const unsigned char * const end = buf + len;
size_t session_len;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ tls_prf_fn prf_func = NULL;
/*
* The context should have been freshly setup or reset.
@@ -6630,6 +6657,10 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
ssl->transform_out = ssl->transform;
ssl->transform_negotiate = NULL;
+ prf_func = ssl_tls12prf_from_cs( ssl->session->ciphersuite );
+ if( prf_func == NULL )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
/* Read random bytes and populate structure */
if( (size_t)( end - p ) < sizeof( ssl->transform->randbytes ) )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
@@ -6648,7 +6679,7 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
#if defined(MBEDTLS_ZLIB_SUPPORT)
ssl->session->compression,
#endif
- ssl_tls12prf_from_cs( ssl->session->ciphersuite ),
+ prf_func,
p, /* currently pointing to randbytes */
MBEDTLS_SSL_MINOR_VERSION_3, /* (D)TLS 1.2 is forced */
ssl->conf->endpoint,
@@ -6921,7 +6952,7 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl )
}
/*
- * Initialze mbedtls_ssl_config
+ * Initialize mbedtls_ssl_config
*/
void mbedtls_ssl_config_init( mbedtls_ssl_config *conf )
{
diff --git a/thirdparty/mbedtls/library/ssl_tls13_keys.c b/thirdparty/mbedtls/library/ssl_tls13_keys.c
index 3de6f03fb8..cc68773d3a 100644
--- a/thirdparty/mbedtls/library/ssl_tls13_keys.c
+++ b/thirdparty/mbedtls/library/ssl_tls13_keys.c
@@ -24,6 +24,7 @@
#include "mbedtls/hkdf.h"
#include "mbedtls/ssl_internal.h"
#include "ssl_tls13_keys.h"
+#include "psa/crypto_sizes.h"
#include <stdint.h>
#include <string.h>
@@ -31,6 +32,9 @@
#define MBEDTLS_SSL_TLS1_3_LABEL( name, string ) \
.name = string,
+#define TLS1_3_EVOLVE_INPUT_SIZE ( PSA_HASH_MAX_SIZE > PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE ) ? \
+ PSA_HASH_MAX_SIZE : PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE
+
struct mbedtls_ssl_tls1_3_labels_struct const mbedtls_ssl_tls1_3_labels =
{
/* This seems to work in C, despite the string literal being one
@@ -292,8 +296,8 @@ int mbedtls_ssl_tls1_3_evolve_secret(
{
int ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
size_t hlen, ilen;
- unsigned char tmp_secret[ MBEDTLS_MD_MAX_SIZE ] = { 0 };
- unsigned char tmp_input [ MBEDTLS_MD_MAX_SIZE ] = { 0 };
+ unsigned char tmp_secret[ PSA_MAC_MAX_SIZE ] = { 0 };
+ unsigned char tmp_input [ TLS1_3_EVOLVE_INPUT_SIZE ] = { 0 };
const mbedtls_md_info_t *md;
md = mbedtls_md_info_from_type( hash_alg );
diff --git a/thirdparty/mbedtls/library/timing.c b/thirdparty/mbedtls/library/timing.c
index 78bfa10cfb..151292e325 100644
--- a/thirdparty/mbedtls/library/timing.c
+++ b/thirdparty/mbedtls/library/timing.c
@@ -19,12 +19,7 @@
#include "common.h"
-#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif
#if defined(MBEDTLS_TIMING_C)
@@ -269,7 +264,7 @@ static void TimerProc( void *TimerContext )
Sleep( alarmMs );
mbedtls_timing_alarmed = 1;
/* _endthread will be called implicitly on return
- * That ensures execution of thread funcition's epilogue */
+ * That ensures execution of thread function's epilogue */
}
void mbedtls_set_alarm( int seconds )
diff --git a/thirdparty/mbedtls/library/x509.c b/thirdparty/mbedtls/library/x509.c
index 3997ebd1f3..54c8666d23 100644
--- a/thirdparty/mbedtls/library/x509.c
+++ b/thirdparty/mbedtls/library/x509.c
@@ -43,16 +43,7 @@
#include "mbedtls/pem.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#define mbedtls_free free
-#define mbedtls_calloc calloc
-#define mbedtls_printf printf
-#define mbedtls_snprintf snprintf
-#endif
#if defined(MBEDTLS_HAVE_TIME)
#include "mbedtls/platform_time.h"
@@ -198,7 +189,7 @@ static int x509_get_hash_alg( const mbedtls_x509_buf *alg, mbedtls_md_type_t *md
*
* RFC 4055 (which defines use of RSASSA-PSS in PKIX) states that the value
* of trailerField MUST be 1, and PKCS#1 v2.2 doesn't even define any other
- * option. Enfore this at parsing time.
+ * option. Enforce this at parsing time.
*/
int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params,
mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md,
@@ -424,6 +415,11 @@ static int x509_get_attr_type_value( unsigned char **p,
* For the general case we still use a flat list, but we mark elements of the
* same set so that they are "merged" together in the functions that consume
* this list, eg mbedtls_x509_dn_gets().
+ *
+ * On success, this function may allocate a linked list starting at cur->next
+ * that must later be free'd by the caller using mbedtls_free(). In error
+ * cases, this function frees all allocated memory internally and the caller
+ * has no freeing responsibilities.
*/
int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end,
mbedtls_x509_name *cur )
@@ -431,6 +427,8 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end,
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t set_len;
const unsigned char *end_set;
+ mbedtls_x509_name *head = cur;
+ mbedtls_x509_name *prev, *allocated;
/* don't use recursion, we'd risk stack overflow if not optimized */
while( 1 )
@@ -440,14 +438,17 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end,
*/
if( ( ret = mbedtls_asn1_get_tag( p, end, &set_len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET ) ) != 0 )
- return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_NAME, ret ) );
+ {
+ ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_NAME, ret );
+ goto error;
+ }
end_set = *p + set_len;
while( 1 )
{
if( ( ret = x509_get_attr_type_value( p, end_set, cur ) ) != 0 )
- return( ret );
+ goto error;
if( *p == end_set )
break;
@@ -458,7 +459,10 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end,
cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) );
if( cur->next == NULL )
- return( MBEDTLS_ERR_X509_ALLOC_FAILED );
+ {
+ ret = MBEDTLS_ERR_X509_ALLOC_FAILED;
+ goto error;
+ }
cur = cur->next;
}
@@ -472,10 +476,30 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end,
cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) );
if( cur->next == NULL )
- return( MBEDTLS_ERR_X509_ALLOC_FAILED );
+ {
+ ret = MBEDTLS_ERR_X509_ALLOC_FAILED;
+ goto error;
+ }
cur = cur->next;
}
+
+error:
+ /* Skip the first element as we did not allocate it */
+ allocated = head->next;
+
+ while( allocated != NULL )
+ {
+ prev = allocated;
+ allocated = allocated->next;
+
+ mbedtls_platform_zeroize( prev, sizeof( *prev ) );
+ mbedtls_free( prev );
+ }
+
+ mbedtls_platform_zeroize( head, sizeof( *head ) );
+
+ return( ret );
}
static int x509_parse_int( unsigned char **p, size_t n, int *res )
diff --git a/thirdparty/mbedtls/library/x509_crl.c b/thirdparty/mbedtls/library/x509_crl.c
index d2d8042029..b943a8d6da 100644
--- a/thirdparty/mbedtls/library/x509_crl.c
+++ b/thirdparty/mbedtls/library/x509_crl.c
@@ -1,5 +1,5 @@
/*
- * X.509 Certidicate Revocation List (CRL) parsing
+ * X.509 Certificate Revocation List (CRL) parsing
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0
@@ -42,15 +42,7 @@
#include "mbedtls/pem.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#include <stdio.h>
-#define mbedtls_free free
-#define mbedtls_calloc calloc
-#define mbedtls_snprintf snprintf
-#endif
#if defined(MBEDTLS_HAVE_TIME)
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
diff --git a/thirdparty/mbedtls/library/x509_crt.c b/thirdparty/mbedtls/library/x509_crt.c
index 96477e4c9d..4361f43ed0 100644
--- a/thirdparty/mbedtls/library/x509_crt.c
+++ b/thirdparty/mbedtls/library/x509_crt.c
@@ -49,15 +49,7 @@
#include "mbedtls/psa_util.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#define mbedtls_free free
-#define mbedtls_calloc calloc
-#define mbedtls_snprintf snprintf
-#endif
#if defined(MBEDTLS_THREADING_C)
#include "mbedtls/threading.h"
@@ -90,6 +82,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
+#include <errno.h>
#endif /* !_WIN32 || EFIX64 || EFI32 */
#endif
@@ -1278,9 +1271,12 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt,
}
}
+ int extensions_allowed = 1;
#if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3)
- if( crt->version == 3 )
+ if( crt->version != 3 )
+ extensions_allowed = 0;
#endif
+ if( extensions_allowed )
{
ret = x509_get_crt_ext( &p, end, crt, cb, p_ctx );
if( ret != 0 )
@@ -1668,8 +1664,22 @@ cleanup:
}
else if( stat( entry_name, &sb ) == -1 )
{
- ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
- goto cleanup;
+ if( errno == ENOENT )
+ {
+ /* Broken symbolic link - ignore this entry.
+ stat(2) will return this error for either (a) a dangling
+ symlink or (b) a missing file.
+ Given that we have just obtained the filename from readdir,
+ assume that it does exist and therefore treat this as a
+ dangling symlink. */
+ continue;
+ }
+ else
+ {
+ /* Some other file error; report the error. */
+ ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
+ goto cleanup;
+ }
}
if( !S_ISREG( sb.st_mode ) )
@@ -1798,6 +1808,7 @@ static int x509_info_subject_alt_name( char **buf, size_t *size,
const char *prefix )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ size_t i;
size_t n = *size;
char *p = *buf;
const mbedtls_x509_sequence *cur = subject_alt_name;
@@ -1850,18 +1861,11 @@ static int x509_info_subject_alt_name( char **buf, size_t *size,
ret = mbedtls_snprintf( p, n, "\n%s hardware serial number : ", prefix );
MBEDTLS_X509_SAFE_SNPRINTF;
- if( other_name->value.hardware_module_name.val.len >= n )
+ for( i = 0; i < other_name->value.hardware_module_name.val.len; i++ )
{
- *p = '\0';
- return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL );
+ ret = mbedtls_snprintf( p, n, "%02X", other_name->value.hardware_module_name.val.p[i] );
+ MBEDTLS_X509_SAFE_SNPRINTF;
}
-
- memcpy( p, other_name->value.hardware_module_name.val.p,
- other_name->value.hardware_module_name.val.len );
- p += other_name->value.hardware_module_name.val.len;
-
- n -= other_name->value.hardware_module_name.val.len;
-
}/* MBEDTLS_OID_ON_HW_MODULE_NAME */
}
break;
diff --git a/thirdparty/mbedtls/library/x509_csr.c b/thirdparty/mbedtls/library/x509_csr.c
index e259410d07..1a22b77086 100644
--- a/thirdparty/mbedtls/library/x509_csr.c
+++ b/thirdparty/mbedtls/library/x509_csr.c
@@ -42,15 +42,7 @@
#include "mbedtls/pem.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#include <stdio.h>
-#define mbedtls_free free
-#define mbedtls_calloc calloc
-#define mbedtls_snprintf snprintf
-#endif
#if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32)
#include <stdio.h>
diff --git a/thirdparty/mbedtls/library/x509write_csr.c b/thirdparty/mbedtls/library/x509write_csr.c
index afda950341..707dd001f0 100644
--- a/thirdparty/mbedtls/library/x509write_csr.c
+++ b/thirdparty/mbedtls/library/x509write_csr.c
@@ -44,13 +44,7 @@
#include "mbedtls/pem.h"
#endif
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx )
{
diff --git a/thirdparty/mbedtls/library/xtea.c b/thirdparty/mbedtls/library/xtea.c
index 77f6cb6f67..28e6972aa8 100644
--- a/thirdparty/mbedtls/library/xtea.c
+++ b/thirdparty/mbedtls/library/xtea.c
@@ -1,5 +1,5 @@
/*
- * An 32-bit implementation of the XTEA algorithm
+ * A 32-bit implementation of the XTEA algorithm
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0
@@ -26,14 +26,7 @@
#include <string.h>
-#if defined(MBEDTLS_SELF_TEST)
-#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
-#else
-#include <stdio.h>
-#define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
-#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_XTEA_ALT)
diff --git a/thirdparty/mbedtls/patches/1453.diff b/thirdparty/mbedtls/patches/1453.diff
index b1c9c43ed2..4a7ca1570b 100644
--- a/thirdparty/mbedtls/patches/1453.diff
+++ b/thirdparty/mbedtls/patches/1453.diff
@@ -1,8 +1,8 @@
-diff --git a/library/entropy_poll.c b/library/entropy_poll.c
-index 4556f88a5..ba56b70f7 100644
---- a/library/entropy_poll.c
-+++ b/library/entropy_poll.c
-@@ -61,28 +61,43 @@
+diff --git a/thirdparty/mbedtls/library/entropy_poll.c b/thirdparty/mbedtls/library/entropy_poll.c
+index a858c1892b..69ac29e4f7 100644
+--- a/thirdparty/mbedtls/library/entropy_poll.c
++++ b/thirdparty/mbedtls/library/entropy_poll.c
+@@ -54,28 +54,43 @@
#define _WIN32_WINNT 0x0400
#endif
#include <windows.h>
@@ -53,12 +53,12 @@ index 4556f88a5..ba56b70f7 100644
*olen = len;
return( 0 );
-diff --git a/library/x509_crt.c b/library/x509_crt.c
-index 76558342e..35a134950 100644
---- a/library/x509_crt.c
-+++ b/library/x509_crt.c
-@@ -65,6 +65,19 @@
-
+diff --git a/thirdparty/mbedtls/library/x509_crt.c b/thirdparty/mbedtls/library/x509_crt.c
+index def1414eca..4361f43ed0 100644
+--- a/thirdparty/mbedtls/library/x509_crt.c
++++ b/thirdparty/mbedtls/library/x509_crt.c
+@@ -58,6 +58,19 @@
+ #if defined(MBEDTLS_HAVE_TIME)
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
#include <windows.h>
+#if defined(_MSC_VER) && _MSC_VER <= 1600
@@ -77,7 +77,7 @@ index 76558342e..35a134950 100644
#else
#include <time.h>
#endif
-@@ -1278,6 +1291,7 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path )
+@@ -1549,6 +1562,7 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path )
char filename[MAX_PATH];
char *p;
size_t len = strlen( path );
@@ -85,7 +85,7 @@ index 76558342e..35a134950 100644
WIN32_FIND_DATAW file_data;
HANDLE hFind;
-@@ -1292,7 +1306,18 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path )
+@@ -1563,7 +1577,18 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path )
p = filename + len;
filename[len++] = '*';
@@ -105,7 +105,7 @@ index 76558342e..35a134950 100644
MAX_PATH - 3 );
if( w_ret == 0 )
return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
-@@ -1309,8 +1334,11 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path )
+@@ -1580,8 +1605,11 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path )
if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
continue;
diff --git a/thirdparty/mbedtls/patches/windows-arm64-hardclock.diff b/thirdparty/mbedtls/patches/windows-arm64-hardclock.diff
new file mode 100644
index 0000000000..c7c5a7e282
--- /dev/null
+++ b/thirdparty/mbedtls/patches/windows-arm64-hardclock.diff
@@ -0,0 +1,16 @@
+diff --git a/thirdparty/mbedtls/library/timing.c b/thirdparty/mbedtls/library/timing.c
+index 6c14a4fd01..151292e325 100644
+--- a/thirdparty/mbedtls/library/timing.c
++++ b/thirdparty/mbedtls/library/timing.c
+@@ -190,8 +190,10 @@ unsigned long mbedtls_timing_hardclock( void )
+ #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
+ __GNUC__ && __ia64__ */
+
+-#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \
++// -- GODOT start --
++#if !defined(HAVE_HARDCLOCK) && defined(_WIN32) && \
+ !defined(EFIX64) && !defined(EFI32)
++// -- GODOT end --
+
+ #define HAVE_HARDCLOCK
+