summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/CODEOWNERS1
-rw-r--r--SConstruct77
-rw-r--r--core/config/project_settings.cpp24
-rw-r--r--core/config/project_settings.h3
-rw-r--r--core/core_bind.cpp655
-rw-r--r--core/core_bind.h159
-rw-r--r--core/doc_data.h1
-rw-r--r--core/extension/extension_api_dump.cpp9
-rw-r--r--core/extension/gdnative_interface.cpp26
-rw-r--r--core/extension/gdnative_interface.h3
-rw-r--r--core/input/input_event.cpp2
-rw-r--r--core/io/dir_access.cpp162
-rw-r--r--core/io/dir_access.h33
-rw-r--r--core/io/file_access.cpp206
-rw-r--r--core/io/file_access.h32
-rw-r--r--core/io/file_access_compressed.cpp2
-rw-r--r--core/io/file_access_compressed.h2
-rw-r--r--core/io/file_access_encrypted.cpp2
-rw-r--r--core/io/file_access_encrypted.h2
-rw-r--r--core/io/file_access_memory.cpp2
-rw-r--r--core/io/file_access_memory.h2
-rw-r--r--core/io/file_access_network.cpp2
-rw-r--r--core/io/file_access_network.h2
-rw-r--r--core/io/file_access_pack.cpp2
-rw-r--r--core/io/file_access_pack.h2
-rw-r--r--core/io/file_access_zip.cpp2
-rw-r--r--core/io/file_access_zip.h2
-rw-r--r--core/io/image_loader.cpp54
-rw-r--r--core/io/image_loader.h51
-rw-r--r--core/io/json.cpp109
-rw-r--r--core/io/json.h26
-rw-r--r--core/io/resource.cpp2
-rw-r--r--core/io/resource_format_binary.cpp4
-rw-r--r--core/io/stream_peer_gzip.cpp209
-rw-r--r--core/io/stream_peer_gzip.h76
-rw-r--r--core/math/basis.cpp51
-rw-r--r--core/math/bvh_structs.inc4
-rw-r--r--core/math/math_fieldwise.cpp4
-rw-r--r--core/math/math_funcs.h44
-rw-r--r--core/math/vector2i.h2
-rw-r--r--core/math/vector3i.h2
-rw-r--r--core/math/vector4.h2
-rw-r--r--core/math/vector4i.h2
-rw-r--r--core/object/ref_counted.cpp3
-rw-r--r--core/object/ref_counted.h2
-rw-r--r--core/object/undo_redo.cpp160
-rw-r--r--core/object/undo_redo.h34
-rw-r--r--core/os/os.cpp4
-rw-r--r--core/os/os.h9
-rw-r--r--core/os/pool_allocator.cpp8
-rw-r--r--core/register_core_types.cpp23
-rw-r--r--core/string/locales.h2
-rw-r--r--core/variant/array.h2
-rw-r--r--core/variant/callable.cpp15
-rw-r--r--core/variant/callable.h1
-rw-r--r--core/variant/variant.cpp30
-rw-r--r--core/variant/variant.h20
-rw-r--r--core/variant/variant_call.cpp9
-rw-r--r--core/variant/variant_construct.cpp1
-rw-r--r--core/variant/variant_construct.h76
-rw-r--r--core/variant/variant_setget.cpp566
-rw-r--r--doc/class.xsd8
-rw-r--r--doc/classes/AESContext.xml1
-rw-r--r--doc/classes/AStarGrid2D.xml14
-rw-r--r--doc/classes/AnimatedSprite2D.xml11
-rw-r--r--doc/classes/AnimatedSprite3D.xml13
-rw-r--r--doc/classes/AnimationNodeBlendTree.xml8
-rw-r--r--doc/classes/AnimationPlayer.xml5
-rw-r--r--doc/classes/AnimationTree.xml7
-rw-r--r--doc/classes/Array.xml54
-rw-r--r--doc/classes/BaseMaterial3D.xml2
-rw-r--r--doc/classes/BoneAttachment3D.xml10
-rw-r--r--doc/classes/Callable.xml7
-rw-r--r--doc/classes/Camera2D.xml6
-rw-r--r--doc/classes/CanvasItem.xml12
-rw-r--r--doc/classes/Cubemap.xml4
-rw-r--r--doc/classes/CubemapArray.xml5
-rw-r--r--doc/classes/DirAccess.xml (renamed from doc/classes/Directory.xml)129
-rw-r--r--doc/classes/DisplayServer.xml15
-rw-r--r--doc/classes/EditorImportPlugin.xml6
-rw-r--r--doc/classes/EditorInspector.xml8
-rw-r--r--doc/classes/EditorPlugin.xml4
-rw-r--r--doc/classes/EditorProperty.xml7
-rw-r--r--doc/classes/EditorScenePostImport.xml2
-rw-r--r--doc/classes/EditorScript.xml2
-rw-r--r--doc/classes/EditorSettings.xml6
-rw-r--r--doc/classes/EditorTranslationParserPlugin.xml4
-rw-r--r--doc/classes/Engine.xml58
-rw-r--r--doc/classes/Environment.xml19
-rw-r--r--doc/classes/FileAccess.xml (renamed from doc/classes/File.xml)92
-rw-r--r--doc/classes/FogMaterial.xml13
-rw-r--r--doc/classes/FogVolume.xml9
-rw-r--r--doc/classes/Font.xml10
-rw-r--r--doc/classes/Geometry2D.xml9
-rw-r--r--doc/classes/HMACContext.xml18
-rw-r--r--doc/classes/ImageFormatLoader.xml19
-rw-r--r--doc/classes/ImageFormatLoaderExtension.xml42
-rw-r--r--doc/classes/ImageTextureLayered.xml6
-rw-r--r--doc/classes/ImporterMesh.xml2
-rw-r--r--doc/classes/JSON.xml23
-rw-r--r--doc/classes/LightmapGI.xml6
-rw-r--r--doc/classes/MultiMesh.xml22
-rw-r--r--doc/classes/NavigationPathQueryParameters2D.xml42
-rw-r--r--doc/classes/NavigationPathQueryParameters3D.xml42
-rw-r--r--doc/classes/NavigationPathQueryResult2D.xml16
-rw-r--r--doc/classes/NavigationPathQueryResult3D.xml16
-rw-r--r--doc/classes/NavigationRegion2D.xml1
-rw-r--r--doc/classes/NavigationRegion3D.xml1
-rw-r--r--doc/classes/NavigationServer2D.xml8
-rw-r--r--doc/classes/NavigationServer3D.xml8
-rw-r--r--doc/classes/Node.xml24
-rw-r--r--doc/classes/Node3D.xml4
-rw-r--r--doc/classes/OS.xml33
-rw-r--r--doc/classes/PackedByteArray.xml6
-rw-r--r--doc/classes/PackedScene.xml4
-rw-r--r--doc/classes/PanoramaSkyMaterial.xml4
-rw-r--r--doc/classes/PhysicsBody2D.xml4
-rw-r--r--doc/classes/PhysicsBody3D.xml8
-rw-r--r--doc/classes/PhysicsServer2D.xml14
-rw-r--r--doc/classes/PhysicsServer2DExtension.xml14
-rw-r--r--doc/classes/PhysicsServer3D.xml14
-rw-r--r--doc/classes/PhysicsServer3DExtension.xml14
-rw-r--r--doc/classes/PhysicsTestMotionParameters2D.xml4
-rw-r--r--doc/classes/PhysicsTestMotionParameters3D.xml4
-rw-r--r--doc/classes/PlaneMesh.xml4
-rw-r--r--doc/classes/ProjectSettings.xml107
-rw-r--r--doc/classes/QuadMesh.xml17
-rw-r--r--doc/classes/Quaternion.xml2
-rw-r--r--doc/classes/RefCounted.xml6
-rw-r--r--doc/classes/ResourceSaver.xml4
-rw-r--r--doc/classes/ScriptEditorBase.xml19
-rw-r--r--doc/classes/Skeleton3D.xml28
-rw-r--r--doc/classes/SkeletonIK3D.xml37
-rw-r--r--doc/classes/SkeletonModification2D.xml2
-rw-r--r--doc/classes/SkeletonModification2DCCDIK.xml2
-rw-r--r--doc/classes/SkeletonModification2DFABRIK.xml2
-rw-r--r--doc/classes/SkeletonModification2DJiggle.xml2
-rw-r--r--doc/classes/SkeletonModification2DLookAt.xml2
-rw-r--r--doc/classes/SkeletonModification2DPhysicalBones.xml3
-rw-r--r--doc/classes/SkeletonModification2DStackHolder.xml2
-rw-r--r--doc/classes/SkeletonModification2DTwoBoneIK.xml2
-rw-r--r--doc/classes/SkeletonModification3D.xml2
-rw-r--r--doc/classes/SkeletonModification3DCCDIK.xml2
-rw-r--r--doc/classes/SkeletonModification3DFABRIK.xml2
-rw-r--r--doc/classes/SkeletonModification3DJiggle.xml2
-rw-r--r--doc/classes/SkeletonModification3DLookAt.xml2
-rw-r--r--doc/classes/SkeletonModification3DStackHolder.xml2
-rw-r--r--doc/classes/SkeletonModification3DTwoBoneIK.xml2
-rw-r--r--doc/classes/SkeletonModificationStack2D.xml2
-rw-r--r--doc/classes/SkeletonModificationStack3D.xml2
-rw-r--r--doc/classes/StreamPeerBuffer.xml2
-rw-r--r--doc/classes/StreamPeerGZIP.xml42
-rw-r--r--doc/classes/TextServer.xml1
-rw-r--r--doc/classes/Texture2DArray.xml3
-rw-r--r--doc/classes/TextureLayered.xml11
-rw-r--r--doc/classes/Tree.xml3
-rw-r--r--doc/classes/TreeItem.xml15
-rw-r--r--doc/classes/Tween.xml187
-rw-r--r--doc/classes/UndoRedo.xml14
-rw-r--r--doc/classes/Window.xml8
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp18
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp5
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h17
-rw-r--r--drivers/gles3/storage/light_storage.h3
-rw-r--r--drivers/gles3/storage/material_storage.cpp8
-rw-r--r--drivers/png/image_loader_png.cpp2
-rw-r--r--drivers/png/image_loader_png.h2
-rw-r--r--drivers/register_driver_types.cpp9
-rw-r--r--drivers/unix/file_access_unix.cpp2
-rw-r--r--drivers/unix/file_access_unix.h2
-rw-r--r--drivers/unix/os_unix.cpp13
-rw-r--r--drivers/unix/os_unix.h3
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp8
-rw-r--r--drivers/windows/file_access_windows.cpp2
-rw-r--r--drivers/windows/file_access_windows.h2
-rw-r--r--editor/animation_bezier_editor.cpp4
-rw-r--r--editor/animation_track_editor.cpp27
-rw-r--r--editor/animation_track_editor.h10
-rw-r--r--editor/connections_dialog.cpp31
-rw-r--r--editor/connections_dialog.h1
-rw-r--r--editor/doc_tools.cpp28
-rw-r--r--editor/editor_command_palette.cpp2
-rw-r--r--editor/editor_feature_profile.cpp2
-rw-r--r--editor/editor_file_dialog.h4
-rw-r--r--editor/editor_file_system.cpp5
-rw-r--r--editor/editor_file_system.h1
-rw-r--r--editor/editor_fonts.cpp10
-rw-r--r--editor/editor_help_search.cpp5
-rw-r--r--editor/editor_inspector.cpp91
-rw-r--r--editor/editor_inspector.h7
-rw-r--r--editor/editor_node.cpp282
-rw-r--r--editor/editor_node.h44
-rw-r--r--editor/editor_plugin_settings.cpp2
-rw-r--r--editor/editor_properties.cpp8
-rw-r--r--editor/editor_properties_array_dict.cpp26
-rw-r--r--editor/editor_quick_open.cpp21
-rw-r--r--editor/editor_quick_open.h1
-rw-r--r--editor/editor_resource_picker.cpp148
-rw-r--r--editor/editor_resource_picker.h1
-rw-r--r--editor/editor_settings_dialog.cpp58
-rw-r--r--editor/editor_themes.cpp374
-rw-r--r--editor/editor_themes.h11
-rw-r--r--editor/editor_undo_redo_manager.cpp4
-rw-r--r--editor/export/editor_export_platform.cpp2
-rw-r--r--editor/export/project_export.cpp8
-rw-r--r--editor/filesystem_dock.cpp17
-rw-r--r--editor/icons/MemberAnnotation.svg2
-rw-r--r--editor/icons/MethodOverride.svg1
-rw-r--r--editor/icons/MethodOverrideAndSlot.svg1
-rw-r--r--editor/icons/VisualScriptComment.svg1
-rw-r--r--editor/icons/VisualScriptExpression.svg1
-rw-r--r--editor/import/dynamic_font_import_settings.cpp8
-rw-r--r--editor/import/resource_importer_scene.cpp36
-rw-r--r--editor/import/resource_importer_scene.h13
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp55
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h5
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp15
-rw-r--r--editor/plugins/animation_tree_editor_plugin.h1
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp9
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h2
-rw-r--r--editor/plugins/font_config_plugin.cpp10
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp12
-rw-r--r--editor/plugins/node_3d_editor_plugin.h2
-rw-r--r--editor/plugins/script_editor_plugin.cpp76
-rw-r--r--editor/plugins/script_editor_plugin.h4
-rw-r--r--editor/plugins/script_text_editor.cpp121
-rw-r--r--editor/plugins/shader_editor_plugin.cpp8
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp31
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h2
-rw-r--r--editor/plugins/texture_3d_editor_plugin.cpp6
-rw-r--r--editor/plugins/texture_3d_editor_plugin.h2
-rw-r--r--editor/plugins/texture_layered_editor_plugin.cpp6
-rw-r--r--editor/plugins/texture_layered_editor_plugin.h1
-rw-r--r--editor/plugins/theme_editor_plugin.cpp32
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp5
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp2
-rw-r--r--editor/project_converter_3_to_4.cpp106
-rw-r--r--editor/project_converter_3_to_4.h1
-rw-r--r--editor/project_manager.cpp115
-rw-r--r--editor/project_manager.h1
-rw-r--r--editor/scene_create_dialog.cpp2
-rw-r--r--editor/scene_tree_dock.cpp89
-rw-r--r--editor/scene_tree_dock.h7
-rw-r--r--editor/scene_tree_editor.cpp19
-rw-r--r--editor/scene_tree_editor.h4
-rw-r--r--editor/shader_globals_editor.cpp2
-rw-r--r--main/main.cpp241
-rw-r--r--methods.py96
-rw-r--r--misc/dist/html/editor.html35
-rw-r--r--misc/dist/html/full-size.html6
-rw-r--r--misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj1
-rw-r--r--misc/dist/shell/_godot.zsh-completion1
-rw-r--r--misc/dist/shell/godot.bash-completion6
-rw-r--r--misc/dist/shell/godot.fish8
-rwxr-xr-xmisc/hooks/pre-commit-clang-format4
-rw-r--r--modules/bmp/image_loader_bmp.cpp2
-rw-r--r--modules/bmp/image_loader_bmp.h2
-rw-r--r--modules/bmp/register_types.cpp7
-rw-r--r--modules/csg/csg.h1
-rw-r--r--modules/denoise/SCsub2
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml2
-rw-r--r--modules/gdscript/gdscript.cpp2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp86
-rw-r--r--modules/gdscript/gdscript_cache.cpp14
-rw-r--r--modules/gdscript/gdscript_cache.h2
-rw-r--r--modules/gdscript/gdscript_parser.cpp29
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp1
-rw-r--r--modules/gltf/SCsub2
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtension.xml8
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml3
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml8
-rw-r--r--modules/gltf/extensions/SCsub9
-rw-r--r--modules/gltf/gltf_defines.h2
-rw-r--r--modules/gltf/gltf_document.cpp95
-rw-r--r--modules/gltf/gltf_document.h4
-rw-r--r--modules/gltf/gltf_document_extension.cpp7
-rw-r--r--modules/gltf/gltf_document_extension.h2
-rw-r--r--modules/gltf/gltf_state.cpp12
-rw-r--r--modules/gltf/gltf_state.h4
-rw-r--r--modules/hdr/image_loader_hdr.cpp2
-rw-r--r--modules/hdr/image_loader_hdr.h2
-rw-r--r--modules/hdr/register_types.cpp7
-rw-r--r--modules/jpg/image_loader_jpegd.cpp2
-rw-r--r--modules/jpg/image_loader_jpegd.h2
-rw-r--r--modules/jpg/register_types.cpp7
-rwxr-xr-xmodules/mono/build_scripts/build_assemblies.py4
-rw-r--r--modules/mono/csharp_script.cpp8
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs53
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs18
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets7
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs70
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs18
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs125
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs4
-rw-r--r--modules/mono/editor/bindings_generator.cpp43
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs4
-rw-r--r--modules/multiplayer/multiplayer_spawner.cpp32
-rw-r--r--modules/multiplayer/multiplayer_spawner.h2
-rw-r--r--modules/multiplayer/multiplayer_synchronizer.cpp10
-rw-r--r--modules/multiplayer/multiplayer_synchronizer.h2
-rw-r--r--modules/navigation/godot_navigation_server.cpp26
-rw-r--r--modules/navigation/godot_navigation_server.h2
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp3
-rw-r--r--modules/openxr/openxr_api.cpp2
-rw-r--r--modules/raycast/SCsub3
-rw-r--r--modules/svg/image_loader_svg.cpp2
-rw-r--r--modules/svg/image_loader_svg.h2
-rw-r--r--modules/svg/register_types.cpp12
-rw-r--r--modules/text_server_adv/gdextension_build/SConstruct29
-rw-r--r--modules/text_server_adv/text_server_adv.cpp81
-rw-r--r--modules/text_server_adv/text_server_adv.h3
-rw-r--r--modules/text_server_fb/gdextension_build/SConstruct20
-rw-r--r--modules/text_server_fb/text_server_fb.cpp50
-rw-r--r--modules/text_server_fb/text_server_fb.h1
-rw-r--r--modules/tga/image_loader_tga.cpp27
-rw-r--r--modules/tga/image_loader_tga.h4
-rw-r--r--modules/tga/register_types.cpp7
-rw-r--r--modules/tinyexr/image_loader_tinyexr.cpp2
-rw-r--r--modules/tinyexr/image_loader_tinyexr.h2
-rw-r--r--modules/tinyexr/register_types.cpp7
-rw-r--r--modules/webp/image_loader_webp.cpp2
-rw-r--r--modules/webp/image_loader_webp.h2
-rw-r--r--modules/webp/register_types.cpp11
-rw-r--r--modules/websocket/websocket_macros.h50
-rw-r--r--modules/webxr/config.py2
-rw-r--r--modules/webxr/godot_webxr.h3
-rw-r--r--modules/webxr/native/library_godot_webxr.js191
-rw-r--r--modules/webxr/webxr_interface_js.cpp56
-rw-r--r--modules/webxr/webxr_interface_js.h1
-rw-r--r--platform/android/detect.py15
-rw-r--r--platform/android/export/export_plugin.cpp9
-rw-r--r--platform/android/export/gradle_export_util.cpp4
-rw-r--r--platform/android/file_access_android.cpp2
-rw-r--r--platform/android/file_access_android.h2
-rw-r--r--platform/android/file_access_filesystem_jandroid.cpp2
-rw-r--r--platform/android/file_access_filesystem_jandroid.h2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java8
-rw-r--r--platform/android/os_android.cpp74
-rw-r--r--platform/android/os_android.h4
-rw-r--r--platform/ios/detect.py18
-rw-r--r--platform/ios/display_layer.mm10
-rw-r--r--platform/ios/display_server_ios.mm4
-rw-r--r--platform/ios/export/export_plugin.cpp1
-rw-r--r--platform/ios/godot_view.mm2
-rw-r--r--platform/ios/os_ios.h2
-rw-r--r--platform/ios/os_ios.mm9
-rw-r--r--platform/linuxbsd/detect.py4
-rw-r--r--platform/linuxbsd/display_server_x11.cpp26
-rw-r--r--platform/linuxbsd/display_server_x11.h2
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp37
-rw-r--r--platform/linuxbsd/os_linuxbsd.h4
-rw-r--r--platform/macos/SCsub1
-rw-r--r--platform/macos/detect.py13
-rw-r--r--platform/macos/display_server_macos.h14
-rw-r--r--platform/macos/display_server_macos.mm123
-rw-r--r--platform/macos/godot_button_view.h52
-rw-r--r--platform/macos/godot_button_view.mm123
-rw-r--r--platform/macos/godot_content_view.mm18
-rw-r--r--platform/macos/godot_window.h2
-rw-r--r--platform/macos/godot_window.mm13
-rw-r--r--platform/macos/godot_window_delegate.h2
-rw-r--r--platform/macos/godot_window_delegate.mm70
-rw-r--r--platform/macos/os_macos.h2
-rw-r--r--platform/macos/os_macos.mm9
-rw-r--r--platform/uwp/os_uwp.cpp10
-rw-r--r--platform/uwp/os_uwp.h2
-rw-r--r--platform/web/.eslintrc.engine.js1
-rw-r--r--platform/web/SCsub1
-rw-r--r--platform/web/detect.py4
-rw-r--r--platform/web/export/export_plugin.cpp8
-rw-r--r--platform/web/js/engine/engine.js25
-rw-r--r--platform/web/js/engine/features.js96
-rw-r--r--platform/web/package.json2
-rw-r--r--platform/windows/detect.py9
-rw-r--r--platform/windows/display_server_windows.cpp212
-rw-r--r--platform/windows/display_server_windows.h4
-rw-r--r--platform/windows/godot.natvis84
-rw-r--r--platform/windows/os_windows.cpp18
-rw-r--r--platform/windows/os_windows.h2
-rw-r--r--scene/2d/animated_sprite_2d.cpp60
-rw-r--r--scene/2d/animated_sprite_2d.h5
-rw-r--r--scene/2d/camera_2d.cpp18
-rw-r--r--scene/2d/camera_2d.h6
-rw-r--r--scene/2d/canvas_modulate.cpp4
-rw-r--r--scene/2d/canvas_modulate.h2
-rw-r--r--scene/2d/collision_object_2d.cpp4
-rw-r--r--scene/2d/collision_object_2d.h2
-rw-r--r--scene/2d/collision_polygon_2d.cpp4
-rw-r--r--scene/2d/collision_polygon_2d.h2
-rw-r--r--scene/2d/collision_shape_2d.cpp4
-rw-r--r--scene/2d/collision_shape_2d.h2
-rw-r--r--scene/2d/cpu_particles_2d.cpp4
-rw-r--r--scene/2d/cpu_particles_2d.h2
-rw-r--r--scene/2d/gpu_particles_2d.cpp4
-rw-r--r--scene/2d/gpu_particles_2d.h2
-rw-r--r--scene/2d/joint_2d.cpp4
-rw-r--r--scene/2d/joint_2d.h2
-rw-r--r--scene/2d/light_2d.cpp4
-rw-r--r--scene/2d/light_2d.h2
-rw-r--r--scene/2d/light_occluder_2d.cpp4
-rw-r--r--scene/2d/light_occluder_2d.h2
-rw-r--r--scene/2d/navigation_agent_2d.cpp4
-rw-r--r--scene/2d/navigation_agent_2d.h2
-rw-r--r--scene/2d/navigation_link_2d.cpp4
-rw-r--r--scene/2d/navigation_link_2d.h2
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp4
-rw-r--r--scene/2d/navigation_obstacle_2d.h2
-rw-r--r--scene/2d/navigation_region_2d.cpp38
-rw-r--r--scene/2d/navigation_region_2d.h6
-rw-r--r--scene/2d/parallax_background.cpp4
-rw-r--r--scene/2d/parallax_layer.cpp14
-rw-r--r--scene/2d/parallax_layer.h6
-rw-r--r--scene/2d/path_2d.cpp4
-rw-r--r--scene/2d/path_2d.h2
-rw-r--r--scene/2d/physical_bone_2d.cpp4
-rw-r--r--scene/2d/physical_bone_2d.h2
-rw-r--r--scene/2d/physics_body_2d.cpp43
-rw-r--r--scene/2d/physics_body_2d.h6
-rw-r--r--scene/2d/remote_transform_2d.cpp4
-rw-r--r--scene/2d/remote_transform_2d.h2
-rw-r--r--scene/2d/shape_cast_2d.cpp4
-rw-r--r--scene/2d/shape_cast_2d.h2
-rw-r--r--scene/2d/skeleton_2d.cpp4
-rw-r--r--scene/2d/skeleton_2d.h2
-rw-r--r--scene/2d/tile_map.cpp6
-rw-r--r--scene/2d/tile_map.h2
-rw-r--r--scene/3d/bone_attachment_3d.cpp4
-rw-r--r--scene/3d/bone_attachment_3d.h2
-rw-r--r--scene/3d/collision_object_3d.cpp4
-rw-r--r--scene/3d/collision_object_3d.h2
-rw-r--r--scene/3d/collision_polygon_3d.cpp4
-rw-r--r--scene/3d/collision_polygon_3d.h2
-rw-r--r--scene/3d/collision_shape_3d.cpp4
-rw-r--r--scene/3d/collision_shape_3d.h2
-rw-r--r--scene/3d/cpu_particles_3d.cpp4
-rw-r--r--scene/3d/cpu_particles_3d.h2
-rw-r--r--scene/3d/decal.cpp4
-rw-r--r--scene/3d/decal.h2
-rw-r--r--scene/3d/fog_volume.cpp4
-rw-r--r--scene/3d/fog_volume.h2
-rw-r--r--scene/3d/gpu_particles_3d.cpp4
-rw-r--r--scene/3d/gpu_particles_3d.h2
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp4
-rw-r--r--scene/3d/gpu_particles_collision_3d.h2
-rw-r--r--scene/3d/joint_3d.cpp4
-rw-r--r--scene/3d/joint_3d.h2
-rw-r--r--scene/3d/light_3d.cpp8
-rw-r--r--scene/3d/light_3d.h4
-rw-r--r--scene/3d/lightmap_gi.cpp5
-rw-r--r--scene/3d/lightmap_gi.h8
-rw-r--r--scene/3d/navigation_agent_3d.cpp4
-rw-r--r--scene/3d/navigation_agent_3d.h2
-rw-r--r--scene/3d/navigation_link_3d.cpp4
-rw-r--r--scene/3d/navigation_link_3d.h2
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp4
-rw-r--r--scene/3d/navigation_obstacle_3d.h2
-rw-r--r--scene/3d/navigation_region_3d.cpp37
-rw-r--r--scene/3d/navigation_region_3d.h6
-rw-r--r--scene/3d/node_3d.cpp1
-rw-r--r--scene/3d/occluder_instance_3d.cpp4
-rw-r--r--scene/3d/occluder_instance_3d.h2
-rw-r--r--scene/3d/path_3d.cpp4
-rw-r--r--scene/3d/path_3d.h2
-rw-r--r--scene/3d/physics_body_3d.cpp52
-rw-r--r--scene/3d/physics_body_3d.h6
-rw-r--r--scene/3d/remote_transform_3d.cpp4
-rw-r--r--scene/3d/remote_transform_3d.h2
-rw-r--r--scene/3d/shape_cast_3d.cpp4
-rw-r--r--scene/3d/shape_cast_3d.h2
-rw-r--r--scene/3d/skeleton_3d.cpp3
-rw-r--r--scene/3d/skeleton_3d.h4
-rw-r--r--scene/3d/soft_body_3d.cpp4
-rw-r--r--scene/3d/soft_body_3d.h2
-rw-r--r--scene/3d/sprite_3d.cpp549
-rw-r--r--scene/3d/sprite_3d.h15
-rw-r--r--scene/3d/vehicle_body_3d.cpp4
-rw-r--r--scene/3d/vehicle_body_3d.h2
-rw-r--r--scene/3d/visual_instance_3d.cpp4
-rw-r--r--scene/3d/visual_instance_3d.h2
-rw-r--r--scene/3d/voxel_gi.cpp4
-rw-r--r--scene/3d/voxel_gi.h2
-rw-r--r--scene/3d/world_environment.cpp4
-rw-r--r--scene/3d/world_environment.h2
-rw-r--r--scene/3d/xr_nodes.cpp12
-rw-r--r--scene/3d/xr_nodes.h6
-rw-r--r--scene/animation/animation_blend_tree.cpp3
-rw-r--r--scene/animation/animation_player.cpp10
-rw-r--r--scene/animation/animation_tree.cpp62
-rw-r--r--scene/animation/animation_tree.h4
-rw-r--r--scene/animation/tween.cpp272
-rw-r--r--scene/animation/tween.h1
-rw-r--r--scene/gui/base_button.cpp2
-rw-r--r--scene/gui/code_edit.cpp35
-rw-r--r--scene/gui/color_picker.cpp7
-rw-r--r--scene/gui/container.cpp4
-rw-r--r--scene/gui/container.h2
-rw-r--r--scene/gui/control.cpp4
-rw-r--r--scene/gui/control.h2
-rw-r--r--scene/gui/graph_edit.cpp8
-rw-r--r--scene/gui/graph_edit.h2
-rw-r--r--scene/gui/item_list.cpp16
-rw-r--r--scene/gui/menu_bar.cpp2
-rw-r--r--scene/gui/range.cpp4
-rw-r--r--scene/gui/range.h2
-rw-r--r--scene/gui/rich_text_label.cpp127
-rw-r--r--scene/gui/rich_text_label.h18
-rw-r--r--scene/gui/scroll_container.cpp4
-rw-r--r--scene/gui/scroll_container.h2
-rw-r--r--scene/gui/subviewport_container.cpp4
-rw-r--r--scene/gui/subviewport_container.h2
-rw-r--r--scene/gui/tab_container.cpp15
-rw-r--r--scene/gui/text_edit.cpp19
-rw-r--r--scene/gui/tree.cpp78
-rw-r--r--scene/gui/tree.h10
-rw-r--r--scene/main/http_request.cpp125
-rw-r--r--scene/main/http_request.h4
-rw-r--r--scene/main/missing_node.cpp4
-rw-r--r--scene/main/missing_node.h2
-rw-r--r--scene/main/node.cpp12
-rw-r--r--scene/main/node.h2
-rw-r--r--scene/main/shader_globals_override.cpp4
-rw-r--r--scene/main/shader_globals_override.h2
-rw-r--r--scene/main/timer.cpp4
-rw-r--r--scene/main/timer.h2
-rw-r--r--scene/main/viewport.cpp51
-rw-r--r--scene/main/viewport.h4
-rw-r--r--scene/main/window.cpp22
-rw-r--r--scene/main/window.h2
-rw-r--r--scene/register_scene_types.cpp2
-rw-r--r--scene/resources/animation.cpp464
-rw-r--r--scene/resources/animation.h6
-rw-r--r--scene/resources/font.cpp12
-rw-r--r--scene/resources/importer_mesh.cpp41
-rw-r--r--scene/resources/importer_mesh.h2
-rw-r--r--scene/resources/material.cpp79
-rw-r--r--scene/resources/material.h11
-rw-r--r--scene/resources/primitive_meshes.h13
-rw-r--r--scene/resources/shader.h37
-rw-r--r--scene/resources/skeleton_modification_stack_2d.cpp6
-rw-r--r--scene/resources/skeleton_profile.cpp4
-rw-r--r--scene/resources/texture.h9
-rw-r--r--scene/resources/visual_shader.h7
-rw-r--r--servers/SCsub1
-rw-r--r--servers/display_server.cpp2
-rw-r--r--servers/display_server.h4
-rw-r--r--servers/extensions/physics_server_2d_extension.cpp5
-rw-r--r--servers/extensions/physics_server_2d_extension.h20
-rw-r--r--servers/extensions/physics_server_3d_extension.cpp5
-rw-r--r--servers/extensions/physics_server_3d_extension.h19
-rw-r--r--servers/navigation/SCsub5
-rw-r--r--servers/navigation/navigation_path_query_parameters_2d.cpp144
-rw-r--r--servers/navigation/navigation_path_query_parameters_2d.h79
-rw-r--r--servers/navigation/navigation_path_query_parameters_3d.cpp144
-rw-r--r--servers/navigation/navigation_path_query_parameters_3d.h79
-rw-r--r--servers/navigation/navigation_path_query_result_2d.cpp46
-rw-r--r--servers/navigation/navigation_path_query_result_2d.h50
-rw-r--r--servers/navigation/navigation_path_query_result_3d.cpp46
-rw-r--r--servers/navigation/navigation_path_query_result_3d.h50
-rw-r--r--servers/navigation/navigation_utilities.h62
-rw-r--r--servers/navigation_server_2d.cpp11
-rw-r--r--servers/navigation_server_2d.h5
-rw-r--r--servers/navigation_server_3d.cpp13
-rw-r--r--servers/navigation_server_3d.h9
-rw-r--r--servers/physics_2d/godot_body_2d.cpp17
-rw-r--r--servers/physics_2d/godot_body_2d.h5
-rw-r--r--servers/physics_2d/godot_collision_solver_2d.cpp11
-rw-r--r--servers/physics_2d/godot_collision_solver_2d.h2
-rw-r--r--servers/physics_2d/godot_physics_server_2d.cpp24
-rw-r--r--servers/physics_2d/godot_physics_server_2d.h8
-rw-r--r--servers/physics_3d/godot_body_3d.cpp17
-rw-r--r--servers/physics_3d/godot_body_3d.h5
-rw-r--r--servers/physics_3d/godot_collision_solver_3d.cpp7
-rw-r--r--servers/physics_3d/godot_physics_server_3d.cpp18
-rw-r--r--servers/physics_3d/godot_physics_server_3d.h7
-rw-r--r--servers/physics_server_2d.cpp3
-rw-r--r--servers/physics_server_2d.h12
-rw-r--r--servers/physics_server_2d_wrap_mt.h7
-rw-r--r--servers/physics_server_3d.cpp3
-rw-r--r--servers/physics_server_3d.h12
-rw-r--r--servers/physics_server_3d_wrap_mt.h7
-rw-r--r--servers/register_server_types.cpp7
-rw-r--r--servers/rendering/dummy/rasterizer_scene_dummy.h2
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp2
-rw-r--r--servers/rendering/renderer_compositor.h2
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp1
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp654
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h94
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h2
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp324
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h86
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h2
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp21
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp11
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp129
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h45
-rw-r--r--servers/rendering/renderer_rd/shaders/SCsub2
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/SCsub2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl5
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl9
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/SCsub2
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/SCsub17
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl (renamed from servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl)60
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl (renamed from servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl)143
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/SCsub17
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl (renamed from servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl)8
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl (renamed from servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl)73
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_data_inc.glsl69
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.h3
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp209
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.h11
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp246
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h157
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp2
-rw-r--r--servers/rendering/renderer_scene_cull.cpp2
-rw-r--r--servers/rendering/renderer_scene_cull.h6
-rw-r--r--servers/rendering/renderer_scene_render.h4
-rw-r--r--servers/rendering/renderer_viewport.cpp77
-rw-r--r--servers/rendering/renderer_viewport.h9
-rw-r--r--servers/rendering/rendering_method.cpp (renamed from servers/rendering/renderer_scene.cpp)8
-rw-r--r--servers/rendering/rendering_method.h (renamed from servers/rendering/renderer_scene.h)14
-rw-r--r--servers/rendering/rendering_server_default.h6
-rw-r--r--servers/rendering/rendering_server_globals.cpp2
-rw-r--r--servers/rendering/rendering_server_globals.h6
-rw-r--r--servers/rendering/shader_types.cpp6
-rw-r--r--servers/rendering_server.cpp38
-rw-r--r--servers/text/text_server_extension.cpp4
-rw-r--r--servers/text/text_server_extension.h4
-rw-r--r--servers/text_server.h2
-rw-r--r--tests/core/math/test_basis.h57
-rw-r--r--tests/core/math/test_vector2.h83
-rw-r--r--tests/core/math/test_vector2i.h16
-rw-r--r--tests/core/math/test_vector3.h73
-rw-r--r--tests/core/math/test_vector3i.h8
-rw-r--r--tests/core/math/test_vector4.h8
-rw-r--r--tests/core/math/test_vector4i.h8
-rw-r--r--thirdparty/README.md4
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh3
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh50
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh3
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh6
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh10
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh6
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh15
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh6
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh6
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh107
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh10
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh27
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh7
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh1
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh15
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh118
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/Glyph.hh127
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh126
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh14
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/glyf.hh42
-rw-r--r--thirdparty/harfbuzz/src/graph/classdef-graph.hh216
-rw-r--r--thirdparty/harfbuzz/src/graph/coverage-graph.hh72
-rw-r--r--thirdparty/harfbuzz/src/graph/graph.hh201
-rw-r--r--thirdparty/harfbuzz/src/graph/gsubgpos-context.cc5
-rw-r--r--thirdparty/harfbuzz/src/graph/gsubgpos-context.hh10
-rw-r--r--thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh120
-rw-r--r--thirdparty/harfbuzz/src/graph/markbasepos-graph.hh507
-rw-r--r--thirdparty/harfbuzz/src/graph/pairpos-graph.hh527
-rw-r--r--thirdparty/harfbuzz/src/graph/split-helpers.hh69
-rw-r--r--thirdparty/harfbuzz/src/graph/test-classdef-graph.cc119
-rw-r--r--thirdparty/harfbuzz/src/hb-array.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-atomic.hh13
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-set.hh22
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh10
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-cache.hh28
-rw-r--r--thirdparty/harfbuzz/src/hb-common.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-common.h8
-rw-r--r--thirdparty/harfbuzz/src/hb-config.hh3
-rw-r--r--thirdparty/harfbuzz/src/hb-debug.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-face.cc6
-rw-r--r--thirdparty/harfbuzz/src/hb-face.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ft.cc101
-rw-r--r--thirdparty/harfbuzz/src/hb-machinery.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-object.hh31
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff1-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-font.cc16
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh45
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-common.hh124
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh46
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh3
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.cc50
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-os2-table.hh61
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-post-table.hh12
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh14
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc18
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh14
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh14
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh1233
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh240
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-tag.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh5
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-mvar-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-repacker.hh64
-rw-r--r--thirdparty/harfbuzz/src/hb-serialize.hh10
-rw-r--r--thirdparty/harfbuzz/src/hb-static.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-input.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.cc203
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.hh61
-rw-r--r--thirdparty/harfbuzz/src/hb-subset.cc40
-rw-r--r--thirdparty/harfbuzz/src/hb-ucd-table.hh5381
-rw-r--r--thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh12
-rw-r--r--thirdparty/harfbuzz/src/hb-version.h4
-rw-r--r--thirdparty/libpng/LICENSE4
-rw-r--r--thirdparty/libpng/arm/arm_init.c28
-rw-r--r--thirdparty/libpng/arm/filter_neon_intrinsics.c2
-rw-r--r--thirdparty/libpng/arm/palette_neon_intrinsics.c14
-rw-r--r--thirdparty/libpng/png.c14
-rw-r--r--thirdparty/libpng/png.h121
-rw-r--r--thirdparty/libpng/pngconf.h8
-rw-r--r--thirdparty/libpng/pngget.c176
-rw-r--r--thirdparty/libpng/pnginfo.h13
-rw-r--r--thirdparty/libpng/pnglibconf.h4
-rw-r--r--thirdparty/libpng/pngpread.c199
-rw-r--r--thirdparty/libpng/pngpriv.h120
-rw-r--r--thirdparty/libpng/pngread.c83
-rw-r--r--thirdparty/libpng/pngrtran.c2
-rw-r--r--thirdparty/libpng/pngrutil.c326
-rw-r--r--thirdparty/libpng/pngset.c159
-rw-r--r--thirdparty/libpng/pngstruct.h33
-rw-r--r--thirdparty/libpng/pngwrite.c58
-rw-r--r--thirdparty/libpng/pngwutil.c139
-rw-r--r--version.py2
748 files changed, 16656 insertions, 11625 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index e7e88e95d7..bd4eb906c0 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -114,7 +114,6 @@ doc_classes/* @godotengine/documentation
/modules/gdscript/ @godotengine/gdscript
/modules/jsonrpc/ @godotengine/gdscript
/modules/mono/ @godotengine/mono
-/modules/visual_script/ @godotengine/visualscript
## Text
/modules/freetype/ @godotengine/buildsystem
diff --git a/SConstruct b/SConstruct
index f7504f72e1..b64e0bddd8 100644
--- a/SConstruct
+++ b/SConstruct
@@ -170,7 +170,7 @@ opts.Add(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectur
opts.Add(EnumVariable("float", "Floating-point precision", "32", ("32", "64")))
opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size", "none")))
opts.Add(BoolVariable("production", "Set defaults to build Godot for use in production", False))
-opts.Add(EnumVariable("lto", "Link-time optimization (for production buids)", "none", ("none", "thin", "full")))
+opts.Add(EnumVariable("lto", "Link-time optimization (for production buids)", "none", ("none", "auto", "thin", "full")))
# Components
opts.Add(BoolVariable("deprecated", "Enable compatibility code for deprecated and removed features", True))
@@ -386,6 +386,9 @@ if env_base["target"] == "debug":
# DEV_ENABLED enables *engine developer* code which should only be compiled for those
# working on the engine itself.
env_base.Append(CPPDEFINES=["DEV_ENABLED"])
+else:
+ # Disable assert() for production targets (only used in thirdparty code).
+ env_base.Append(CPPDEFINES=["NDEBUG"])
# SCons speed optimization controlled by the `fast_unsafe` option, which provide
# more than 10 s speed up for incremental rebuilds.
@@ -460,36 +463,17 @@ if selected_platform in platform_list:
env["LINKFLAGS"] = ""
env.Append(LINKFLAGS=str(LINKFLAGS).split())
- # Platform specific flags
+ # Platform specific flags.
+ # These can sometimes override default options.
flag_list = platform_flags[selected_platform]
for f in flag_list:
if not (f[0] in ARGUMENTS) or ARGUMENTS[f[0]] == "auto": # Allow command line to override platform flags
env[f[0]] = f[1]
- # Must happen after the flags' definition, so that they can be used by platform detect
- detect.configure(env)
-
- print(
- 'Building for platform "%s", architecture "%s", %s, target "%s".'
- % (selected_platform, env["arch"], "editor" if env["tools"] else "template", env["target"])
- )
-
- # Set our C and C++ standard requirements.
- # C++17 is required as we need guaranteed copy elision as per GH-36436.
- # Prepending to make it possible to override.
- # This needs to come after `configure`, otherwise we don't have env.msvc.
- if not env.msvc:
- # Specifying GNU extensions support explicitly, which are supported by
- # both GCC and Clang. Both currently default to gnu11 and gnu++14.
- env.Prepend(CFLAGS=["-std=gnu11"])
- env.Prepend(CXXFLAGS=["-std=gnu++17"])
- else:
- # MSVC doesn't have clear C standard support, /std only covers C++.
- # We apply it to CCFLAGS (both C and C++ code) in case it impacts C features.
- env.Prepend(CCFLAGS=["/std:c++17"])
-
- # 'dev' and 'production' are aliases to set default options if they haven't been set
- # manually by the user.
+ # 'dev' and 'production' are aliases to set default options if they haven't been
+ # set manually by the user.
+ # These need to be checked *after* platform specific flags so that different
+ # default values can be set (e.g. to keep LTO off for `production` on some platforms).
if env["dev"]:
env["verbose"] = methods.get_cmdline_bool("verbose", True)
env["warnings"] = ARGUMENTS.get("warnings", "extra")
@@ -498,27 +482,43 @@ if selected_platform in platform_list:
env["tests"] = methods.get_cmdline_bool("tests", True)
if env["production"]:
env["use_static_cpp"] = methods.get_cmdline_bool("use_static_cpp", True)
- env["lto"] = ARGUMENTS.get("lto", "full")
env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", False)
+ # LTO "auto" means we handle the preferred option in each platform detect.py.
+ env["lto"] = ARGUMENTS.get("lto", "auto")
if not env["tools"] and env["target"] == "debug":
print(
"WARNING: Requested `production` build with `tools=no target=debug`, "
"this will give you a full debug template (use `target=release_debug` "
"for an optimized template with debug features)."
)
- if env.msvc:
- print(
- "WARNING: For `production` Windows builds, you should use MinGW with GCC "
- "or Clang instead of Visual Studio, as they can better optimize the "
- "GDScript VM in a very significant way. MSVC LTO also doesn't work "
- "reliably for our use case."
- "If you want to use MSVC nevertheless for production builds, set "
- "`debug_symbols=no lto=none` instead of the `production=yes` option."
- )
- Exit(255)
+
+ # Must happen after the flags' definition, as configure is when most flags
+ # are actually handled to change compile options, etc.
+ detect.configure(env)
+
+ # Needs to happen after configure to handle "auto".
if env["lto"] != "none":
print("Using LTO: " + env["lto"])
+ # Set our C and C++ standard requirements.
+ # C++17 is required as we need guaranteed copy elision as per GH-36436.
+ # Prepending to make it possible to override.
+ # This needs to come after `configure`, otherwise we don't have env.msvc.
+ if not env.msvc:
+ # Specifying GNU extensions support explicitly, which are supported by
+ # both GCC and Clang. Both currently default to gnu11 and gnu++14.
+ env.Prepend(CFLAGS=["-std=gnu11"])
+ env.Prepend(CXXFLAGS=["-std=gnu++17"])
+ else:
+ # MSVC doesn't have clear C standard support, /std only covers C++.
+ # We apply it to CCFLAGS (both C and C++ code) in case it impacts C features.
+ env.Prepend(CCFLAGS=["/std:c++17"])
+
+ print(
+ 'Building for platform "%s", architecture "%s", %s, target "%s".'
+ % (selected_platform, env["arch"], "editor" if env["tools"] else "template", env["target"])
+ )
+
# Enforce our minimal compiler version requirements
cc_version = methods.get_compiler_version(env) or {
"major": None,
@@ -672,7 +672,6 @@ if selected_platform in platform_list:
print(" Use `tools=no target=release` to build a release export template.")
Exit(255)
suffix += ".opt"
- env.Append(CPPDEFINES=["NDEBUG"])
elif env["target"] == "release_debug":
if env["tools"]:
suffix += ".opt.tools"
@@ -737,7 +736,7 @@ if selected_platform in platform_list:
env.module_list = modules_enabled
methods.sort_module_list(env)
- methods.update_version(env.module_version_string)
+ methods.generate_version_header(env.module_version_string)
env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"]
env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"]
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 6275502378..a1b22e7f7d 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -101,10 +101,15 @@ const PackedStringArray ProjectSettings::_get_supported_features() {
features.append(VERSION_BRANCH "." _MKSTR(VERSION_PATCH));
features.append(VERSION_FULL_CONFIG);
features.append(VERSION_FULL_BUILD);
- // For now, assume Vulkan is always supported.
- // This should be removed if it's possible to build the editor without Vulkan.
- features.append("Vulkan Clustered");
- features.append("Vulkan Mobile");
+
+#ifdef VULKAN_ENABLED
+ features.append("Forward Plus");
+ features.append("Mobile");
+#endif
+
+#ifdef GLES3_ENABLED
+ features.append("GL Compatibility");
+#endif
return features;
}
@@ -909,7 +914,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
project_features = ProjectSettings::get_required_features();
}
// Check the rendering API.
- const String rendering_api = has_setting("rendering/quality/driver/driver_name") ? (String)get_setting("rendering/quality/driver/driver_name") : String();
+ const String rendering_api = has_setting("rendering/renderer/rendering_method") ? (String)get_setting("rendering/renderer/rendering_method") : String();
if (!rendering_api.is_empty()) {
// Add the rendering API as a project feature if it doesn't already exist.
if (!project_features.has(rendering_api)) {
@@ -1139,6 +1144,7 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order);
ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value);
ClassDB::bind_method(D_METHOD("add_property_info", "hint"), &ProjectSettings::_add_property_info_bind);
+ ClassDB::bind_method(D_METHOD("set_restart_if_changed", "name", "restart"), &ProjectSettings::set_restart_if_changed);
ClassDB::bind_method(D_METHOD("clear", "name"), &ProjectSettings::clear);
ClassDB::bind_method(D_METHOD("localize_path", "path"), &ProjectSettings::localize_path);
ClassDB::bind_method(D_METHOD("globalize_path", "path"), &ProjectSettings::globalize_path);
@@ -1201,10 +1207,16 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC("display/window/size/viewport_height", 648);
custom_prop_info["display/window/size/viewport_height"] = PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
+ GLOBAL_DEF_BASIC("display/window/size/mode", 0);
+ custom_prop_info["display/window/size/mode"] = PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen");
+
GLOBAL_DEF_BASIC("display/window/size/resizable", true);
GLOBAL_DEF_BASIC("display/window/size/borderless", false);
- GLOBAL_DEF_BASIC("display/window/size/fullscreen", false);
GLOBAL_DEF("display/window/size/always_on_top", false);
+ GLOBAL_DEF("display/window/size/transparent", false);
+ GLOBAL_DEF("display/window/size/extend_to_title", false);
+ GLOBAL_DEF("display/window/size/no_focus", false);
+
GLOBAL_DEF("display/window/size/window_width_override", 0);
custom_prop_info["display/window/size/window_width_override"] = PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution
GLOBAL_DEF("display/window/size/window_height_override", 0);
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index a9af63ee39..960dfe0395 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -45,9 +45,10 @@ public:
static const String PROJECT_DATA_DIR_NAME_SUFFIX;
enum {
- //properties that are not for built in values begin from this value, so builtin ones are displayed first
+ // Properties that are not for built in values begin from this value, so builtin ones are displayed first.
NO_BUILTIN_ORDER_BASE = 1 << 16
};
+
#ifdef TOOLS_ENABLED
const static PackedStringArray get_required_features();
const static PackedStringArray get_unsupported_features(const PackedStringArray &p_project_features);
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 9daf58cb71..a164221fc2 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -322,6 +322,14 @@ String OS::get_name() const {
return ::OS::get_singleton()->get_name();
}
+String OS::get_distribution_name() const {
+ return ::OS::get_singleton()->get_distribution_name();
+}
+
+String OS::get_version() const {
+ return ::OS::get_singleton()->get_version();
+}
+
Vector<String> OS::get_cmdline_args() {
List<String> cmdline = ::OS::get_singleton()->get_cmdline_args();
Vector<String> cmdlinev;
@@ -535,6 +543,8 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_environment", "variable"), &OS::has_environment);
ClassDB::bind_method(D_METHOD("get_name"), &OS::get_name);
+ ClassDB::bind_method(D_METHOD("get_distribution_name"), &OS::get_distribution_name);
+ ClassDB::bind_method(D_METHOD("get_version"), &OS::get_version);
ClassDB::bind_method(D_METHOD("get_cmdline_args"), &OS::get_cmdline_args);
ClassDB::bind_method(D_METHOD("get_cmdline_user_args"), &OS::get_cmdline_user_args);
@@ -699,6 +709,17 @@ Vector<Point2> Geometry2D::convex_hull(const Vector<Point2> &p_points) {
return ::Geometry2D::convex_hull(p_points);
}
+TypedArray<PackedVector2Array> Geometry2D::decompose_polygon_in_convex(const Vector<Vector2> &p_polygon) {
+ Vector<Vector<Point2>> decomp = ::Geometry2D::decompose_polygon_in_convex(p_polygon);
+
+ TypedArray<PackedVector2Array> ret;
+
+ for (int i = 0; i < decomp.size(); ++i) {
+ ret.push_back(decomp[i]);
+ }
+ return ret;
+}
+
TypedArray<PackedVector2Array> Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
Vector<Vector<Point2>> polys = ::Geometry2D::merge_polygons(p_polygon_a, p_polygon_b);
@@ -800,14 +821,13 @@ Dictionary Geometry2D::make_atlas(const Vector<Size2> &p_rects) {
::Geometry2D::make_atlas(rects, result, size);
- Size2 r_size = size;
Vector<Point2> r_result;
for (int i = 0; i < result.size(); i++) {
r_result.push_back(result[i]);
}
ret["points"] = r_result;
- ret["size"] = r_size;
+ ret["size"] = size;
return ret;
}
@@ -831,6 +851,7 @@ void Geometry2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("triangulate_polygon", "polygon"), &Geometry2D::triangulate_polygon);
ClassDB::bind_method(D_METHOD("triangulate_delaunay", "points"), &Geometry2D::triangulate_delaunay);
ClassDB::bind_method(D_METHOD("convex_hull", "points"), &Geometry2D::convex_hull);
+ ClassDB::bind_method(D_METHOD("decompose_polygon_in_convex", "polygon"), &Geometry2D::decompose_polygon_in_convex);
ClassDB::bind_method(D_METHOD("merge_polygons", "polygon_a", "polygon_b"), &Geometry2D::merge_polygons);
ClassDB::bind_method(D_METHOD("clip_polygons", "polygon_a", "polygon_b"), &Geometry2D::clip_polygons);
@@ -982,636 +1003,6 @@ void Geometry3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &Geometry3D::clip_polygon);
}
-////// File //////
-
-Error File::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
- Error err = open(p_path, p_mode_flags);
- if (err) {
- return err;
- }
-
- Ref<FileAccessEncrypted> fae;
- fae.instantiate();
- err = fae->open_and_parse(f, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
- if (err) {
- close();
- return err;
- }
- f = fae;
- return OK;
-}
-
-Error File::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) {
- Error err = open(p_path, p_mode_flags);
- if (err) {
- return err;
- }
-
- Ref<FileAccessEncrypted> fae;
- fae.instantiate();
- err = fae->open_and_parse_password(f, p_pass, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
- if (err) {
- close();
- return err;
- }
-
- f = fae;
- return OK;
-}
-
-Error File::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) {
- Ref<FileAccessCompressed> fac;
- fac.instantiate();
- fac->configure("GCPF", (Compression::Mode)p_compress_mode);
-
- Error err = fac->_open(p_path, p_mode_flags);
-
- if (err) {
- return err;
- }
-
- f = fac;
- return OK;
-}
-
-Error File::open(const String &p_path, ModeFlags p_mode_flags) {
- Error err;
- f = FileAccess::open(p_path, p_mode_flags, &err);
- if (f.is_valid()) {
- f->set_big_endian(big_endian);
- }
- return err;
-}
-
-void File::flush() {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before flushing.");
- f->flush();
-}
-
-void File::close() {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened.");
- f.unref();
-}
-
-bool File::is_open() const {
- return f != nullptr;
-}
-
-String File::get_path() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission.");
- return f->get_path();
-}
-
-String File::get_path_absolute() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission.");
- return f->get_path_absolute();
-}
-
-void File::seek(int64_t p_position) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
- ERR_FAIL_COND_MSG(p_position < 0, "Seek position must be a positive integer.");
- f->seek(p_position);
-}
-
-void File::seek_end(int64_t p_position) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
- f->seek_end(p_position);
-}
-
-uint64_t File::get_position() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_position();
-}
-
-uint64_t File::get_length() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_length();
-}
-
-bool File::eof_reached() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), false, "File must be opened before use, or is lacking read-write permission.");
- return f->eof_reached();
-}
-
-uint8_t File::get_8() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_8();
-}
-
-uint16_t File::get_16() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_16();
-}
-
-uint32_t File::get_32() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_32();
-}
-
-uint64_t File::get_64() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_64();
-}
-
-float File::get_float() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_float();
-}
-
-double File::get_double() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_double();
-}
-
-real_t File::get_real() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_real();
-}
-
-Vector<uint8_t> File::get_buffer(int64_t p_length) const {
- Vector<uint8_t> data;
- ERR_FAIL_COND_V_MSG(f.is_null(), data, "File must be opened before use, or is lacking read-write permission.");
-
- ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0.");
- if (p_length == 0) {
- return data;
- }
-
- Error err = data.resize(p_length);
- ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements.");
-
- uint8_t *w = data.ptrw();
- int64_t len = f->get_buffer(&w[0], p_length);
-
- if (len < p_length) {
- data.resize(len);
- }
-
- return data;
-}
-
-String File::get_as_text(bool p_skip_cr) const {
- ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission.");
-
- uint64_t original_pos = f->get_position();
- const_cast<FileAccess *>(*f)->seek(0);
-
- String text = f->get_as_utf8_string(p_skip_cr);
-
- const_cast<FileAccess *>(*f)->seek(original_pos);
-
- return text;
-}
-
-String File::get_md5(const String &p_path) const {
- return FileAccess::get_md5(p_path);
-}
-
-String File::get_sha256(const String &p_path) const {
- return FileAccess::get_sha256(p_path);
-}
-
-String File::get_line() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission.");
- return f->get_line();
-}
-
-Vector<String> File::get_csv_line(const String &p_delim) const {
- ERR_FAIL_COND_V_MSG(f.is_null(), Vector<String>(), "File must be opened before use, or is lacking read-write permission.");
- return f->get_csv_line(p_delim);
-}
-
-/**< use this for files WRITTEN in _big_ endian machines (i.e. amiga/mac)
- * It's not about the current CPU type but file formats.
- * These flags get reset to false (little endian) on each open
- */
-
-void File::set_big_endian(bool p_big_endian) {
- big_endian = p_big_endian;
- if (f.is_valid()) {
- f->set_big_endian(p_big_endian);
- }
-}
-
-bool File::is_big_endian() {
- return big_endian;
-}
-
-Error File::get_error() const {
- if (f.is_null()) {
- return ERR_UNCONFIGURED;
- }
- return f->get_error();
-}
-
-void File::store_8(uint8_t p_dest) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_8(p_dest);
-}
-
-void File::store_16(uint16_t p_dest) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_16(p_dest);
-}
-
-void File::store_32(uint32_t p_dest) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_32(p_dest);
-}
-
-void File::store_64(uint64_t p_dest) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_64(p_dest);
-}
-
-void File::store_float(float p_dest) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_float(p_dest);
-}
-
-void File::store_double(double p_dest) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_double(p_dest);
-}
-
-void File::store_real(real_t p_real) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_real(p_real);
-}
-
-void File::store_string(const String &p_string) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_string(p_string);
-}
-
-void File::store_pascal_string(const String &p_string) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_pascal_string(p_string);
-}
-
-String File::get_pascal_string() {
- ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission.");
-
- return f->get_pascal_string();
-}
-
-void File::store_line(const String &p_string) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
- f->store_line(p_string);
-}
-
-void File::store_csv_line(const Vector<String> &p_values, const String &p_delim) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
- f->store_csv_line(p_values, p_delim);
-}
-
-void File::store_buffer(const Vector<uint8_t> &p_buffer) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- uint64_t len = p_buffer.size();
- if (len == 0) {
- return;
- }
-
- const uint8_t *r = p_buffer.ptr();
-
- f->store_buffer(&r[0], len);
-}
-
-bool File::file_exists(const String &p_name) {
- return FileAccess::exists(p_name);
-}
-
-void File::store_var(const Variant &p_var, bool p_full_objects) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
- int len;
- Error err = encode_variant(p_var, nullptr, len, p_full_objects);
- ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
-
- Vector<uint8_t> buff;
- buff.resize(len);
-
- uint8_t *w = buff.ptrw();
- err = encode_variant(p_var, &w[0], len, p_full_objects);
- ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
-
- store_32(len);
- store_buffer(buff);
-}
-
-Variant File::get_var(bool p_allow_objects) const {
- ERR_FAIL_COND_V_MSG(f.is_null(), Variant(), "File must be opened before use, or is lacking read-write permission.");
- uint32_t len = get_32();
- Vector<uint8_t> buff = get_buffer(len);
- ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant());
-
- const uint8_t *r = buff.ptr();
-
- Variant v;
- Error err = decode_variant(v, &r[0], len, nullptr, p_allow_objects);
- ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to encode Variant.");
-
- return v;
-}
-
-uint64_t File::get_modified_time(const String &p_file) const {
- return FileAccess::get_modified_time(p_file);
-}
-
-void File::_bind_methods() {
- ClassDB::bind_method(D_METHOD("open_encrypted", "path", "mode_flags", "key"), &File::open_encrypted);
- ClassDB::bind_method(D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &File::open_encrypted_pass);
- ClassDB::bind_method(D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &File::open_compressed, DEFVAL(0));
-
- ClassDB::bind_method(D_METHOD("open", "path", "flags"), &File::open);
- ClassDB::bind_method(D_METHOD("flush"), &File::flush);
- ClassDB::bind_method(D_METHOD("close"), &File::close);
- ClassDB::bind_method(D_METHOD("get_path"), &File::get_path);
- ClassDB::bind_method(D_METHOD("get_path_absolute"), &File::get_path_absolute);
- ClassDB::bind_method(D_METHOD("is_open"), &File::is_open);
- ClassDB::bind_method(D_METHOD("seek", "position"), &File::seek);
- ClassDB::bind_method(D_METHOD("seek_end", "position"), &File::seek_end, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("get_position"), &File::get_position);
- ClassDB::bind_method(D_METHOD("get_length"), &File::get_length);
- ClassDB::bind_method(D_METHOD("eof_reached"), &File::eof_reached);
- ClassDB::bind_method(D_METHOD("get_8"), &File::get_8);
- ClassDB::bind_method(D_METHOD("get_16"), &File::get_16);
- ClassDB::bind_method(D_METHOD("get_32"), &File::get_32);
- ClassDB::bind_method(D_METHOD("get_64"), &File::get_64);
- ClassDB::bind_method(D_METHOD("get_float"), &File::get_float);
- ClassDB::bind_method(D_METHOD("get_double"), &File::get_double);
- ClassDB::bind_method(D_METHOD("get_real"), &File::get_real);
- ClassDB::bind_method(D_METHOD("get_buffer", "length"), &File::get_buffer);
- ClassDB::bind_method(D_METHOD("get_line"), &File::get_line);
- ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &File::get_csv_line, DEFVAL(","));
- ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &File::get_as_text, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_md5", "path"), &File::get_md5);
- ClassDB::bind_method(D_METHOD("get_sha256", "path"), &File::get_sha256);
- ClassDB::bind_method(D_METHOD("is_big_endian"), &File::is_big_endian);
- ClassDB::bind_method(D_METHOD("set_big_endian", "big_endian"), &File::set_big_endian);
- ClassDB::bind_method(D_METHOD("get_error"), &File::get_error);
- ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &File::get_var, DEFVAL(false));
-
- ClassDB::bind_method(D_METHOD("store_8", "value"), &File::store_8);
- ClassDB::bind_method(D_METHOD("store_16", "value"), &File::store_16);
- ClassDB::bind_method(D_METHOD("store_32", "value"), &File::store_32);
- ClassDB::bind_method(D_METHOD("store_64", "value"), &File::store_64);
- ClassDB::bind_method(D_METHOD("store_float", "value"), &File::store_float);
- ClassDB::bind_method(D_METHOD("store_double", "value"), &File::store_double);
- ClassDB::bind_method(D_METHOD("store_real", "value"), &File::store_real);
- ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &File::store_buffer);
- ClassDB::bind_method(D_METHOD("store_line", "line"), &File::store_line);
- ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &File::store_csv_line, DEFVAL(","));
- ClassDB::bind_method(D_METHOD("store_string", "string"), &File::store_string);
- ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &File::store_var, DEFVAL(false));
-
- ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &File::store_pascal_string);
- ClassDB::bind_method(D_METHOD("get_pascal_string"), &File::get_pascal_string);
-
- ClassDB::bind_static_method("File", D_METHOD("file_exists", "path"), &File::file_exists);
- ClassDB::bind_method(D_METHOD("get_modified_time", "file"), &File::get_modified_time);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian");
-
- BIND_ENUM_CONSTANT(READ);
- BIND_ENUM_CONSTANT(WRITE);
- BIND_ENUM_CONSTANT(READ_WRITE);
- BIND_ENUM_CONSTANT(WRITE_READ);
-
- BIND_ENUM_CONSTANT(COMPRESSION_FASTLZ);
- BIND_ENUM_CONSTANT(COMPRESSION_DEFLATE);
- BIND_ENUM_CONSTANT(COMPRESSION_ZSTD);
- BIND_ENUM_CONSTANT(COMPRESSION_GZIP);
-}
-
-////// Directory //////
-
-Error Directory::open(const String &p_path) {
- Error err;
- Ref<DirAccess> alt = DirAccess::open(p_path, &err);
- if (alt.is_null()) {
- return err;
- }
- d = alt;
- dir_open = true;
-
- return OK;
-}
-
-bool Directory::is_open() const {
- return d.is_valid() && dir_open;
-}
-
-Error Directory::list_dir_begin() {
- ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- return d->list_dir_begin();
-}
-
-String Directory::get_next() {
- ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
-
- String next = d->get_next();
- while (!next.is_empty() && ((!include_navigational && (next == "." || next == "..")) || (!include_hidden && d->current_is_hidden()))) {
- next = d->get_next();
- }
- return next;
-}
-
-bool Directory::current_is_dir() const {
- ERR_FAIL_COND_V_MSG(!is_open(), false, "Directory must be opened before use.");
- return d->current_is_dir();
-}
-
-void Directory::list_dir_end() {
- ERR_FAIL_COND_MSG(!is_open(), "Directory must be opened before use.");
- d->list_dir_end();
-}
-
-PackedStringArray Directory::get_files() {
- return _get_contents(false);
-}
-
-PackedStringArray Directory::get_directories() {
- return _get_contents(true);
-}
-
-PackedStringArray Directory::_get_contents(bool p_directories) {
- PackedStringArray ret;
- ERR_FAIL_COND_V_MSG(!is_open(), ret, "Directory must be opened before use.");
-
- list_dir_begin();
- String s = get_next();
- while (!s.is_empty()) {
- if (current_is_dir() == p_directories) {
- ret.append(s);
- }
- s = get_next();
- }
-
- ret.sort();
- return ret;
-}
-
-void Directory::set_include_navigational(bool p_enable) {
- include_navigational = p_enable;
-}
-
-bool Directory::get_include_navigational() const {
- return include_navigational;
-}
-
-void Directory::set_include_hidden(bool p_enable) {
- include_hidden = p_enable;
-}
-
-bool Directory::get_include_hidden() const {
- return include_hidden;
-}
-
-int Directory::get_drive_count() {
- ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use.");
- return d->get_drive_count();
-}
-
-String Directory::get_drive(int p_drive) {
- ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
- return d->get_drive(p_drive);
-}
-
-int Directory::get_current_drive() {
- ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use.");
- return d->get_current_drive();
-}
-
-Error Directory::change_dir(String p_dir) {
- ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
- Error err = d->change_dir(p_dir);
-
- if (err != OK) {
- return err;
- }
- dir_open = true;
-
- return OK;
-}
-
-String Directory::get_current_dir() {
- ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
- return d->get_current_dir();
-}
-
-Error Directory::make_dir(String p_dir) {
- ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
- if (!p_dir.is_relative_path()) {
- Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
- return da->make_dir(p_dir);
- }
- return d->make_dir(p_dir);
-}
-
-Error Directory::make_dir_recursive(String p_dir) {
- ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
- if (!p_dir.is_relative_path()) {
- Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
- return da->make_dir_recursive(p_dir);
- }
- return d->make_dir_recursive(p_dir);
-}
-
-bool Directory::file_exists(String p_file) {
- ERR_FAIL_COND_V_MSG(d.is_null(), false, "Directory is not configured properly.");
- if (!p_file.is_relative_path()) {
- return FileAccess::exists(p_file);
- }
- return d->file_exists(p_file);
-}
-
-bool Directory::dir_exists(String p_dir) {
- ERR_FAIL_COND_V_MSG(d.is_null(), false, "Directory is not configured properly.");
- if (!p_dir.is_relative_path()) {
- return DirAccess::exists(p_dir);
- }
- return d->dir_exists(p_dir);
-}
-
-uint64_t Directory::get_space_left() {
- ERR_FAIL_COND_V_MSG(d.is_null(), 0, "Directory must be opened before use.");
- return d->get_space_left() / 1024 * 1024; // Truncate to closest MiB.
-}
-
-Error Directory::copy(String p_from, String p_to) {
- ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- return d->copy(p_from, p_to);
-}
-
-Error Directory::rename(String p_from, String p_to) {
- ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- ERR_FAIL_COND_V_MSG(p_from.is_empty() || p_from == "." || p_from == "..", ERR_INVALID_PARAMETER, "Invalid path to rename.");
-
- if (!p_from.is_relative_path()) {
- Ref<DirAccess> da = DirAccess::create_for_path(p_from);
- ERR_FAIL_COND_V_MSG(!da->file_exists(p_from) && !da->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
- return da->rename(p_from, p_to);
- }
-
- ERR_FAIL_COND_V_MSG(!d->file_exists(p_from) && !d->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
- return d->rename(p_from, p_to);
-}
-
-Error Directory::remove(String p_name) {
- ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- if (!p_name.is_relative_path()) {
- Ref<DirAccess> da = DirAccess::create_for_path(p_name);
- return da->remove(p_name);
- }
-
- return d->remove(p_name);
-}
-
-void Directory::_bind_methods() {
- ClassDB::bind_method(D_METHOD("open", "path"), &Directory::open);
- ClassDB::bind_method(D_METHOD("list_dir_begin"), &Directory::list_dir_begin, DEFVAL(false), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_next"), &Directory::get_next);
- ClassDB::bind_method(D_METHOD("current_is_dir"), &Directory::current_is_dir);
- ClassDB::bind_method(D_METHOD("list_dir_end"), &Directory::list_dir_end);
- ClassDB::bind_method(D_METHOD("get_files"), &Directory::get_files);
- ClassDB::bind_method(D_METHOD("get_directories"), &Directory::get_directories);
- ClassDB::bind_method(D_METHOD("get_drive_count"), &Directory::get_drive_count);
- ClassDB::bind_method(D_METHOD("get_drive", "idx"), &Directory::get_drive);
- ClassDB::bind_method(D_METHOD("get_current_drive"), &Directory::get_current_drive);
- ClassDB::bind_method(D_METHOD("change_dir", "todir"), &Directory::change_dir);
- ClassDB::bind_method(D_METHOD("get_current_dir"), &Directory::get_current_dir);
- ClassDB::bind_method(D_METHOD("make_dir", "path"), &Directory::make_dir);
- ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &Directory::make_dir_recursive);
- ClassDB::bind_method(D_METHOD("file_exists", "path"), &Directory::file_exists);
- ClassDB::bind_method(D_METHOD("dir_exists", "path"), &Directory::dir_exists);
- ClassDB::bind_method(D_METHOD("get_space_left"), &Directory::get_space_left);
- ClassDB::bind_method(D_METHOD("copy", "from", "to"), &Directory::copy);
- ClassDB::bind_method(D_METHOD("rename", "from", "to"), &Directory::rename);
- ClassDB::bind_method(D_METHOD("remove", "path"), &Directory::remove);
-
- ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &Directory::set_include_navigational);
- ClassDB::bind_method(D_METHOD("get_include_navigational"), &Directory::get_include_navigational);
- ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &Directory::set_include_hidden);
- ClassDB::bind_method(D_METHOD("get_include_hidden"), &Directory::get_include_hidden);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
-}
-
-Directory::Directory() {
- d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
-}
-
////// Marshalls //////
Marshalls *Marshalls::singleton = nullptr;
diff --git a/core/core_bind.h b/core/core_bind.h
index cd382d2915..ba22971d78 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -32,9 +32,6 @@
#define CORE_BIND_H
#include "core/debugger/engine_profiler.h"
-#include "core/io/compression.h"
-#include "core/io/dir_access.h"
-#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
@@ -193,6 +190,8 @@ public:
bool set_environment(const String &p_var, const String &p_value) const;
String get_name() const;
+ String get_distribution_name() const;
+ String get_version() const;
Vector<String> get_cmdline_args();
Vector<String> get_cmdline_user_args();
@@ -287,6 +286,7 @@ public:
Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon);
Vector<int> triangulate_delaunay(const Vector<Vector2> &p_points);
Vector<Point2> convex_hull(const Vector<Point2> &p_points);
+ TypedArray<PackedVector2Array> decompose_polygon_in_convex(const Vector<Vector2> &p_polygon);
enum PolyBooleanOperation {
OPERATION_UNION,
@@ -353,156 +353,6 @@ public:
Geometry3D() { singleton = this; }
};
-class File : public RefCounted {
- GDCLASS(File, RefCounted);
-
- Ref<FileAccess> f;
- bool big_endian = false;
-
-protected:
- static void _bind_methods();
-
-public:
- enum ModeFlags {
- READ = 1,
- WRITE = 2,
- READ_WRITE = 3,
- WRITE_READ = 7,
- };
-
- enum CompressionMode {
- COMPRESSION_FASTLZ = Compression::MODE_FASTLZ,
- COMPRESSION_DEFLATE = Compression::MODE_DEFLATE,
- COMPRESSION_ZSTD = Compression::MODE_ZSTD,
- COMPRESSION_GZIP = Compression::MODE_GZIP
- };
-
- Error open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
- Error open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
- Error open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
-
- Error open(const String &p_path, ModeFlags p_mode_flags); // open a file.
- void flush(); // Flush a file (write its buffer to disk).
- void close(); // Close a file.
- bool is_open() const; // True when file is open.
-
- String get_path() const; // Returns the path for the current open file.
- String get_path_absolute() const; // Returns the absolute path for the current open file.
-
- void seek(int64_t p_position); // Seek to a given position.
- void seek_end(int64_t p_position = 0); // Seek from the end of file.
- uint64_t get_position() const; // Get position in the file.
- uint64_t get_length() const; // Get size of the file.
-
- bool eof_reached() const; // Reading passed EOF.
-
- uint8_t get_8() const; // Get a byte.
- uint16_t get_16() const; // Get 16 bits uint.
- uint32_t get_32() const; // Get 32 bits uint.
- uint64_t get_64() const; // Get 64 bits uint.
-
- float get_float() const;
- double get_double() const;
- real_t get_real() const;
-
- Variant get_var(bool p_allow_objects = false) const;
-
- Vector<uint8_t> get_buffer(int64_t p_length) const; // Get an array of bytes.
- String get_line() const;
- Vector<String> get_csv_line(const String &p_delim = ",") const;
- String get_as_text(bool p_skip_cr = false) const;
- String get_md5(const String &p_path) const;
- String get_sha256(const String &p_path) const;
-
- /*
- * Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac).
- * It's not about the current CPU type but file formats.
- * This flag gets reset to `false` (little endian) on each open.
- */
- void set_big_endian(bool p_big_endian);
- bool is_big_endian();
-
- Error get_error() const; // Get last error.
-
- void store_8(uint8_t p_dest); // Store a byte.
- void store_16(uint16_t p_dest); // Store 16 bits uint.
- void store_32(uint32_t p_dest); // Store 32 bits uint.
- void store_64(uint64_t p_dest); // Store 64 bits uint.
-
- void store_float(float p_dest);
- void store_double(double p_dest);
- void store_real(real_t p_real);
-
- void store_string(const String &p_string);
- void store_line(const String &p_string);
- void store_csv_line(const Vector<String> &p_values, const String &p_delim = ",");
-
- virtual void store_pascal_string(const String &p_string);
- virtual String get_pascal_string();
-
- void store_buffer(const Vector<uint8_t> &p_buffer); // Store an array of bytes.
-
- void store_var(const Variant &p_var, bool p_full_objects = false);
-
- static bool file_exists(const String &p_name); // Return true if a file exists.
-
- uint64_t get_modified_time(const String &p_file) const;
-
- File() {}
-};
-
-class Directory : public RefCounted {
- GDCLASS(Directory, RefCounted);
- Ref<DirAccess> d;
-
- bool dir_open = false;
- bool include_navigational = false;
- bool include_hidden = false;
-
-protected:
- static void _bind_methods();
-
-public:
- Error open(const String &p_path);
-
- bool is_open() const;
-
- Error list_dir_begin();
- String get_next();
- bool current_is_dir() const;
- void list_dir_end();
-
- PackedStringArray get_files();
- PackedStringArray get_directories();
- PackedStringArray _get_contents(bool p_directories);
-
- void set_include_navigational(bool p_enable);
- bool get_include_navigational() const;
- void set_include_hidden(bool p_enable);
- bool get_include_hidden() const;
-
- int get_drive_count();
- String get_drive(int p_drive);
- int get_current_drive();
-
- Error change_dir(String p_dir); // Can be relative or absolute, return false on success.
- String get_current_dir(); // Return current dir location.
-
- Error make_dir(String p_dir);
- Error make_dir_recursive(String p_dir);
-
- bool file_exists(String p_file);
- bool dir_exists(String p_dir);
-
- uint64_t get_space_left();
-
- Error copy(String p_from, String p_to);
- Error rename(String p_from, String p_to);
- Error remove(String p_name);
-
- Directory();
-};
-
class Marshalls : public Object {
GDCLASS(Marshalls, Object);
@@ -736,9 +586,6 @@ VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType);
-VARIANT_ENUM_CAST(core_bind::File::ModeFlags);
-VARIANT_ENUM_CAST(core_bind::File::CompressionMode);
-
VARIANT_ENUM_CAST(core_bind::Thread::Priority);
#endif // CORE_BIND_H
diff --git a/core/doc_data.h b/core/doc_data.h
index 3b7bf149b4..bb356f027e 100644
--- a/core/doc_data.h
+++ b/core/doc_data.h
@@ -32,7 +32,6 @@
#define DOC_DATA_H
#include "core/io/xml_parser.h"
-#include "core/templates/rb_map.h"
#include "core/variant/variant.h"
struct ScriptMemberInfo {
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 5cf951a93c..e6e0fff266 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -46,6 +46,9 @@ static String get_type_name(const PropertyInfo &p_info) {
return p_info.hint_string + "*";
}
}
+ if (p_info.type == Variant::ARRAY && (p_info.hint == PROPERTY_HINT_ARRAY_TYPE)) {
+ return String("typedarray::") + p_info.hint_string;
+ }
if (p_info.type == Variant::INT && (p_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM))) {
return String("enum::") + String(p_info.class_name);
}
@@ -215,7 +218,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t);
Dictionary d2;
d2["name"] = name;
- uint32_t size;
+ uint32_t size = 0;
switch (i) {
case 0:
size = type_size_array[j].size_32_bits_real_float;
@@ -330,7 +333,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
last_type = t;
}
Dictionary d3;
- uint32_t offset;
+ uint32_t offset = 0;
switch (i) {
case 0:
offset = member_offset_array[idx].offset_32_bits_real_float;
@@ -462,7 +465,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
d["indexing_return_type"] = index_type == Variant::NIL ? String("Variant") : Variant::get_type_name(index_type);
}
- d["is_keyed"] = Variant::ValidatedKeyedSetter(type);
+ d["is_keyed"] = Variant::is_keyed(type);
{
//members
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index ef0b590030..67dc55bdb7 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -251,27 +251,6 @@ static GDNativeBool gdnative_variant_booleanize(const GDNativeVariantPtr p_self)
return self->booleanize();
}
-static void gdnative_variant_sub(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst) {
- const Variant *a = (const Variant *)p_a;
- const Variant *b = (const Variant *)p_b;
- memnew_placement(r_dst, Variant);
- Variant::sub(*a, *b, *(Variant *)r_dst);
-}
-
-static void gdnative_variant_blend(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) {
- const Variant *a = (const Variant *)p_a;
- const Variant *b = (const Variant *)p_b;
- memnew_placement(r_dst, Variant);
- Variant::blend(*a, *b, p_c, *(Variant *)r_dst);
-}
-
-static void gdnative_variant_interpolate(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) {
- const Variant *a = (const Variant *)p_a;
- const Variant *b = (const Variant *)p_b;
- memnew_placement(r_dst, Variant);
- Variant::interpolate(*a, *b, p_c, *(Variant *)r_dst);
-}
-
static void gdnative_variant_duplicate(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep) {
const Variant *self = (const Variant *)p_self;
memnew_placement(r_ret, Variant(self->duplicate(p_deep)));
@@ -905,7 +884,7 @@ static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const char *p_clas
MethodBind *mb = ClassDB::get_method(StringName(p_classname), StringName(p_methodname));
ERR_FAIL_COND_V(!mb, nullptr);
if (mb->get_hash() != p_hash) {
- ERR_PRINT_ONCE("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'.");
+ ERR_PRINT("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'.");
return nullptr;
}
// MethodBind *mb = ClassDB::get_method("Node", "get_name");
@@ -970,9 +949,6 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.variant_recursive_hash = gdnative_variant_recursive_hash;
gdni.variant_hash_compare = gdnative_variant_hash_compare;
gdni.variant_booleanize = gdnative_variant_booleanize;
- gdni.variant_sub = gdnative_variant_sub;
- gdni.variant_blend = gdnative_variant_blend;
- gdni.variant_interpolate = gdnative_variant_interpolate;
gdni.variant_duplicate = gdnative_variant_duplicate;
gdni.variant_stringify = gdnative_variant_stringify;
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index cb2adcb562..39378d8261 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -427,9 +427,6 @@ typedef struct {
GDNativeInt (*variant_recursive_hash)(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count);
GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other);
GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self);
- void (*variant_sub)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst);
- void (*variant_blend)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst);
- void (*variant_interpolate)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst);
void (*variant_duplicate)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep);
void (*variant_stringify)(const GDNativeVariantPtr p_self, GDNativeStringPtr r_ret);
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 596b704732..712fc68c93 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -1325,7 +1325,7 @@ bool InputEventAction::is_match(const Ref<InputEvent> &p_event, bool p_exact_mat
return false;
}
- return p_event->is_action(action);
+ return p_event->is_action(action, p_exact_match);
}
bool InputEventAction::is_action(const StringName &p_action) const {
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index bed41b8d89..79e7fa16e3 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -36,6 +36,8 @@
#include "core/os/os.h"
#include "core/templates/local_vector.h"
+thread_local Error DirAccess::last_dir_open_error = OK;
+
String DirAccess::_get_root_path() const {
switch (_access_type) {
case ACCESS_RESOURCES:
@@ -249,6 +251,61 @@ Ref<DirAccess> DirAccess::open(const String &p_path, Error *r_error) {
return da;
}
+Ref<DirAccess> DirAccess::_open(const String &p_path) {
+ Error err = OK;
+ Ref<DirAccess> da = open(p_path, &err);
+ last_dir_open_error = err;
+ if (err) {
+ return Ref<DirAccess>();
+ }
+ return da;
+}
+
+int DirAccess::_get_drive_count() {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ return d->get_drive_count();
+}
+
+String DirAccess::get_drive_name(int p_idx) {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ return d->get_drive(p_idx);
+}
+
+Error DirAccess::make_dir_absolute(const String &p_dir) {
+ Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
+ return d->make_dir(p_dir);
+}
+
+Error DirAccess::make_dir_recursive_absolute(const String &p_dir) {
+ Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
+ return d->make_dir_recursive(p_dir);
+}
+
+bool DirAccess::dir_exists_absolute(const String &p_dir) {
+ Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
+ return d->dir_exists(p_dir);
+}
+
+Error DirAccess::copy_absolute(const String &p_from, const String &p_to, int p_chmod_flags) {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ // Support copying from res:// to user:// etc.
+ String from = ProjectSettings::get_singleton()->globalize_path(p_from);
+ String to = ProjectSettings::get_singleton()->globalize_path(p_to);
+ return d->copy(from, to, p_chmod_flags);
+}
+
+Error DirAccess::rename_absolute(const String &p_from, const String &p_to) {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ String from = ProjectSettings::get_singleton()->globalize_path(p_from);
+ String to = ProjectSettings::get_singleton()->globalize_path(p_to);
+ return d->rename(from, to);
+}
+
+Error DirAccess::remove_absolute(const String &p_path) {
+ Ref<DirAccess> d = DirAccess::create_for_path(p_path);
+ return d->remove(p_path);
+}
+
Ref<DirAccess> DirAccess::create(AccessType p_access) {
Ref<DirAccess> da = create_func[p_access] ? create_func[p_access]() : nullptr;
if (da.is_valid()) {
@@ -266,6 +323,10 @@ Ref<DirAccess> DirAccess::create(AccessType p_access) {
return da;
}
+Error DirAccess::get_open_error() {
+ return last_dir_open_error;
+}
+
String DirAccess::get_full_path(const String &p_path, AccessType p_access) {
Ref<DirAccess> d = DirAccess::create(p_access);
if (d.is_null()) {
@@ -424,3 +485,104 @@ bool DirAccess::exists(String p_dir) {
Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
return da->change_dir(p_dir) == OK;
}
+
+PackedStringArray DirAccess::get_files() {
+ return _get_contents(false);
+}
+
+PackedStringArray DirAccess::get_files_at(const String &p_path) {
+ Ref<DirAccess> da = DirAccess::open(p_path);
+ ERR_FAIL_COND_V_MSG(da.is_null(), PackedStringArray(), vformat("Couldn't open directory at path \"%s\".", p_path));
+ return da->get_files();
+}
+
+PackedStringArray DirAccess::get_directories() {
+ return _get_contents(true);
+}
+
+PackedStringArray DirAccess::get_directories_at(const String &p_path) {
+ Ref<DirAccess> da = DirAccess::open(p_path);
+ ERR_FAIL_COND_V_MSG(da.is_null(), PackedStringArray(), vformat("Couldn't open directory at path \"%s\".", p_path));
+ return da->get_directories();
+}
+
+PackedStringArray DirAccess::_get_contents(bool p_directories) {
+ PackedStringArray ret;
+
+ list_dir_begin();
+ String s = _get_next();
+ while (!s.is_empty()) {
+ if (current_is_dir() == p_directories) {
+ ret.append(s);
+ }
+ s = _get_next();
+ }
+
+ ret.sort();
+ return ret;
+}
+
+String DirAccess::_get_next() {
+ String next = get_next();
+ while (!next.is_empty() && ((!include_navigational && (next == "." || next == "..")) || (!include_hidden && current_is_hidden()))) {
+ next = get_next();
+ }
+ return next;
+}
+
+void DirAccess::set_include_navigational(bool p_enable) {
+ include_navigational = p_enable;
+}
+
+bool DirAccess::get_include_navigational() const {
+ return include_navigational;
+}
+
+void DirAccess::set_include_hidden(bool p_enable) {
+ include_hidden = p_enable;
+}
+
+bool DirAccess::get_include_hidden() const {
+ return include_hidden;
+}
+
+void DirAccess::_bind_methods() {
+ ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error);
+
+ ClassDB::bind_method(D_METHOD("list_dir_begin"), &DirAccess::list_dir_begin, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_next"), &DirAccess::_get_next);
+ ClassDB::bind_method(D_METHOD("current_is_dir"), &DirAccess::current_is_dir);
+ ClassDB::bind_method(D_METHOD("list_dir_end"), &DirAccess::list_dir_end);
+ ClassDB::bind_method(D_METHOD("get_files"), &DirAccess::get_files);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_files_at", "path"), &DirAccess::get_files_at);
+ ClassDB::bind_method(D_METHOD("get_directories"), &DirAccess::get_directories);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_directories_at", "path"), &DirAccess::get_directories_at);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_count"), &DirAccess::_get_drive_count);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_name", "idx"), &DirAccess::get_drive_name);
+ ClassDB::bind_method(D_METHOD("get_current_drive"), &DirAccess::get_current_drive);
+ ClassDB::bind_method(D_METHOD("change_dir", "to_dir"), &DirAccess::change_dir);
+ ClassDB::bind_method(D_METHOD("get_current_dir", "include_drive"), &DirAccess::get_current_dir, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("make_dir", "path"), &DirAccess::make_dir);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("make_dir_absolute", "path"), &DirAccess::make_dir_absolute);
+ ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &DirAccess::make_dir_recursive);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("make_dir_recursive_absolute", "path"), &DirAccess::make_dir_recursive_absolute);
+ ClassDB::bind_method(D_METHOD("file_exists", "path"), &DirAccess::file_exists);
+ ClassDB::bind_method(D_METHOD("dir_exists", "path"), &DirAccess::dir_exists);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("dir_exists_absolute", "path"), &DirAccess::dir_exists_absolute);
+ ClassDB::bind_method(D_METHOD("get_space_left"), &DirAccess::get_space_left);
+ ClassDB::bind_method(D_METHOD("copy", "from", "to", "chmod_flags"), &DirAccess::copy, DEFVAL(-1));
+ ClassDB::bind_static_method("DirAccess", D_METHOD("copy_absolute", "from", "to", "chmod_flags"), &DirAccess::copy_absolute, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("rename", "from", "to"), &DirAccess::rename);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("rename_absolute", "from", "to"), &DirAccess::rename_absolute);
+ ClassDB::bind_method(D_METHOD("remove", "path"), &DirAccess::remove);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("remove_absolute", "path"), &DirAccess::remove_absolute);
+
+ ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &DirAccess::set_include_navigational);
+ ClassDB::bind_method(D_METHOD("get_include_navigational"), &DirAccess::get_include_navigational);
+ ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &DirAccess::set_include_hidden);
+ ClassDB::bind_method(D_METHOD("get_include_hidden"), &DirAccess::get_include_hidden);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
+}
diff --git a/core/io/dir_access.h b/core/io/dir_access.h
index 2469c2a080..ee675f1c89 100644
--- a/core/io/dir_access.h
+++ b/core/io/dir_access.h
@@ -37,6 +37,8 @@
//@ TODO, excellent candidate for THREAD_SAFE MACRO, should go through all these and add THREAD_SAFE where it applies
class DirAccess : public RefCounted {
+ GDCLASS(DirAccess, RefCounted);
+
public:
enum AccessType {
ACCESS_RESOURCES,
@@ -53,7 +55,13 @@ private:
Error _copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod_flags, bool p_copy_links);
+ thread_local static Error last_dir_open_error;
+ bool include_navigational = false;
+ bool include_hidden = false;
+
protected:
+ static void _bind_methods();
+
String _get_root_path() const;
virtual String _get_root_string() const;
@@ -118,6 +126,7 @@ public:
static Ref<DirAccess> create_for_path(const String &p_path);
static Ref<DirAccess> create(AccessType p_access);
+ static Error get_open_error();
template <class T>
static void make_default(AccessType p_access) {
@@ -125,6 +134,30 @@ public:
}
static Ref<DirAccess> open(const String &p_path, Error *r_error = nullptr);
+ static Ref<DirAccess> _open(const String &p_path);
+
+ static int _get_drive_count();
+ static String get_drive_name(int p_idx);
+
+ static Error make_dir_absolute(const String &p_dir);
+ static Error make_dir_recursive_absolute(const String &p_dir);
+ static bool dir_exists_absolute(const String &p_dir);
+
+ static Error copy_absolute(const String &p_from, const String &p_to, int p_chmod_flags = -1);
+ static Error rename_absolute(const String &p_from, const String &p_to);
+ static Error remove_absolute(const String &p_path);
+
+ PackedStringArray get_files();
+ static PackedStringArray get_files_at(const String &p_path);
+ PackedStringArray get_directories();
+ static PackedStringArray get_directories_at(const String &p_path);
+ PackedStringArray _get_contents(bool p_directories);
+ String _get_next();
+
+ void set_include_navigational(bool p_enable);
+ bool get_include_navigational() const;
+ void set_include_hidden(bool p_enable);
+ bool get_include_hidden() const;
DirAccess() {}
virtual ~DirAccess() {}
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index 72c00bd678..499f083f51 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -32,6 +32,8 @@
#include "core/config/project_settings.h"
#include "core/crypto/crypto_core.h"
+#include "core/io/file_access_compressed.h"
+#include "core/io/file_access_encrypted.h"
#include "core/io/file_access_pack.h"
#include "core/io/marshalls.h"
#include "core/os/os.h"
@@ -41,6 +43,7 @@ FileAccess::CreateFunc FileAccess::create_func[ACCESS_MAX] = { nullptr, nullptr
FileAccess::FileCloseFailNotify FileAccess::close_fail_notify = nullptr;
bool FileAccess::backup_save = false;
+thread_local Error FileAccess::last_file_open_error = OK;
Ref<FileAccess> FileAccess::create(AccessType p_access) {
ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr);
@@ -81,7 +84,7 @@ Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
}
Error FileAccess::reopen(const String &p_path, int p_mode_flags) {
- return _open(p_path, p_mode_flags);
+ return open_internal(p_path, p_mode_flags);
}
Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *r_error) {
@@ -99,7 +102,7 @@ Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *
}
ret = create_for_path(p_path);
- Error err = ret->_open(p_path, p_mode_flags);
+ Error err = ret->open_internal(p_path, p_mode_flags);
if (r_error) {
*r_error = err;
@@ -111,6 +114,66 @@ Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *
return ret;
}
+Ref<FileAccess> FileAccess::_open(const String &p_path, ModeFlags p_mode_flags) {
+ Error err = OK;
+ Ref<FileAccess> fa = open(p_path, p_mode_flags, &err);
+ last_file_open_error = err;
+ if (err) {
+ return Ref<FileAccess>();
+ }
+ return fa;
+}
+
+Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
+ Ref<FileAccess> fa = _open(p_path, p_mode_flags);
+ if (fa.is_null()) {
+ return fa;
+ }
+
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
+ Error err = fae->open_and_parse(fa, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
+ if (err) {
+ last_file_open_error = err;
+ return Ref<FileAccess>();
+ }
+ return fae;
+}
+
+Ref<FileAccess> FileAccess::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) {
+ Ref<FileAccess> fa = _open(p_path, p_mode_flags);
+ if (fa.is_null()) {
+ return fa;
+ }
+
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
+ Error err = fae->open_and_parse_password(fa, p_pass, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
+ if (err) {
+ last_file_open_error = err;
+ return Ref<FileAccess>();
+ }
+ return fae;
+}
+
+Ref<FileAccess> FileAccess::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) {
+ Ref<FileAccessCompressed> fac;
+ fac.instantiate();
+ fac->configure("GCPF", (Compression::Mode)p_compress_mode);
+ Error err = fac->open_internal(p_path, p_mode_flags);
+
+ if (err) {
+ last_file_open_error = err;
+ return Ref<FileAccess>();
+ }
+
+ return fac;
+}
+
+Error FileAccess::get_open_error() {
+ return last_file_open_error;
+}
+
FileAccess::CreateFunc FileAccess::get_create_func(AccessType p_access) {
return create_func[p_access];
}
@@ -227,6 +290,20 @@ real_t FileAccess::get_real() const {
}
}
+Variant FileAccess::get_var(bool p_allow_objects) const {
+ uint32_t len = get_32();
+ Vector<uint8_t> buff = _get_buffer(len);
+ ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant());
+
+ const uint8_t *r = buff.ptr();
+
+ Variant v;
+ Error err = decode_variant(v, &r[0], len, nullptr, p_allow_objects);
+ ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to encode Variant.");
+
+ return v;
+}
+
double FileAccess::get_double() const {
MarshallDouble m;
m.l = get_64();
@@ -370,6 +447,17 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
return strings;
}
+String FileAccess::get_as_text(bool p_skip_cr) const {
+ uint64_t original_pos = get_position();
+ const_cast<FileAccess *>(this)->seek(0);
+
+ String text = get_as_utf8_string(p_skip_cr);
+
+ const_cast<FileAccess *>(this)->seek(original_pos);
+
+ return text;
+}
+
uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
@@ -381,6 +469,27 @@ uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
return i;
}
+Vector<uint8_t> FileAccess::_get_buffer(int64_t p_length) const {
+ Vector<uint8_t> data;
+
+ ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0.");
+ if (p_length == 0) {
+ return data;
+ }
+
+ Error err = data.resize(p_length);
+ ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements.");
+
+ uint8_t *w = data.ptrw();
+ int64_t len = get_buffer(&w[0], p_length);
+
+ if (len < p_length) {
+ data.resize(len);
+ }
+
+ return data;
+}
+
String FileAccess::get_as_utf8_string(bool p_skip_cr) const {
Vector<uint8_t> sourcef;
uint64_t len = get_length();
@@ -554,6 +663,33 @@ void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
}
}
+void FileAccess::_store_buffer(const Vector<uint8_t> &p_buffer) {
+ uint64_t len = p_buffer.size();
+ if (len == 0) {
+ return;
+ }
+
+ const uint8_t *r = p_buffer.ptr();
+
+ store_buffer(&r[0], len);
+}
+
+void FileAccess::store_var(const Variant &p_var, bool p_full_objects) {
+ int len;
+ Error err = encode_variant(p_var, nullptr, len, p_full_objects);
+ ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
+
+ Vector<uint8_t> buff;
+ buff.resize(len);
+
+ uint8_t *w = buff.ptrw();
+ err = encode_variant(p_var, &w[0], len, p_full_objects);
+ ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
+
+ store_32(len);
+ _store_buffer(buff);
+}
+
Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_error) {
Ref<FileAccess> f = FileAccess::open(p_path, READ, r_error);
if (f.is_null()) {
@@ -666,3 +802,69 @@ String FileAccess::get_sha256(const String &p_file) {
return String::hex_encode_buffer(hash, 32);
}
+
+void FileAccess::_bind_methods() {
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open", "path", "flags"), &FileAccess::_open);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::open_encrypted);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &FileAccess::open_encrypted_pass);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0));
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error);
+
+ ClassDB::bind_method(D_METHOD("flush"), &FileAccess::flush);
+ ClassDB::bind_method(D_METHOD("get_path"), &FileAccess::get_path);
+ ClassDB::bind_method(D_METHOD("get_path_absolute"), &FileAccess::get_path_absolute);
+ ClassDB::bind_method(D_METHOD("is_open"), &FileAccess::is_open);
+ ClassDB::bind_method(D_METHOD("seek", "position"), &FileAccess::seek);
+ ClassDB::bind_method(D_METHOD("seek_end", "position"), &FileAccess::seek_end, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_position"), &FileAccess::get_position);
+ ClassDB::bind_method(D_METHOD("get_length"), &FileAccess::get_length);
+ ClassDB::bind_method(D_METHOD("eof_reached"), &FileAccess::eof_reached);
+ ClassDB::bind_method(D_METHOD("get_8"), &FileAccess::get_8);
+ ClassDB::bind_method(D_METHOD("get_16"), &FileAccess::get_16);
+ ClassDB::bind_method(D_METHOD("get_32"), &FileAccess::get_32);
+ ClassDB::bind_method(D_METHOD("get_64"), &FileAccess::get_64);
+ ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float);
+ ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double);
+ ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real);
+ ClassDB::bind_method(D_METHOD("get_buffer", "length"), &FileAccess::_get_buffer);
+ ClassDB::bind_method(D_METHOD("get_line"), &FileAccess::get_line);
+ ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &FileAccess::get_csv_line, DEFVAL(","));
+ ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &FileAccess::get_as_text, DEFVAL(false));
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_md5", "path"), &FileAccess::get_md5);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_sha256", "path"), &FileAccess::get_sha256);
+ ClassDB::bind_method(D_METHOD("is_big_endian"), &FileAccess::is_big_endian);
+ ClassDB::bind_method(D_METHOD("set_big_endian", "big_endian"), &FileAccess::set_big_endian);
+ ClassDB::bind_method(D_METHOD("get_error"), &FileAccess::get_error);
+ ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &FileAccess::get_var, DEFVAL(false));
+
+ ClassDB::bind_method(D_METHOD("store_8", "value"), &FileAccess::store_8);
+ ClassDB::bind_method(D_METHOD("store_16", "value"), &FileAccess::store_16);
+ ClassDB::bind_method(D_METHOD("store_32", "value"), &FileAccess::store_32);
+ ClassDB::bind_method(D_METHOD("store_64", "value"), &FileAccess::store_64);
+ ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float);
+ ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double);
+ ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real);
+ ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &FileAccess::_store_buffer);
+ ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line);
+ ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(","));
+ ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string);
+ ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &FileAccess::store_var, DEFVAL(false));
+
+ ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &FileAccess::store_pascal_string);
+ ClassDB::bind_method(D_METHOD("get_pascal_string"), &FileAccess::get_pascal_string);
+
+ ClassDB::bind_static_method("FileAccess", D_METHOD("file_exists", "path"), &FileAccess::exists);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_modified_time", "file"), &FileAccess::get_modified_time);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian");
+
+ BIND_ENUM_CONSTANT(READ);
+ BIND_ENUM_CONSTANT(WRITE);
+ BIND_ENUM_CONSTANT(READ_WRITE);
+ BIND_ENUM_CONSTANT(WRITE_READ);
+
+ BIND_ENUM_CONSTANT(COMPRESSION_FASTLZ);
+ BIND_ENUM_CONSTANT(COMPRESSION_DEFLATE);
+ BIND_ENUM_CONSTANT(COMPRESSION_ZSTD);
+ BIND_ENUM_CONSTANT(COMPRESSION_GZIP);
+}
diff --git a/core/io/file_access.h b/core/io/file_access.h
index fc0eb95d44..f8c42d3c0d 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -31,6 +31,7 @@
#ifndef FILE_ACCESS_H
#define FILE_ACCESS_H
+#include "core/io/compression.h"
#include "core/math/math_defs.h"
#include "core/object/ref_counted.h"
#include "core/os/memory.h"
@@ -42,6 +43,8 @@
*/
class FileAccess : public RefCounted {
+ GDCLASS(FileAccess, RefCounted);
+
public:
enum AccessType {
ACCESS_RESOURCES,
@@ -60,15 +63,18 @@ public:
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0;
protected:
+ static void _bind_methods();
+
AccessType get_access_type() const;
String fix_path(const String &p_path) const;
- virtual Error _open(const String &p_path, int p_mode_flags) = 0; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) = 0; ///< open a file
virtual uint64_t _get_modified_time(const String &p_file) = 0;
static FileCloseFailNotify close_fail_notify;
private:
static bool backup_save;
+ thread_local static Error last_file_open_error;
AccessType _access_type = ACCESS_FILESYSTEM;
static CreateFunc create_func[ACCESS_MAX]; /** default file access creation function for a platform */
@@ -89,6 +95,13 @@ public:
WRITE_READ = 7,
};
+ enum CompressionMode {
+ COMPRESSION_FASTLZ = Compression::MODE_FASTLZ,
+ COMPRESSION_DEFLATE = Compression::MODE_DEFLATE,
+ COMPRESSION_ZSTD = Compression::MODE_ZSTD,
+ COMPRESSION_GZIP = Compression::MODE_GZIP
+ };
+
virtual bool is_open() const = 0; ///< true when file is open
virtual String get_path() const { return ""; } /// returns the path for the current open file
@@ -110,10 +123,14 @@ public:
virtual double get_double() const;
virtual real_t get_real() const;
+ Variant get_var(bool p_allow_objects = false) const;
+
virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes
+ Vector<uint8_t> _get_buffer(int64_t p_length) const;
virtual String get_line() const;
virtual String get_token() const;
virtual Vector<String> get_csv_line(const String &p_delim = ",") const;
+ String get_as_text(bool p_skip_cr = false) const;
virtual String get_as_utf8_string(bool p_skip_cr = false) const;
/**
@@ -144,6 +161,9 @@ public:
virtual String get_pascal_string();
virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ void _store_buffer(const Vector<uint8_t> &p_buffer);
+
+ void store_var(const Variant &p_var, bool p_full_objects = false);
virtual bool file_exists(const String &p_name) = 0; ///< return true if a file exists
@@ -152,6 +172,13 @@ public:
static Ref<FileAccess> create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files.
static Ref<FileAccess> create_for_path(const String &p_path);
static Ref<FileAccess> open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files.
+
+ static Ref<FileAccess> _open(const String &p_path, ModeFlags p_mode_flags);
+ static Ref<FileAccess> open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
+ static Ref<FileAccess> open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
+ static Ref<FileAccess> open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
+ static Error get_open_error();
+
static CreateFunc get_create_func(AccessType p_access);
static bool exists(const String &p_name); ///< return true if a file exists
static uint64_t get_modified_time(const String &p_file);
@@ -177,4 +204,7 @@ public:
virtual ~FileAccess() {}
};
+VARIANT_ENUM_CAST(FileAccess::CompressionMode);
+VARIANT_ENUM_CAST(FileAccess::ModeFlags);
+
#endif // FILE_ACCESS_H
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 1d0a718166..d2c8a88269 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -95,7 +95,7 @@ Error FileAccessCompressed::open_after_magic(Ref<FileAccess> p_base) {
return ret == -1 ? ERR_FILE_CORRUPT : OK;
}
-Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessCompressed::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags == READ_WRITE, ERR_UNAVAILABLE);
_close();
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index e41491a92c..ee114c2c65 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -70,7 +70,7 @@ public:
Error open_after_magic(Ref<FileAccess> p_base);
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index d1b014a0be..be502dacd9 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -111,7 +111,7 @@ Error FileAccessEncrypted::open_and_parse_password(Ref<FileAccess> p_base, const
return open_and_parse(p_base, key, p_mode);
}
-Error FileAccessEncrypted::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessEncrypted::open_internal(const String &p_path, int p_mode_flags) {
return OK;
}
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index 6200f87a7a..6b4588841d 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -60,7 +60,7 @@ public:
Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true);
Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual String get_path() const override; /// returns the path for the current open file
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index 499d001234..21ded4247f 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -78,7 +78,7 @@ Error FileAccessMemory::open_custom(const uint8_t *p_data, uint64_t p_len) {
return OK;
}
-Error FileAccessMemory::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessMemory::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(!files, ERR_FILE_NOT_FOUND);
String name = fix_path(p_path);
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index f2bd2aa832..b1f408eb98 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -45,7 +45,7 @@ public:
static void cleanup();
virtual Error open_custom(const uint8_t *p_data, uint64_t p_len); ///< open a file
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 1365b4b593..13730518bf 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -252,7 +252,7 @@ void FileAccessNetwork::_respond(uint64_t p_len, Error p_status) {
pages.resize(pc);
}
-Error FileAccessNetwork::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessNetwork::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags != READ, ERR_UNAVAILABLE);
_close();
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index ceadc715a1..ee92d3b9db 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -132,7 +132,7 @@ public:
RESPONSE_GET_MODTIME,
};
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index adae0db0f4..dfcce30ab5 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -259,7 +259,7 @@ Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::Pack
//////////////////////////////////////////////////////////////////
-Error FileAccessPack::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessPack::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_V(ERR_UNAVAILABLE);
return ERR_UNAVAILABLE;
}
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 023758ac0f..4b9b49a161 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -148,7 +148,7 @@ class FileAccessPack : public FileAccess {
uint64_t off;
Ref<FileAccess> f;
- virtual Error _open(const String &p_path, int p_mode_flags) override;
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override;
virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 17f2335a8e..2af6f370cf 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -234,7 +234,7 @@ ZipArchive::~ZipArchive() {
packages.clear();
}
-Error FileAccessZip::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessZip::open_internal(const String &p_path, int p_mode_flags) {
_close();
ERR_FAIL_COND_V(p_mode_flags & FileAccess::WRITE, FAILED);
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index 74a48192f3..6d61b9a291 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -85,7 +85,7 @@ class FileAccessZip : public FileAccess {
void _close();
public:
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index d09697b951..d6854666c0 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -32,6 +32,12 @@
#include "core/string/print_string.h"
+void ImageFormatLoader::_bind_methods() {
+ BIND_BITFIELD_FLAG(FLAG_NONE);
+ BIND_BITFIELD_FLAG(FLAG_FORCE_LINEAR);
+ BIND_BITFIELD_FLAG(FLAG_CONVERT_COLORS);
+}
+
bool ImageFormatLoader::recognize(const String &p_extension) const {
List<String> extensions;
get_recognized_extensions(&extensions);
@@ -44,7 +50,39 @@ bool ImageFormatLoader::recognize(const String &p_extension) const {
return false;
}
-Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, uint32_t p_flags, float p_scale) {
+Error ImageFormatLoaderExtension::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
+ Error err;
+ if (GDVIRTUAL_CALL(_load_image, p_image, p_fileaccess, p_flags, p_scale, err)) {
+ return err;
+ }
+ return ERR_UNAVAILABLE;
+}
+
+void ImageFormatLoaderExtension::get_recognized_extensions(List<String> *p_extension) const {
+ PackedStringArray ext;
+ if (GDVIRTUAL_CALL(_get_recognized_extensions, ext)) {
+ for (int i = 0; i < ext.size(); i++) {
+ p_extension->push_back(ext[i]);
+ }
+ }
+}
+
+void ImageFormatLoaderExtension::add_format_loader() {
+ ImageLoader::add_image_format_loader(this);
+}
+
+void ImageFormatLoaderExtension::remove_format_loader() {
+ ImageLoader::remove_image_format_loader(this);
+}
+
+void ImageFormatLoaderExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_recognized_extensions);
+ GDVIRTUAL_BIND(_load_image, "image", "fileaccess", "flags", "scale");
+ ClassDB::bind_method(D_METHOD("add_format_loader"), &ImageFormatLoaderExtension::add_format_loader);
+ ClassDB::bind_method(D_METHOD("remove_format_loader"), &ImageFormatLoaderExtension::remove_format_loader);
+}
+
+Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
ERR_FAIL_COND_V_MSG(p_image.is_null(), ERR_INVALID_PARAMETER, "It's not a reference to a valid Image object.");
Ref<FileAccess> f = p_custom;
@@ -60,7 +98,7 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess>
if (!loader[i]->recognize(extension)) {
continue;
}
- Error err = loader[i]->load_image(p_image, f, p_flags, p_scale);
+ Error err = loader.write[i]->load_image(p_image, f, p_flags, p_scale);
if (err != OK) {
ERR_PRINT("Error loading image: " + p_file);
}
@@ -79,7 +117,7 @@ void ImageLoader::get_recognized_extensions(List<String> *p_extensions) {
}
}
-ImageFormatLoader *ImageLoader::recognize(const String &p_extension) {
+Ref<ImageFormatLoader> ImageLoader::recognize(const String &p_extension) {
for (int i = 0; i < loader.size(); i++) {
if (loader[i]->recognize(p_extension)) {
return loader[i];
@@ -89,17 +127,17 @@ ImageFormatLoader *ImageLoader::recognize(const String &p_extension) {
return nullptr;
}
-Vector<ImageFormatLoader *> ImageLoader::loader;
+Vector<Ref<ImageFormatLoader>> ImageLoader::loader;
-void ImageLoader::add_image_format_loader(ImageFormatLoader *p_loader) {
+void ImageLoader::add_image_format_loader(Ref<ImageFormatLoader> p_loader) {
loader.push_back(p_loader);
}
-void ImageLoader::remove_image_format_loader(ImageFormatLoader *p_loader) {
+void ImageLoader::remove_image_format_loader(Ref<ImageFormatLoader> p_loader) {
loader.erase(p_loader);
}
-const Vector<ImageFormatLoader *> &ImageLoader::get_image_format_loaders() {
+const Vector<Ref<ImageFormatLoader>> &ImageLoader::get_image_format_loaders() {
return loader;
}
@@ -152,7 +190,7 @@ Ref<Resource> ResourceFormatLoaderImage::load(const String &p_path, const String
Ref<Image> image;
image.instantiate();
- Error err = ImageLoader::loader[idx]->load_image(image, f);
+ Error err = ImageLoader::loader.write[idx]->load_image(image, f);
if (err != OK) {
if (r_error) {
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index bf78005e40..f70fdf22aa 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -31,23 +31,23 @@
#ifndef IMAGE_LOADER_H
#define IMAGE_LOADER_H
+#include "core/core_bind.h"
#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/resource_loader.h"
+#include "core/object/gdvirtual.gen.inc"
#include "core/string/ustring.h"
#include "core/templates/list.h"
+#include "core/variant/binder_common.h"
class ImageLoader;
-class ImageFormatLoader {
+class ImageFormatLoader : public RefCounted {
+ GDCLASS(ImageFormatLoader, RefCounted);
+
friend class ImageLoader;
friend class ResourceFormatLoaderImage;
-protected:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags = (uint32_t)FLAG_NONE, float p_scale = 1.0) = 0;
- virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
- bool recognize(const String &p_extension) const;
-
public:
enum LoaderFlags {
FLAG_NONE = 0,
@@ -55,23 +55,50 @@ public:
FLAG_CONVERT_COLORS = 2,
};
+protected:
+ static void _bind_methods();
+
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags = FLAG_NONE, float p_scale = 1.0) = 0;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
+ bool recognize(const String &p_extension) const;
+
+public:
virtual ~ImageFormatLoader() {}
};
+VARIANT_BITFIELD_CAST(ImageFormatLoader::LoaderFlags);
+
+class ImageFormatLoaderExtension : public ImageFormatLoader {
+ GDCLASS(ImageFormatLoaderExtension, ImageFormatLoader);
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags = FLAG_NONE, float p_scale = 1.0) override;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+
+ void add_format_loader();
+ void remove_format_loader();
+
+ GDVIRTUAL0RC(PackedStringArray, _get_recognized_extensions);
+ GDVIRTUAL4R(Error, _load_image, Ref<Image>, Ref<FileAccess>, BitField<ImageFormatLoader::LoaderFlags>, float);
+};
+
class ImageLoader {
- static Vector<ImageFormatLoader *> loader;
+ static Vector<Ref<ImageFormatLoader>> loader;
friend class ResourceFormatLoaderImage;
protected:
public:
- static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), uint32_t p_flags = (uint32_t)ImageFormatLoader::FLAG_NONE, float p_scale = 1.0);
+ static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), BitField<ImageFormatLoader::LoaderFlags> p_flags = ImageFormatLoader::FLAG_NONE, float p_scale = 1.0);
static void get_recognized_extensions(List<String> *p_extensions);
- static ImageFormatLoader *recognize(const String &p_extension);
+ static Ref<ImageFormatLoader> recognize(const String &p_extension);
- static void add_image_format_loader(ImageFormatLoader *p_loader);
- static void remove_image_format_loader(ImageFormatLoader *p_loader);
+ static void add_image_format_loader(Ref<ImageFormatLoader> p_loader);
+ static void remove_image_format_loader(Ref<ImageFormatLoader> p_loader);
- static const Vector<ImageFormatLoader *> &get_image_format_loaders();
+ static const Vector<Ref<ImageFormatLoader>> &get_image_format_loaders();
static void cleanup();
};
diff --git a/core/io/json.cpp b/core/io/json.cpp
index 91500ff3d5..7e267d35d4 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -56,6 +56,8 @@ String JSON::_make_indent(const String &p_indent, int p_size) {
}
String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision) {
+ ERR_FAIL_COND_V_MSG(p_cur_indent > Variant::MAX_RECURSION_DEPTH, "...", "JSON structure is too deep. Bailing.");
+
String colon = ":";
String end_statement = "";
@@ -357,17 +359,22 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to
return ERR_PARSE_ERROR;
}
-Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
+ if (p_depth > Variant::MAX_RECURSION_DEPTH) {
+ r_err_str = "JSON structure is too deep. Bailing.";
+ return ERR_OUT_OF_MEMORY;
+ }
+
if (token.type == TK_CURLY_BRACKET_OPEN) {
Dictionary d;
- Error err = _parse_object(d, p_str, index, p_len, line, r_err_str);
+ Error err = _parse_object(d, p_str, index, p_len, line, p_depth + 1, r_err_str);
if (err) {
return err;
}
value = d;
} else if (token.type == TK_BRACKET_OPEN) {
Array a;
- Error err = _parse_array(a, p_str, index, p_len, line, r_err_str);
+ Error err = _parse_array(a, p_str, index, p_len, line, p_depth + 1, r_err_str);
if (err) {
return err;
}
@@ -396,7 +403,7 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in
return OK;
}
-Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
Token token;
bool need_comma = false;
@@ -421,7 +428,7 @@ Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_
}
Variant v;
- err = _parse_value(v, token, p_str, index, p_len, line, r_err_str);
+ err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str);
if (err) {
return err;
}
@@ -434,7 +441,7 @@ Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_
return ERR_PARSE_ERROR;
}
-Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
bool at_key = true;
String key;
Token token;
@@ -483,7 +490,7 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index,
}
Variant v;
- err = _parse_value(v, token, p_str, index, p_len, line, r_err_str);
+ err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str);
if (err) {
return err;
}
@@ -497,6 +504,10 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index,
return ERR_PARSE_ERROR;
}
+void JSON::set_data(const Variant &p_data) {
+ data = p_data;
+}
+
Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) {
const char32_t *str = p_json.ptr();
int idx = 0;
@@ -510,7 +521,7 @@ Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_st
return err;
}
- err = _parse_value(r_ret, token, str, idx, len, r_err_line, r_err_str);
+ err = _parse_value(r_ret, token, str, idx, len, r_err_line, 0, r_err_str);
// Check if EOF is reached
// or it's a type of the next token.
@@ -557,6 +568,88 @@ void JSON::_bind_methods() {
ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse);
ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data);
+ ClassDB::bind_method(D_METHOD("set_data", "data"), &JSON::set_data);
ClassDB::bind_method(D_METHOD("get_error_line"), &JSON::get_error_line);
ClassDB::bind_method(D_METHOD("get_error_message"), &JSON::get_error_message);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NIL, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), "set_data", "get_data"); // Ensures that it can be serialized as binary.
+}
+
+////
+
+////////////
+
+Ref<Resource> ResourceFormatLoaderJSON::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ if (r_error) {
+ *r_error = ERR_FILE_CANT_OPEN;
+ }
+
+ if (!FileAccess::exists(p_path)) {
+ *r_error = ERR_FILE_NOT_FOUND;
+ return Ref<Resource>();
+ }
+
+ Ref<JSON> json;
+ json.instantiate();
+
+ Error err = json->parse(FileAccess::get_file_as_string(p_path));
+ if (err != OK) {
+ if (r_error) {
+ *r_error = err;
+ }
+ ERR_PRINT("Error parsing JSON file at '" + p_path + "', on line " + itos(json->get_error_line()) + ": " + json->get_error_message());
+ return Ref<Resource>();
+ }
+
+ if (r_error) {
+ *r_error = OK;
+ }
+
+ return json;
+}
+
+void ResourceFormatLoaderJSON::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("json");
+}
+
+bool ResourceFormatLoaderJSON::handles_type(const String &p_type) const {
+ return (p_type == "JSON");
+}
+
+String ResourceFormatLoaderJSON::get_resource_type(const String &p_path) const {
+ String el = p_path.get_extension().to_lower();
+ if (el == "json") {
+ return "JSON";
+ }
+ return "";
+}
+
+Error ResourceFormatSaverJSON::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
+ Ref<JSON> json = p_resource;
+ ERR_FAIL_COND_V(json.is_null(), ERR_INVALID_PARAMETER);
+
+ String source = JSON::stringify(json->get_data(), "\t", false, true);
+
+ Error err;
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+
+ ERR_FAIL_COND_V_MSG(err, err, "Cannot save json '" + p_path + "'.");
+
+ file->store_string(source);
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ return ERR_CANT_CREATE;
+ }
+
+ return OK;
+}
+
+void ResourceFormatSaverJSON::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
+ Ref<JSON> json = p_resource;
+ if (json.is_valid()) {
+ p_extensions->push_back("json");
+ }
+}
+
+bool ResourceFormatSaverJSON::recognize(const Ref<Resource> &p_resource) const {
+ return p_resource->get_class_name() == "JSON"; //only json, not inherited
}
diff --git a/core/io/json.h b/core/io/json.h
index 840b1cc08a..829a5f922b 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -31,7 +31,9 @@
#ifndef JSON_H
#define JSON_H
-#include "core/object/ref_counted.h"
+#include "core/io/resource.h"
+#include "core/io/resource_loader.h"
+#include "core/io/resource_saver.h"
#include "core/variant/variant.h"
class JSON : public RefCounted {
@@ -72,9 +74,9 @@ class JSON : public RefCounted {
static String _make_indent(const String &p_indent, int p_size);
static String _stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision = false);
static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str);
- static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
- static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
- static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
+ static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str);
+ static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str);
+ static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str);
static Error _parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line);
protected:
@@ -86,8 +88,24 @@ public:
static Variant parse_string(const String &p_json_string);
inline Variant get_data() const { return data; }
+ void set_data(const Variant &p_data);
inline int get_error_line() const { return err_line; }
inline String get_error_message() const { return err_str; }
};
+class ResourceFormatLoaderJSON : public ResourceFormatLoader {
+public:
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+class ResourceFormatSaverJSON : public ResourceFormatSaver {
+public:
+ virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0);
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize(const Ref<Resource> &p_resource) const;
+};
+
#endif // JSON_H
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 553698f8a6..ab30fb1ca3 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -489,7 +489,7 @@ bool ResourceCache::has(const String &p_path) {
Resource **res = resources.getptr(p_path);
- if (res && (*res)->reference_get_count() == 0) {
+ if (res && (*res)->get_reference_count() == 0) {
// This resource is in the process of being deleted, ignore its existence.
(*res)->path_cache = String();
resources.erase(p_path);
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 4f1204fc48..06649aba5b 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1206,7 +1206,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
Ref<FileAccessCompressed> facw;
facw.instantiate();
facw->configure("RSCC");
- err = facw->_open(p_path + ".depren", FileAccess::WRITE);
+ err = facw->open_internal(p_path + ".depren", FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(err, ERR_FILE_CORRUPT, "Cannot create file '" + p_path + ".depren'.");
fw = facw;
@@ -1986,7 +1986,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re
fac.instantiate();
fac->configure("RSCC");
f = fac;
- err = fac->_open(p_path, FileAccess::WRITE);
+ err = fac->open_internal(p_path, FileAccess::WRITE);
} else {
f = FileAccess::open(p_path, FileAccess::WRITE, &err);
}
diff --git a/core/io/stream_peer_gzip.cpp b/core/io/stream_peer_gzip.cpp
new file mode 100644
index 0000000000..ca8be2d62e
--- /dev/null
+++ b/core/io/stream_peer_gzip.cpp
@@ -0,0 +1,209 @@
+/*************************************************************************/
+/* stream_peer_gzip.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "core/io/stream_peer_gzip.h"
+
+#include "core/io/zip_io.h"
+#include <zlib.h>
+
+void StreamPeerGZIP::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("start_compression", "use_deflate", "buffer_size"), &StreamPeerGZIP::start_compression, DEFVAL(false), DEFVAL(65535));
+ ClassDB::bind_method(D_METHOD("start_decompression", "use_deflate", "buffer_size"), &StreamPeerGZIP::start_decompression, DEFVAL(false), DEFVAL(65535));
+ ClassDB::bind_method(D_METHOD("finish"), &StreamPeerGZIP::finish);
+ ClassDB::bind_method(D_METHOD("clear"), &StreamPeerGZIP::clear);
+}
+
+StreamPeerGZIP::StreamPeerGZIP() {
+}
+
+StreamPeerGZIP::~StreamPeerGZIP() {
+ _close();
+}
+
+void StreamPeerGZIP::_close() {
+ if (ctx) {
+ z_stream *strm = (z_stream *)ctx;
+ if (compressing) {
+ deflateEnd(strm);
+ } else {
+ inflateEnd(strm);
+ }
+ memfree(strm);
+ ctx = nullptr;
+ }
+}
+
+void StreamPeerGZIP::clear() {
+ _close();
+ rb.clear();
+ buffer.clear();
+}
+
+Error StreamPeerGZIP::start_compression(bool p_is_deflate, int buffer_size) {
+ return _start(true, p_is_deflate, buffer_size);
+}
+
+Error StreamPeerGZIP::start_decompression(bool p_is_deflate, int buffer_size) {
+ return _start(false, p_is_deflate, buffer_size);
+}
+
+Error StreamPeerGZIP::_start(bool p_compress, bool p_is_deflate, int buffer_size) {
+ ERR_FAIL_COND_V(ctx != nullptr, ERR_ALREADY_IN_USE);
+ clear();
+ compressing = p_compress;
+ rb.resize(nearest_shift(buffer_size - 1));
+ buffer.resize(1024);
+
+ // Create ctx.
+ ctx = memalloc(sizeof(z_stream));
+ z_stream &strm = *(z_stream *)ctx;
+ strm.next_in = Z_NULL;
+ strm.avail_in = 0;
+ strm.zalloc = zipio_alloc;
+ strm.zfree = zipio_free;
+ strm.opaque = Z_NULL;
+ int window_bits = p_is_deflate ? 15 : (15 + 16);
+ int err = Z_OK;
+ int level = Z_DEFAULT_COMPRESSION;
+ if (compressing) {
+ err = deflateInit2(&strm, level, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
+ } else {
+ err = inflateInit2(&strm, window_bits);
+ }
+ ERR_FAIL_COND_V(err != Z_OK, FAILED);
+ return OK;
+}
+
+Error StreamPeerGZIP::_process(uint8_t *p_dst, int p_dst_size, const uint8_t *p_src, int p_src_size, int &r_consumed, int &r_out, bool p_close) {
+ ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED);
+ z_stream &strm = *(z_stream *)ctx;
+ strm.avail_in = p_src_size;
+ strm.avail_out = p_dst_size;
+ strm.next_in = (Bytef *)p_src;
+ strm.next_out = (Bytef *)p_dst;
+ int flush = p_close ? Z_FINISH : Z_NO_FLUSH;
+ if (compressing) {
+ int err = deflate(&strm, flush);
+ ERR_FAIL_COND_V(err != (p_close ? Z_STREAM_END : Z_OK), FAILED);
+ } else {
+ int err = inflate(&strm, flush);
+ ERR_FAIL_COND_V(err != Z_OK && err != Z_STREAM_END, FAILED);
+ }
+ r_out = p_dst_size - strm.avail_out;
+ r_consumed = p_src_size - strm.avail_in;
+ return OK;
+}
+
+Error StreamPeerGZIP::put_data(const uint8_t *p_data, int p_bytes) {
+ int wrote = 0;
+ Error err = put_partial_data(p_data, p_bytes, wrote);
+ if (err != OK) {
+ return err;
+ }
+ ERR_FAIL_COND_V(p_bytes != wrote, ERR_OUT_OF_MEMORY);
+ return OK;
+}
+
+Error StreamPeerGZIP::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
+ ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(p_bytes < 0, ERR_INVALID_PARAMETER);
+
+ // Ensure we have enough space in temporary buffer.
+ if (buffer.size() < p_bytes) {
+ buffer.resize(p_bytes);
+ }
+
+ r_sent = 0;
+ while (r_sent < p_bytes && rb.space_left() > 1024) { // Keep the ring buffer size meaningful.
+ int sent = 0;
+ int to_write = 0;
+ // Compress or decompress
+ Error err = _process(buffer.ptrw(), MIN(buffer.size(), rb.space_left()), p_data + r_sent, p_bytes - r_sent, sent, to_write);
+ if (err != OK) {
+ return err;
+ }
+ // When decompressing, we might need to do another round.
+ r_sent += sent;
+
+ // We can't write more than this buffer is full.
+ if (sent == 0 && to_write == 0) {
+ return OK;
+ }
+ if (to_write) {
+ // Copy to ring buffer.
+ int wrote = rb.write(buffer.ptr(), to_write);
+ ERR_FAIL_COND_V(wrote != to_write, ERR_BUG);
+ }
+ }
+ return OK;
+}
+
+Error StreamPeerGZIP::get_data(uint8_t *p_buffer, int p_bytes) {
+ int received = 0;
+ Error err = get_partial_data(p_buffer, p_bytes, received);
+ if (err != OK) {
+ return err;
+ }
+ ERR_FAIL_COND_V(p_bytes != received, ERR_UNAVAILABLE);
+ return OK;
+}
+
+Error StreamPeerGZIP::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) {
+ ERR_FAIL_COND_V(p_bytes < 0, ERR_INVALID_PARAMETER);
+
+ r_received = MIN(p_bytes, rb.data_left());
+ if (r_received == 0) {
+ return OK;
+ }
+ int received = rb.read(p_buffer, r_received);
+ ERR_FAIL_COND_V(received != r_received, ERR_BUG);
+ return OK;
+}
+
+int StreamPeerGZIP::get_available_bytes() const {
+ return rb.data_left();
+}
+
+Error StreamPeerGZIP::finish() {
+ ERR_FAIL_COND_V(!ctx || !compressing, ERR_UNAVAILABLE);
+ // Ensure we have enough space in temporary buffer.
+ if (buffer.size() < 1024) {
+ buffer.resize(1024); // 1024 should be more than enough.
+ }
+ int consumed = 0;
+ int to_write = 0;
+ Error err = _process(buffer.ptrw(), 1024, nullptr, 0, consumed, to_write, true); // compress
+ if (err != OK) {
+ return err;
+ }
+ int wrote = rb.write(buffer.ptr(), to_write);
+ ERR_FAIL_COND_V(wrote != to_write, ERR_OUT_OF_MEMORY);
+ return OK;
+}
diff --git a/core/io/stream_peer_gzip.h b/core/io/stream_peer_gzip.h
new file mode 100644
index 0000000000..5bafdbca9b
--- /dev/null
+++ b/core/io/stream_peer_gzip.h
@@ -0,0 +1,76 @@
+/*************************************************************************/
+/* stream_peer_gzip.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef STREAM_PEER_GZIP_H
+#define STREAM_PEER_GZIP_H
+
+#include "core/io/stream_peer.h"
+
+#include "core/core_bind.h"
+#include "core/io/compression.h"
+#include "core/templates/ring_buffer.h"
+
+class StreamPeerGZIP : public StreamPeer {
+ GDCLASS(StreamPeerGZIP, StreamPeer);
+
+private:
+ void *ctx = nullptr; // Will hold our z_stream instance.
+ bool compressing = true;
+
+ RingBuffer<uint8_t> rb;
+ Vector<uint8_t> buffer;
+
+ Error _process(uint8_t *p_dst, int p_dst_size, const uint8_t *p_src, int p_src_size, int &r_consumed, int &r_out, bool p_close = false);
+ void _close();
+ Error _start(bool p_compress, bool p_is_deflate, int buffer_size = 65535);
+
+protected:
+ static void _bind_methods();
+
+public:
+ Error start_compression(bool p_is_deflate, int buffer_size = 65535);
+ Error start_decompression(bool p_is_deflate, int buffer_size = 65535);
+
+ Error finish();
+ void clear();
+
+ virtual Error put_data(const uint8_t *p_data, int p_bytes) override;
+ virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override;
+
+ virtual Error get_data(uint8_t *p_buffer, int p_bytes) override;
+ virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override;
+
+ virtual int get_available_bytes() const override;
+
+ StreamPeerGZIP();
+ ~StreamPeerGZIP();
+};
+
+#endif // STREAM_PEER_GZIP_H
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 0eb6320ac6..4b163409ce 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -754,29 +754,28 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND(!is_rotation());
#endif
-*/
- real_t angle, x, y, z; // variables for result
- real_t angle_epsilon = 0.1; // margin to distinguish between 0 and 180 degrees
-
- if ((Math::abs(rows[1][0] - rows[0][1]) < CMP_EPSILON) && (Math::abs(rows[2][0] - rows[0][2]) < CMP_EPSILON) && (Math::abs(rows[2][1] - rows[1][2]) < CMP_EPSILON)) {
- // singularity found
- // first check for identity matrix which must have +1 for all terms
- // in leading diagonal and zero in other terms
- if ((Math::abs(rows[1][0] + rows[0][1]) < angle_epsilon) && (Math::abs(rows[2][0] + rows[0][2]) < angle_epsilon) && (Math::abs(rows[2][1] + rows[1][2]) < angle_epsilon) && (Math::abs(rows[0][0] + rows[1][1] + rows[2][2] - 3) < angle_epsilon)) {
- // this singularity is identity matrix so angle = 0
+ */
+
+ // https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
+ real_t x, y, z; // Variables for result.
+ if (Math::is_zero_approx(rows[0][1] - rows[1][0]) && Math::is_zero_approx(rows[0][2] - rows[2][0]) && Math::is_zero_approx(rows[1][2] - rows[2][1])) {
+ // Singularity found.
+ // First check for identity matrix which must have +1 for all terms in leading diagonal and zero in other terms.
+ if (is_diagonal() && (Math::abs(rows[0][0] + rows[1][1] + rows[2][2] - 3) < 3 * CMP_EPSILON)) {
+ // This singularity is identity matrix so angle = 0.
r_axis = Vector3(0, 1, 0);
r_angle = 0;
return;
}
- // otherwise this singularity is angle = 180
- angle = Math_PI;
+ // Otherwise this singularity is angle = 180.
real_t xx = (rows[0][0] + 1) / 2;
real_t yy = (rows[1][1] + 1) / 2;
real_t zz = (rows[2][2] + 1) / 2;
- real_t xy = (rows[1][0] + rows[0][1]) / 4;
- real_t xz = (rows[2][0] + rows[0][2]) / 4;
- real_t yz = (rows[2][1] + rows[1][2]) / 4;
- if ((xx > yy) && (xx > zz)) { // rows[0][0] is the largest diagonal term
+ real_t xy = (rows[0][1] + rows[1][0]) / 4;
+ real_t xz = (rows[0][2] + rows[2][0]) / 4;
+ real_t yz = (rows[1][2] + rows[2][1]) / 4;
+
+ if ((xx > yy) && (xx > zz)) { // rows[0][0] is the largest diagonal term.
if (xx < CMP_EPSILON) {
x = 0;
y = Math_SQRT12;
@@ -786,7 +785,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
y = xy / x;
z = xz / x;
}
- } else if (yy > zz) { // rows[1][1] is the largest diagonal term
+ } else if (yy > zz) { // rows[1][1] is the largest diagonal term.
if (yy < CMP_EPSILON) {
x = Math_SQRT12;
y = 0;
@@ -796,7 +795,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
x = xy / y;
z = yz / y;
}
- } else { // rows[2][2] is the largest diagonal term so base result on this
+ } else { // rows[2][2] is the largest diagonal term so base result on this.
if (zz < CMP_EPSILON) {
x = Math_SQRT12;
y = Math_SQRT12;
@@ -808,22 +807,24 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
}
}
r_axis = Vector3(x, y, z);
- r_angle = angle;
+ r_angle = Math_PI;
return;
}
- // as we have reached here there are no singularities so we can handle normally
- real_t s = Math::sqrt((rows[1][2] - rows[2][1]) * (rows[1][2] - rows[2][1]) + (rows[2][0] - rows[0][2]) * (rows[2][0] - rows[0][2]) + (rows[0][1] - rows[1][0]) * (rows[0][1] - rows[1][0])); // s=|axis||sin(angle)|, used to normalise
+ // As we have reached here there are no singularities so we can handle normally.
+ double s = Math::sqrt((rows[2][1] - rows[1][2]) * (rows[2][1] - rows[1][2]) + (rows[0][2] - rows[2][0]) * (rows[0][2] - rows[2][0]) + (rows[1][0] - rows[0][1]) * (rows[1][0] - rows[0][1])); // Used to normalise.
- angle = Math::acos((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2);
- if (angle < 0) {
- s = -s;
+ if (Math::abs(s) < CMP_EPSILON) {
+ // Prevent divide by zero, should not happen if matrix is orthogonal and should be caught by singularity test above.
+ s = 1;
}
+
x = (rows[2][1] - rows[1][2]) / s;
y = (rows[0][2] - rows[2][0]) / s;
z = (rows[1][0] - rows[0][1]) / s;
r_axis = Vector3(x, y, z);
- r_angle = angle;
+ // CLAMP to avoid NaN if the value passed to acos is not in [0,1].
+ r_angle = Math::acos(CLAMP((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2, (real_t)0.0, (real_t)1.0));
}
void Basis::set_quaternion(const Quaternion &p_quaternion) {
diff --git a/core/math/bvh_structs.inc b/core/math/bvh_structs.inc
index 58c8f0479a..06f6e5d05d 100644
--- a/core/math/bvh_structs.inc
+++ b/core/math/bvh_structs.inc
@@ -100,7 +100,11 @@ public:
num_items++;
return id;
}
+#ifdef DEV_ENABLED
return -1;
+#else
+ ERR_FAIL_V_MSG(0, "BVH request_item error.");
+#endif
}
};
diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp
index 208f89f449..f36b228543 100644
--- a/core/math/math_fieldwise.cpp
+++ b/core/math/math_fieldwise.cpp
@@ -76,6 +76,7 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+
case Variant::VECTOR3I: {
SETUP_TYPE(Vector3i)
@@ -85,6 +86,7 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+
case Variant::VECTOR4: {
SETUP_TYPE(Vector4)
@@ -95,6 +97,7 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+
case Variant::VECTOR4I: {
SETUP_TYPE(Vector4i)
@@ -106,7 +109,6 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
-
case Variant::PLANE: {
SETUP_TYPE(Plane)
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 656fc9f798..7fa674a23d 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -267,6 +267,7 @@ public:
return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
}
+
static _ALWAYS_INLINE_ float cubic_interpolate_angle(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
float from_rot = fmod(p_from, (float)Math_TAU);
@@ -293,6 +294,7 @@ public:
double b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0 : t / p_post_t);
return Math::lerp(b1, b2, p_to_t == 0 ? 0.5 : t / p_to_t);
}
+
static _ALWAYS_INLINE_ float cubic_interpolate_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
float p_to_t, float p_pre_t, float p_post_t) {
/* Barry-Goldman method */
@@ -320,6 +322,7 @@ public:
return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
}
+
static _ALWAYS_INLINE_ float cubic_interpolate_angle_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
float p_to_t, float p_pre_t, float p_post_t) {
float from_rot = fmod(p_from, (float)Math_TAU);
@@ -346,6 +349,7 @@ public:
return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
}
+
static _ALWAYS_INLINE_ float bezier_interpolate(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) {
/* Formula from Wikipedia article on Bezier curves. */
float omt = (1.0f - p_t);
@@ -368,11 +372,19 @@ public:
return p_from + distance * p_weight;
}
- static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) { return (p_value - p_from) / (p_to - p_from); }
- static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) { return (p_value - p_from) / (p_to - p_from); }
+ static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) {
+ return (p_value - p_from) / (p_to - p_from);
+ }
+ static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) {
+ return (p_value - p_from) / (p_to - p_from);
+ }
- static _ALWAYS_INLINE_ double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
- static _ALWAYS_INLINE_ float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
+ static _ALWAYS_INLINE_ double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) {
+ return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
+ }
+ static _ALWAYS_INLINE_ float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) {
+ return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
+ }
static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) {
if (is_equal_approx(p_from, p_to)) {
@@ -388,14 +400,26 @@ public:
float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f);
return s * s * (3.0f - 2.0f * s);
}
- static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; }
- static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; }
+ static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) {
+ return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta;
+ }
+ static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) {
+ return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta;
+ }
- static _ALWAYS_INLINE_ double linear_to_db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
- static _ALWAYS_INLINE_ float linear_to_db(float p_linear) { return Math::log(p_linear) * (float)8.6858896380650365530225783783321; }
+ static _ALWAYS_INLINE_ double linear_to_db(double p_linear) {
+ return Math::log(p_linear) * 8.6858896380650365530225783783321;
+ }
+ static _ALWAYS_INLINE_ float linear_to_db(float p_linear) {
+ return Math::log(p_linear) * (float)8.6858896380650365530225783783321;
+ }
- static _ALWAYS_INLINE_ double db_to_linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
- static _ALWAYS_INLINE_ float db_to_linear(float p_db) { return Math::exp(p_db * (float)0.11512925464970228420089957273422); }
+ static _ALWAYS_INLINE_ double db_to_linear(double p_db) {
+ return Math::exp(p_db * 0.11512925464970228420089957273422);
+ }
+ static _ALWAYS_INLINE_ float db_to_linear(float p_db) {
+ return Math::exp(p_db * (float)0.11512925464970228420089957273422);
+ }
static _ALWAYS_INLINE_ double round(double p_val) { return ::round(p_val); }
static _ALWAYS_INLINE_ float round(float p_val) { return ::roundf(p_val); }
diff --git a/core/math/vector2i.h b/core/math/vector2i.h
index 0245900a3b..e131bdea94 100644
--- a/core/math/vector2i.h
+++ b/core/math/vector2i.h
@@ -38,6 +38,8 @@ class String;
struct Vector2;
struct _NO_DISCARD_ Vector2i {
+ static const int AXIS_COUNT = 2;
+
enum Axis {
AXIS_X,
AXIS_Y,
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
index 825ce40318..c6d03cd031 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -38,6 +38,8 @@ class String;
struct Vector3;
struct _NO_DISCARD_ Vector3i {
+ static const int AXIS_COUNT = 3;
+
enum Axis {
AXIS_X,
AXIS_Y,
diff --git a/core/math/vector4.h b/core/math/vector4.h
index f964264108..d89f3ddb05 100644
--- a/core/math/vector4.h
+++ b/core/math/vector4.h
@@ -37,6 +37,8 @@
#include "core/string/ustring.h"
struct _NO_DISCARD_ Vector4 {
+ static const int AXIS_COUNT = 4;
+
enum Axis {
AXIS_X,
AXIS_Y,
diff --git a/core/math/vector4i.h b/core/math/vector4i.h
index d08e40d754..fdf33b9569 100644
--- a/core/math/vector4i.h
+++ b/core/math/vector4i.h
@@ -38,6 +38,8 @@ class String;
struct Vector4;
struct _NO_DISCARD_ Vector4i {
+ static const int AXIS_COUNT = 4;
+
enum Axis {
AXIS_X,
AXIS_Y,
diff --git a/core/object/ref_counted.cpp b/core/object/ref_counted.cpp
index cac2400744..50467d795d 100644
--- a/core/object/ref_counted.cpp
+++ b/core/object/ref_counted.cpp
@@ -48,9 +48,10 @@ void RefCounted::_bind_methods() {
ClassDB::bind_method(D_METHOD("init_ref"), &RefCounted::init_ref);
ClassDB::bind_method(D_METHOD("reference"), &RefCounted::reference);
ClassDB::bind_method(D_METHOD("unreference"), &RefCounted::unreference);
+ ClassDB::bind_method(D_METHOD("get_reference_count"), &RefCounted::get_reference_count);
}
-int RefCounted::reference_get_count() const {
+int RefCounted::get_reference_count() const {
return refcount.get();
}
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index bd06a84bd8..71790fb825 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -47,7 +47,7 @@ public:
bool init_ref();
bool reference(); // returns false if refcount is at zero and didn't get increased
bool unreference();
- int reference_get_count() const;
+ int get_reference_count() const;
RefCounted();
~RefCounted() {}
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index d3c48853f1..aa66e86bc0 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -126,27 +126,28 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
force_keep_in_merge_ends = false;
}
-void UndoRedo::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
- ERR_FAIL_COND(p_object == nullptr);
+void UndoRedo::add_do_method(const Callable &p_callable) {
+ ERR_FAIL_COND(p_callable.is_null());
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
+
+ Object *object = p_callable.get_object();
+ ERR_FAIL_NULL(object);
+
Operation do_op;
- do_op.object = p_object->get_instance_id();
- if (Object::cast_to<RefCounted>(p_object)) {
- do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
+ do_op.callable = p_callable;
+ do_op.object = p_callable.get_object_id();
+ if (Object::cast_to<RefCounted>(object)) {
+ do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(object));
}
-
do_op.type = Operation::TYPE_METHOD;
- do_op.name = p_method;
+ do_op.name = p_callable.get_method();
- for (int i = 0; i < p_argcount; i++) {
- do_op.args.push_back(*p_args[i]);
- }
actions.write[current_action + 1].do_ops.push_back(do_op);
}
-void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
- ERR_FAIL_COND(p_object == nullptr);
+void UndoRedo::add_undo_method(const Callable &p_callable) {
+ ERR_FAIL_COND(p_callable.is_null());
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -155,19 +156,19 @@ void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, co
return;
}
+ Object *object = p_callable.get_object();
+ ERR_FAIL_NULL(object);
+
Operation undo_op;
- undo_op.object = p_object->get_instance_id();
- if (Object::cast_to<RefCounted>(p_object)) {
- undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
+ undo_op.callable = p_callable;
+ undo_op.object = p_callable.get_object_id();
+ if (Object::cast_to<RefCounted>(object)) {
+ undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(object));
}
-
undo_op.type = Operation::TYPE_METHOD;
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
- undo_op.name = p_method;
+ undo_op.name = p_callable.get_method();
- for (int i = 0; i < p_argcount; i++) {
- undo_op.args.push_back(*p_args[i]);
- }
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}
@@ -183,7 +184,7 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c
do_op.type = Operation::TYPE_PROPERTY;
do_op.name = p_property;
- do_op.args.push_back(p_value);
+ do_op.value = p_value;
actions.write[current_action + 1].do_ops.push_back(do_op);
}
@@ -206,7 +207,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property,
undo_op.type = Operation::TYPE_PROPERTY;
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
undo_op.name = p_property;
- undo_op.args.push_back(p_value);
+ undo_op.value = p_value;
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}
@@ -312,33 +313,42 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
switch (op.type) {
case Operation::TYPE_METHOD: {
- int argc = op.args.size();
- Vector<const Variant *> argptrs;
- argptrs.resize(argc);
-
- for (int i = 0; i < argc; i++) {
- argptrs.write[i] = &op.args[i];
- }
-
Callable::CallError ce;
- obj->callp(op.name, (const Variant **)argptrs.ptr(), argc, ce);
+ Variant ret;
+ op.callable.callp(nullptr, 0, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce));
+ ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, nullptr, 0, ce));
}
#ifdef TOOLS_ENABLED
Resource *res = Object::cast_to<Resource>(obj);
if (res) {
res->set_edited(true);
}
-
#endif
if (method_callback) {
- method_callback(method_callback_ud, obj, op.name, (const Variant **)argptrs.ptr(), argc);
+ Vector<Variant> binds;
+ if (op.callable.is_custom()) {
+ CallableCustomBind *ccb = dynamic_cast<CallableCustomBind *>(op.callable.get_custom());
+ if (ccb) {
+ binds = ccb->get_binds();
+ }
+ }
+
+ if (binds.is_empty()) {
+ method_callback(method_callback_ud, obj, op.name, nullptr, 0);
+ } else {
+ const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * binds.size());
+ for (int i = 0; i < binds.size(); i++) {
+ args[i] = (const Variant *)&binds[i];
+ }
+
+ method_callback(method_callback_ud, obj, op.name, args, binds.size());
+ }
}
} break;
case Operation::TYPE_PROPERTY: {
- obj->set(op.name, op.args[0]);
+ obj->set(op.name, op.value);
#ifdef TOOLS_ENABLED
Resource *res = Object::cast_to<Resource>(obj);
if (res) {
@@ -346,7 +356,7 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
}
#endif
if (property_callback) {
- property_callback(prop_callback_ud, obj, op.name, op.args[0]);
+ property_callback(prop_callback_ud, obj, op.name, op.value);
}
} break;
case Operation::TYPE_REFERENCE: {
@@ -444,87 +454,13 @@ UndoRedo::~UndoRedo() {
clear_history();
}
-void UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (p_argcount < 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 0;
- return;
- }
-
- if (p_args[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- return;
- }
-
- if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::STRING_NAME;
- return;
- }
-
- r_error.error = Callable::CallError::CALL_OK;
-
- Object *object = *p_args[0];
- StringName method = *p_args[1];
-
- add_do_methodp(object, method, p_args + 2, p_argcount - 2);
-}
-
-void UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (p_argcount < 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 0;
- return;
- }
-
- if (p_args[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- return;
- }
-
- if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::STRING_NAME;
- return;
- }
-
- r_error.error = Callable::CallError::CALL_OK;
-
- Object *object = *p_args[0];
- StringName method = *p_args[1];
-
- add_undo_methodp(object, method, p_args + 2, p_argcount - 2);
-}
-
void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE));
ClassDB::bind_method(D_METHOD("commit_action", "execute"), &UndoRedo::commit_action, DEFVAL(true));
ClassDB::bind_method(D_METHOD("is_committing_action"), &UndoRedo::is_committing_action);
- {
- MethodInfo mi;
- mi.name = "add_do_method";
- mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
- mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
-
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_do_method", &UndoRedo::_add_do_method, mi, varray(), false);
- }
-
- {
- MethodInfo mi;
- mi.name = "add_undo_method";
- mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
- mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
-
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_undo_method", &UndoRedo::_add_undo_method, mi, varray(), false);
- }
-
+ ClassDB::bind_method(D_METHOD("add_do_method", "callable"), &UndoRedo::add_do_method);
+ ClassDB::bind_method(D_METHOD("add_undo_method", "callable"), &UndoRedo::add_undo_method);
ClassDB::bind_method(D_METHOD("add_do_property", "object", "property", "value"), &UndoRedo::add_do_property);
ClassDB::bind_method(D_METHOD("add_undo_property", "object", "property", "value"), &UndoRedo::add_undo_property);
ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &UndoRedo::add_do_reference);
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index 63cf3e5cbe..c7c58697c3 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -46,8 +46,6 @@ public:
};
typedef void (*CommitNotifyCallback)(void *p_ud, const String &p_name);
- void _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- void _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount);
typedef void (*PropertyNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value);
@@ -58,14 +56,14 @@ private:
TYPE_METHOD,
TYPE_PROPERTY,
TYPE_REFERENCE
- };
+ } type;
- Type type;
bool force_keep_in_merge_ends;
Ref<RefCounted> ref;
ObjectID object;
StringName name;
- Vector<Variant> args;
+ Callable callable;
+ Variant value;
void delete_reference();
};
@@ -106,30 +104,8 @@ protected:
public:
void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE);
- void add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
- void add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
-
- template <typename... VarArgs>
- void add_do_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
- Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
- const Variant *argptrs[sizeof...(p_args) + 1];
- for (uint32_t i = 0; i < sizeof...(p_args); i++) {
- argptrs[i] = &args[i];
- }
-
- add_do_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
- }
- template <typename... VarArgs>
- void add_undo_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
- Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
- const Variant *argptrs[sizeof...(p_args) + 1];
- for (uint32_t i = 0; i < sizeof...(p_args); i++) {
- argptrs[i] = &args[i];
- }
-
- add_undo_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
- }
-
+ void add_do_method(const Callable &p_callable);
+ void add_undo_method(const Callable &p_callable);
void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value);
void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value);
void add_do_reference(Object *p_object);
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 526b31ae7e..ee8da21751 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -54,10 +54,6 @@ double OS::get_unix_time() const {
return 0;
}
-void OS::debug_break() {
- // something
-}
-
void OS::_set_logger(CompositeLogger *p_logger) {
if (_logger) {
memdelete(_logger);
diff --git a/core/os/os.h b/core/os/os.h
index 363697ea30..aa45a3b8a8 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -69,6 +69,7 @@ class OS {
// so we can retrieve the rendering drivers available
int _display_driver_id = -1;
String _current_rendering_driver_name;
+ String _current_rendering_method;
protected:
void _set_logger(CompositeLogger *p_logger);
@@ -98,6 +99,8 @@ protected:
virtual void initialize_joypads() = 0;
void set_current_rendering_driver_name(String p_driver_name) { _current_rendering_driver_name = p_driver_name; }
+ void set_current_rendering_method(String p_name) { _current_rendering_method = p_name; }
+
void set_display_driver_id(int p_display_driver_id) { _display_driver_id = p_display_driver_id; }
virtual void set_main_loop(MainLoop *p_main_loop) = 0;
@@ -116,6 +119,8 @@ public:
static OS *get_singleton();
String get_current_rendering_driver_name() const { return _current_rendering_driver_name; }
+ String get_current_rendering_method() const { return _current_rendering_method; }
+
int get_display_driver_id() const { return _display_driver_id; }
void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, Logger::ErrorType p_type = Logger::ERR_ERROR);
@@ -161,6 +166,8 @@ public:
virtual bool set_environment(const String &p_var, const String &p_value) const = 0;
virtual String get_name() const = 0;
+ virtual String get_distribution_name() const = 0;
+ virtual String get_version() const = 0;
virtual List<String> get_cmdline_args() const { return _cmdline; }
virtual List<String> get_cmdline_user_args() const { return _user_args; }
virtual List<String> get_cmdline_platform_args() const { return List<String>(); }
@@ -280,8 +287,6 @@ public:
virtual Error move_to_trash(const String &p_path) { return FAILED; }
- virtual void debug_break();
-
virtual int get_exit_code() const;
// `set_exit_code` should only be used from `SceneTree` (or from a similar
// level, e.g. from the `Main::start` if leaving without creating a `SceneTree`).
diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp
index f622e2c7c5..e7f2cff7c5 100644
--- a/core/os/pool_allocator.cpp
+++ b/core/os/pool_allocator.cpp
@@ -35,8 +35,6 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-#include <assert.h>
-
#define COMPACT_CHUNK(m_entry, m_to_pos) \
do { \
void *_dst = &((unsigned char *)pool)[m_to_pos]; \
@@ -169,11 +167,6 @@ bool PoolAllocator::find_entry_index(EntryIndicesPos *p_map_pos, const Entry *p_
PoolAllocator::ID PoolAllocator::alloc(int p_size) {
ERR_FAIL_COND_V(p_size < 1, POOL_ALLOCATOR_INVALID_ID);
-#ifdef DEBUG_ENABLED
- if (p_size > free_mem) {
- OS::get_singleton()->debug_break();
- }
-#endif
ERR_FAIL_COND_V(p_size > free_mem, POOL_ALLOCATOR_INVALID_ID);
mt_lock();
@@ -482,7 +475,6 @@ void *PoolAllocator::get(ID p_mem) {
ERR_FAIL_COND_V(!e, nullptr);
}
if (e->lock == 0) {
- //assert(0);
mt_unlock();
ERR_PRINT("e->lock == 0");
return nullptr;
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 6650d9be23..2e144a4c9a 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -44,6 +44,7 @@
#include "core/input/input_map.h"
#include "core/input/shortcut.h"
#include "core/io/config_file.h"
+#include "core/io/dir_access.h"
#include "core/io/dtls_server.h"
#include "core/io/http_client.h"
#include "core/io/image_loader.h"
@@ -58,6 +59,7 @@
#include "core/io/resource_format_binary.h"
#include "core/io/resource_importer.h"
#include "core/io/resource_uid.h"
+#include "core/io/stream_peer_gzip.h"
#include "core/io/stream_peer_tls.h"
#include "core/io/tcp_server.h"
#include "core/io/translation_loader_po.h"
@@ -87,6 +89,8 @@ static Ref<TranslationLoaderPO> resource_format_po;
static Ref<ResourceFormatSaverCrypto> resource_format_saver_crypto;
static Ref<ResourceFormatLoaderCrypto> resource_format_loader_crypto;
static Ref<NativeExtensionResourceLoader> resource_loader_native_extension;
+static Ref<ResourceFormatSaverJSON> resource_saver_json;
+static Ref<ResourceFormatLoaderJSON> resource_loader_json;
static core_bind::ResourceLoader *_resource_loader = nullptr;
static core_bind::ResourceSaver *_resource_saver = nullptr;
@@ -182,6 +186,7 @@ void register_core_types() {
GDREGISTER_ABSTRACT_CLASS(StreamPeer);
GDREGISTER_CLASS(StreamPeerExtension);
GDREGISTER_CLASS(StreamPeerBuffer);
+ GDREGISTER_CLASS(StreamPeerGZIP);
GDREGISTER_CLASS(StreamPeerTCP);
GDREGISTER_CLASS(TCPServer);
@@ -211,6 +216,12 @@ void register_core_types() {
resource_format_loader_crypto.instantiate();
ResourceLoader::add_resource_format_loader(resource_format_loader_crypto);
+ resource_loader_json.instantiate();
+ ResourceLoader::add_resource_format_loader(resource_loader_json);
+
+ resource_saver_json.instantiate();
+ ResourceSaver::add_resource_format_saver(resource_saver_json);
+
GDREGISTER_CLASS(MainLoop);
GDREGISTER_CLASS(Translation);
GDREGISTER_CLASS(OptimizedTranslation);
@@ -220,8 +231,8 @@ void register_core_types() {
GDREGISTER_CLASS(ResourceFormatLoader);
GDREGISTER_CLASS(ResourceFormatSaver);
- GDREGISTER_CLASS(core_bind::File);
- GDREGISTER_CLASS(core_bind::Directory);
+ GDREGISTER_ABSTRACT_CLASS(FileAccess);
+ GDREGISTER_ABSTRACT_CLASS(DirAccess);
GDREGISTER_CLASS(core_bind::Thread);
GDREGISTER_CLASS(core_bind::Mutex);
GDREGISTER_CLASS(core_bind::Semaphore);
@@ -241,6 +252,8 @@ void register_core_types() {
GDREGISTER_CLASS(EncodedObjectAsID);
GDREGISTER_CLASS(RandomNumberGenerator);
+ GDREGISTER_ABSTRACT_CLASS(ImageFormatLoader);
+ GDREGISTER_CLASS(ImageFormatLoaderExtension);
GDREGISTER_ABSTRACT_CLASS(ResourceImporter);
GDREGISTER_CLASS(NativeExtension);
@@ -387,6 +400,12 @@ void unregister_core_types() {
ResourceLoader::remove_resource_format_loader(resource_format_loader_crypto);
resource_format_loader_crypto.unref();
+ ResourceSaver::remove_resource_format_saver(resource_saver_json);
+ resource_saver_json.unref();
+
+ ResourceLoader::remove_resource_format_loader(resource_loader_json);
+ resource_loader_json.unref();
+
if (ip) {
memdelete(ip);
}
diff --git a/core/string/locales.h b/core/string/locales.h
index 32d6608ec2..0ccb17a436 100644
--- a/core/string/locales.h
+++ b/core/string/locales.h
@@ -1072,6 +1072,7 @@ static const char *script_list[][2] = {
{ "Jurchen", "Jurc" },
{ "Kayah Li", "Kali" },
{ "Katakana", "Kana" },
+ { "Kawi", "Kawi" },
{ "Kharoshthi", "Khar" },
{ "Khmer", "Khmr" },
{ "Khojki", "Khoj" },
@@ -1110,6 +1111,7 @@ static const char *script_list[][2] = {
{ "Meitei Mayek", "Mtei" },
{ "Multani", "Mult" },
{ "Myanmar (Burmese)", "Mymr" },
+ { "​Nag Mundari", "Nagm" },
{ "Nandinagari", "Nand" },
{ "Old North Arabian", "Narb" },
{ "Nabataean", "Nbat" },
diff --git a/core/variant/array.h b/core/variant/array.h
index c007376734..3d9a794969 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -47,7 +47,6 @@ class Array {
void _unref() const;
protected:
- Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
bool _assign(const Array &p_array);
public:
@@ -131,6 +130,7 @@ public:
void set_read_only(bool p_enable);
bool is_read_only() const;
+ Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
Array(const Array &p_from);
Array();
~Array();
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index 28efb43fc5..b35e2f004b 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -63,6 +63,21 @@ void Callable::callp(const Variant **p_arguments, int p_argcount, Variant &r_ret
}
}
+Variant Callable::callv(const Array &p_arguments) const {
+ int argcount = p_arguments.size();
+ const Variant **argptrs = nullptr;
+ if (argcount) {
+ argptrs = (const Variant **)alloca(sizeof(Variant *) * argcount);
+ for (int i = 0; i < argcount; i++) {
+ argptrs[i] = &p_arguments[i];
+ }
+ }
+ CallError ce;
+ Variant ret;
+ callp(argptrs, argcount, ret, ce);
+ return ret;
+}
+
Error Callable::rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const {
if (is_null()) {
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
diff --git a/core/variant/callable.h b/core/variant/callable.h
index 1f1c983eb3..0305dc55c3 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -71,6 +71,7 @@ public:
void callp(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const;
void call_deferredp(const Variant **p_arguments, int p_argcount) const;
+ Variant callv(const Array &p_arguments) const;
Error rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const;
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index b280fc9fe3..f24ffeb1a9 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -3727,36 +3727,6 @@ String Variant::get_callable_error_text(const Callable &p_callable, const Varian
return get_call_error_text(p_callable.get_object(), p_callable.get_method(), p_argptrs, p_argcount, ce);
}
-String vformat(const String &p_text, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) {
- Array args;
- if (p1.get_type() != Variant::NIL) {
- args.push_back(p1);
-
- if (p2.get_type() != Variant::NIL) {
- args.push_back(p2);
-
- if (p3.get_type() != Variant::NIL) {
- args.push_back(p3);
-
- if (p4.get_type() != Variant::NIL) {
- args.push_back(p4);
-
- if (p5.get_type() != Variant::NIL) {
- args.push_back(p5);
- }
- }
- }
- }
- }
-
- bool error = false;
- String fmt = p_text.sprintf(args, &error);
-
- ERR_FAIL_COND_V_MSG(error, String(), fmt);
-
- return fmt;
-}
-
void Variant::register_types() {
_register_variant_operators();
_register_variant_methods();
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 212f94a9a8..b0738e7d44 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -552,9 +552,6 @@ public:
void zero();
Variant duplicate(bool p_deep = false) const;
Variant recursive_duplicate(bool p_deep, int recursion_count) const;
- static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst);
- static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst);
- static void sub(const Variant &a, const Variant &b, Variant &r_dst);
/* Built-In Methods */
@@ -807,7 +804,22 @@ const Variant::ObjData &Variant::_get_obj() const {
return *reinterpret_cast<const ObjData *>(&_data._mem[0]);
}
-String vformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant());
+template <typename... VarArgs>
+String vformat(const String &p_text, const VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ Array args_array;
+ args_array.resize(sizeof...(p_args));
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ args_array[i] = args[i];
+ }
+
+ bool error = false;
+ String fmt = p_text.sprintf(args_array, &error);
+
+ ERR_FAIL_COND_V_MSG(error, String(), fmt);
+
+ return fmt;
+}
template <typename... VarArgs>
Callable Callable::bind(VarArgs... p_args) {
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index f09885b325..1831f7b72a 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1859,6 +1859,7 @@ static void _register_variant_builtin_methods() {
/* Callable */
+ bind_method(Callable, callv, sarray("arguments"), varray());
bind_method(Callable, is_null, sarray(), varray());
bind_method(Callable, is_custom, sarray(), varray());
bind_method(Callable, is_standard, sarray(), varray());
@@ -2065,6 +2066,14 @@ static void _register_variant_builtin_methods() {
bind_method(Array, all, sarray("method"), varray());
bind_method(Array, max, sarray(), varray());
bind_method(Array, min, sarray(), varray());
+ bind_method(Array, typed_assign, sarray("array"), varray());
+ bind_method(Array, set_typed, sarray("type", "class_name", "script"), varray());
+ bind_method(Array, is_typed, sarray(), varray());
+ bind_method(Array, get_typed_builtin, sarray(), varray());
+ bind_method(Array, get_typed_class_name, sarray(), varray());
+ bind_method(Array, get_typed_script, sarray(), varray());
+ bind_method(Array, set_read_only, sarray("enable"), varray());
+ bind_method(Array, is_read_only, sarray(), varray());
/* Byte Array */
bind_method(PackedByteArray, size, sarray(), varray());
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index d048f45737..3b88dc11ca 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -200,6 +200,7 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructNoArgs<Array>>(sarray());
add_constructor<VariantConstructor<Array, Array>>(sarray("from"));
+ add_constructor<VariantConstructorTypedArray>(sarray("base", "type", "class_name", "script"));
add_constructor<VariantConstructorToArray<PackedByteArray>>(sarray("from"));
add_constructor<VariantConstructorToArray<PackedInt32Array>>(sarray("from"));
add_constructor<VariantConstructorToArray<PackedInt64Array>>(sarray("from"));
diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h
index 58a0f34c1e..34d228f4d2 100644
--- a/core/variant/variant_construct.h
+++ b/core/variant/variant_construct.h
@@ -336,6 +336,82 @@ public:
}
};
+class VariantConstructorTypedArray {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ if (p_args[0]->get_type() != Variant::ARRAY) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::ARRAY;
+ return;
+ }
+
+ if (p_args[1]->get_type() != Variant::INT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::INT;
+ return;
+ }
+
+ if (p_args[2]->get_type() != Variant::STRING_NAME) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 2;
+ r_error.expected = Variant::STRING_NAME;
+ return;
+ }
+
+ const Array &base_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
+ const uint32_t type = p_args[1]->operator uint32_t();
+ const StringName &class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[2]);
+ r_ret = Array(base_arr, type, class_name, *p_args[3]);
+ }
+
+ static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
+ const Array &base_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
+ const uint32_t type = p_args[1]->operator uint32_t();
+ const StringName &class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[2]);
+ *r_ret = Array(base_arr, type, class_name, *p_args[3]);
+ }
+
+ static void ptr_construct(void *base, const void **p_args) {
+ const Array &base_arr = PtrToArg<Array>::convert(p_args[0]);
+ const uint32_t type = PtrToArg<uint32_t>::convert(p_args[1]);
+ const StringName &class_name = PtrToArg<StringName>::convert(p_args[2]);
+ const Variant &script = PtrToArg<Variant>::convert(p_args[3]);
+ Array dst_arr = Array(base_arr, type, class_name, script);
+
+ PtrConstruct<Array>::construct(dst_arr, base);
+ }
+
+ static int get_argument_count() {
+ return 4;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ switch (p_arg) {
+ case 0: {
+ return Variant::ARRAY;
+ } break;
+ case 1: {
+ return Variant::INT;
+ } break;
+ case 2: {
+ return Variant::STRING_NAME;
+ } break;
+ case 3: {
+ return Variant::NIL;
+ } break;
+ default: {
+ return Variant::NIL;
+ } break;
+ }
+ }
+
+ static Variant::Type get_base_type() {
+ return Variant::ARRAY;
+ }
+};
+
template <class T>
class VariantConstructorToArray {
public:
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index 57b953f7f0..ff67b187ef 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -1911,572 +1911,6 @@ Variant Variant::recursive_duplicate(bool p_deep, int recursion_count) const {
}
}
-void Variant::sub(const Variant &a, const Variant &b, Variant &r_dst) {
- if (a.type != b.type) {
- return;
- }
-
- switch (a.type) {
- case NIL: {
- r_dst = Variant();
- }
- return;
- case INT: {
- int64_t va = a._data._int;
- int64_t vb = b._data._int;
- r_dst = int(va - vb);
- }
- return;
- case FLOAT: {
- double ra = a._data._float;
- double rb = b._data._float;
- r_dst = ra - rb;
- }
- return;
- case VECTOR2: {
- r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) - *reinterpret_cast<const Vector2 *>(b._data._mem);
- }
- return;
- case VECTOR2I: {
- int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
- r_dst = Vector2i(int32_t(vax - vbx), int32_t(vay - vby));
- }
- return;
- case RECT2: {
- const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem);
- const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem);
- r_dst = Rect2(ra->position - rb->position, ra->size - rb->size);
- }
- return;
- case RECT2I: {
- const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
- const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
-
- int32_t vax = ra->position.x;
- int32_t vay = ra->position.y;
- int32_t vbx = ra->size.x;
- int32_t vby = ra->size.y;
- int32_t vcx = rb->position.x;
- int32_t vcy = rb->position.y;
- int32_t vdx = rb->size.x;
- int32_t vdy = rb->size.y;
-
- r_dst = Rect2i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vcx - vdx), int32_t(vcy - vdy));
- }
- return;
- case VECTOR3: {
- r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) - *reinterpret_cast<const Vector3 *>(b._data._mem);
- }
- return;
- case VECTOR3I: {
- int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
- int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
- int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
- r_dst = Vector3i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vaz - vbz));
- }
- return;
- case AABB: {
- const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem);
- const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem);
- r_dst = ::AABB(ra->position - rb->position, ra->size - rb->size);
- }
- return;
- case QUATERNION: {
- Quaternion empty_rot;
- const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem);
- const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem);
- r_dst = (*qb).inverse() * *qa;
- }
- return;
- case COLOR: {
- const Color *ca = reinterpret_cast<const Color *>(a._data._mem);
- const Color *cb = reinterpret_cast<const Color *>(b._data._mem);
- float new_r = ca->r - cb->r;
- float new_g = ca->g - cb->g;
- float new_b = ca->b - cb->b;
- float new_a = ca->a - cb->a;
- new_r = new_r > 1.0 ? 1.0 : new_r;
- new_g = new_g > 1.0 ? 1.0 : new_g;
- new_b = new_b > 1.0 ? 1.0 : new_b;
- new_a = new_a > 1.0 ? 1.0 : new_a;
- r_dst = Color(new_r, new_g, new_b, new_a);
- }
- return;
- default: {
- r_dst = a;
- }
- return;
- }
-}
-
-void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) {
- if (a.type != b.type) {
- if (a.is_num() && b.is_num()) {
- real_t va = a;
- real_t vb = b;
- r_dst = va + vb * c;
- } else {
- r_dst = a;
- }
- return;
- }
-
- switch (a.type) {
- case NIL: {
- r_dst = Variant();
- }
- return;
- case INT: {
- int64_t va = a._data._int;
- int64_t vb = b._data._int;
- r_dst = int(va + vb * c + 0.5);
- }
- return;
- case FLOAT: {
- double ra = a._data._float;
- double rb = b._data._float;
- r_dst = ra + rb * c;
- }
- return;
- case VECTOR2: {
- r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) + *reinterpret_cast<const Vector2 *>(b._data._mem) * c;
- }
- return;
- case VECTOR2I: {
- int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
- r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5));
- }
- return;
- case RECT2: {
- const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem);
- const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem);
- r_dst = Rect2(ra->position + rb->position * c, ra->size + rb->size * c);
- }
- return;
- case RECT2I: {
- const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
- const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
-
- int32_t vax = ra->position.x;
- int32_t vay = ra->position.y;
- int32_t vbx = ra->size.x;
- int32_t vby = ra->size.y;
- int32_t vcx = rb->position.x;
- int32_t vcy = rb->position.y;
- int32_t vdx = rb->size.x;
- int32_t vdy = rb->size.y;
-
- r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5));
- }
- return;
- case VECTOR3: {
- r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) + *reinterpret_cast<const Vector3 *>(b._data._mem) * c;
- }
- return;
- case VECTOR3I: {
- int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
- int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
- int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
- r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5));
- }
- return;
- case AABB: {
- const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem);
- const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem);
- r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c);
- }
- return;
- case QUATERNION: {
- Quaternion empty_rot;
- const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem);
- const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem);
- r_dst = *qa * empty_rot.slerp(*qb, c);
- }
- return;
- case COLOR: {
- const Color *ca = reinterpret_cast<const Color *>(a._data._mem);
- const Color *cb = reinterpret_cast<const Color *>(b._data._mem);
- float new_r = ca->r + cb->r * c;
- float new_g = ca->g + cb->g * c;
- float new_b = ca->b + cb->b * c;
- float new_a = ca->a + cb->a * c;
- new_r = new_r > 1.0 ? 1.0 : new_r;
- new_g = new_g > 1.0 ? 1.0 : new_g;
- new_b = new_b > 1.0 ? 1.0 : new_b;
- new_a = new_a > 1.0 ? 1.0 : new_a;
- r_dst = Color(new_r, new_g, new_b, new_a);
- }
- return;
- default: {
- r_dst = c < 0.5 ? a : b;
- }
- return;
- }
-}
-
-void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst) {
- if (a.type != b.type) {
- if (a.is_num() && b.is_num()) {
- //not as efficient but..
- real_t va = a;
- real_t vb = b;
- r_dst = va + (vb - va) * c;
-
- } else {
- r_dst = a;
- }
- return;
- }
-
- switch (a.type) {
- case NIL: {
- r_dst = Variant();
- }
- return;
- case BOOL: {
- r_dst = a;
- }
- return;
- case INT: {
- int64_t va = a._data._int;
- int64_t vb = b._data._int;
- r_dst = int(va + (vb - va) * c);
- }
- return;
- case FLOAT: {
- real_t va = a._data._float;
- real_t vb = b._data._float;
- r_dst = va + (vb - va) * c;
- }
- return;
- case STRING: {
- //this is pretty funny and bizarre, but artists like to use it for typewriter effects
- String sa = *reinterpret_cast<const String *>(a._data._mem);
- String sb = *reinterpret_cast<const String *>(b._data._mem);
- String dst;
- int sa_len = sa.length();
- int sb_len = sb.length();
- int csize = sa_len + (sb_len - sa_len) * c;
- if (csize == 0) {
- r_dst = "";
- return;
- }
- dst.resize(csize + 1);
- dst[csize] = 0;
- int split = csize / 2;
-
- for (int i = 0; i < csize; i++) {
- char32_t chr = ' ';
-
- if (i < split) {
- if (i < sa.length()) {
- chr = sa[i];
- } else if (i < sb.length()) {
- chr = sb[i];
- }
-
- } else {
- if (i < sb.length()) {
- chr = sb[i];
- } else if (i < sa.length()) {
- chr = sa[i];
- }
- }
-
- dst[i] = chr;
- }
-
- r_dst = dst;
- }
- return;
- case VECTOR2: {
- r_dst = reinterpret_cast<const Vector2 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector2 *>(b._data._mem), c);
- }
- return;
- case VECTOR2I: {
- int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
- r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5));
- }
- return;
-
- case RECT2: {
- r_dst = Rect2(reinterpret_cast<const Rect2 *>(a._data._mem)->position.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->position, c), reinterpret_cast<const Rect2 *>(a._data._mem)->size.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->size, c));
- }
- return;
- case RECT2I: {
- const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
- const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
-
- int32_t vax = ra->position.x;
- int32_t vay = ra->position.y;
- int32_t vbx = ra->size.x;
- int32_t vby = ra->size.y;
- int32_t vcx = rb->position.x;
- int32_t vcy = rb->position.y;
- int32_t vdx = rb->size.x;
- int32_t vdy = rb->size.y;
-
- r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5));
- }
- return;
-
- case VECTOR3: {
- r_dst = reinterpret_cast<const Vector3 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector3 *>(b._data._mem), c);
- }
- return;
- case VECTOR3I: {
- int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
- int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
- int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
- r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5));
- }
- return;
-
- case TRANSFORM2D: {
- r_dst = a._data._transform2d->interpolate_with(*b._data._transform2d, c);
- }
- return;
- case PLANE: {
- r_dst = a;
- }
- return;
- case QUATERNION: {
- r_dst = reinterpret_cast<const Quaternion *>(a._data._mem)->slerp(*reinterpret_cast<const Quaternion *>(b._data._mem), c);
- }
- return;
- case AABB: {
- r_dst = ::AABB(a._data._aabb->position.lerp(b._data._aabb->position, c), a._data._aabb->size.lerp(b._data._aabb->size, c));
- }
- return;
- case BASIS: {
- r_dst = a._data._basis->lerp(*b._data._basis, c);
- }
- return;
- case TRANSFORM3D: {
- r_dst = a._data._transform3d->interpolate_with(*b._data._transform3d, c);
- }
- return;
- case COLOR: {
- r_dst = reinterpret_cast<const Color *>(a._data._mem)->lerp(*reinterpret_cast<const Color *>(b._data._mem), c);
- }
- return;
- case STRING_NAME: {
- r_dst = a;
- }
- return;
- case NODE_PATH: {
- r_dst = a;
- }
- return;
- case RID: {
- r_dst = a;
- }
- return;
- case OBJECT: {
- r_dst = a;
- }
- return;
- case DICTIONARY: {
- }
- return;
- case ARRAY: {
- r_dst = a;
- }
- return;
- case PACKED_BYTE_ARRAY: {
- r_dst = a;
- }
- return;
- case PACKED_INT32_ARRAY: {
- const Vector<int32_t> *arr_a = &PackedArrayRef<int32_t>::get_array(a._data.packed_array);
- const Vector<int32_t> *arr_b = &PackedArrayRef<int32_t>::get_array(b._data.packed_array);
- int32_t sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<int32_t> v;
- v.resize(sz);
- {
- int32_t *vw = v.ptrw();
- const int32_t *ar = arr_a->ptr();
- const int32_t *br = arr_b->ptr();
-
- Variant va;
- for (int32_t i = 0; i < sz; i++) {
- Variant::interpolate(ar[i], br[i], c, va);
- vw[i] = va;
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_INT64_ARRAY: {
- const Vector<int64_t> *arr_a = &PackedArrayRef<int64_t>::get_array(a._data.packed_array);
- const Vector<int64_t> *arr_b = &PackedArrayRef<int64_t>::get_array(b._data.packed_array);
- int64_t sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<int64_t> v;
- v.resize(sz);
- {
- int64_t *vw = v.ptrw();
- const int64_t *ar = arr_a->ptr();
- const int64_t *br = arr_b->ptr();
-
- Variant va;
- for (int64_t i = 0; i < sz; i++) {
- Variant::interpolate(ar[i], br[i], c, va);
- vw[i] = va;
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_FLOAT32_ARRAY: {
- const Vector<float> *arr_a = &PackedArrayRef<float>::get_array(a._data.packed_array);
- const Vector<float> *arr_b = &PackedArrayRef<float>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<float> v;
- v.resize(sz);
- {
- float *vw = v.ptrw();
- const float *ar = arr_a->ptr();
- const float *br = arr_b->ptr();
-
- Variant va;
- for (int i = 0; i < sz; i++) {
- Variant::interpolate(ar[i], br[i], c, va);
- vw[i] = va;
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_FLOAT64_ARRAY: {
- const Vector<double> *arr_a = &PackedArrayRef<double>::get_array(a._data.packed_array);
- const Vector<double> *arr_b = &PackedArrayRef<double>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<double> v;
- v.resize(sz);
- {
- double *vw = v.ptrw();
- const double *ar = arr_a->ptr();
- const double *br = arr_b->ptr();
-
- Variant va;
- for (int i = 0; i < sz; i++) {
- Variant::interpolate(ar[i], br[i], c, va);
- vw[i] = va;
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_STRING_ARRAY: {
- r_dst = a;
- }
- return;
- case PACKED_VECTOR2_ARRAY: {
- const Vector<Vector2> *arr_a = &PackedArrayRef<Vector2>::get_array(a._data.packed_array);
- const Vector<Vector2> *arr_b = &PackedArrayRef<Vector2>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<Vector2> v;
- v.resize(sz);
- {
- Vector2 *vw = v.ptrw();
- const Vector2 *ar = arr_a->ptr();
- const Vector2 *br = arr_b->ptr();
-
- for (int i = 0; i < sz; i++) {
- vw[i] = ar[i].lerp(br[i], c);
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_VECTOR3_ARRAY: {
- const Vector<Vector3> *arr_a = &PackedArrayRef<Vector3>::get_array(a._data.packed_array);
- const Vector<Vector3> *arr_b = &PackedArrayRef<Vector3>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<Vector3> v;
- v.resize(sz);
- {
- Vector3 *vw = v.ptrw();
- const Vector3 *ar = arr_a->ptr();
- const Vector3 *br = arr_b->ptr();
-
- for (int i = 0; i < sz; i++) {
- vw[i] = ar[i].lerp(br[i], c);
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_COLOR_ARRAY: {
- const Vector<Color> *arr_a = &PackedArrayRef<Color>::get_array(a._data.packed_array);
- const Vector<Color> *arr_b = &PackedArrayRef<Color>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<Color> v;
- v.resize(sz);
- {
- Color *vw = v.ptrw();
- const Color *ar = arr_a->ptr();
- const Color *br = arr_b->ptr();
-
- for (int i = 0; i < sz; i++) {
- vw[i] = ar[i].lerp(br[i], c);
- }
- }
- r_dst = v;
- }
- }
- return;
- default: {
- r_dst = a;
- }
- }
-}
-
void Variant::_register_variant_setters_getters() {
register_named_setters_getters();
register_indexed_setters_getters();
diff --git a/doc/class.xsd b/doc/class.xsd
index 7681ddad3d..d29d053006 100644
--- a/doc/class.xsd
+++ b/doc/class.xsd
@@ -95,6 +95,8 @@
</xs:sequence>
<xs:attribute type="xs:string" name="name" use="optional" />
<xs:attribute type="xs:string" name="qualifiers" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
@@ -114,6 +116,8 @@
<xs:attribute type="xs:string" name="overrides" use="optional" />
<xs:attribute type="xs:string" name="enum" use="optional" />
<xs:attribute type="xs:string" name="default" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
@@ -156,6 +160,8 @@
<xs:attribute type="xs:string" name="value" />
<xs:attribute type="xs:string" name="enum" use="optional" />
<xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
@@ -256,6 +262,8 @@
</xs:sequence>
<xs:attribute type="xs:string" name="name" />
<xs:attribute type="xs:string" name="inherits" />
+ <xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
<xs:attribute type="xs:float" name="version" />
</xs:complexType>
</xs:element>
diff --git a/doc/classes/AESContext.xml b/doc/classes/AESContext.xml
index 69cd54a79b..7f582e4be7 100644
--- a/doc/classes/AESContext.xml
+++ b/doc/classes/AESContext.xml
@@ -45,6 +45,7 @@
public class Example : Node
{
public AESContext Aes = new AESContext();
+
public override void _Ready()
{
string key = "My secret key!!!"; // Key must be either 16 or 32 bytes.
diff --git a/doc/classes/AStarGrid2D.xml b/doc/classes/AStarGrid2D.xml
index 19cd9d21d7..331862ebfa 100644
--- a/doc/classes/AStarGrid2D.xml
+++ b/doc/classes/AStarGrid2D.xml
@@ -6,14 +6,24 @@
<description>
Compared to [AStar2D] you don't need to manually create points or connect them together. It also supports multiple type of heuristics and modes for diagonal movement. This class also provides a jumping mode which is faster to calculate than without it in the [AStar2D] class.
In contrast to [AStar2D], you only need set the [member size] of the grid, optionally set the [member cell_size] and then call the [method update] method:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var astar_grid = AStarGrid2D.new()
astar_grid.size = Vector2i(32, 32)
astar_grid.cell_size = Vector2(16, 16)
astar_grid.update()
print(astar_grid.get_id_path(Vector2i(0, 0), Vector2i(3, 4))) # prints (0, 0), (1, 1), (2, 2), (3, 3), (3, 4)
print(astar_grid.get_point_path(Vector2i(0, 0), Vector2i(3, 4))) # prints (0, 0), (16, 16), (32, 32), (48, 48), (48, 64)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ AStarGrid2D astarGrid = new AStarGrid2D();
+ astarGrid.Size = new Vector2i(32, 32);
+ astarGrid.CellSize = new Vector2i(16, 16);
+ astarGrid.Update();
+ GD.Print(astarGrid.GetIdPath(Vector2i.Zero, new Vector2i(3, 4))); // prints (0, 0), (1, 1), (2, 2), (3, 3), (3, 4)
+ GD.Print(astarGrid.GetPointPath(Vector2i.Zero, new Vector2i(3, 4))); // prints (0, 0), (16, 16), (32, 32), (48, 48), (48, 64)
+ [/csharp]
+ [/codeblocks]
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml
index b207eda27f..afbe34816a 100644
--- a/doc/classes/AnimatedSprite2D.xml
+++ b/doc/classes/AnimatedSprite2D.xml
@@ -5,6 +5,8 @@
</brief_description>
<description>
[AnimatedSprite2D] is similar to the [Sprite2D] node, except it carries multiple textures as animation frames. Animations are created using a [SpriteFrames] resource, which allows you to import image files (or a folder containing said files) to provide the animation frames for the sprite. The [SpriteFrames] resource can be configured in the editor via the SpriteFrames bottom panel.
+ After setting up [member frames], [method play] may be called. It's also possible to select an [member animation] and toggle [member playing], even within the editor.
+ To pause the current animation, call [method stop] or set [member playing] to [code]false[/code]. Alternatively, setting [member speed_scale] to [code]0[/code] also preserves the current frame's elapsed time.
[b]Note:[/b] You can associate a set of normal or specular maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] or [code]_specular[/code] suffix. For example, having 3 [SpriteFrames] resources [code]run[/code], [code]run_normal[/code], and [code]run_specular[/code] will make it so the [code]run[/code] animation uses normal and specular maps.
</description>
<tutorials>
@@ -17,13 +19,14 @@
<param index="0" name="anim" type="StringName" default="&amp;&quot;&quot;" />
<param index="1" name="backwards" type="bool" default="false" />
<description>
- Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [code]backwards[/code] is [code]true[/code], the animation will be played in reverse.
+ Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [param backwards] is [code]true[/code], the animation is played in reverse.
</description>
</method>
<method name="stop">
<return type="void" />
<description>
- Stops the current animation (does not reset the frame counter).
+ Stops the current [member animation] at the current [member frame].
+ [b]Note:[/b] This method resets the current frame's elapsed time. If this behavior is undesired, consider setting [member speed_scale] to [code]0[/code], instead.
</description>
</method>
</methods>
@@ -50,10 +53,10 @@
The texture's drawing offset.
</member>
<member name="playing" type="bool" setter="set_playing" getter="is_playing" default="false">
- If [code]true[/code], the [member animation] is currently playing.
+ If [code]true[/code], the [member animation] is currently playing. Setting this property to [code]false[/code] is the equivalent of calling [method stop].
</member>
<member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
- The animation speed is multiplied by this value.
+ The animation speed is multiplied by this value. If set to a negative value, the animation is played in reverse. If set to [code]0[/code], the animation is paused, preserving the current frame's elapsed time.
</member>
</members>
<signals>
diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml
index 58d3ca6ad3..09baf882fb 100644
--- a/doc/classes/AnimatedSprite3D.xml
+++ b/doc/classes/AnimatedSprite3D.xml
@@ -4,7 +4,9 @@
2D sprite node in 3D world, that can use multiple 2D textures for animation.
</brief_description>
<description>
- Animations are created using a [SpriteFrames] resource, which can be configured in the editor via the SpriteFrames panel.
+ [AnimatedSprite3D] is similar to the [Sprite3D] node, except it carries multiple textures as animation [member frames]. Animations are created using a [SpriteFrames] resource, which allows you to import image files (or a folder containing said files) to provide the animation frames for the sprite. The [SpriteFrames] resource can be configured in the editor via the SpriteFrames bottom panel.
+ After setting up [member frames], [method play] may be called. It's also possible to select an [member animation] and toggle [member playing], even within the editor.
+ To pause the current animation, call [method stop] or set [member playing] to [code]false[/code]. Alternatively, setting [member speed_scale] to [code]0[/code] also preserves the current frame's elapsed time.
</description>
<tutorials>
<link title="2D Sprite animation (also applies to 3D)">$DOCS_URL/tutorials/2d/2d_sprite_animation.html</link>
@@ -15,13 +17,14 @@
<param index="0" name="anim" type="StringName" default="&amp;&quot;&quot;" />
<param index="1" name="backwards" type="bool" default="false" />
<description>
- Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [param backwards] is [code]true[/code], the animation will be played in reverse.
+ Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [param backwards] is [code]true[/code], the animation is played in reverse.
</description>
</method>
<method name="stop">
<return type="void" />
<description>
- Stops the current animation (does not reset the frame counter).
+ Stops the current [member animation] at the current [member frame].
+ [b]Note:[/b] This method resets the current frame's elapsed time. If this behavior is undesired, consider setting [member speed_scale] to [code]0[/code], instead.
</description>
</method>
</methods>
@@ -36,10 +39,10 @@
The [SpriteFrames] resource containing the animation(s).
</member>
<member name="playing" type="bool" setter="set_playing" getter="is_playing" default="false">
- If [code]true[/code], the [member animation] is currently playing.
+ If [code]true[/code], the [member animation] is currently playing. Setting this property to [code]false[/code] is the equivalent of calling [method stop].
</member>
<member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
- The animation speed is multiplied by this value.
+ The animation speed is multiplied by this value. If set to a negative value, the animation is played in reverse. If set to [code]0[/code], the animation is paused, preserving the current frame's elapsed time.
</member>
</members>
<signals>
diff --git a/doc/classes/AnimationNodeBlendTree.xml b/doc/classes/AnimationNodeBlendTree.xml
index 4c7943ece3..2a765ac8d6 100644
--- a/doc/classes/AnimationNodeBlendTree.xml
+++ b/doc/classes/AnimationNodeBlendTree.xml
@@ -87,6 +87,14 @@
The global offset of all sub-nodes.
</member>
</members>
+ <signals>
+ <signal name="node_changed">
+ <param index="0" name="node_name" type="StringName" />
+ <description>
+ Emitted when the input port information is changed.
+ </description>
+ </signal>
+ </signals>
<constants>
<constant name="CONNECTION_OK" value="0">
The connection was successful.
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index 710dc55a4b..d24703203b 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -268,6 +268,11 @@
[b]Note:[/b] This signal is not emitted if an animation is looping.
</description>
</signal>
+ <signal name="animation_list_changed">
+ <description>
+ Notifies when an animation list is changed.
+ </description>
+ </signal>
<signal name="animation_started">
<param index="0" name="anim_name" type="StringName" />
<description>
diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml
index f2bf74f495..27797b00b5 100644
--- a/doc/classes/AnimationTree.xml
+++ b/doc/classes/AnimationTree.xml
@@ -54,6 +54,13 @@
The root animation node of this [AnimationTree]. See [AnimationNode].
</member>
</members>
+ <signals>
+ <signal name="animation_player_changed">
+ <description>
+ Emitted when the [member anim_player] is changed.
+ </description>
+ </signal>
+ </signals>
<constants>
<constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessCallback">
The animations will progress during the physics frame (i.e. [method Node._physics_process]).
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index f6d926031d..d8c4b8fdb5 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -53,6 +53,15 @@
</constructor>
<constructor name="Array">
<return type="Array" />
+ <param index="0" name="base" type="Array" />
+ <param index="1" name="type" type="int" />
+ <param index="2" name="class_name" type="StringName" />
+ <param index="3" name="script" type="Variant" />
+ <description>
+ </description>
+ </constructor>
+ <constructor name="Array">
+ <return type="Array" />
<param index="0" name="from" type="Array" />
<description>
Constructs an [Array] as a copy of the given [Array].
@@ -303,6 +312,21 @@
[b]Note:[/b] Calling this function is not the same as writing [code]array[0][/code]. If the array is empty, accessing by index will pause project execution when running from the editor.
</description>
</method>
+ <method name="get_typed_builtin" qualifiers="const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="get_typed_class_name" qualifiers="const">
+ <return type="StringName" />
+ <description>
+ </description>
+ </method>
+ <method name="get_typed_script" qualifiers="const">
+ <return type="Variant" />
+ <description>
+ </description>
+ </method>
<method name="has" qualifiers="const">
<return type="bool" />
<param index="0" name="value" type="Variant" />
@@ -366,6 +390,16 @@
Returns [code]true[/code] if the array is empty.
</description>
</method>
+ <method name="is_read_only" qualifiers="const">
+ <return type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="is_typed" qualifiers="const">
+ <return type="bool" />
+ <description>
+ </description>
+ </method>
<method name="map" qualifiers="const">
<return type="Array" />
<param index="0" name="method" type="Callable" />
@@ -479,6 +513,20 @@
Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array.
</description>
</method>
+ <method name="set_read_only">
+ <return type="void" />
+ <param index="0" name="enable" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="set_typed">
+ <return type="void" />
+ <param index="0" name="type" type="int" />
+ <param index="1" name="class_name" type="StringName" />
+ <param index="2" name="script" type="Variant" />
+ <description>
+ </description>
+ </method>
<method name="shuffle">
<return type="void" />
<description>
@@ -556,6 +604,12 @@
[/codeblocks]
</description>
</method>
+ <method name="typed_assign">
+ <return type="bool" />
+ <param index="0" name="array" type="Array" />
+ <description>
+ </description>
+ </method>
</methods>
<operators>
<operator name="operator !=">
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index ee28675d89..cbb58a3e1e 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -28,7 +28,7 @@
<return type="Texture2D" />
<param index="0" name="param" type="int" enum="BaseMaterial3D.TextureParam" />
<description>
- Returns the [Texture] associated with the specified [enum TextureParam].
+ Returns the [Texture2D] associated with the specified [enum TextureParam].
</description>
</method>
<method name="set_feature">
diff --git a/doc/classes/BoneAttachment3D.xml b/doc/classes/BoneAttachment3D.xml
index dc3d448621..f29525038e 100644
--- a/doc/classes/BoneAttachment3D.xml
+++ b/doc/classes/BoneAttachment3D.xml
@@ -16,10 +16,11 @@
Returns the [NodePath] to the external [Skeleton3D] node, if one has been set.
</description>
</method>
- <method name="get_override_mode" qualifiers="const">
+ <method name="get_override_mode" qualifiers="const" is_deprecated="true">
<return type="int" />
<description>
- Returns the override mode for the BoneAttachment3D node.
+ Deprecated. Local pose overrides will be removed.
+ Returns the override mode for the BoneAttachment3D node (0=global / 1=local).
</description>
</method>
<method name="get_override_pose" qualifiers="const">
@@ -48,11 +49,12 @@
Sets the [NodePath] to the external skeleton that the BoneAttachment3D node should use. The external [Skeleton3D] node is only used when [code]use_external_skeleton[/code] is set to [code]true[/code].
</description>
</method>
- <method name="set_override_mode">
+ <method name="set_override_mode" is_deprecated="true">
<return type="void" />
<param index="0" name="override_mode" type="int" />
<description>
- Sets the override mode for the BoneAttachment3D node. The override mode defines which of the bone poses the BoneAttachment3D node will override.
+ Deprecated. Local pose overrides will be removed.
+ Sets the override mode for the BoneAttachment3D node (0=global / 1=local). The override mode defines which of the bone poses the BoneAttachment3D node will override.
</description>
</method>
<method name="set_override_pose">
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index 1fcaf6d866..dd48ee6790 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -81,6 +81,13 @@
[/codeblock]
</description>
</method>
+ <method name="callv" qualifiers="const">
+ <return type="Variant" />
+ <param index="0" name="arguments" type="Array" />
+ <description>
+ Calls the method represented by this [Callable]. Contrary to [method call], this method does not take a variable number of arguments but expects all arguments to be passed via a single [Array].
+ </description>
+ </method>
<method name="get_method" qualifiers="const">
<return type="StringName" />
<description>
diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml
index bb78d537ad..a1d24f778d 100644
--- a/doc/classes/Camera2D.xml
+++ b/doc/classes/Camera2D.xml
@@ -124,6 +124,9 @@
<member name="editor_draw_screen" type="bool" setter="set_screen_drawing_enabled" getter="is_screen_drawing_enabled" default="true">
If [code]true[/code], draws the camera's screen rectangle in the editor.
</member>
+ <member name="ignore_rotation" type="bool" setter="set_ignore_rotation" getter="is_ignoring_rotation" default="true">
+ If [code]true[/code], the camera's rendered view is not affected by its [member Node2D.rotation] and [member Node2D.global_rotation].
+ </member>
<member name="limit_bottom" type="int" setter="set_limit" getter="get_limit" default="10000000">
Bottom scroll limit in pixels. The camera stops moving when reaching this value, but [member offset] can push the view past the limit.
</member>
@@ -147,9 +150,6 @@
<member name="process_callback" type="int" setter="set_process_callback" getter="get_process_callback" enum="Camera2D.Camera2DProcessCallback" default="1">
The camera's process callback. See [enum Camera2DProcessCallback].
</member>
- <member name="rotating" type="bool" setter="set_rotating" getter="is_rotating" default="false">
- If [code]true[/code], the camera view rotates with the target.
- </member>
<member name="smoothing_enabled" type="bool" setter="set_enable_follow_smoothing" getter="is_follow_smoothing_enabled" default="false">
If [code]true[/code], the camera smoothly moves towards the target at [member smoothing_speed].
</member>
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 70d825efac..d74f49c897 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -310,16 +310,16 @@
# If using this method in a script that redraws constantly, move the
# `default_font` declaration to a member variable assigned in `_ready()`
# so the Control is only created once.
- var default_font = Control.new().get_font("font")
- var default_font_size = Control.new().get_font_size("font_size")
- draw_string(default_font, Vector2(64, 64), "Hello world", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size)
+ var default_font = ThemeDB.fallback_font
+ var default_font_size = ThemeDB.fallback_font_size
+ draw_string(default_font, Vector2(64, 64), "Hello world", HORIZONTAL_ALIGNMENT_LEFT, -1, default_font_size)
[/gdscript]
[csharp]
// If using this method in a script that redraws constantly, move the
- // `default_font` declaration to a member variable assigned in `_ready()`
+ // `default_font` declaration to a member variable assigned in `_Ready()`
// so the Control is only created once.
- Font defaultFont = new Control().GetFont("font");
- int defaultFontSize = new Control().GetFontSize("font_size");
+ Font defaultFont = ThemeDB.FallbackFont;
+ int defaultFontSize = ThemeDB.FallbackFontSize;
DrawString(defaultFont, new Vector2(64, 64), "Hello world", HORIZONTAL_ALIGNMENT_LEFT, -1, defaultFontSize);
[/csharp]
[/codeblocks]
diff --git a/doc/classes/Cubemap.xml b/doc/classes/Cubemap.xml
index 7173388027..0cdebeda95 100644
--- a/doc/classes/Cubemap.xml
+++ b/doc/classes/Cubemap.xml
@@ -4,9 +4,9 @@
6-sided texture typically used in 3D rendering.
</brief_description>
<description>
- A cubemap is a 6-sided texture typically used for faking reflections in 3D rendering. It can be used to make an object look as if it's reflecting its surroundings. This usually delivers much better performance than other reflection methods.
+ A cubemap is made of 6 textures organized in layers. They are typically used for faking reflections (see [ReflectionProbe]) in 3D rendering. It can be used to make an object look as if it's reflecting its surroundings. This usually delivers much better performance than other reflection methods.
This resource is typically used as a uniform in custom shaders. Few core Godot methods make use of Cubemap resources.
- [b]Note:[/b] Godot doesn't support using cubemaps as a [PanoramaSkyMaterial]. You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cube map to an equirectangular sky map.
+ [b]Note:[/b] Godot doesn't support using cubemaps in a [PanoramaSkyMaterial]. You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cubemap to an equirectangular sky map.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/CubemapArray.xml b/doc/classes/CubemapArray.xml
index 4fca842b5a..7f001155e4 100644
--- a/doc/classes/CubemapArray.xml
+++ b/doc/classes/CubemapArray.xml
@@ -1,8 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CubemapArray" inherits="ImageTextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ A single composite texture resource which consists of multiple [Cubemap]s.
</brief_description>
<description>
+ [CubemapArray]s are made of an array of [Cubemap]s. Accordingly, like [Cubemap]s they are made of multiple textures the amount of which must be divisible by 6 (one image for each face of the cube). The primary benefit of [CubemapArray]s is that they can be accessed in shader code using a single texture reference. In other words, you can pass multiple [Cubemap]s into a shader using a single [CubemapArray].
+ Generally, [CubemapArray]s provide a more efficent way for storing multiple [Cubemap]s, than storing multiple [Cubemap]s themselves in an array.
+ Internally Godot, uses [CubemapArray]s for many effects including the [Sky], if you set [member ProjectSettings.rendering/reflections/sky_reflections/texture_array_reflections] to [code]true[/code].
+ [b]Note:[/b] [CubemapArray] is not supported in the OpenGL 3 rendering backend.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Directory.xml b/doc/classes/DirAccess.xml
index c9a9f346a5..af498a6519 100644
--- a/doc/classes/Directory.xml
+++ b/doc/classes/DirAccess.xml
@@ -1,18 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Directory" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="DirAccess" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Type used to handle the filesystem.
</brief_description>
<description>
Directory type. It is used to manage directories and their content (not restricted to the project folder).
- When creating a new [Directory], it must be explicitly opened using [method open] before most methods can be used. However, [method file_exists] and [method dir_exists] can be used without opening a directory. If so, they use a path relative to [code]res://[/code].
+ [DirAccess] can't be instantiated directly. Instead it is created with a static method that takes a path for which it will be opened.
+ Most of the methods have a static alternative that can be used without creating a [DirAccess]. Static methods only support absolute paths (including [code]res://[/code] and [code]user://[/code]).
+ [codeblock]
+ # Standard
+ var dir = DirAccess.open("user://levels")
+ dir.make_dir("world1")
+ # Static
+ DirAccess.make_dir_absolute("user://levels/world1")
+ [/codeblock]
[b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. Use [ResourceLoader] to access imported resources.
Here is an example on how to iterate through the files of a directory:
[codeblocks]
[gdscript]
func dir_contents(path):
- var dir = Directory.new()
- if dir.open(path) == OK:
+ var dir = DirAccess.open(path)
+ if dir:
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
@@ -27,8 +35,8 @@
[csharp]
public void DirContents(string path)
{
- var dir = new Directory();
- if (dir.Open(path) == Error.Ok)
+ using var dir = DirAccess.Open(path);
+ if (dir != null)
{
dir.ListDirBegin();
string fileName = dir.GetNext();
@@ -59,7 +67,7 @@
<methods>
<method name="change_dir">
<return type="int" enum="Error" />
- <param index="0" name="todir" type="String" />
+ <param index="0" name="to_dir" type="String" />
<description>
Changes the currently opened directory to the one passed as an argument. The argument can be relative to the current directory (e.g. [code]newdir[/code] or [code]../newdir[/code]), or an absolute path (e.g. [code]/tmp/newdir[/code] or [code]res://somedir/newdir[/code]).
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
@@ -69,11 +77,22 @@
<return type="int" enum="Error" />
<param index="0" name="from" type="String" />
<param index="1" name="to" type="String" />
+ <param index="2" name="chmod_flags" type="int" default="-1" />
<description>
Copies the [param from] file to the [param to] destination. Both arguments should be paths to files, either relative or absolute. If the destination file exists and is not access-protected, it will be overwritten.
+ If [param chmod_flags] is different than [code]-1[/code], the unix permissions for the destination path will be set to the provided value, if available on the current operating system.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
+ <method name="copy_absolute" qualifiers="static">
+ <return type="int" enum="Error" />
+ <param index="0" name="from" type="String" />
+ <param index="1" name="to" type="String" />
+ <param index="2" name="chmod_flags" type="int" default="-1" />
+ <description>
+ Static version of [method copy]. Supports only absolute paths.
+ </description>
+ </method>
<method name="current_is_dir" qualifiers="const">
<return type="bool" />
<description>
@@ -85,7 +104,13 @@
<param index="0" name="path" type="String" />
<description>
Returns whether the target directory exists. The argument can be relative to the current directory, or an absolute path.
- If the [Directory] is not open, the path is relative to [code]res://[/code].
+ </description>
+ </method>
+ <method name="dir_exists_absolute" qualifiers="static">
+ <return type="bool" />
+ <param index="0" name="path" type="String" />
+ <description>
+ Static version of [method dir_exists]. Supports only absolute paths.
</description>
</method>
<method name="file_exists">
@@ -93,11 +118,12 @@
<param index="0" name="path" type="String" />
<description>
Returns whether the target file exists. The argument can be relative to the current directory, or an absolute path.
- If the [Directory] is not open, the path is relative to [code]res://[/code].
+ For a static equivalent, use [method FileAccess.file_exists].
</description>
</method>
- <method name="get_current_dir">
+ <method name="get_current_dir" qualifiers="const">
<return type="String" />
+ <param index="0" name="include_drive" type="bool" default="true" />
<description>
Returns the absolute path to the currently opened directory (e.g. [code]res://folder[/code] or [code]C:\tmp\folder[/code]).
</description>
@@ -105,7 +131,7 @@
<method name="get_current_drive">
<return type="int" />
<description>
- Returns the currently opened directory's drive index. See [method get_drive] to convert returned index to the name of the drive.
+ Returns the currently opened directory's drive index. See [method get_drive_name] to convert returned index to the name of the drive.
</description>
</method>
<method name="get_directories">
@@ -115,17 +141,15 @@
Affected by [member include_hidden] and [member include_navigational].
</description>
</method>
- <method name="get_drive">
- <return type="String" />
- <param index="0" name="idx" type="int" />
+ <method name="get_directories_at" qualifiers="static">
+ <return type="PackedStringArray" />
+ <param index="0" name="path" type="String" />
<description>
- On Windows, returns the name of the drive (partition) passed as an argument (e.g. [code]C:[/code]).
- On macOS, returns the path to the mounted volume passed as an argument.
- On Linux, returns the path to the mounted volume or GTK 3 bookmark passed as an argument.
- On other platforms, or if the requested drive does not exist, the method returns an empty String.
+ Returns a [PackedStringArray] containing filenames of the directory contents, excluding files, at the given [param path]. The array is sorted alphabetically.
+ Use [method get_directories] if you want more control of what gets included.
</description>
</method>
- <method name="get_drive_count">
+ <method name="get_drive_count" qualifiers="static">
<return type="int" />
<description>
On Windows, returns the number of drives (partitions) mounted on the current filesystem.
@@ -134,6 +158,16 @@
On other platforms, the method returns 0.
</description>
</method>
+ <method name="get_drive_name" qualifiers="static">
+ <return type="String" />
+ <param index="0" name="idx" type="int" />
+ <description>
+ On Windows, returns the name of the drive (partition) passed as an argument (e.g. [code]C:[/code]).
+ On macOS, returns the path to the mounted volume passed as an argument.
+ On Linux, returns the path to the mounted volume or GTK 3 bookmark passed as an argument.
+ On other platforms, or if the requested drive does not exist, the method returns an empty String.
+ </description>
+ </method>
<method name="get_files">
<return type="PackedStringArray" />
<description>
@@ -141,11 +175,25 @@
Affected by [member include_hidden].
</description>
</method>
+ <method name="get_files_at" qualifiers="static">
+ <return type="PackedStringArray" />
+ <param index="0" name="path" type="String" />
+ <description>
+ Returns a [PackedStringArray] containing filenames of the directory contents, excluding directories, at the given [param path]. The array is sorted alphabetically.
+ Use [method get_files] if you want more control of what gets included.
+ </description>
+ </method>
<method name="get_next">
<return type="String" />
<description>
- Returns the next element (file or directory) in the current directory (including [code].[/code] and [code]..[/code], unless [code]skip_navigational[/code] was given to [method list_dir_begin]).
- The name of the file or directory is returned (and not its full path). Once the stream has been fully processed, the method returns an empty String and closes the stream automatically (i.e. [method list_dir_end] would not be mandatory in such a case).
+ Returns the next element (file or directory) in the current directory.
+ The name of the file or directory is returned (and not its full path). Once the stream has been fully processed, the method returns an empty [String] and closes the stream automatically (i.e. [method list_dir_end] would not be mandatory in such a case).
+ </description>
+ </method>
+ <method name="get_open_error" qualifiers="static">
+ <return type="int" enum="Error" />
+ <description>
+ Returns the result of the last [method open] call in the current thread.
</description>
</method>
<method name="get_space_left">
@@ -176,6 +224,13 @@
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
+ <method name="make_dir_absolute" qualifiers="static">
+ <return type="int" enum="Error" />
+ <param index="0" name="path" type="String" />
+ <description>
+ Static version of [method make_dir]. Supports only absolute paths.
+ </description>
+ </method>
<method name="make_dir_recursive">
<return type="int" enum="Error" />
<param index="0" name="path" type="String" />
@@ -184,12 +239,19 @@
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
- <method name="open">
+ <method name="make_dir_recursive_absolute" qualifiers="static">
<return type="int" enum="Error" />
<param index="0" name="path" type="String" />
<description>
- Opens an existing directory of the filesystem. The [param path] argument can be within the project tree ([code]res://folder[/code]), the user directory ([code]user://folder[/code]) or an absolute path of the user filesystem (e.g. [code]/tmp/folder[/code] or [code]C:\tmp\folder[/code]).
- Returns one of the [enum Error] code constants ([code]OK[/code] on success).
+ Static version of [method make_dir_recursive]. Supports only absolute paths.
+ </description>
+ </method>
+ <method name="open" qualifiers="static">
+ <return type="DirAccess" />
+ <param index="0" name="path" type="String" />
+ <description>
+ Creates a new [DirAccess] object and opens an existing directory of the filesystem. The [param path] argument can be within the project tree ([code]res://folder[/code]), the user directory ([code]user://folder[/code]) or an absolute path of the user filesystem (e.g. [code]/tmp/folder[/code] or [code]C:\tmp\folder[/code]).
+ Returns [code]null[/code] if opening the directory failed. You can use [method get_open_error] to check the error that ocurred.
</description>
</method>
<method name="remove">
@@ -201,6 +263,13 @@
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
+ <method name="remove_absolute" qualifiers="static">
+ <return type="int" enum="Error" />
+ <param index="0" name="path" type="String" />
+ <description>
+ Static version of [method remove]. Supports only absolute paths.
+ </description>
+ </method>
<method name="rename">
<return type="int" enum="Error" />
<param index="0" name="from" type="String" />
@@ -210,13 +279,21 @@
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
+ <method name="rename_absolute" qualifiers="static">
+ <return type="int" enum="Error" />
+ <param index="0" name="from" type="String" />
+ <param index="1" name="to" type="String" />
+ <description>
+ Static version of [method rename]. Supports only absolute paths.
+ </description>
+ </method>
</methods>
<members>
- <member name="include_hidden" type="bool" setter="set_include_hidden" getter="get_include_hidden" default="false">
+ <member name="include_hidden" type="bool" setter="set_include_hidden" getter="get_include_hidden">
If [code]true[/code], hidden files are included when the navigating directory.
Affects [method list_dir_begin], [method get_directories] and [method get_files].
</member>
- <member name="include_navigational" type="bool" setter="set_include_navigational" getter="get_include_navigational" default="false">
+ <member name="include_navigational" type="bool" setter="set_include_navigational" getter="get_include_navigational">
If [code]true[/code], [code].[/code] and [code]..[/code] are included when navigating the directory.
Affects [method list_dir_begin] and [method get_directories].
</member>
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index d22d64c276..6d3f3a7362 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -1324,6 +1324,7 @@
<param index="0" name="window_id" type="int" />
<param index="1" name="parent_window_id" type="int" />
<description>
+ Sets window transient parent. Transient window is will be destroyed with its transient parent and displayed on top of non-exclusive full-screen parent window. Transient windows can't enter full-screen mode.
</description>
</method>
<method name="window_set_vsync_mode">
@@ -1336,6 +1337,15 @@
Depending on the platform and used renderer, the engine will fall back to [constant VSYNC_ENABLED], if the desired mode is not supported.
</description>
</method>
+ <method name="window_set_window_buttons_offset">
+ <return type="void" />
+ <param index="0" name="offset" type="Vector2i" />
+ <param index="1" name="window_id" type="int" default="0" />
+ <description>
+ When [constant WINDOW_FLAG_EXTEND_TO_TITLE] flag is set, set offset to the center of the first titlebar button.
+ [b]Note:[/b] This flag is implemented on macOS.
+ </description>
+ </method>
<method name="window_set_window_event_callback">
<return type="void" />
<param index="0" name="callback" type="Callable" />
@@ -1509,7 +1519,8 @@
Window is floating above other regular windows. This flag is ignored for full-screen windows.
</constant>
<constant name="WINDOW_FLAG_TRANSPARENT" value="3" enum="WindowFlags">
- Window is will be destroyed with its transient parent and displayed on top of non-exclusive full-screen parent window. Transient windows can't enter full-screen mode.
+ Window background can be transparent.
+ [b]Note:[/b] This flag has no effect if [member ProjectSettings.display/window/per_pixel_transparency/allowed] is set to [code]false[/code].
</constant>
<constant name="WINDOW_FLAG_NO_FOCUS" value="4" enum="WindowFlags">
Window can't be focused. No-focus window will ignore all input, except mouse clicks.
@@ -1537,6 +1548,8 @@
</constant>
<constant name="WINDOW_EVENT_DPI_CHANGE" value="6" enum="WindowEvent">
</constant>
+ <constant name="WINDOW_EVENT_TITLEBAR_CHANGE" value="7" enum="WindowEvent">
+ </constant>
<constant name="VSYNC_DISABLED" value="0" enum="VSyncMode">
No vertical synchronization, which means the engine will display frames as fast as possible (tearing may be visible).
</constant>
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index 348347c4ef..c395815117 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -9,7 +9,7 @@
Below is an example EditorImportPlugin that imports a [Mesh] from a file with the extension ".special" or ".spec":
[codeblocks]
[gdscript]
- tool
+ @tool
extends EditorImportPlugin
func _get_importer_name():
@@ -44,7 +44,7 @@
# Fill the Mesh with data read in "file", left as an exercise to the reader.
var filename = save_path + "." + _get_save_extension()
- return ResourceSaver.save(filename, mesh)
+ return ResourceSaver.save(mesh, filename)
[/gdscript]
[csharp]
using Godot;
@@ -103,7 +103,7 @@
var mesh = new ArrayMesh();
// Fill the Mesh with data read in "file", left as an exercise to the reader.
String filename = savePath + "." + GetSaveExtension();
- return (int)ResourceSaver.Save(filename, mesh);
+ return (int)ResourceSaver.Save(mesh, filename);
}
}
[/csharp]
diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml
index 280a7bf34a..a1a43dd5bf 100644
--- a/doc/classes/EditorInspector.xml
+++ b/doc/classes/EditorInspector.xml
@@ -13,6 +13,14 @@
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="get_selected_path" qualifiers="const">
+ <return type="String" />
+ <description>
+ Gets the path of the currently selected property.
+ </description>
+ </method>
+ </methods>
<members>
<member name="horizontal_scroll_mode" type="int" setter="set_horizontal_scroll_mode" getter="get_horizontal_scroll_mode" overrides="ScrollContainer" enum="ScrollContainer.ScrollMode" default="0" />
</members>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 8f4c848041..27cf410c15 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -237,7 +237,7 @@
# You can use a custom icon:
return preload("res://addons/my_plugin/my_plugin_icon.svg")
# Or use a built-in icon:
- return get_editor_interface().get_base_control().get_icon("Node", "EditorIcons")
+ return get_editor_interface().get_base_control().get_theme_icon("Node", "EditorIcons")
[/gdscript]
[csharp]
public override Texture2D GetPluginIcon()
@@ -245,7 +245,7 @@
// You can use a custom icon:
return ResourceLoader.Load&lt;Texture2D&gt;("res://addons/my_plugin/my_plugin_icon.svg");
// Or use a built-in icon:
- return GetEditorInterface().GetBaseControl().GetIcon("Node", "EditorIcons");
+ return GetEditorInterface().GetBaseControl().GetThemeIcon("Node", "EditorIcons");
}
[/csharp]
[/codeblocks]
diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml
index 7bac4bf7ac..9170c449bf 100644
--- a/doc/classes/EditorProperty.xml
+++ b/doc/classes/EditorProperty.xml
@@ -9,6 +9,13 @@
<tutorials>
</tutorials>
<methods>
+ <method name="_set_read_only" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="read_only" type="bool" />
+ <description>
+ Called when the read-only status of the property is changed. It may be used to change custom controls into a read-only or modifiable state.
+ </description>
+ </method>
<method name="_update_property" qualifiers="virtual">
<return type="void" />
<description>
diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml
index 395b094bf2..2bf2accf17 100644
--- a/doc/classes/EditorScenePostImport.xml
+++ b/doc/classes/EditorScenePostImport.xml
@@ -8,7 +8,7 @@
The [method _post_import] callback receives the imported scene's root node and returns the modified version of the scene. Usage example:
[codeblocks]
[gdscript]
- tool # Needed so it runs in editor.
+ @tool # Needed so it runs in editor.
extends EditorScenePostImport
# This sample changes all node names.
# Called right after the scene is imported and gets the root node.
diff --git a/doc/classes/EditorScript.xml b/doc/classes/EditorScript.xml
index 2ff8a7ba2a..dfc04c9cde 100644
--- a/doc/classes/EditorScript.xml
+++ b/doc/classes/EditorScript.xml
@@ -9,7 +9,7 @@
[b]Example script:[/b]
[codeblocks]
[gdscript]
- tool
+ @tool
extends EditorScript
func _run():
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 329cd3fe63..6007128965 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -405,7 +405,7 @@
If [code]true[/code], allows panning by holding down [kbd]Space[/kbd] in the 2D editor viewport (in addition to panning with the middle or right mouse buttons). If [code]false[/code], the left mouse button must be held down while holding down [kbd]Space[/kbd] to pan in the 2D editor viewport.
</member>
<member name="editors/panning/sub_editors_panning_scheme" type="int" setter="" getter="">
- Controls whether the mouse wheel scroll zooms or pans in subeditors. The list of affected subeditors is: animation blend tree editor, [Polygon2D] editor, tileset editor, texture region editor, visual shader editor and visual script editor. See also [member editors/panning/2d_editor_panning_scheme] and [member editors/panning/animation_editors_panning_scheme].
+ Controls whether the mouse wheel scroll zooms or pans in subeditors. The list of affected subeditors is: animation blend tree editor, [Polygon2D] editor, tileset editor, texture region editor and visual shader editor. See also [member editors/panning/2d_editor_panning_scheme] and [member editors/panning/animation_editors_panning_scheme].
</member>
<member name="editors/panning/warped_mouse_panning" type="bool" setter="" getter="">
If [code]true[/code], warps the mouse around the 2D viewport while panning in the 2D editor. This makes it possible to pan over a large area without having to exit panning then mouse the mouse back constantly.
@@ -424,10 +424,10 @@
[b]Note:[/b] Only effective if [member editors/tiles_editor/display_grid] is [code]true[/code].
</member>
<member name="editors/visual_editors/lines_curvature" type="float" setter="" getter="">
- The curvature to use for connection lines in the visual script and visual shader editors. Higher values will make connection lines appear more curved, with values above [code]0.5[/code] resulting in more "angular" turns in the middle of connection lines.
+ The curvature to use for connection lines in the visual shader editor. Higher values will make connection lines appear more curved, with values above [code]0.5[/code] resulting in more "angular" turns in the middle of connection lines.
</member>
<member name="editors/visual_editors/minimap_opacity" type="float" setter="" getter="">
- The opacity of the minimap displayed in the bottom-right corner of the visual script and visual shader editors.
+ The opacity of the minimap displayed in the bottom-right corner of the visual shader editor.
</member>
<member name="editors/visual_editors/visual_shader/port_preview_size" type="int" setter="" getter="">
The size to use for port previews in the visual shader uniforms (toggled by clicking the "eye" icon next to an output). The value is defined in pixels at 100% zoom, and will scale with zoom automatically.
diff --git a/doc/classes/EditorTranslationParserPlugin.xml b/doc/classes/EditorTranslationParserPlugin.xml
index d028996db8..df10c645ef 100644
--- a/doc/classes/EditorTranslationParserPlugin.xml
+++ b/doc/classes/EditorTranslationParserPlugin.xml
@@ -11,7 +11,7 @@
Below shows an example of a custom parser that extracts strings from a CSV file to write into a POT.
[codeblocks]
[gdscript]
- tool
+ @tool
extends EditorTranslationParserPlugin
func _parse_file(path, msgids, msgids_context_plural):
@@ -72,7 +72,7 @@
msgidsContextPlural.Add(new Godot.Collections.Array{"Only with context", "a friendly context", ""});
[/csharp]
[/codeblocks]
- [b]Note:[/b] If you override parsing logic for standard script types (GDScript, C#, etc.), it would be better to load the [code]path[/code] argument using [method ResourceLoader.load]. This is because built-in scripts are loaded as [Resource] type, not [File] type.
+ [b]Note:[/b] If you override parsing logic for standard script types (GDScript, C#, etc.), it would be better to load the [code]path[/code] argument using [method ResourceLoader.load]. This is because built-in scripts are loaded as [Resource] type, not [FileAccess] type.
For example:
[codeblocks]
[gdscript]
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index 301a3e55fb..ecf3d87a70 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -14,12 +14,20 @@
<description>
Returns the name of the CPU architecture the Godot binary was built for. Possible return values are [code]x86_64[/code], [code]x86_32[/code], [code]arm64[/code], [code]armv7[/code], [code]rv64[/code], [code]riscv[/code], [code]ppc64[/code], [code]ppc[/code], [code]wasm64[/code] and [code]wasm32[/code].
To detect whether the current CPU architecture is 64-bit, you can use the fact that all 64-bit architecture names have [code]64[/code] in their name:
- [codeblock]
+ [codeblocks]
+ [gdscript]
if "64" in Engine.get_architecture_name():
print("Running on 64-bit CPU.")
else:
print("Running on 32-bit CPU.")
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ if (Engine.GetArchitectureName().Contains("64"))
+ GD.Print("Running on 64-bit CPU.");
+ else
+ GD.Print("Running on 32-bit CPU.");
+ [/csharp]
+ [/codeblocks]
[b]Note:[/b] [method get_architecture_name] does [i]not[/i] return the name of the host CPU architecture. For example, if running an x86_32 Godot binary on a x86_64 system, the returned value will be [code]x86_32[/code].
</description>
</method>
@@ -83,11 +91,24 @@
<description>
Returns the total number of frames passed since engine initialization which is advanced on each [b]physics frame[/b]. See also [method get_process_frames].
[method get_physics_frames] can be used to run expensive logic less often without relying on a [Timer]:
- [codeblock]
+ [codeblocks]
+ [gdscript]
func _physics_process(_delta):
if Engine.get_physics_frames() % 2 == 0:
pass # Run expensive logic only once every 2 physics frames here.
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ public override void _PhysicsProcess(double delta)
+ {
+ base._PhysicsProcess(delta);
+
+ if (Engine.GetPhysicsFrames() % 2 == 0)
+ {
+ // Run expensive logic only once every 2 physics frames here.
+ }
+ }
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="get_physics_interpolation_fraction" qualifiers="const">
@@ -101,11 +122,24 @@
<description>
Returns the total number of frames passed since engine initialization which is advanced on each [b]process frame[/b], regardless of whether the render loop is enabled. See also [method get_frames_drawn] and [method get_physics_frames].
[method get_process_frames] can be used to run expensive logic less often without relying on a [Timer]:
- [codeblock]
+ [codeblocks]
+ [gdscript]
func _process(_delta):
if Engine.get_process_frames() % 2 == 0:
pass # Run expensive logic only once every 2 process (render) frames here.
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ public override void _Process(double delta)
+ {
+ base._Process(delta);
+
+ if (Engine.GetProcessFrames() % 2 == 0)
+ {
+ // Run expensive logic only once every 2 physics frames here.
+ }
+ }
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="get_script_language" qualifiers="const">
@@ -182,12 +216,20 @@
<return type="bool" />
<description>
Returns [code]true[/code] if the script is currently running inside the editor, [code]false[/code] otherwise. This is useful for [code]@tool[/code] scripts to conditionally draw editor helpers, or prevent accidentally running "game" code that would affect the scene state while in the editor:
- [codeblock]
+ [codeblocks]
+ [gdscript]
if Engine.is_editor_hint():
draw_gizmos()
else:
simulate_physics()
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ if (Engine.IsEditorHint())
+ DrawGizmos();
+ else
+ SimulatePhysics();
+ [/csharp]
+ [/codeblocks]
See [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url] in the documentation for more information.
[b]Note:[/b] To detect whether the script is run from an editor [i]build[/i] (e.g. when pressing [kbd]F5[/kbd]), use [method OS.has_feature] with the [code]"editor"[/code] argument instead. [code]OS.has_feature("editor")[/code] will evaluate to [code]true[/code] both when the code is running in the editor and when running the project from the editor, but it will evaluate to [code]false[/code] when the code is run from an exported project.
</description>
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index 695f2cbc66..243a28e73d 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -86,7 +86,7 @@
This is useful to simulate [url=https://en.wikipedia.org/wiki/Aerial_perspective]aerial perspective[/url] in large scenes with low density fog. However, it is not very useful for high-density fog, as the sky will shine through. When set to [code]1.0[/code], the fog color comes completely from the [Sky]. If set to [code]0.0[/code], aerial perspective is disabled.
</member>
<member name="fog_density" type="float" setter="set_fog_density" getter="get_fog_density" default="0.01">
- The exponential fog density to use. Higher values result in a more dense fog.
+ The [i]exponential[/i] fog density to use. Higher values result in a more dense fog. Fog rendering is exponential as in real life.
</member>
<member name="fog_enabled" type="bool" setter="set_fog_enabled" getter="is_fog_enabled" default="false">
If [code]true[/code], fog effects are enabled.
@@ -292,13 +292,15 @@
The [Color] of the volumetric fog when interacting with lights. Mist and fog have an albedo close to [code]Color(1, 1, 1, 1)[/code] while smoke has a darker albedo.
</member>
<member name="volumetric_fog_ambient_inject" type="float" setter="set_volumetric_fog_ambient_inject" getter="get_volumetric_fog_ambient_inject" default="0.0">
- Scales the strength of ambient light used in the volumetric fog. A value of [code]0[/code] means that ambient light will not impact the volumetric fog.
+ Scales the strength of ambient light used in the volumetric fog. A value of [code]0.0[/code] means that ambient light will not impact the volumetric fog. [member volumetric_fog_ambient_inject] has a small performance cost when set above [code]0.0[/code].
+ [b]Note:[/b] This has no visible effect if [member volumetric_fog_density] is [code]0.0[/code] or if [member volumetric_fog_albedo] is a fully black color.
</member>
<member name="volumetric_fog_anisotropy" type="float" setter="set_volumetric_fog_anisotropy" getter="get_volumetric_fog_anisotropy" default="0.2">
- The direction of scattered light as it goes through the volumetric fog. A value close [code]1[/code] means almost all light is scattered forward. A value close to [code]0[/code] means light is scattered equally in all directions. A value close to [code]-1[/code] means light is scattered mostly backward. Fog and mist scatter light slightly forward, while smoke scatters light equally in all directions.
+ The direction of scattered light as it goes through the volumetric fog. A value close to [code]1.0[/code] means almost all light is scattered forward. A value close to [code]0.0[/code] means light is scattered equally in all directions. A value close to [code]-1.0[/code] means light is scattered mostly backward. Fog and mist scatter light slightly forward, while smoke scatters light equally in all directions.
</member>
<member name="volumetric_fog_density" type="float" setter="set_volumetric_fog_density" getter="get_volumetric_fog_density" default="0.05">
- The base density of the volumetric fog. Set this to the lowest density you want to have globally.
+ The base [i]exponential[/i] density of the volumetric fog. Set this to the lowest density you want to have globally. [FogVolume]s can be used to add to or subtract from this density in specific areas. Fog rendering is exponential as in real life.
+ A value of [code]0.0[/code] disables global volumetric fog while allowing [FogVolume]s to display volumetric fog in specific areas.
</member>
<member name="volumetric_fog_detail_spread" type="float" setter="set_volumetric_fog_detail_spread" getter="get_volumetric_fog_detail_spread" default="2.0">
The distribution of size down the length of the froxel buffer. A higher value compresses the froxels closer to the camera and places more detail closer to the camera.
@@ -311,22 +313,25 @@
</member>
<member name="volumetric_fog_enabled" type="bool" setter="set_volumetric_fog_enabled" getter="is_volumetric_fog_enabled" default="false">
Enables the volumetric fog effect. Volumetric fog uses a screen-aligned froxel buffer to calculate accurate volumetric scattering in the short to medium range. Volumetric fog interacts with [FogVolume]s and lights to calculate localized and global fog. Volumetric fog uses a PBR single-scattering model based on extinction, scattering, and emission which it exposes to users as density, albedo, and emission.
+ [b]Note:[/b] Volumetric fog is only available in the forward plus renderer. It is not available in the mobile renderer or the compatibility renderer.
</member>
<member name="volumetric_fog_gi_inject" type="float" setter="set_volumetric_fog_gi_inject" getter="get_volumetric_fog_gi_inject" default="1.0">
- Scales the strength of Global Illumination used in the volumetric fog. A value of [code]0.0[/code] means that Global Illumination will not impact the volumetric fog.
+ Scales the strength of Global Illumination used in the volumetric fog's albedo color. A value of [code]0.0[/code] means that Global Illumination will not impact the volumetric fog. [member volumetric_fog_gi_inject] has a small performance cost when set above [code]0.0[/code].
+ [b]Note:[/b] This has no visible effect if [member volumetric_fog_density] is [code]0.0[/code] or if [member volumetric_fog_albedo] is a fully black color.
[b]Note:[/b] Only [VoxelGI] and SDFGI ([member Environment.sdfgi_enabled]) are taken into account when using [member volumetric_fog_gi_inject]. Global illumination from [LightmapGI], [ReflectionProbe] and SSIL (see [member ssil_enabled]) will be ignored by volumetric fog.
</member>
<member name="volumetric_fog_length" type="float" setter="set_volumetric_fog_length" getter="get_volumetric_fog_length" default="64.0">
- The distance over which the volumetric fog is computed. Increase to compute fog over a greater range, decrease to add more detail when a long range is not needed. For best quality fog, keep this as low as possible.
+ The distance over which the volumetric fog is computed. Increase to compute fog over a greater range, decrease to add more detail when a long range is not needed. For best quality fog, keep this as low as possible. See also [member ProjectSettings.rendering/environment/volumetric_fog/volume_depth].
</member>
<member name="volumetric_fog_sky_affect" type="float" setter="set_volumetric_fog_sky_affect" getter="get_volumetric_fog_sky_affect" default="1.0">
The factor to use when affecting the sky with volumetric fog. [code]1.0[/code] means that volumetric fog can fully obscure the sky. Lower values reduce the impact of volumetric fog on sky rendering, with [code]0.0[/code] not affecting sky rendering at all.
+ [b]Note:[/b] [member volumetric_fog_sky_affect] also affects [FogVolume]s, even if [member volumetric_fog_density] is [code]0.0[/code]. If you notice [FogVolume]s are disappearing when looking towards the sky, set [member volumetric_fog_sky_affect] to [code]1.0[/code].
</member>
<member name="volumetric_fog_temporal_reprojection_amount" type="float" setter="set_volumetric_fog_temporal_reprojection_amount" getter="get_volumetric_fog_temporal_reprojection_amount" default="0.9">
The amount by which to blend the last frame with the current frame. A higher number results in smoother volumetric fog, but makes "ghosting" much worse. A lower value reduces ghosting but can result in the per-frame temporal jitter becoming visible.
</member>
<member name="volumetric_fog_temporal_reprojection_enabled" type="bool" setter="set_volumetric_fog_temporal_reprojection_enabled" getter="is_volumetric_fog_temporal_reprojection_enabled" default="true">
- Enables temporal reprojection in the volumetric fog. Temporal reprojection blends the current frame's volumetric fog with the last frame's volumetric fog to smooth out jagged edges. The performance cost is minimal, however it does lead to moving [FogVolume]s and [Light3D]s "ghosting" and leaving a trail behind them. When temporal reprojection is enabled, try to avoid moving [FogVolume]s or [Light3D]s too fast.
+ Enables temporal reprojection in the volumetric fog. Temporal reprojection blends the current frame's volumetric fog with the last frame's volumetric fog to smooth out jagged edges. The performance cost is minimal; however, it leads to moving [FogVolume]s and [Light3D]s "ghosting" and leaving a trail behind them. When temporal reprojection is enabled, try to avoid moving [FogVolume]s or [Light3D]s too fast. Short-lived dynamic lighting effects should have [member Light3D.light_volumetric_fog_energy] set to [code]0.0[/code] to avoid ghosting.
</member>
</members>
<constants>
diff --git a/doc/classes/File.xml b/doc/classes/FileAccess.xml
index 76c6a4871c..adc0f4c3dd 100644
--- a/doc/classes/File.xml
+++ b/doc/classes/FileAccess.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="File" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="FileAccess" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Type to handle file reading and writing operations.
</brief_description>
@@ -9,39 +9,42 @@
[codeblocks]
[gdscript]
func save(content):
- var file = File.new()
- file.open("user://save_game.dat", File.WRITE)
+ var file = FileAccess.open("user://save_game.dat", FileAccess.WRITE)
file.store_string(content)
- file.close()
func load():
- var file = File.new()
- file.open("user://save_game.dat", File.READ)
+ var file = FileAccess.open("user://save_game.dat", FileAccess.READ)
var content = file.get_as_text()
- file.close()
return content
[/gdscript]
[csharp]
public void Save(string content)
{
- var file = new File();
- file.Open("user://save_game.dat", File.ModeFlags.Write);
+ using var file = FileAccess.Open("user://save_game.dat", File.ModeFlags.Write);
file.StoreString(content);
- file.Close();
}
public string Load()
{
- var file = new File();
- file.Open("user://save_game.dat", File.ModeFlags.Read);
+ using var file = FileAccess.Open("user://save_game.dat", File.ModeFlags.Read);
string content = file.GetAsText();
- file.Close();
return content;
}
[/csharp]
[/codeblocks]
In the example above, the file will be saved in the user data folder as specified in the [url=$DOCS_URL/tutorials/io/data_paths.html]Data paths[/url] documentation.
- [b]Note:[/b] To access project resources once exported, it is recommended to use [ResourceLoader] instead of the [File] API, as some files are converted to engine-specific formats and their original source files might not be present in the exported PCK package.
+ There is no method to close a file in order to free it from use. Instead, [FileAccess] will close when it's freed, which happens when it goes out of scope or when it gets assigned with [code]null[/code]. In C# the reference must be disposed after we are done using it, this can be done with the [code]using[/code] statement or calling the [code]Dispose[/code] method directly.
+ [codeblocks]
+ [gdscript]
+ var file = FileAccess.open("res://something") # File is opened and locked for use.
+ file = null # File is closed.
+ [/gdscript]
+ [csharp]
+ using var file = FileAccess.Open("res://something"); // File is opened and locked for use.
+ // The using statement calls Dispose when going out of scope.
+ [/csharp]
+ [/codeblocks]
+ [b]Note:[/b] To access project resources once exported, it is recommended to use [ResourceLoader] instead of the [FileAccess] API, as some files are converted to engine-specific formats and their original source files might not be present in the exported PCK package.
[b]Note:[/b] Files are automatically closed only if the process exits "normally" (such as by clicking the window manager's close button or pressing [b]Alt + F4[/b]). If you stop the project execution by pressing [b]F8[/b] while the project is running, the file won't be closed as the game process will be killed. You can work around this by calling [method flush] at regular intervals.
</description>
<tutorials>
@@ -49,12 +52,6 @@
<link title="3D Voxel Demo">https://godotengine.org/asset-library/asset/676</link>
</tutorials>
<methods>
- <method name="close">
- <return type="void" />
- <description>
- Closes the currently opened file and prevents subsequent read/write operations. Use [method flush] to persist the data to disk without closing the file.
- </description>
- </method>
<method name="eof_reached" qualifiers="const">
<return type="bool" />
<description>
@@ -80,12 +77,13 @@
<description>
Returns [code]true[/code] if the file exists in the given path.
[b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. See [method ResourceLoader.exists] for an alternative approach that takes resource remapping into account.
+ For a non-static, relative equivalent, use [method DirAccess.file_exists].
</description>
</method>
<method name="flush">
<return type="void" />
<description>
- Writes the file's buffer to disk. Flushing is automatically performed when the file is closed. This means you don't need to call [method flush] manually before closing a file using [method close]. Still, calling [method flush] can be used to ensure the data is safe even if the project crashes instead of being closed gracefully.
+ Writes the file's buffer to disk. Flushing is automatically performed when the file is closed. This means you don't need to call [method flush] manually before closing a file. Still, calling [method flush] can be used to ensure the data is safe even if the project crashes instead of being closed gracefully.
[b]Note:[/b] Only call [method flush] when you actually need it. Otherwise, it will decrease performance due to constant disk writes.
</description>
</method>
@@ -174,20 +172,26 @@
Text is interpreted as being UTF-8 encoded.
</description>
</method>
- <method name="get_md5" qualifiers="const">
+ <method name="get_md5" qualifiers="static">
<return type="String" />
<param index="0" name="path" type="String" />
<description>
Returns an MD5 String representing the file at the given path or an empty [String] on failure.
</description>
</method>
- <method name="get_modified_time" qualifiers="const">
+ <method name="get_modified_time" qualifiers="static">
<return type="int" />
<param index="0" name="file" type="String" />
<description>
Returns the last time the [param file] was modified in Unix timestamp format or returns a [String] "ERROR IN [code]file[/code]". This Unix timestamp can be converted to another format using the [Time] singleton.
</description>
</method>
+ <method name="get_open_error" qualifiers="static">
+ <return type="int" enum="Error" />
+ <description>
+ Returns the result of the last [method open] call in the current thread.
+ </description>
+ </method>
<method name="get_pascal_string">
<return type="String" />
<description>
@@ -219,7 +223,7 @@
Returns the next bits from the file as a floating-point number.
</description>
</method>
- <method name="get_sha256" qualifiers="const">
+ <method name="get_sha256" qualifiers="static">
<return type="String" />
<param index="0" name="path" type="String" />
<description>
@@ -240,41 +244,45 @@
Returns [code]true[/code] if the file is currently opened.
</description>
</method>
- <method name="open">
- <return type="int" enum="Error" />
+ <method name="open" qualifiers="static">
+ <return type="FileAccess" />
<param index="0" name="path" type="String" />
- <param index="1" name="flags" type="int" enum="File.ModeFlags" />
+ <param index="1" name="flags" type="int" enum="FileAccess.ModeFlags" />
<description>
- Opens the file for writing or reading, depending on the flags.
+ Creates a new [FileAccess] object and opens the file for writing or reading, depending on the flags.
+ Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that ocurred.
</description>
</method>
- <method name="open_compressed">
- <return type="int" enum="Error" />
+ <method name="open_compressed" qualifiers="static">
+ <return type="FileAccess" />
<param index="0" name="path" type="String" />
- <param index="1" name="mode_flags" type="int" enum="File.ModeFlags" />
- <param index="2" name="compression_mode" type="int" enum="File.CompressionMode" default="0" />
+ <param index="1" name="mode_flags" type="int" enum="FileAccess.ModeFlags" />
+ <param index="2" name="compression_mode" type="int" enum="FileAccess.CompressionMode" default="0" />
<description>
- Opens a compressed file for reading or writing.
+ Creates a new [FileAccess] object and opens a compressed file for reading or writing.
[b]Note:[/b] [method open_compressed] can only read files that were saved by Godot, not third-party compression formats. See [url=https://github.com/godotengine/godot/issues/28999]GitHub issue #28999[/url] for a workaround.
+ Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that ocurred.
</description>
</method>
- <method name="open_encrypted">
- <return type="int" enum="Error" />
+ <method name="open_encrypted" qualifiers="static">
+ <return type="FileAccess" />
<param index="0" name="path" type="String" />
- <param index="1" name="mode_flags" type="int" enum="File.ModeFlags" />
+ <param index="1" name="mode_flags" type="int" enum="FileAccess.ModeFlags" />
<param index="2" name="key" type="PackedByteArray" />
<description>
- Opens an encrypted file in write or read mode. You need to pass a binary key to encrypt/decrypt it.
+ Creates a new [FileAccess] object and opens an encrypted file in write or read mode. You need to pass a binary key to encrypt/decrypt it.
[b]Note:[/b] The provided key must be 32 bytes long.
+ Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that ocurred.
</description>
</method>
- <method name="open_encrypted_with_pass">
- <return type="int" enum="Error" />
+ <method name="open_encrypted_with_pass" qualifiers="static">
+ <return type="FileAccess" />
<param index="0" name="path" type="String" />
- <param index="1" name="mode_flags" type="int" enum="File.ModeFlags" />
+ <param index="1" name="mode_flags" type="int" enum="FileAccess.ModeFlags" />
<param index="2" name="pass" type="String" />
<description>
- Opens an encrypted file in write or read mode. You need to pass a password to encrypt/decrypt it.
+ Creates a new [FileAccess] object and opens an encrypted file in write or read mode. You need to pass a password to encrypt/decrypt it.
+ Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that ocurred.
</description>
</method>
<method name="seek">
@@ -432,7 +440,7 @@
</method>
</methods>
<members>
- <member name="big_endian" type="bool" setter="set_big_endian" getter="is_big_endian" default="false">
+ <member name="big_endian" type="bool" setter="set_big_endian" getter="is_big_endian">
If [code]true[/code], the file is read with big-endian [url=https://en.wikipedia.org/wiki/Endianness]endianness[/url]. If [code]false[/code], the file is read with little-endian endianness. If in doubt, leave this to [code]false[/code] as most files are written with little-endian endianness.
[b]Note:[/b] [member big_endian] is only about the file format, not the CPU type. The CPU endianness doesn't affect the default endianness for files written.
[b]Note:[/b] This is always reset to [code]false[/code] whenever you open the file. Therefore, you must set [member big_endian] [i]after[/i] opening the file, not before.
diff --git a/doc/classes/FogMaterial.xml b/doc/classes/FogMaterial.xml
index e63d4ddf3e..7428d6169a 100644
--- a/doc/classes/FogMaterial.xml
+++ b/doc/classes/FogMaterial.xml
@@ -5,27 +5,28 @@
</brief_description>
<description>
A [Material] resource that can be used by [FogVolume]s to draw volumetric effects.
+ If you need more advanced effects, use a custom [url=$DOCS_URL/tutorials/shaders/shader_reference/fog_shader.html]fog shader[/url].
</description>
<tutorials>
</tutorials>
<members>
<member name="albedo" type="Color" setter="set_albedo" getter="get_albedo" default="Color(1, 1, 1, 1)">
- Sets the single-scattering [Color] of the [FogVolume]. Internally [member albedo] is converted into single-scattering which is additively blended with other [FogVolume]s and the [member Environment.volumetric_fog_albedo].
+ The single-scattering [Color] of the [FogVolume]. Internally, [member albedo] is converted into single-scattering, which is additively blended with other [FogVolume]s and the [member Environment.volumetric_fog_albedo].
</member>
<member name="density" type="float" setter="set_density" getter="get_density" default="1.0">
- Sets the density of the [FogVolume]. Denser objects are more opaque, but may suffer from under-sampling artifacts that look like stripes.
+ The density of the [FogVolume]. Denser objects are more opaque, but may suffer from under-sampling artifacts that look like stripes. Negative values can be used to subtract fog from other [FogVolume]s or global volumetric fog.
</member>
<member name="density_texture" type="Texture3D" setter="set_density_texture" getter="get_density_texture">
- Sets a 3D texture that is used to scale the [member density] of the [FogVolume].
+ The 3D texture that is used to scale the [member density] of the [FogVolume]. This can be used to vary fog density within the [FogVolume] with any kind of static pattern. For animated effects, consider using a custom [url=$DOCS_URL/tutorials/shaders/shader_reference/fog_shader.html]fog shader[/url].
</member>
<member name="edge_fade" type="float" setter="set_edge_fade" getter="get_edge_fade" default="0.1">
- Sets the hardness of the edges of the [FogVolume]. A higher number will result in softer edges while a lower number will result in harder edges.
+ The hardness of the edges of the [FogVolume]. A higher value will result in softer edges, while a lower value will result in harder edges.
</member>
<member name="emission" type="Color" setter="set_emission" getter="get_emission" default="Color(0, 0, 0, 1)">
- Sets the [Color] of the light emitted by the [FogVolume]. Emitted light will not cast light or shadows on other objects, but can be useful for modulating the [Color] of the [FogVolume] independently from light sources.
+ The [Color] of the light emitted by the [FogVolume]. Emitted light will not cast light or shadows on other objects, but can be useful for modulating the [Color] of the [FogVolume] independently from light sources.
</member>
<member name="height_falloff" type="float" setter="set_height_falloff" getter="get_height_falloff" default="0.0">
- Sets the rate by which the height-based fog decreases in density as height increases in world space. A high falloff will result in a sharp transition, while a low falloff will result in a smoother transition. A value of [code]0[/code] results in uniform-density fog. The height threshold is determined by the height of the associated [FogVolume].
+ The rate by which the height-based fog decreases in density as height increases in world space. A high falloff will result in a sharp transition, while a low falloff will result in a smoother transition. A value of [code]0.0[/code] results in uniform-density fog. The height threshold is determined by the height of the associated [FogVolume].
</member>
</members>
</class>
diff --git a/doc/classes/FogVolume.xml b/doc/classes/FogVolume.xml
index 3f2ee3035c..d9fa2e6ebb 100644
--- a/doc/classes/FogVolume.xml
+++ b/doc/classes/FogVolume.xml
@@ -4,22 +4,23 @@
A node used to add local fog with the volumetric fog effect.
</brief_description>
<description>
- [FogVolume]s are used to add localized fog into the global volumetric fog effect.
+ [FogVolume]s are used to add localized fog into the global volumetric fog effect. [FogVolume]s can also remove volumetric fog from specific areas if using a [FogMaterial] with a negative [member FogMaterial.density].
Performance of [FogVolume]s is directly related to their relative size on the screen and the complexity of their attached [FogMaterial]. It is best to keep [FogVolume]s relatively small and simple where possible.
+ [b]Note:[/b] [FogVolume]s only have a visible effect if [member Environment.volumetric_fog_enabled] is [code]true[/code]. If you don't want fog to be globally visible (but only within [FogVolume] nodes), set [member Environment.volumetric_fog_density] to [code]0.0[/code].
</description>
<tutorials>
</tutorials>
<members>
<member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)">
- Sets the size of the [FogVolume] when [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX].
+ The size of the [FogVolume] when [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX].
[b]Note:[/b] Thin fog volumes may appear to flicker when the camera moves or rotates. This can be alleviated by increasing [member ProjectSettings.rendering/environment/volumetric_fog/volume_depth] (at a performance cost) or by decreasing [member Environment.volumetric_fog_length] (at no performance cost, but at the cost of lower fog range). Alternatively, the [FogVolume] can be made thicker and use a lower density in the [member material].
[b]Note:[/b] If [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_CONE] or [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], the cone/cylinder will be adjusted to fit within the extents. Non-uniform scaling of cone/cylinder shapes via the [member extents] property is not supported, but you can scale the [FogVolume] node instead.
</member>
<member name="material" type="Material" setter="set_material" getter="get_material">
- Sets the [Material] to be used by the [FogVolume]. Can be either a [FogMaterial] or a custom [ShaderMaterial].
+ The [Material] used by the [FogVolume]. Can be either a built-in [FogMaterial] or a custom [ShaderMaterial].
</member>
<member name="shape" type="int" setter="set_shape" getter="get_shape" enum="RenderingServer.FogVolumeShape" default="3">
- Sets the shape of the [FogVolume] to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD].
+ The shape of the [FogVolume]. This can be set to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD].
</member>
</members>
</class>
diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml
index ad3a16afbb..6a42b62bcf 100644
--- a/doc/classes/Font.xml
+++ b/doc/classes/Font.xml
@@ -228,9 +228,15 @@
<description>
Returns the size of a bounding box of a single-line string, taking kerning and advance into account. See also [method get_multiline_string_size] and [method draw_string].
For example, to get the string size as displayed by a single-line Label, use:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var string_size = $Label.get_theme_font("font").get_string_size($Label.text, HORIZONTAL_ALIGNMENT_LEFT, -1, $Label.get_theme_font_size("font_size"))
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Label label = GetNode&lt;Label&gt;("Label");
+ Vector2 stringSize = label.GetThemeFont("font").GetStringSize(label.Text, HorizontalAlignment.Left, -1, label.GetThemeFontSize("font_size"));
+ [/csharp]
+ [/codeblocks]
[b]Note:[/b] Real height of the string is context-dependent and can be significantly different from the value returned by [method get_height].
</description>
</method>
diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml
index 392ca2cabb..0142018f1a 100644
--- a/doc/classes/Geometry2D.xml
+++ b/doc/classes/Geometry2D.xml
@@ -33,6 +33,13 @@
Given an array of [Vector2]s, returns the convex hull as a list of points in counterclockwise order. The last point is the same as the first one.
</description>
</method>
+ <method name="decompose_polygon_in_convex">
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="polygon" type="PackedVector2Array" />
+ <description>
+ Decomposes the [param polygon] into multiple convex hulls and returns an array of [PackedVector2Array].
+ </description>
+ </method>
<method name="exclude_polygons">
<return type="PackedVector2Array[]" />
<param index="0" name="polygon_a" type="PackedVector2Array" />
@@ -126,7 +133,7 @@
<return type="Dictionary" />
<param index="0" name="sizes" type="PackedVector2Array" />
<description>
- Given an array of [Vector2]s representing tiles, builds an atlas. The returned dictionary has two keys: [code]points[/code] is an array of [Vector2] that specifies the positions of each tile, [code]size[/code] contains the overall size of the whole atlas as [Vector2].
+ Given an array of [Vector2]s representing tiles, builds an atlas. The returned dictionary has two keys: [code]points[/code] is a [PackedVector2Array] that specifies the positions of each tile, [code]size[/code] contains the overall size of the whole atlas as [Vector2i].
</description>
</method>
<method name="merge_polygons">
diff --git a/doc/classes/HMACContext.xml b/doc/classes/HMACContext.xml
index 52d4fce28f..706ee30963 100644
--- a/doc/classes/HMACContext.xml
+++ b/doc/classes/HMACContext.xml
@@ -32,22 +32,22 @@
public class CryptoNode : Node
{
private HMACContext ctx = new HMACContext();
+
public override void _Ready()
{
- PackedByteArray key = String("supersecret").to_utf8();
- Error err = ctx.Start(HashingContext.HASH_SHA256, key);
- GD.Assert(err == OK);
- PackedByteArray msg1 = String("this is ").to_utf8();
- PackedByteArray msg2 = String("super duper secret").to_utf8();
+ byte[] key = "supersecret".ToUTF8();
+ Error err = ctx.Start(HashingContext.HashType.Sha256, key);
+ Debug.Assert(err == Error.Ok);
+ byte[] msg1 = "this is ".ToUTF8();
+ byte[] msg2 = "super duper secret".ToUTF8();
err = ctx.Update(msg1);
- GD.Assert(err == OK);
+ Debug.Assert(err == Error.Ok);
err = ctx.Update(msg2);
- GD.Assert(err == OK);
- PackedByteArray hmac = ctx.Finish();
+ Debug.Assert(err == Error.Ok);
+ byte[] hmac = ctx.Finish();
GD.Print(hmac.HexEncode());
}
}
-
[/csharp]
[/codeblocks]
</description>
diff --git a/doc/classes/ImageFormatLoader.xml b/doc/classes/ImageFormatLoader.xml
new file mode 100644
index 0000000000..c6b1ec922a
--- /dev/null
+++ b/doc/classes/ImageFormatLoader.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ImageFormatLoader" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Base class to add support for specific image formats.
+ </brief_description>
+ <description>
+ The engine supports multiple image formats out of the box (PNG, SVG, JPEG, WebP to name a few), but you can choose to implement support for additional image formats by extending [ImageFormatLoaderExtension].
+ </description>
+ <tutorials>
+ </tutorials>
+ <constants>
+ <constant name="FLAG_NONE" value="0" enum="LoaderFlags" is_bitfield="true">
+ </constant>
+ <constant name="FLAG_FORCE_LINEAR" value="1" enum="LoaderFlags" is_bitfield="true">
+ </constant>
+ <constant name="FLAG_CONVERT_COLORS" value="2" enum="LoaderFlags" is_bitfield="true">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/ImageFormatLoaderExtension.xml b/doc/classes/ImageFormatLoaderExtension.xml
new file mode 100644
index 0000000000..b2a7ebc60f
--- /dev/null
+++ b/doc/classes/ImageFormatLoaderExtension.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ImageFormatLoaderExtension" inherits="ImageFormatLoader" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Base class for creating [ImageFormatLoader] extensions (adding support for extra image formats).
+ </brief_description>
+ <description>
+ The engine supports multiple image formats out of the box (PNG, SVG, JPEG, WebP to name a few), but you can choose to implement support for additional image formats by extending this class.
+ Be sure to respect the documented return types and values. You should create an instance of it, and call [method add_format_loader] to register that loader during the initializaiton phase.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_get_recognized_extensions" qualifiers="virtual const">
+ <return type="PackedStringArray" />
+ <description>
+ Returns the list of file extensions for this image format. Files with the given extentions will be treated as image file and loaded using this class.
+ </description>
+ </method>
+ <method name="_load_image" qualifiers="virtual">
+ <return type="int" enum="Error" />
+ <param index="0" name="image" type="Image" />
+ <param index="1" name="fileaccess" type="FileAccess" />
+ <param index="2" name="flags" type="int" enum="ImageFormatLoader.LoaderFlags" />
+ <param index="3" name="scale" type="float" />
+ <description>
+ Loads the content of [param fileaccess] into the provided [param image].
+ </description>
+ </method>
+ <method name="add_format_loader">
+ <return type="void" />
+ <description>
+ Add this format loader to the engine, allowing it to recognize the file extensions returned by [method _get_recognized_extensions].
+ </description>
+ </method>
+ <method name="remove_format_loader">
+ <return type="void" />
+ <description>
+ Remove this format loader from the engine.
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/ImageTextureLayered.xml b/doc/classes/ImageTextureLayered.xml
index f5b338542b..f5786f070a 100644
--- a/doc/classes/ImageTextureLayered.xml
+++ b/doc/classes/ImageTextureLayered.xml
@@ -11,6 +11,8 @@
<return type="int" enum="Error" />
<param index="0" name="images" type="Image[]" />
<description>
+ Creates an [ImageTextureLayered] from an array of [Image]s. The first image decides the width, height, image format and mipmapping setting. The other images must have the same width, height, image format and mipmapping setting.
+ Each [Image] represents one [code]layer[/code].
</description>
</method>
<method name="update_layer">
@@ -18,6 +20,10 @@
<param index="0" name="image" type="Image" />
<param index="1" name="layer" type="int" />
<description>
+ Replaces the existing [Image] data at the given [code]layer[/code] with this new image.
+ The given [Image] must have the same width, height, image format and mipmapping setting (a [code]bool[/code] value) as the rest of the referenced images.
+ If the image format is unsupported, it will be decompressed and converted to a similar and supported [enum Image.Format].
+ The update is immediate: synced with the draw.
</description>
</method>
</methods>
diff --git a/doc/classes/ImporterMesh.xml b/doc/classes/ImporterMesh.xml
index 3c3dbe4d87..1c9655c266 100644
--- a/doc/classes/ImporterMesh.xml
+++ b/doc/classes/ImporterMesh.xml
@@ -43,10 +43,12 @@
<return type="void" />
<param index="0" name="normal_merge_angle" type="float" />
<param index="1" name="normal_split_angle" type="float" />
+ <param index="2" name="bone_transform_array" type="Array" />
<description>
Generates all lods for this ImporterMesh.
[param normal_merge_angle] and [param normal_split_angle] are in degrees and used in the same way as the importer settings in [code]lods[/code]. As a good default, use 25 and 60 respectively.
The number of generated lods can be accessed using [method get_surface_lod_count], and each LOD is available in [method get_surface_lod_size] and [method get_surface_lod_indices].
+ [param bone_transform_array] is an [Array] which can be either empty or contain [Transform3D]s which, for each of the mesh's bone IDs, will apply mesh skinning when generating the LOD mesh variations. This is usually used to account for discrepancies in scale between the mesh itself and its skinning data.
</description>
</method>
<method name="get_blend_shape_count" qualifiers="const">
diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml
index 46e46cc164..125d016632 100644
--- a/doc/classes/JSON.xml
+++ b/doc/classes/JSON.xml
@@ -6,7 +6,7 @@
<description>
The [JSON] enables all data types to be converted to and from a JSON string. This useful for serializing data to save to a file or send over the network.
[method stringify] is used to convert any data type into a JSON string.
- [method parse] is used to convert any existing JSON data into a [Variant] that can be used within Godot. If successfully parsed, use [method get_data] to retrieve the [Variant], and use [code]typeof[/code] to check if the Variant's type is what you expect. JSON Objects are converted into a [Dictionary], but JSON data can be used to store [Array]s, numbers, [String]s and even just a boolean.
+ [method parse] is used to convert any existing JSON data into a [Variant] that can be used within Godot. If successfully parsed, use [member data] to retrieve the [Variant], and use [code]typeof[/code] to check if the Variant's type is what you expect. JSON Objects are converted into a [Dictionary], but JSON data can be used to store [Array]s, numbers, [String]s and even just a boolean.
[b]Example[/b]
[codeblock]
var data_to_send = ["a", "b", "c"]
@@ -16,7 +16,7 @@
# Retrieve data
var error = json.parse(json_string)
if error == OK:
- var data_received = json.get_data()
+ var data_received = json.data
if typeof(data_received) == TYPE_ARRAY:
print(data_received) # Prints array
else:
@@ -28,17 +28,15 @@
[codeblock]
var data = JSON.parse_string(json_string) # Returns null if parsing failed.
[/codeblock]
+ [b]Note:[/b] Both parse methods do not fully comply with the JSON specification:
+ - Trailing commas in arrays or objects are ignored, instead of causing a parser error.
+ - New line and tab characters are accepted in string literals, and are treated like their corresponding escape sequences [code]\n[/code] and [code]\t[/code].
+ - Numbers are parsed using [method String.to_float] which is generally more lax than the JSON specification.
+ - Certain errors, such as invalid Unicode sequences, do not cause a parser error. Instead, the string is cleansed and an error is logged to the console.
</description>
<tutorials>
</tutorials>
<methods>
- <method name="get_data" qualifiers="const">
- <return type="Variant" />
- <description>
- Returns the [Variant] containing the data of a successful [method parse].
- [b]Note:[/b] It will return [code]Null[/code] if the last call to parse was unsuccessful or [method parse] has not yet been called.
- </description>
- </method>
<method name="get_error_line" qualifiers="const">
<return type="int" />
<description>
@@ -56,7 +54,7 @@
<param index="0" name="json_string" type="String" />
<description>
Attempts to parse the [param json_string] provided.
- Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] and the result can be retrieved using [method get_data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure.
+ Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] and the result can be retrieved using [member data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure.
Non-static variant of [method parse_string], if you want custom error handling.
</description>
</method>
@@ -118,4 +116,9 @@
</description>
</method>
</methods>
+ <members>
+ <member name="data" type="Variant" setter="set_data" getter="get_data" default="null">
+ Contains the parsed JSON data in [Variant] form.
+ </member>
+ </members>
</class>
diff --git a/doc/classes/LightmapGI.xml b/doc/classes/LightmapGI.xml
index dd8c7be489..53dae1a8e6 100644
--- a/doc/classes/LightmapGI.xml
+++ b/doc/classes/LightmapGI.xml
@@ -17,7 +17,7 @@
<member name="bias" type="float" setter="set_bias" getter="get_bias" default="0.0005">
The bias to use when computing shadows. Increasing [member bias] can fix shadow acne on the resulting baked lightmap, but can introduce peter-panning (shadows not connecting to their casters). Real-time [Light3D] shadows are not affected by this [member bias] property.
</member>
- <member name="bounces" type="int" setter="set_bounces" getter="get_bounces" default="1">
+ <member name="bounces" type="int" setter="set_bounces" getter="get_bounces" default="3">
Number of light bounces that are taken into account during baking. Higher values result in brighter, more realistic lighting, at the cost of longer bake times. If set to [code]0[/code], only environment lighting, direct light and emissive lighting is baked.
</member>
<member name="camera_attributes" type="CameraAttributes" setter="set_camera_attributes" getter="get_camera_attributes">
@@ -36,10 +36,10 @@
<member name="environment_custom_sky" type="Sky" setter="set_environment_custom_sky" getter="get_environment_custom_sky">
The sky to use as a source of environment lighting. Only effective if [member environment_mode] is [constant ENVIRONMENT_MODE_CUSTOM_SKY].
</member>
- <member name="environment_mode" type="int" setter="set_environment_mode" getter="get_environment_mode" enum="LightmapGI.EnvironmentMode" default="0">
+ <member name="environment_mode" type="int" setter="set_environment_mode" getter="get_environment_mode" enum="LightmapGI.EnvironmentMode" default="1">
The environment mode to use when baking lightmaps.
</member>
- <member name="generate_probes_subdiv" type="int" setter="set_generate_probes" getter="get_generate_probes" enum="LightmapGI.GenerateProbes" default="0">
+ <member name="generate_probes_subdiv" type="int" setter="set_generate_probes" getter="get_generate_probes" enum="LightmapGI.GenerateProbes" default="2">
The level of subdivision to use when automatically generating [LightmapProbe]s for dynamic object lighting. Higher values result in more accurate indirect lighting on dynamic objects, at the cost of longer bake times and larger file sizes.
[b]Note:[/b] Automatically generated [LightmapProbe]s are not visible as nodes in the Scene tree dock, and cannot be modified this way after they are generated.
[b]Note:[/b] Regardless of [member generate_probes_subdiv], direct lighting on dynamic objects is always applied using [Light3D] nodes in real-time.
diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml
index bae2335cfb..ce2b5f2584 100644
--- a/doc/classes/MultiMesh.xml
+++ b/doc/classes/MultiMesh.xml
@@ -1,13 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="MultiMesh" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Provides high-performance mesh instancing.
+ Provides high-performance drawing of a mesh multiple times using GPU instancing.
</brief_description>
<description>
MultiMesh provides low-level mesh instancing. Drawing thousands of [MeshInstance3D] nodes can be slow, since each object is submitted to the GPU then drawn individually.
MultiMesh is much faster as it can draw thousands of instances with a single draw call, resulting in less API overhead.
As a drawback, if the instances are too far away from each other, performance may be reduced as every single instance will always render (they are spatially indexed as one, for the whole object).
Since instances may have any behavior, the AABB used for visibility must be provided by the user.
+ [b]Note:[/b] A MultiMesh is a single object, therefore the same maximum lights per object restriction applies. This means, that once the maximum lights are consumed by one or more instances, the rest of the MultiMesh instances will [b]not[/b] receive any lighting.
+ [b]Note:[/b] Blend Shapes will be ignored if used in a MultiMesh.
</description>
<tutorials>
<link title="Animating thousands of fish with MultiMeshInstance">$DOCS_URL/tutorials/performance/vertex_animation/animating_thousands_of_fish.html</link>
@@ -24,7 +26,7 @@
<return type="Color" />
<param index="0" name="instance" type="int" />
<description>
- Gets a specific instance's color.
+ Gets a specific instance's color multiplier.
</description>
</method>
<method name="get_instance_custom_data" qualifiers="const">
@@ -53,8 +55,8 @@
<param index="0" name="instance" type="int" />
<param index="1" name="color" type="Color" />
<description>
- Sets the color of a specific instance by [i]multiplying[/i] the mesh's existing vertex colors.
- For the color to take effect, ensure that [member use_colors] is [code]true[/code] on the [MultiMesh] and [member BaseMaterial3D.vertex_color_use_as_albedo] is [code]true[/code] on the material. If the color doesn't look as expected, make sure the material's albedo color is set to pure white ([code]Color(1, 1, 1)[/code]).
+ Sets the color of a specific instance by [i]multiplying[/i] the mesh's existing vertex colors. This allows for different color tinting per instance.
+ For the color to take effect, ensure that [member use_colors] is [code]true[/code] on the [MultiMesh] and [member BaseMaterial3D.vertex_color_use_as_albedo] is [code]true[/code] on the material. If you intend to set an absolute color instead of tinting, make sure the material's albedo color is set to pure white ([code]Color(1, 1, 1)[/code]).
</description>
</method>
<method name="set_instance_custom_data">
@@ -64,6 +66,7 @@
<description>
Sets custom data for a specific instance. Although [Color] is used, it is just a container for 4 floating point numbers.
For the custom data to be used, ensure that [member use_custom_data] is [code]true[/code].
+ This custom instance data has to be manually accessed in your custom shader using [code]INSTANCE_CUSTOM[/code].
</description>
</method>
<method name="set_instance_transform">
@@ -87,28 +90,33 @@
<member name="buffer" type="PackedFloat32Array" setter="set_buffer" getter="get_buffer" default="PackedFloat32Array()">
</member>
<member name="color_array" type="PackedColorArray" setter="_set_color_array" getter="_get_color_array">
+ See [method set_instance_color].
</member>
<member name="custom_data_array" type="PackedColorArray" setter="_set_custom_data_array" getter="_get_custom_data_array">
+ See [method set_instance_custom_data].
</member>
<member name="instance_count" type="int" setter="set_instance_count" getter="get_instance_count" default="0">
Number of instances that will get drawn. This clears and (re)sizes the buffers. Setting data format or flags afterwards will have no effect.
By default, all instances are drawn but you can limit this with [member visible_instance_count].
</member>
<member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
- Mesh to be drawn.
+ [Mesh] resource to be instanced.
+ The looks of the individual instances can be modified using [method set_instance_color] and [method set_instance_custom_data].
</member>
<member name="transform_2d_array" type="PackedVector2Array" setter="_set_transform_2d_array" getter="_get_transform_2d_array">
+ See [method set_instance_transform_2d].
</member>
<member name="transform_array" type="PackedVector3Array" setter="_set_transform_array" getter="_get_transform_array">
+ See [method set_instance_transform].
</member>
<member name="transform_format" type="int" setter="set_transform_format" getter="get_transform_format" enum="MultiMesh.TransformFormat" default="0">
Format of transform used to transform mesh, either 2D or 3D.
</member>
<member name="use_colors" type="bool" setter="set_use_colors" getter="is_using_colors" default="false">
- If [code]true[/code], the [MultiMesh] will use color data (see [member color_array]).
+ If [code]true[/code], the [MultiMesh] will use color data (see [method set_instance_color]). Can only be set when [member instance_count] is [code]0[/code] or less. This means that you need to call this method before setting the instance count, or temporarily reset it to [code]0[/code].
</member>
<member name="use_custom_data" type="bool" setter="set_use_custom_data" getter="is_using_custom_data" default="false">
- If [code]true[/code], the [MultiMesh] will use custom data (see [member custom_data_array]).
+ If [code]true[/code], the [MultiMesh] will use custom data (see [method set_instance_custom_data]). Can only be set when [member instance_count] is [code]0[/code] or less. This means that you need to call this method before setting the instance count, or temporarily reset it to [code]0[/code].
</member>
<member name="visible_instance_count" type="int" setter="set_visible_instance_count" getter="get_visible_instance_count" default="-1">
Limits the number of instances drawn, -1 draws all instances. Changing this does not change the sizes of the buffers.
diff --git a/doc/classes/NavigationPathQueryParameters2D.xml b/doc/classes/NavigationPathQueryParameters2D.xml
new file mode 100644
index 0000000000..364f495a72
--- /dev/null
+++ b/doc/classes/NavigationPathQueryParameters2D.xml
@@ -0,0 +1,42 @@
+<?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">
+ <brief_description>
+ Parameters to be sent to a 2D navigation path query.
+ </brief_description>
+ <description>
+ This class contains the start and target position and other parameters to be used with [method NavigationServer2D.query_path].
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <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="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>
+ <member name="path_postprocessing" type="int" setter="set_path_postprocessing" getter="get_path_postprocessing" enum="NavigationPathQueryParameters2D.PathPostProcessing" default="0">
+ The path postprocessing applied to the raw path corridor found by the [member pathfinding_algorithm].
+ </member>
+ <member name="pathfinding_algorithm" type="int" setter="set_pathfinding_algorithm" getter="get_pathfinding_algorithm" enum="NavigationPathQueryParameters2D.PathfindingAlgorithm" default="0">
+ The pathfinding algorithm used in the path query.
+ </member>
+ <member name="start_position" type="Vector2" setter="set_start_position" getter="get_start_position" default="Vector2(0, 0)">
+ The pathfinding start position in global coordinates.
+ </member>
+ <member name="target_position" type="Vector2" setter="set_target_position" getter="get_target_position" default="Vector2(0, 0)">
+ The pathfinding target position in global coordinates.
+ </member>
+ </members>
+ <constants>
+ <constant name="PATHFINDING_ALGORITHM_ASTAR" value="0" enum="PathfindingAlgorithm">
+ 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 artifical 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.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/NavigationPathQueryParameters3D.xml b/doc/classes/NavigationPathQueryParameters3D.xml
new file mode 100644
index 0000000000..59c907c5b5
--- /dev/null
+++ b/doc/classes/NavigationPathQueryParameters3D.xml
@@ -0,0 +1,42 @@
+<?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">
+ <brief_description>
+ Parameters to be sent to a 3D navigation path query.
+ </brief_description>
+ <description>
+ This class contains the start and target position and other parameters to be used with [method NavigationServer3D.query_path].
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <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="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>
+ <member name="path_postprocessing" type="int" setter="set_path_postprocessing" getter="get_path_postprocessing" enum="NavigationPathQueryParameters3D.PathPostProcessing" default="0">
+ The path postprocessing applied to the raw path corridor found by the [member pathfinding_algorithm].
+ </member>
+ <member name="pathfinding_algorithm" type="int" setter="set_pathfinding_algorithm" getter="get_pathfinding_algorithm" enum="NavigationPathQueryParameters3D.PathfindingAlgorithm" default="0">
+ The pathfinding algorithm used in the path query.
+ </member>
+ <member name="start_position" type="Vector3" setter="set_start_position" getter="get_start_position" default="Vector3(0, 0, 0)">
+ The pathfinding start position in global coordinates.
+ </member>
+ <member name="target_position" type="Vector3" setter="set_target_position" getter="get_target_position" default="Vector3(0, 0, 0)">
+ The pathfinding target position in global coordinates.
+ </member>
+ </members>
+ <constants>
+ <constant name="PATHFINDING_ALGORITHM_ASTAR" value="0" enum="PathfindingAlgorithm">
+ 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 artifical 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.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/NavigationPathQueryResult2D.xml b/doc/classes/NavigationPathQueryResult2D.xml
new file mode 100644
index 0000000000..a9b12d3b94
--- /dev/null
+++ b/doc/classes/NavigationPathQueryResult2D.xml
@@ -0,0 +1,16 @@
+<?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">
+ <brief_description>
+ Result from a [NavigationPathQueryParameters2D] navigation path query.
+ </brief_description>
+ <description>
+ This class contains the result of a navigation path query from [method NavigationServer2D.query_path].
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <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>
+ </members>
+</class>
diff --git a/doc/classes/NavigationPathQueryResult3D.xml b/doc/classes/NavigationPathQueryResult3D.xml
new file mode 100644
index 0000000000..d8336111fc
--- /dev/null
+++ b/doc/classes/NavigationPathQueryResult3D.xml
@@ -0,0 +1,16 @@
+<?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">
+ <brief_description>
+ Result from a [NavigationPathQueryParameters3D] navigation path query.
+ </brief_description>
+ <description>
+ This class contains the result of a navigation path query from [method NavigationServer3D.query_path].
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <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>
+ </members>
+</class>
diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml
index 89f7dcb4af..0f28081201 100644
--- a/doc/classes/NavigationRegion2D.xml
+++ b/doc/classes/NavigationRegion2D.xml
@@ -10,6 +10,7 @@
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.
+ [b]Note:[/b] This node caches changes to its properties, so if you make changes to the underlying region [RID] in [NavigationServer2D], they will not be reflected in this node's properties.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml
index 87e82e7b2e..85f163b3c2 100644
--- a/doc/classes/NavigationRegion3D.xml
+++ b/doc/classes/NavigationRegion3D.xml
@@ -10,6 +10,7 @@
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.
+ [b]Note:[/b] This node caches changes to its properties, so if you make changes to the underlying region [RID] in [NavigationServer3D], they will not be reflected in this node's properties.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index 0874e183e4..981ab8a5e1 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -368,6 +368,14 @@
Set the map's link connection radius used to connect links to navigation polygons.
</description>
</method>
+ <method name="query_path" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="parameters" type="NavigationPathQueryParameters2D" />
+ <param index="1" name="result" type="NavigationPathQueryResult2D" />
+ <description>
+ Queries a path in a given navigation map. Start and target position and other parameters are defined through [NavigationPathQueryParameters2D]. Updates the provided [NavigationPathQueryResult2D] result object with the path among other results requested by the query.
+ </description>
+ </method>
<method name="region_create" qualifiers="const">
<return type="RID" />
<description>
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index 255f2a902c..943aa03ef7 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -410,6 +410,14 @@
[b]Note:[/b] This function is not thread safe.
</description>
</method>
+ <method name="query_path" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="parameters" type="NavigationPathQueryParameters3D" />
+ <param index="1" name="result" type="NavigationPathQueryResult3D" />
+ <description>
+ 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">
<return type="void" />
<param index="0" name="mesh" type="NavigationMesh" />
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index d8ad65082f..d9732da3a3 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -179,9 +179,14 @@
<return type="Tween" />
<description>
Creates a new [Tween] and binds it to this node. This is equivalent of doing:
- [codeblock]
+ [codeblocks]
+ [gdscript]
get_tree().create_tween().bind_node(self)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ GetTree().CreateTween().BindNode(this);
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="duplicate" qualifiers="const">
@@ -267,13 +272,24 @@
Returns an array listing the groups that the node is a member of.
[b]Note:[/b] For performance reasons, the order of node groups is [i]not[/i] guaranteed. The order of node groups should not be relied upon as it can vary across project runs.
[b]Note:[/b] The engine uses some group names internally (all starting with an underscore). To avoid conflicts with internal groups, do not add custom groups whose name starts with an underscore. To exclude internal groups while looping over [method get_groups], use the following snippet:
- [codeblock]
+ [codeblocks]
+ [gdscript]
# Stores the node's non-internal groups only (as an array of Strings).
var non_internal_groups = []
for group in get_groups():
if not group.begins_with("_"):
non_internal_groups.push_back(group)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ // Stores the node's non-internal groups only (as a List of strings).
+ List&lt;string&gt; nonInternalGroups = new List&lt;string&gt;();
+ foreach (string group in GetGroups())
+ {
+ if (!group.BeginsWith("_"))
+ nonInternalGroups.Add(group);
+ }
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="get_index" qualifiers="const">
diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml
index c8e2f1ac68..96ce10745d 100644
--- a/doc/classes/Node3D.xml
+++ b/doc/classes/Node3D.xml
@@ -331,6 +331,10 @@
<constant name="NOTIFICATION_VISIBILITY_CHANGED" value="43">
Node3D nodes receives this notification when their visibility changes.
</constant>
+ <constant name="NOTIFICATION_LOCAL_TRANSFORM_CHANGED" value="44">
+ Node3D nodes receives this notification when their local transform changes. This is not received when the transform of a parent node is changed.
+ In order for [constant NOTIFICATION_LOCAL_TRANSFORM_CHANGED] to work, users first need to ask for it, with [method set_notify_local_transform].
+ </constant>
<constant name="ROTATION_EDIT_MODE_EULER" value="0" enum="RotationEditMode">
</constant>
<constant name="ROTATION_EDIT_MODE_QUATERNION" value="1" enum="RotationEditMode">
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 059766656f..be7bacd994 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -216,6 +216,15 @@
Not to be confused with [method get_user_data_dir], which returns the [i]project-specific[/i] user data path.
</description>
</method>
+ <method name="get_distribution_name" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the name of the distribution for Linux and BSD platforms (e.g. Ubuntu, Manjaro, OpenBSD, etc.).
+ Returns the same value as [method get_name] for stock Android ROMs, but attempts to return the custom ROM name for popular Android derivatives such as LineageOS.
+ Returns the same value as [method get_name] for other platforms.
+ [b]Note:[/b] This method is not supported on the web platform. It returns an empty string.
+ </description>
+ </method>
<method name="get_environment" qualifiers="const">
<return type="String" />
<param index="0" name="variable" type="String" />
@@ -430,6 +439,18 @@
Not to be confused with [method get_data_dir], which returns the [i]global[/i] (non-project-specific) user home directory.
</description>
</method>
+ <method name="get_version" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the exact production and build version of the operating system. This is different from the branded version used in marketing. This helps to distinguish between different releases of operating systems, including minor versions, and insider and custom builds.
+ For Windows, the major and minor version are returned, as well as the build number. For example, the returned string can look like [code]10.0.9926[/code] for a build of Windows 10, and it can look like [code]6.1.7601[/code] for a build of Windows 7 SP1.
+ For rolling distributions, such as Arch Linux, an empty string is returned.
+ For macOS and iOS, the major and minor version are returned, as well as the patch number.
+ For UWP, the device family version is returned.
+ For Android, the SDK version and the incremental build number are returned. If it's a custom ROM, it attempts to return its version instead.
+ [b]Note:[/b] This method is not supported on the web platform. It returns an empty string.
+ </description>
+ </method>
<method name="has_environment" qualifiers="const">
<return type="bool" />
<param index="0" name="variable" type="String" />
@@ -501,13 +522,19 @@
<return type="int" enum="Error" />
<param index="0" name="path" type="String" />
<description>
- Moves the file or directory to the system's recycle bin. See also [method Directory.remove].
+ Moves the file or directory to the system's recycle bin. See also [method DirAccess.remove].
The method takes only global paths, so you may need to use [method ProjectSettings.globalize_path]. Do not use it for files in [code]res://[/code] as it will not work in exported project.
[b]Note:[/b] If the user has disabled the recycle bin on their system, the file will be permanently deleted instead.
- [codeblock]
+ [codeblocks]
+ [gdscript]
var file_to_remove = "user://slot1.sav"
OS.move_to_trash(ProjectSettings.globalize_path(file_to_remove))
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ var fileToRemove = "user://slot1.sav";
+ OS.MoveToTrash(ProjectSettings.GlobalizePath(fileToRemove));
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="open_midi_inputs">
diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml
index efb559522a..ccf012f82c 100644
--- a/doc/classes/PackedByteArray.xml
+++ b/doc/classes/PackedByteArray.xml
@@ -65,7 +65,7 @@
<return type="PackedByteArray" />
<param index="0" name="compression_mode" type="int" default="0" />
<description>
- Returns a new [PackedByteArray] with the data compressed. Set the compression mode using one of [enum File.CompressionMode]'s constants.
+ Returns a new [PackedByteArray] with the data compressed. Set the compression mode using one of [enum FileAccess.CompressionMode]'s constants.
</description>
</method>
<method name="count" qualifiers="const">
@@ -173,7 +173,7 @@
<param index="0" name="buffer_size" type="int" />
<param index="1" name="compression_mode" type="int" default="0" />
<description>
- Returns a new [PackedByteArray] with the data decompressed. Set [param buffer_size] to the size of the uncompressed data. Set the compression mode using one of [enum File.CompressionMode]'s constants.
+ Returns a new [PackedByteArray] with the data decompressed. Set [param buffer_size] to the size of the uncompressed data. Set the compression mode using one of [enum FileAccess.CompressionMode]'s constants.
</description>
</method>
<method name="decompress_dynamic" qualifiers="const">
@@ -181,7 +181,7 @@
<param index="0" name="max_output_size" type="int" />
<param index="1" name="compression_mode" type="int" default="0" />
<description>
- Returns a new [PackedByteArray] with the data decompressed. Set the compression mode using one of [enum File.CompressionMode]'s constants. [b]This method only accepts gzip and deflate compression modes.[/b]
+ Returns a new [PackedByteArray] with the data decompressed. Set the compression mode using one of [enum FileAccess.CompressionMode]'s constants. [b]This method only accepts gzip and deflate compression modes.[/b]
This method is potentially slower than [code]decompress[/code], as it may have to re-allocate its output buffer multiple times while decompressing, whereas [code]decompress[/code] knows it's output buffer size from the beginning.
GZIP has a maximal compression ratio of 1032:1, meaning it's very possible for a small compressed payload to decompress to a potentially very large output. To guard against this, you may provide a maximum size this function is allowed to allocate in bytes via [param max_output_size]. Passing -1 will allow for unbounded output. If any positive value is passed, and the decompression exceeds that amount in bytes, then an error will be returned.
</description>
diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml
index 97595a6984..7ca1d5d60d 100644
--- a/doc/classes/PackedScene.xml
+++ b/doc/classes/PackedScene.xml
@@ -41,7 +41,7 @@
# Only `node` and `body` are now packed.
var result = scene.pack(node)
if result == OK:
- var error = ResourceSaver.save("res://path/name.tscn", scene) # Or "user://..."
+ var error = ResourceSaver.save(scene, "res://path/name.tscn") # Or "user://..."
if error != OK:
push_error("An error occurred while saving the scene to disk.")
[/gdscript]
@@ -63,7 +63,7 @@
Error result = scene.Pack(node);
if (result == Error.Ok)
{
- Error error = ResourceSaver.Save("res://path/name.tscn", scene); // Or "user://..."
+ Error error = ResourceSaver.Save(scene, "res://path/name.tscn"); // Or "user://..."
if (error != Error.Ok)
{
GD.PushError("An error occurred while saving the scene to disk.");
diff --git a/doc/classes/PanoramaSkyMaterial.xml b/doc/classes/PanoramaSkyMaterial.xml
index 21c7f29585..0c27037f28 100644
--- a/doc/classes/PanoramaSkyMaterial.xml
+++ b/doc/classes/PanoramaSkyMaterial.xml
@@ -4,9 +4,9 @@
A [Material] used with [Sky] to draw a background texture.
</brief_description>
<description>
- A resource referenced in a [Sky] that is used to draw a background. The Panorama sky material functions similar to skyboxes in other engines, except it uses an equirectangular sky map instead of a cube map.
+ A resource referenced in a [Sky] that is used to draw a background. The Panorama sky material functions similar to skyboxes in other engines, except it uses an equirectangular sky map instead of a cubemap.
Using an HDR panorama is strongly recommended for accurate, high-quality reflections. Godot supports the Radiance HDR ([code].hdr[/code]) and OpenEXR ([code].exr[/code]) image formats for this purpose.
- You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cube map to an equirectangular sky map.
+ You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cubemap to an equirectangular sky map.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml
index e8d7ac9920..59660b4de5 100644
--- a/doc/classes/PhysicsBody2D.xml
+++ b/doc/classes/PhysicsBody2D.xml
@@ -28,11 +28,13 @@
<param index="0" name="distance" type="Vector2" />
<param index="1" name="test_only" type="bool" default="false" />
<param index="2" name="safe_margin" type="float" default="0.08" />
+ <param index="3" name="recovery_as_collision" type="bool" default="false" />
<description>
Moves the body along the vector [param distance]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code].
Returns a [KinematicCollision2D], which contains information about the collision when stopped, or when touching another body along the motion.
If [param test_only] is [code]true[/code], the body does not move but the would-be collision information is given.
[param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody2D.safe_margin] for more details).
+ If [param recovery_as_collision] is [code]true[/code], any depenetration from the recovery phase is also reported as a collision; this is used e.g. by [CharacterBody2D] for improving floor detection during floor snapping.
</description>
</method>
<method name="remove_collision_exception_with">
@@ -48,11 +50,13 @@
<param index="1" name="distance" type="Vector2" />
<param index="2" name="collision" type="KinematicCollision2D" default="null" />
<param index="3" name="safe_margin" type="float" default="0.08" />
+ <param index="4" name="recovery_as_collision" type="bool" default="false" />
<description>
Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code].
Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [param distance]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path.
[param collision] is an optional object of type [KinematicCollision2D], which contains additional information about the collision when stopped, or when touching another body along the motion.
[param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody2D.safe_margin] for more details).
+ If [param recovery_as_collision] is [code]true[/code], any depenetration from the recovery phase is also reported as a collision; this is useful for checking whether the body would [i]touch[/i] any other bodies.
</description>
</method>
</methods>
diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml
index 310671274f..bf7882a1ea 100644
--- a/doc/classes/PhysicsBody3D.xml
+++ b/doc/classes/PhysicsBody3D.xml
@@ -35,12 +35,14 @@
<param index="0" name="distance" type="Vector3" />
<param index="1" name="test_only" type="bool" default="false" />
<param index="2" name="safe_margin" type="float" default="0.001" />
- <param index="3" name="max_collisions" type="int" default="1" />
+ <param index="3" name="recovery_as_collision" type="bool" default="false" />
+ <param index="4" name="max_collisions" type="int" default="1" />
<description>
Moves the body along the vector [param distance]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code].
The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision when stopped, or when touching another body along the motion.
If [param test_only] is [code]true[/code], the body does not move but the would-be collision information is given.
[param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody3D.safe_margin] for more details).
+ If [param recovery_as_collision] is [code]true[/code], any depenetration from the recovery phase is also reported as a collision; this is used e.g. by [CharacterBody3D] for improving floor detection during floor snapping.
[param max_collisions] allows to retrieve more than one collision result.
</description>
</method>
@@ -65,12 +67,14 @@
<param index="1" name="distance" type="Vector3" />
<param index="2" name="collision" type="KinematicCollision3D" default="null" />
<param index="3" name="safe_margin" type="float" default="0.001" />
- <param index="4" name="max_collisions" type="int" default="1" />
+ <param index="4" name="recovery_as_collision" type="bool" default="false" />
+ <param index="5" name="max_collisions" type="int" default="1" />
<description>
Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code].
Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [param distance]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path.
[param collision] is an optional object of type [KinematicCollision3D], which contains additional information about the collision when stopped, or when touching another body along the motion.
[param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody3D.safe_margin] for more details).
+ If [param recovery_as_collision] is [code]true[/code], any depenetration from the recovery phase is also reported as a collision; this is useful for checking whether the body would [i]touch[/i] any other bodies.
[param max_collisions] allows to retrieve more than one collision result.
</description>
</method>
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index 4b588033c0..18ac8a11df 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -53,6 +53,20 @@
<description>
</description>
</method>
+ <method name="area_get_collision_layer" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ Returns the physics layer or layers an area belongs to.
+ </description>
+ </method>
+ <method name="area_get_collision_mask" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ Returns the physics layer or layers an area can contact with.
+ </description>
+ </method>
<method name="area_get_object_instance_id" qualifiers="const">
<return type="int" />
<param index="0" name="area" type="RID" />
diff --git a/doc/classes/PhysicsServer2DExtension.xml b/doc/classes/PhysicsServer2DExtension.xml
index a63aa8a30f..9bb11e0d89 100644
--- a/doc/classes/PhysicsServer2DExtension.xml
+++ b/doc/classes/PhysicsServer2DExtension.xml
@@ -47,6 +47,18 @@
<description>
</description>
</method>
+ <method name="_area_get_collision_layer" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_collision_mask" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
<method name="_area_get_object_instance_id" qualifiers="virtual const">
<return type="int" />
<param index="0" name="area" type="RID" />
@@ -602,7 +614,7 @@
<method name="_body_set_state_sync_callback" qualifiers="virtual">
<return type="void" />
<param index="0" name="body" type="RID" />
- <param index="1" name="callback" type="PhysicsServer2DExtensionStateCallback*" />
+ <param index="1" name="callable" type="Callable" />
<description>
</description>
</method>
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index da9e10c420..95f7fb69a2 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -40,6 +40,20 @@
Creates an [Area3D].
</description>
</method>
+ <method name="area_get_collision_layer" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ Returns the physics layer or layers an area belongs to.
+ </description>
+ </method>
+ <method name="area_get_collision_mask" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ Returns the physics layer or layers an area can contact with.
+ </description>
+ </method>
<method name="area_get_object_instance_id" qualifiers="const">
<return type="int" />
<param index="0" name="area" type="RID" />
diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml
index f42276ddd8..1e9df54de5 100644
--- a/doc/classes/PhysicsServer3DExtension.xml
+++ b/doc/classes/PhysicsServer3DExtension.xml
@@ -34,6 +34,18 @@
<description>
</description>
</method>
+ <method name="_area_get_collision_layer" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_collision_mask" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
<method name="_area_get_object_instance_id" qualifiers="virtual const">
<return type="int" />
<param index="0" name="area" type="RID" />
@@ -575,7 +587,7 @@
<method name="_body_set_state_sync_callback" qualifiers="virtual">
<return type="void" />
<param index="0" name="body" type="RID" />
- <param index="1" name="callback" type="PhysicsServer3DExtensionStateCallback*" />
+ <param index="1" name="callable" type="Callable" />
<description>
</description>
</method>
diff --git a/doc/classes/PhysicsTestMotionParameters2D.xml b/doc/classes/PhysicsTestMotionParameters2D.xml
index 4f2b62f2d9..d8f96511dd 100644
--- a/doc/classes/PhysicsTestMotionParameters2D.xml
+++ b/doc/classes/PhysicsTestMotionParameters2D.xml
@@ -29,8 +29,8 @@
Motion vector to define the length and direction of the motion to test.
</member>
<member name="recovery_as_collision" type="bool" setter="set_recovery_as_collision_enabled" getter="is_recovery_as_collision_enabled" default="false">
- If set to [code]true[/code], any depenetration from the recovery phase is reported as a collision; this is used e.g. by [method CharacterBody2D.move_and_slide] for improving floor detection when floor snapping is disabled.
- If set to [code]false[/code], only collisions resulting from the motion are reported; this is used e.g. by [method PhysicsBody2D.move_and_collide].
+ If set to [code]true[/code], any depenetration from the recovery phase is reported as a collision; this is used e.g. by [CharacterBody2D] for improving floor detection during floor snapping.
+ If set to [code]false[/code], only collisions resulting from the motion are reported, which is generally the desired behaviour.
</member>
</members>
</class>
diff --git a/doc/classes/PhysicsTestMotionParameters3D.xml b/doc/classes/PhysicsTestMotionParameters3D.xml
index 5b07796a10..e8f80ae131 100644
--- a/doc/classes/PhysicsTestMotionParameters3D.xml
+++ b/doc/classes/PhysicsTestMotionParameters3D.xml
@@ -32,8 +32,8 @@
Motion vector to define the length and direction of the motion to test.
</member>
<member name="recovery_as_collision" type="bool" setter="set_recovery_as_collision_enabled" getter="is_recovery_as_collision_enabled" default="false">
- If set to [code]true[/code], any depenetration from the recovery phase is reported as a collision; this is used e.g. by [method CharacterBody3D.move_and_slide] for improving floor detection when floor snapping is disabled.
- If set to [code]false[/code], only collisions resulting from the motion are detected; this is used e.g. by [method PhysicsBody3D.move_and_collide].
+ If set to [code]true[/code], any depenetration from the recovery phase is reported as a collision; this is used e.g. by [CharacterBody3D] for improving floor detection during floor snapping.
+ If set to [code]false[/code], only collisions resulting from the motion are reported, which is generally the desired behaviour.
</member>
</members>
</class>
diff --git a/doc/classes/PlaneMesh.xml b/doc/classes/PlaneMesh.xml
index 564b6fe743..1dceac70b0 100644
--- a/doc/classes/PlaneMesh.xml
+++ b/doc/classes/PlaneMesh.xml
@@ -31,10 +31,10 @@
[PlaneMesh] will face the positive X-axis.
</constant>
<constant name="FACE_Y" value="1" enum="Orientation">
- [PlaneMesh] will face the positive Y-axis. This matches the behaviour of the [PlaneMesh] in Godot 3.x.
+ [PlaneMesh] will face the positive Y-axis. This matches the behavior of the [PlaneMesh] in Godot 3.x.
</constant>
<constant name="FACE_Z" value="2" enum="Orientation">
- [PlaneMesh] will face the positive Z-axis. This matches the behvaiour of the QuadMesh in Godot 3.x.
+ [PlaneMesh] will face the positive Z-axis. This matches the behavior of the QuadMesh in Godot 3.x.
</constant>
</constants>
</class>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 1f07a13c94..498283b2f3 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -159,6 +159,15 @@
Sets the order of a configuration value (influences when saved to the config file).
</description>
</method>
+ <method name="set_restart_if_changed">
+ <return type="void" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="restart" type="bool" />
+ <description>
+ Sets whether a setting requires restarting the editor to properly take effect.
+ [b]Note:[/b] This is just a hint to display to the user that the editor must be restarted for changes to take effect. Enabling [method set_restart_if_changed] does [i]not[/i] delay the setting being set when changed.
+ </description>
+ </method>
<method name="set_setting">
<return type="void" />
<param index="0" name="name" type="String" />
@@ -562,15 +571,25 @@
Forces the main window to be borderless.
[b]Note:[/b] This setting is ignored on iOS, Android, and Web.
</member>
- <member name="display/window/size/fullscreen" type="bool" setter="" getter="" default="false">
- Sets the main window to full screen when the project starts. Note that this is not [i]exclusive[/i] fullscreen. On Windows and Linux, a borderless window is used to emulate fullscreen. On macOS, a new desktop is used to display the running project.
- Regardless of the platform, enabling fullscreen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling fullscreen mode.
- [b]Note:[/b] This setting is ignored on iOS, Android, and Web.
+ <member name="display/window/size/extend_to_title" type="bool" setter="" getter="" default="false">
+ Main window content is expanded to the full size of the window. Unlike borderless window, the frame is left intact and can be used to resize the window, title bar is transparent, but have minimize/maximize/close buttons.
+ [b]Note:[/b] This setting is implemented on macOS.
+ </member>
+ <member name="display/window/size/mode" type="int" setter="" getter="" default="0">
+ Main window mode. See [enum DisplayServer.WindowMode] for possible values and how each mode behaves.
+ </member>
+ <member name="display/window/size/no_focus" type="bool" setter="" getter="" default="false">
+ Main window can't be focused. No-focus window will ignore all input, except mouse clicks.
</member>
<member name="display/window/size/resizable" type="bool" setter="" getter="" default="true">
Allows the window to be resizable by default.
[b]Note:[/b] This setting is ignored on iOS.
</member>
+ <member name="display/window/size/transparent" type="bool" setter="" getter="" default="false">
+ Main window background can be transparent.
+ [b]Note:[/b] To use 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>
<member name="display/window/size/viewport_height" type="int" setter="" getter="" default="648">
Sets the game's main viewport height. On desktop platforms, this is also the initial window height, represented by an indigo-colored rectangle in the 2D editor. Stretch mode settings also use this as a reference when using the [code]canvas_items[/code] or [code]viewport[/code] stretch modes. See also [member display/window/size/viewport_width], [member display/window/size/window_width_override] and [member display/window/size/window_height_override].
</member>
@@ -1705,13 +1724,6 @@
If [code]true[/code], performs a previous depth pass before rendering 3D materials. This increases performance significantly in scenes with high overdraw, when complex materials and lighting are used. However, in scenes with few occluded surfaces, the depth prepass may reduce performance. If your game is viewed from a fixed angle that makes it easy to avoid overdraw (such as top-down or side-scrolling perspective), consider disabling the depth prepass to improve performance. This setting can be changed at run-time to optimize performance depending on the scene currently being viewed.
[b]Note:[/b] Only supported when using the Vulkan Clustered backend or the OpenGL backend. When using Vulkan Mobile there is no depth prepass performed.
</member>
- <member name="rendering/driver/driver_name" type="String" setter="" getter="" default="&quot;vulkan&quot;">
- The video driver to use.
- [b]Note:[/b] OpenGL support is currently incomplete. Only basic rendering is supported.
- [b]Note:[/b] The backend in use can be overridden at runtime via the [code]--rendering-driver[/code] command line argument.
- [b]FIXME:[/b] No longer valid after DisplayServer split:
- In such cases, this property is not updated, so use [code]OS.get_current_video_driver[/code] to query it at run-time.
- </member>
<member name="rendering/driver/threads/thread_model" type="int" setter="" getter="" default="1">
Thread model for rendering. Rendering on a thread can vastly improve performance, but synchronizing to the main thread can cause a bit more jitter.
</member>
@@ -1782,11 +1794,32 @@
Enables filtering of the volumetric fog effect prior to integration. This substantially blurs the fog which reduces fine details but also smooths out harsh edges and aliasing artifacts. Disable when more detail is required.
</member>
<member name="rendering/environment/volumetric_fog/volume_depth" type="int" setter="" getter="" default="64">
- Number of slices to use along the depth of the froxel buffer for volumetric fog. A lower number will be more efficient but may result in artifacts appearing during camera movement.
+ Number of slices to use along the depth of the froxel buffer for volumetric fog. A lower number will be more efficient but may result in artifacts appearing during camera movement. See also [member Environment.volumetric_fog_length].
</member>
<member name="rendering/environment/volumetric_fog/volume_size" type="int" setter="" getter="" default="64">
Base size used to determine size of froxel buffer in the camera X-axis and Y-axis. The final size is scaled by the aspect ratio of the screen, so actual values may differ from what is set. Set a larger size for more detailed fog, set a smaller size for better performance.
</member>
+ <member name="rendering/gl_compatibility/driver" type="String" setter="" getter="" default="&quot;opengl3&quot;">
+ Sets the driver to be used by the renderer when using the Compatibility renderer. This property can not be edited directly, instead, set the driver using the platform-specific overrides.
+ </member>
+ <member name="rendering/gl_compatibility/driver.android" type="String" setter="" getter="" default="&quot;opengl3&quot;">
+ Android override for [member rendering/gl_compatibility/driver].
+ </member>
+ <member name="rendering/gl_compatibility/driver.ios" type="String" setter="" getter="" default="&quot;opengl3&quot;">
+ iOS override for [member rendering/gl_compatibility/driver].
+ </member>
+ <member name="rendering/gl_compatibility/driver.linuxbsd" type="String" setter="" getter="" default="&quot;opengl3&quot;">
+ LinuxBSD override for [member rendering/gl_compatibility/driver].
+ </member>
+ <member name="rendering/gl_compatibility/driver.macos" type="String" setter="" getter="" default="&quot;opengl3&quot;">
+ macOS override for [member rendering/gl_compatibility/driver].
+ </member>
+ <member name="rendering/gl_compatibility/driver.web" type="String" setter="" getter="" default="&quot;opengl3&quot;">
+ Web override for [member rendering/gl_compatibility/driver].
+ </member>
+ <member name="rendering/gl_compatibility/driver.windows" type="String" setter="" getter="" default="&quot;opengl3&quot;">
+ Windows override for [member rendering/gl_compatibility/driver].
+ </member>
<member name="rendering/global_illumination/gi/use_half_resolution" type="bool" setter="" getter="" default="false">
If [code]true[/code], renders [VoxelGI] and SDFGI ([member Environment.sdfgi_enabled]) buffers at halved resolution (e.g. 960×540 when the viewport size is 1920×1080). This improves performance significantly when VoxelGI or SDFGI is enabled, at the cost of artifacts that may be visible on polygon edges. The loss in quality becomes less noticeable as the viewport resolution increases. [LightmapGI] rendering is not affected by this setting.
[b]Note:[/b] This property is only read when the project starts. To set half-resolution GI at run-time, call [method RenderingServer.gi_set_use_half_resolution] instead.
@@ -1947,6 +1980,44 @@
<member name="rendering/reflections/sky_reflections/texture_array_reflections.mobile" type="bool" setter="" getter="" default="false">
Lower-end override for [member rendering/reflections/sky_reflections/texture_array_reflections] on mobile devices, due to performance concerns or driver support.
</member>
+ <member name="rendering/renderer/rendering_method" type="String" setter="" getter="" default="&quot;forward_plus&quot;">
+ Sets the renderer that will be used by the project. Options are:
+ [b]Clustered[/b]: High-end renderer designed for Desktop devices. Has a higher base overhead, but scales well with complex scenes. Not suitable for older devices or mobile.
+ [b]Mobile[/b]: Modern renderer designed for mobile devices. Has a lower base overhead than Clustered, but does not scale as well to large scenes with many elements.
+ [b]Compatibility[/b]: Low-end renderer designed for older devices. Based on the limitations of the OpenGL 3.3/ OpenGL ES 3.0 / WebGL 2 APIs.
+ </member>
+ <member name="rendering/renderer/rendering_method.mobile" type="String" setter="" getter="" default="&quot;forward_plus&quot;">
+ Override for [member rendering/renderer/rendering_method] on mobile devices.
+ </member>
+ <member name="rendering/renderer/rendering_method.web" type="String" setter="" getter="" default="&quot;gl_compatibility&quot;">
+ Override for [member rendering/renderer/rendering_method] on web.
+ </member>
+ <member name="rendering/rendering_device/descriptor_pools/max_descriptors_per_pool" type="int" setter="" getter="" default="64">
+ </member>
+ <member name="rendering/rendering_device/driver" type="String" setter="" getter="" default="&quot;vulkan&quot;">
+ Sets the driver to be used by the renderer when using a RenderingDevice-based renderer like the clustered renderer or the mobile renderer. This property can not be edited directly, instead, set the driver using the platform-specific overrides.
+ </member>
+ <member name="rendering/rendering_device/driver.android" type="String" setter="" getter="" default="&quot;vulkan&quot;">
+ Android override for [member rendering/rendering_device/driver].
+ </member>
+ <member name="rendering/rendering_device/driver.ios" type="String" setter="" getter="" default="&quot;vulkan&quot;">
+ iOS override for [member rendering/rendering_device/driver].
+ </member>
+ <member name="rendering/rendering_device/driver.linuxbsd" type="String" setter="" getter="" default="&quot;vulkan&quot;">
+ LinuxBSD override for [member rendering/rendering_device/driver].
+ </member>
+ <member name="rendering/rendering_device/driver.macos" type="String" setter="" getter="" default="&quot;vulkan&quot;">
+ macOS override for [member rendering/rendering_device/driver].
+ </member>
+ <member name="rendering/rendering_device/driver.windows" type="String" setter="" getter="" default="&quot;vulkan&quot;">
+ Windows override for [member rendering/rendering_device/driver].
+ </member>
+ <member name="rendering/rendering_device/staging_buffer/block_size_kb" type="int" setter="" getter="" default="256">
+ </member>
+ <member name="rendering/rendering_device/staging_buffer/max_size_mb" type="int" setter="" getter="" default="128">
+ </member>
+ <member name="rendering/rendering_device/staging_buffer/texture_upload_region_size_px" type="int" setter="" getter="" default="64">
+ </member>
<member name="rendering/scaling_3d/fsr_sharpness" type="float" setter="" getter="" default="0.2">
Determines how sharp the upscaled image will be when using the FSR upscaling mode. Sharpness halves with every whole number. Values go from 0.0 (sharpest) to 2.0. Values above 2.0 won't make a visible difference.
</member>
@@ -2028,18 +2099,6 @@
<member name="rendering/vrs/texture" type="String" setter="" getter="" default="&quot;&quot;">
If [member rendering/vrs/mode] is set to texture, this is the path to default texture loaded as the VRS image.
</member>
- <member name="rendering/vulkan/descriptor_pools/max_descriptors_per_pool" type="int" setter="" getter="" default="64">
- </member>
- <member name="rendering/vulkan/rendering/back_end" type="int" setter="" getter="" default="0">
- </member>
- <member name="rendering/vulkan/rendering/back_end.mobile" type="int" setter="" getter="" default="1">
- </member>
- <member name="rendering/vulkan/staging_buffer/block_size_kb" type="int" setter="" getter="" default="256">
- </member>
- <member name="rendering/vulkan/staging_buffer/max_size_mb" type="int" setter="" getter="" default="128">
- </member>
- <member name="rendering/vulkan/staging_buffer/texture_upload_region_size_px" type="int" setter="" getter="" default="64">
- </member>
<member name="threading/worker_pool/low_priority_thread_ratio" type="float" setter="" getter="" default="0.3">
</member>
<member name="threading/worker_pool/max_threads" type="int" setter="" getter="" default="-1">
diff --git a/doc/classes/QuadMesh.xml b/doc/classes/QuadMesh.xml
new file mode 100644
index 0000000000..b869774601
--- /dev/null
+++ b/doc/classes/QuadMesh.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="QuadMesh" inherits="PlaneMesh" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Class representing a square mesh facing the camera.
+ </brief_description>
+ <description>
+ Class representing a square [PrimitiveMesh]. This flat mesh does not have a thickness. By default, this mesh is aligned on the X and Y axes; this rotation is more suited for use with billboarded materials. A [QuadMesh] is equivalent to a [PlaneMesh] except its default [member PlaneMesh.orientation] is [constant PlaneMesh.FACE_Z].
+ </description>
+ <tutorials>
+ <link title="GUI in 3D Demo">https://godotengine.org/asset-library/asset/127</link>
+ <link title="2D in 3D Demo">https://godotengine.org/asset-library/asset/129</link>
+ </tutorials>
+ <members>
+ <member name="orientation" type="int" setter="set_orientation" getter="get_orientation" overrides="PlaneMesh" enum="PlaneMesh.Orientation" default="2" />
+ <member name="size" type="Vector2" setter="set_size" getter="get_size" overrides="PlaneMesh" default="Vector2(1, 1)" />
+ </members>
+</class>
diff --git a/doc/classes/Quaternion.xml b/doc/classes/Quaternion.xml
index a521af5709..f21ebf57e2 100644
--- a/doc/classes/Quaternion.xml
+++ b/doc/classes/Quaternion.xml
@@ -71,7 +71,7 @@
<param index="0" name="to" type="Quaternion" />
<description>
Returns the angle between this quaternion and [param to]. This is the magnitude of the angle you would need to rotate by to get from one to the other.
- [b]Note:[/b] This method has an abnormally high number of floating-point errors, so methods such as [code]is_zero_approx[/code] will not work reliably.
+ [b]Note:[/b] The magnitude of the floating-point error for this method is abnormally high, so methods such as [code]is_zero_approx[/code] will not work reliably.
</description>
</method>
<method name="dot" qualifiers="const">
diff --git a/doc/classes/RefCounted.xml b/doc/classes/RefCounted.xml
index 3daf3534b0..223e572254 100644
--- a/doc/classes/RefCounted.xml
+++ b/doc/classes/RefCounted.xml
@@ -13,6 +13,12 @@
<link title="When and how to avoid using nodes for everything">$DOCS_URL/tutorials/best_practices/node_alternatives.html</link>
</tutorials>
<methods>
+ <method name="get_reference_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the current reference count.
+ </description>
+ </method>
<method name="init_ref">
<return type="bool" />
<description>
diff --git a/doc/classes/ResourceSaver.xml b/doc/classes/ResourceSaver.xml
index b0c9056cbc..8cd701e0d8 100644
--- a/doc/classes/ResourceSaver.xml
+++ b/doc/classes/ResourceSaver.xml
@@ -62,10 +62,10 @@
Do not save editor-specific metadata (identified by their [code]__editor[/code] prefix).
</constant>
<constant name="FLAG_SAVE_BIG_ENDIAN" value="16" enum="SaverFlags" is_bitfield="true">
- Save as big endian (see [member File.big_endian]).
+ Save as big endian (see [member FileAccess.big_endian]).
</constant>
<constant name="FLAG_COMPRESS" value="32" enum="SaverFlags" is_bitfield="true">
- Compress the resource on save using [constant File.COMPRESSION_ZSTD]. Only available for binary resource types.
+ Compress the resource on save using [constant FileAccess.COMPRESSION_ZSTD]. Only available for binary resource types.
</constant>
<constant name="FLAG_REPLACE_SUBRESOURCE_PATHS" value="64" enum="SaverFlags" is_bitfield="true">
Take over the paths of the saved subresources (see [method Resource.take_over_path]).
diff --git a/doc/classes/ScriptEditorBase.xml b/doc/classes/ScriptEditorBase.xml
index c365e0971b..a3fcf53228 100644
--- a/doc/classes/ScriptEditorBase.xml
+++ b/doc/classes/ScriptEditorBase.xml
@@ -19,14 +19,14 @@
<method name="get_base_editor" qualifiers="const">
<return type="Control" />
<description>
- Returns the underlying [Control] used for editing scripts. This can be either [CodeEdit] (for text scripts) or [GraphEdit] (for visual scripts).
+ Returns the underlying [Control] used for editing scripts. For text scripts, this is a [CodeEdit].
</description>
</method>
</methods>
<signals>
<signal name="edited_script_changed">
<description>
- Emitted after script validation. For visual scripts on modification.
+ Emitted after script validation.
</description>
</signal>
<signal name="go_to_help">
@@ -35,15 +35,22 @@
Emitted when the user requests a specific documentation page.
</description>
</signal>
+ <signal name="go_to_method">
+ <param index="0" name="script" type="Object" />
+ <param index="1" name="method" type="String" />
+ <description>
+ Emitted when the user requests to view a specific method of a script, similar to [signal request_open_script_at_line].
+ </description>
+ </signal>
<signal name="name_changed">
<description>
- Emitted after script validation or when the edited resource has changed. Not used by visual scripts.
+ Emitted after script validation or when the edited resource has changed.
</description>
</signal>
<signal name="replace_in_files_requested">
<param index="0" name="text" type="String" />
<description>
- Emitted when the user request to find and replace text in the file system. Not used by visual scripts.
+ Emitted when the user request to find and replace text in the file system.
</description>
</signal>
<signal name="request_help">
@@ -56,7 +63,7 @@
<param index="0" name="script" type="Object" />
<param index="1" name="line" type="int" />
<description>
- Emitted when the user requests a script.
+ Emitted when the user requests to view a specific line of a script, similar to [signal go_to_method].
</description>
</signal>
<signal name="request_save_history">
@@ -67,7 +74,7 @@
<signal name="search_in_files_requested">
<param index="0" name="text" type="String" />
<description>
- Emitted when the user request to search text in the file system. Not used by visual scripts.
+ Emitted when the user request to search text in the file system.
</description>
</signal>
</signals>
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index 5a0766263a..3bd0e04b92 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -32,9 +32,10 @@
Removes the global pose override on all bones in the skeleton.
</description>
</method>
- <method name="clear_bones_local_pose_override">
+ <method name="clear_bones_local_pose_override" is_deprecated="true">
<return type="void" />
<description>
+ Deprecated. Local pose overrides will be removed.
Removes the local pose override on all bones in the skeleton.
</description>
</method>
@@ -43,7 +44,7 @@
<description>
</description>
</method>
- <method name="execute_modifications">
+ <method name="execute_modifications" is_deprecated="true">
<return type="void" />
<param index="0" name="delta" type="float" />
<param index="1" name="execution_mode" type="int" />
@@ -58,7 +59,7 @@
Returns the bone index that matches [param name] as its name.
</description>
</method>
- <method name="force_update_all_bone_transforms">
+ <method name="force_update_all_bone_transforms" is_deprecated="true">
<return type="void" />
<description>
Force updates the bone transforms/poses for all bones in the skeleton.
@@ -166,7 +167,7 @@
Returns the rest transform for a bone [param bone_idx].
</description>
</method>
- <method name="get_modification_stack">
+ <method name="get_modification_stack" is_deprecated="true">
<return type="SkeletonModificationStack3D" />
<description>
Returns the modification stack attached to this skeleton, if one exists.
@@ -178,7 +179,7 @@
Returns an array with all of the bones that are parentless. Another way to look at this is that it returns the indexes of all the bones that are not dependent or modified by other bones in the Skeleton.
</description>
</method>
- <method name="global_pose_to_local_pose">
+ <method name="global_pose_to_local_pose" is_deprecated="true">
<return type="Transform3D" />
<param index="0" name="bone_idx" type="int" />
<param index="1" name="global_pose" type="Transform3D" />
@@ -187,15 +188,16 @@
This can be used to easily convert a global pose from [method get_bone_global_pose] to a global transform in [method set_bone_local_pose_override].
</description>
</method>
- <method name="global_pose_to_world_transform">
+ <method name="global_pose_to_world_transform" is_deprecated="true">
<return type="Transform3D" />
<param index="0" name="global_pose" type="Transform3D" />
<description>
+ Deprecated. Use [Node3D] apis instead.
Takes the passed-in global pose and converts it to a world transform.
This can be used to easily convert a global pose from [method get_bone_global_pose] to a global transform usable with a node's transform, like [member Node3D.global_transform] for example.
</description>
</method>
- <method name="global_pose_z_forward_to_bone_forward">
+ <method name="global_pose_z_forward_to_bone_forward" is_deprecated="true">
<return type="Basis" />
<param index="0" name="bone_idx" type="int" />
<param index="1" name="basis" type="Basis" />
@@ -211,7 +213,7 @@
Returns whether the bone pose for the bone at [param bone_idx] is enabled.
</description>
</method>
- <method name="local_pose_to_global_pose">
+ <method name="local_pose_to_global_pose" is_deprecated="true">
<return type="Transform3D" />
<param index="0" name="bone_idx" type="int" />
<param index="1" name="local_pose" type="Transform3D" />
@@ -293,16 +295,17 @@
<description>
Sets the global pose transform, [param pose], for the bone at [param bone_idx].
[param amount] is the interpolation strength that will be used when applying the pose, and [param persistent] determines if the applied pose will remain.
- [b]Note:[/b] The pose transform needs to be a global pose! Use [method world_transform_to_global_pose] to convert a world transform, like one you can get from a [Node3D], to a global pose.
+ [b]Note:[/b] The pose transform needs to be a global pose! To convert a world transform from a [Node3D] to a global bone pose, multiply the [method Transform3D.affine_inverse] of the node's [member Node3D.global_transform] by the desired world transform
</description>
</method>
- <method name="set_bone_local_pose_override">
+ <method name="set_bone_local_pose_override" is_deprecated="true">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
<param index="1" name="pose" type="Transform3D" />
<param index="2" name="amount" type="float" />
<param index="3" name="persistent" type="bool" default="false" />
<description>
+ Deprecated. Local pose overrides will be removed.
Sets the local pose transform, [param pose], for the bone at [param bone_idx].
[param amount] is the interpolation strength that will be used when applying the pose, and [param persistent] determines if the applied pose will remain.
[b]Note:[/b] The pose transform needs to be a local pose! Use [method global_pose_to_local_pose] to convert a global pose to a local pose.
@@ -353,7 +356,7 @@
Sets the rest transform for bone [param bone_idx].
</description>
</method>
- <method name="set_modification_stack">
+ <method name="set_modification_stack" is_deprecated="true">
<return type="void" />
<param index="0" name="modification_stack" type="SkeletonModificationStack3D" />
<description>
@@ -367,10 +370,11 @@
Unparents the bone at [param bone_idx] and sets its rest position to that of its parent prior to being reset.
</description>
</method>
- <method name="world_transform_to_global_pose">
+ <method name="world_transform_to_global_pose" is_deprecated="true">
<return type="Transform3D" />
<param index="0" name="world_transform" type="Transform3D" />
<description>
+ Deprecated. Use [Node3D] apis instead.
Takes the passed-in global transform and converts it to a global pose.
This can be used to easily convert a global transform from [member Node3D.global_transform] to a global pose usable with [method set_bone_global_pose_override], for example.
</description>
diff --git a/doc/classes/SkeletonIK3D.xml b/doc/classes/SkeletonIK3D.xml
index 788ba3e248..1d50a97954 100644
--- a/doc/classes/SkeletonIK3D.xml
+++ b/doc/classes/SkeletonIK3D.xml
@@ -1,8 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonIK3D" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonIK3D" inherits="Node" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ SkeletonIK3D is used to place the end bone of a [Skeleton3D] bone chain at a certain point in 3D by rotating all bones in the chain accordingly.
</brief_description>
<description>
+ SkeletonIK3D is used to place the end bone of a [Skeleton3D] bone chain at a certain point in 3D by rotating all bones in the chain accordingly. A typical scenario for IK in games is to place a characters feet on the ground or a characters hands on a currently hold object. SkeletonIK uses FabrikInverseKinematic internally to solve the bone chain and applies the results to the [Skeleton3D] [code]bones_global_pose_override[/code] property for all affected bones in the chain. If fully applied this overwrites any bone transform from [Animation]s or bone custom poses set by users. The applied amount can be controlled with the [code]interpolation[/code] property.
+ [codeblock]
+ # Apply IK effect automatically on every new frame (not the current)
+ skeleton_ik_node.start()
+
+ # Apply IK effect only on the current frame
+ skeleton_ik_node.start(true)
+
+ # Stop IK effect and reset bones_global_pose_override on Skeleton
+ skeleton_ik_node.stop()
+
+ # Apply full IK effect
+ skeleton_ik_node.set_interpolation(1.0)
+
+ # Apply half IK effect
+ skeleton_ik_node.set_interpolation(0.5)
+
+ # Apply zero IK effect (a value at or below 0.01 also removes bones_global_pose_override on Skeleton)
+ skeleton_ik_node.set_interpolation(0.0)
+ [/codeblock]
</description>
<tutorials>
<link title="3D Inverse Kinematics Demo">https://godotengine.org/asset-library/asset/523</link>
@@ -11,45 +32,59 @@
<method name="get_parent_skeleton" qualifiers="const">
<return type="Skeleton3D" />
<description>
+ Returns the parent [Skeleton3D] Node that was present when SkeletonIK entered the [SceneTree]. Returns null if the parent node was not a [Skeleton3D] Node when SkeletonIK3D entered the [SceneTree].
</description>
</method>
<method name="is_running">
<return type="bool" />
<description>
+ Returns [code]true[/code] if SkeletonIK is applying IK effects on continues frames to the [Skeleton3D] bones. Returns [code]false[/code] if SkeletonIK is stopped or [method start] was used with the [code]one_time[/code] parameter set to [code]true[/code].
</description>
</method>
<method name="start">
<return type="void" />
<param index="0" name="one_time" type="bool" default="false" />
<description>
+ Starts applying IK effects on each frame to the [Skeleton3D] bones but will only take effect starting on the next frame. If [code]one_time[/code] is [code]true[/code], this will take effect immediately but also reset on the next frame.
</description>
</method>
<method name="stop">
<return type="void" />
<description>
+ Stops applying IK effects on each frame to the [Skeleton3D] bones and also calls [method Skeleton3D.clear_bones_global_pose_override] to remove existing overrides on all bones.
</description>
</method>
</methods>
<members>
<member name="interpolation" type="float" setter="set_interpolation" getter="get_interpolation" default="1.0">
+ Interpolation value for how much the IK results are applied to the current skeleton bone chain. A value of [code]1.0[/code] will overwrite all skeleton bone transforms completely while a value of [code]0.0[/code] will visually disable the SkeletonIK. A value at or below [code]0.01[/code] also calls [method Skeleton3D.clear_bones_global_pose_override].
</member>
<member name="magnet" type="Vector3" setter="set_magnet_position" getter="get_magnet_position" default="Vector3(0, 0, 0)">
+ Secondary target position (first is [member target] property or [member target_node]) for the IK chain. Use magnet position (pole target) to control the bending of the IK chain. Only works if the bone chain has more than 2 bones. The middle chain bone position will be linearly interpolated with the magnet position.
</member>
<member name="max_iterations" type="int" setter="set_max_iterations" getter="get_max_iterations" default="10">
+ Number of iteration loops used by the IK solver to produce more accurate (and elegant) bone chain results.
</member>
<member name="min_distance" type="float" setter="set_min_distance" getter="get_min_distance" default="0.01">
+ The minimum distance between bone and goal target. If the distance is below this value, the IK solver stops further iterations.
</member>
<member name="override_tip_basis" type="bool" setter="set_override_tip_basis" getter="is_override_tip_basis" default="true">
+ If [code]true[/code] overwrites the rotation of the tip bone with the rotation of the [member target] (or [member target_node] if defined).
</member>
<member name="root_bone" type="StringName" setter="set_root_bone" getter="get_root_bone" default="&amp;&quot;&quot;">
+ The name of the current root bone, the first bone in the IK chain.
</member>
<member name="target" type="Transform3D" setter="set_target_transform" getter="get_target_transform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)">
+ First target of the IK chain where the tip bone is placed and, if [member override_tip_basis] is [code]true[/code], how the tip bone is rotated. If a [member target_node] path is available the nodes transform is used instead and this property is ignored.
</member>
<member name="target_node" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
+ Target node [NodePath] for the IK chain. If available, the node's current [Transform3D] is used instead of the [member target] property.
</member>
<member name="tip_bone" type="StringName" setter="set_tip_bone" getter="get_tip_bone" default="&amp;&quot;&quot;">
+ The name of the current tip bone, the last bone in the IK chain placed at the [member target] transform (or [member target_node] if defined).
</member>
<member name="use_magnet" type="bool" setter="set_use_magnet" getter="is_using_magnet" default="false">
+ If [code]true[/code], instructs the IK solver to consider the secondary magnet target (pole target) when calculating the bone chain. Use the magnet position (pole target) to control the bending of the IK chain.
</member>
</members>
</class>
diff --git a/doc/classes/SkeletonModification2D.xml b/doc/classes/SkeletonModification2D.xml
index 46d32aef41..77aaf0213b 100644
--- a/doc/classes/SkeletonModification2D.xml
+++ b/doc/classes/SkeletonModification2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2D" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2D" inherits="Resource" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A resource that operates on [Bone2D] nodes in a [Skeleton2D].
</brief_description>
diff --git a/doc/classes/SkeletonModification2DCCDIK.xml b/doc/classes/SkeletonModification2DCCDIK.xml
index c8fee3f94d..0d80b1b914 100644
--- a/doc/classes/SkeletonModification2DCCDIK.xml
+++ b/doc/classes/SkeletonModification2DCCDIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DCCDIK" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DCCDIK" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that uses CCDIK to manipulate a series of bones to reach a target in 2D.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DFABRIK.xml b/doc/classes/SkeletonModification2DFABRIK.xml
index ff3a65fe1a..8d1cd4b4d4 100644
--- a/doc/classes/SkeletonModification2DFABRIK.xml
+++ b/doc/classes/SkeletonModification2DFABRIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DFABRIK" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DFABRIK" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that uses FABRIK to manipulate a series of [Bone2D] nodes to reach a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DJiggle.xml b/doc/classes/SkeletonModification2DJiggle.xml
index 7329b2d865..3321fffe1b 100644
--- a/doc/classes/SkeletonModification2DJiggle.xml
+++ b/doc/classes/SkeletonModification2DJiggle.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DJiggle" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DJiggle" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that jiggles [Bone2D] nodes as they move towards a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DLookAt.xml b/doc/classes/SkeletonModification2DLookAt.xml
index 4747b06056..136fed37de 100644
--- a/doc/classes/SkeletonModification2DLookAt.xml
+++ b/doc/classes/SkeletonModification2DLookAt.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DLookAt" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DLookAt" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that rotates a [Bone2D] node to look at a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DPhysicalBones.xml b/doc/classes/SkeletonModification2DPhysicalBones.xml
index d5f46b2ea0..209602e974 100644
--- a/doc/classes/SkeletonModification2DPhysicalBones.xml
+++ b/doc/classes/SkeletonModification2DPhysicalBones.xml
@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DPhysicalBones" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DPhysicalBones" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that applies the transforms of [PhysicalBone2D] nodes to [Bone2D] nodes.
</brief_description>
<description>
This modification takes the transforms of [PhysicalBone2D] nodes and applies them to [Bone2D] nodes. This allows the [Bone2D] nodes to react to physics thanks to the linked [PhysicalBone2D] nodes.
+ Experimental. Physical bones may be changed in the future to perform the position update of [Bone2D] on their own.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/SkeletonModification2DStackHolder.xml b/doc/classes/SkeletonModification2DStackHolder.xml
index 791dea2fb1..85df111c0d 100644
--- a/doc/classes/SkeletonModification2DStackHolder.xml
+++ b/doc/classes/SkeletonModification2DStackHolder.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DStackHolder" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DStackHolder" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that holds and executes a [SkeletonModificationStack2D].
</brief_description>
diff --git a/doc/classes/SkeletonModification2DTwoBoneIK.xml b/doc/classes/SkeletonModification2DTwoBoneIK.xml
index edd5431a0c..c476d71d44 100644
--- a/doc/classes/SkeletonModification2DTwoBoneIK.xml
+++ b/doc/classes/SkeletonModification2DTwoBoneIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DTwoBoneIK" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DTwoBoneIK" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that rotates two bones using the law of cosigns to reach the target.
</brief_description>
diff --git a/doc/classes/SkeletonModification3D.xml b/doc/classes/SkeletonModification3D.xml
index 8457179651..25431ea96f 100644
--- a/doc/classes/SkeletonModification3D.xml
+++ b/doc/classes/SkeletonModification3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3D" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3D" inherits="Resource" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A resource that operates on bones in a [Skeleton3D].
</brief_description>
diff --git a/doc/classes/SkeletonModification3DCCDIK.xml b/doc/classes/SkeletonModification3DCCDIK.xml
index dec0fbe99f..90b2e78449 100644
--- a/doc/classes/SkeletonModification3DCCDIK.xml
+++ b/doc/classes/SkeletonModification3DCCDIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DCCDIK" inherits="SkeletonModification3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3DCCDIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that uses CCDIK to manipulate a series of bones to reach a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification3DFABRIK.xml b/doc/classes/SkeletonModification3DFABRIK.xml
index 325cc2a12e..a2bec2b559 100644
--- a/doc/classes/SkeletonModification3DFABRIK.xml
+++ b/doc/classes/SkeletonModification3DFABRIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DFABRIK" inherits="SkeletonModification3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3DFABRIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that uses FABRIK to manipulate a series of bones to reach a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification3DJiggle.xml b/doc/classes/SkeletonModification3DJiggle.xml
index ef469d42ea..304f08bb20 100644
--- a/doc/classes/SkeletonModification3DJiggle.xml
+++ b/doc/classes/SkeletonModification3DJiggle.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DJiggle" inherits="SkeletonModification3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3DJiggle" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that jiggles bones as they move towards a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification3DLookAt.xml b/doc/classes/SkeletonModification3DLookAt.xml
index 3602cfad95..aeed953ca9 100644
--- a/doc/classes/SkeletonModification3DLookAt.xml
+++ b/doc/classes/SkeletonModification3DLookAt.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DLookAt" inherits="SkeletonModification3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3DLookAt" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that rotates a bone to look at a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification3DStackHolder.xml b/doc/classes/SkeletonModification3DStackHolder.xml
index 24240236a4..9448e2c783 100644
--- a/doc/classes/SkeletonModification3DStackHolder.xml
+++ b/doc/classes/SkeletonModification3DStackHolder.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DStackHolder" inherits="SkeletonModification3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3DStackHolder" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that holds and executes a [SkeletonModificationStack3D].
</brief_description>
diff --git a/doc/classes/SkeletonModification3DTwoBoneIK.xml b/doc/classes/SkeletonModification3DTwoBoneIK.xml
index 6618ebbcfb..0e7ffd5c80 100644
--- a/doc/classes/SkeletonModification3DTwoBoneIK.xml
+++ b/doc/classes/SkeletonModification3DTwoBoneIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DTwoBoneIK" inherits="SkeletonModification3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3DTwoBoneIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that moves two bones to reach the target.
</brief_description>
diff --git a/doc/classes/SkeletonModificationStack2D.xml b/doc/classes/SkeletonModificationStack2D.xml
index 950e52e622..d96833e335 100644
--- a/doc/classes/SkeletonModificationStack2D.xml
+++ b/doc/classes/SkeletonModificationStack2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModificationStack2D" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModificationStack2D" inherits="Resource" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A resource that holds a stack of [SkeletonModification2D]s.
</brief_description>
diff --git a/doc/classes/SkeletonModificationStack3D.xml b/doc/classes/SkeletonModificationStack3D.xml
index 34c7099bca..9eaeeefd8e 100644
--- a/doc/classes/SkeletonModificationStack3D.xml
+++ b/doc/classes/SkeletonModificationStack3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModificationStack3D" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModificationStack3D" inherits="Resource" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A resource that holds a stack of [SkeletonModification3D]s.
</brief_description>
diff --git a/doc/classes/StreamPeerBuffer.xml b/doc/classes/StreamPeerBuffer.xml
index 4bef9f44b7..f33c38e595 100644
--- a/doc/classes/StreamPeerBuffer.xml
+++ b/doc/classes/StreamPeerBuffer.xml
@@ -4,7 +4,7 @@
Data buffer stream peer.
</brief_description>
<description>
- Data buffer stream peer that uses a byte array as the stream. This object can be used to handle binary data from network sessions. To handle binary data stored in files, [File] can be used directly.
+ Data buffer stream peer that uses a byte array as the stream. This object can be used to handle binary data from network sessions. To handle binary data stored in files, [FileAccess] can be used directly.
A [StreamPeerBuffer] object keeps an internal cursor which is the offset in bytes to the start of the buffer. Get and put operations are performed at the cursor position and will move the cursor accordingly.
</description>
<tutorials>
diff --git a/doc/classes/StreamPeerGZIP.xml b/doc/classes/StreamPeerGZIP.xml
new file mode 100644
index 0000000000..71dd36160d
--- /dev/null
+++ b/doc/classes/StreamPeerGZIP.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="StreamPeerGZIP" inherits="StreamPeer" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Stream peer handling GZIP and deflate compression/decompresison.
+ </brief_description>
+ <description>
+ This class allows to compress or decompress data using GZIP/deflate in a streaming fashion. This is particularly useful when compressing or decompressing files that has to be sent through the network without having to allocate them all in memory.
+ After starting the stream via [method start_compression] (or [method start_decompression]), calling [method StreamPeer.put_partial_data] on this stream will compress (or decompress) the data, writing it to the internal buffer. Calling [method StreamPeer.get_available_bytes] will return the pending bytes in the internal buffer, and [method StreamPeer.get_partial_data] will retrieve the compressed (or decompressed) bytes from it. When the stream is over, you must call [method finish] to ensure the internal buffer is properly flushed (make sure to call [method StreamPeer.get_available_bytes] on last time to check if more data needs to be read after that).
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears this stream, resetting the internal state.
+ </description>
+ </method>
+ <method name="finish">
+ <return type="int" enum="Error" />
+ <description>
+ Finalizes the stream, compressing or decompressing any buffered chunk left.
+ </description>
+ </method>
+ <method name="start_compression">
+ <return type="int" enum="Error" />
+ <param index="0" name="use_deflate" type="bool" default="false" />
+ <param index="1" name="buffer_size" type="int" default="65535" />
+ <description>
+ Start the stream in compression mode with the given [param buffer_size], if [param use_deflate] is [code]true[/code] uses deflate instead of GZIP.
+ </description>
+ </method>
+ <method name="start_decompression">
+ <return type="int" enum="Error" />
+ <param index="0" name="use_deflate" type="bool" default="false" />
+ <param index="1" name="buffer_size" type="int" default="65535" />
+ <description>
+ Start the stream in decompression mode with the given [param buffer_size], if [param use_deflate] is [code]true[/code] uses deflate instead of GZIP.
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 0db16b491d..2e67c61e54 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -1720,6 +1720,7 @@
</constant>
<constant name="HINTING_NORMAL" value="2" enum="Hinting">
Use the default font hinting mode (crisper but less smooth).
+ [b]Note:[/b] This hinting mode changes both horizontal and vertical glyph metrics. If applied to monospace font, some glyphs might have different width.
</constant>
<constant name="SUBPIXEL_POSITIONING_DISABLED" value="0" enum="SubpixelPositioning">
Glyph horizontal position is rounded to the whole pixel size, each glyph is rasterized once.
diff --git a/doc/classes/Texture2DArray.xml b/doc/classes/Texture2DArray.xml
index 6f059b5fbf..113f37f974 100644
--- a/doc/classes/Texture2DArray.xml
+++ b/doc/classes/Texture2DArray.xml
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Texture2DArray" inherits="ImageTextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ A single texture resource which consists of multiple, separate images. Each image has the same dimensions and number of mipmap levels.
</brief_description>
<description>
+ A Texture2DArray is different from a Texture3D: The Texture2DArray does not support trilinear interpolation between the [Image]s, i.e. no blending.
+ A Texture2DArray is also different from an [AtlasTexture]: In a Texture2DArray, all images are treated separately. In an atlas, the regions (i.e. the single images) can be of different sizes. Furthermore, you usually need to add a padding around the regions, to prevent accidental UV mapping to more than one region. The same goes for mipmapping: Mipmap chains are handled separately for each layer. In an atlas, the slicing has to be done manually in the fragment shader.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/TextureLayered.xml b/doc/classes/TextureLayered.xml
index 7b528e2082..5e6afcbc5c 100644
--- a/doc/classes/TextureLayered.xml
+++ b/doc/classes/TextureLayered.xml
@@ -1,10 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="TextureLayered" inherits="Texture" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Base class for 3D texture types.
+ Base class for texture types which contain the data of multiple [Image]s. Each image is of the same size and format.
</brief_description>
<description>
- Base class for [Texture2DArray], [Cubemap] and [CubemapArray]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types. Data is set on a per-layer basis. For [Texture2DArray]s, the layer specifies the array layer.
+ Base class for [Texture2DArray], [Cubemap] and [CubemapArray]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types.
+ Data is set on a per-layer basis. For [Texture2DArray]s, the layer specifies the array layer.
+ All images need to have the same width, height and number of mipmap levels.
+ A [TextureLayered] can be loaded with [code]method ResourceFormatLoader.load[/code].
+ To create such a texture file yourself, re-import your image files using the Godot Editor import presets.
+ Internally, Godot maps these files to their respective counterparts in the target rendering driver (GLES3, Vulkan).
</description>
<tutorials>
</tutorials>
@@ -72,6 +77,7 @@
<method name="get_layers" qualifiers="const">
<return type="int" />
<description>
+ Returns the number of referenced [Image]s.
</description>
</method>
<method name="get_width" qualifiers="const">
@@ -83,6 +89,7 @@
<method name="has_mipmaps" qualifiers="const">
<return type="bool" />
<description>
+ Returns [code]true[/code] if the layers have generated mipmaps.
</description>
</method>
</methods>
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index f6a078602c..539ca38190 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -312,6 +312,9 @@
The drop mode as an OR combination of flags. See [enum DropModeFlags] constants. Once dropping is done, reverts to [constant DROP_MODE_DISABLED]. Setting this during [method Control._can_drop_data] is recommended.
This controls the drop sections, i.e. the decision and drawing of possible drop locations based on the mouse position.
</member>
+ <member name="enable_recursive_folding" type="bool" setter="set_enable_recursive_folding" getter="is_recursive_folding_enabled" default="true">
+ If [code]true[/code], recursive folding is enabled for this [Tree]. Holding down Shift while clicking the fold arrow collapses or uncollapses the [TreeItem] and all its descendants.
+ </member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" />
<member name="hide_folding" type="bool" setter="set_hide_folding" getter="is_folding_hidden" default="false">
If [code]true[/code], the folding arrow is hidden.
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index fdae6d205d..c109dc57f7 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -321,6 +321,14 @@
Returns the [Tree] that owns this TreeItem.
</description>
</method>
+ <method name="is_any_collapsed">
+ <return type="bool" />
+ <param index="0" name="only_visible" type="bool" default="false" />
+ <description>
+ Returns [code]true[/code] if this [TreeItem], or any of its descendants, is collapsed.
+ If [param only_visible] is [code]true[/code] it ignores non-visible [TreeItem]s.
+ </description>
+ </method>
<method name="is_button_disabled" qualifiers="const">
<return type="bool" />
<param index="0" name="column" type="int" />
@@ -442,6 +450,13 @@
If [code]true[/code], the given [param column] is checked. Clears column's indeterminate status.
</description>
</method>
+ <method name="set_collapsed_recursive">
+ <return type="void" />
+ <param index="0" name="enable" type="bool" />
+ <description>
+ Collapses or uncollapses this [TreeItem] and all the descendants of this item.
+ </description>
+ </method>
<method name="set_custom_as_button">
<return type="void" />
<param index="0" name="column" type="int" />
diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml
index 5186972477..acf900ae55 100644
--- a/doc/classes/Tween.xml
+++ b/doc/classes/Tween.xml
@@ -8,42 +8,85 @@
[Tween] is more suited than [AnimationPlayer] for animations where you don't know the final values in advance. For example, interpolating a dynamically-chosen camera zoom value is best done with a [Tween]; it would be difficult to do the same thing with an [AnimationPlayer] node. Tweens are also more light-weight than [AnimationPlayer], so they are very much suited for simple animations or general tasks that don't require visual tweaking provided by the editor. They can be used in a fire-and-forget manner for some logic that normally would be done by code. You can e.g. make something shoot periodically by using a looped [CallbackTweener] with a delay.
A [Tween] can be created by using either [method SceneTree.create_tween] or [method Node.create_tween]. [Tween]s created manually (i.e. by using [code]Tween.new()[/code]) are invalid and can't be used for tweening values.
A tween animation is created by adding [Tweener]s to the [Tween] object, using [method tween_property], [method tween_interval], [method tween_callback] or [method tween_method]:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = get_tree().create_tween()
tween.tween_property($Sprite, "modulate", Color.red, 1)
tween.tween_property($Sprite, "scale", Vector2(), 1)
tween.tween_callback($Sprite.queue_free)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Tween tween = GetTree().CreateTween();
+ tween.TweenProperty(GetNode("Sprite"), "modulate", Colors.Red, 1.0f);
+ tween.TweenProperty(GetNode("Sprite"), "scale", Vector2.Zero, 1.0f);
+ tween.TweenCallback(new Callable(GetNode("Sprite").QueueFree));
+ [/csharp]
+ [/codeblocks]
This sequence will make the [code]$Sprite[/code] node turn red, then shrink, before finally calling [method Node.queue_free] to free the sprite. [Tweener]s are executed one after another by default. This behavior can be changed using [method parallel] and [method set_parallel].
When a [Tweener] is created with one of the [code]tween_*[/code] methods, a chained method call can be used to tweak the properties of this [Tweener]. For example, if you want to set a different transition type in the above example, you can use [method set_trans]:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = get_tree().create_tween()
tween.tween_property($Sprite, "modulate", Color.red, 1).set_trans(Tween.TRANS_SINE)
tween.tween_property($Sprite, "scale", Vector2(), 1).set_trans(Tween.TRANS_BOUNCE)
tween.tween_callback($Sprite.queue_free)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Tween tween = GetTree().CreateTween();
+ tween.TweenProperty(GetNode("Sprite"), "modulate", Colors.Red, 1.0f).SetTrans(Tween.TransitionType.Sine);
+ tween.TweenProperty(GetNode("Sprite"), "scale", Vector2.Zero, 1.0f).SetTrans(Tween.TransitionType.Bounce);
+ tween.TweenCallback(new Callable(GetNode("Sprite").QueueFree));
+ [/csharp]
+ [/codeblocks]
Most of the [Tween] methods can be chained this way too. In the following example the [Tween] is bound to the running script's node and a default transition is set for its [Tweener]s:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = get_tree().create_tween().bind_node(self).set_trans(Tween.TRANS_ELASTIC)
tween.tween_property($Sprite, "modulate", Color.red, 1)
tween.tween_property($Sprite, "scale", Vector2(), 1)
tween.tween_callback($Sprite.queue_free)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ var tween = GetTree().CreateTween().BindNode(this).SetTrans(Tween.TransitionType.Elastic);
+ tween.TweenProperty(GetNode("Sprite"), "modulate", Colors.Red, 1.0f);
+ tween.TweenProperty(GetNode("Sprite"), "scale", Vector2.Zero, 1.0f);
+ tween.TweenCallback(new Callable(GetNode("Sprite").QueueFree));
+ [/csharp]
+ [/codeblocks]
Another interesting use for [Tween]s is animating arbitrary sets of objects:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = create_tween()
for sprite in get_children():
tween.tween_property(sprite, "position", Vector2(0, 0), 1)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Tween tween = CreateTween();
+ foreach (Node sprite in GetChildren())
+ tween.TweenProperty(sprite, "position", Vector2.Zero, 1.0f);
+ [/csharp]
+ [/codeblocks]
In the example above, all children of a node are moved one after another to position (0, 0).
You should avoid using more than one [Tween] per object's property. If two or more tweens animate one property at the same time, the last one created will take priority and assign the final value. If you want to interrupt and restart an animation, consider assigning the [Tween] to a variable:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween
func animate():
if tween:
tween.kill() # Abort the previous animation.
tween = create_tween()
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ private Tween tween;
+
+ public void Animate()
+ {
+ if (tween != null)
+ tween.Kill(); // Abort the previous animation
+ tween = CreateTween();
+ }
+ [/csharp]
+ [/codeblocks]
Some [Tweener]s use transitions and eases. The first accepts a [enum TransitionType] constant, and refers to the way the timing of the animation is handled (see [url=https://easings.net/]easings.net[/url] for some examples). The second accepts an [enum EaseType] constant, and controls where the [code]trans_type[/code] is applied to the interpolation (in the beginning, the end, or both). If you don't know which transition and easing to pick, you can try different [enum TransitionType] constants with [constant EASE_IN_OUT], and use the one that looks best.
[url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/tween_cheatsheet.png]Tween easing and transition types cheatsheet[/url]
[b]Note:[/b] All [Tween]s will automatically start by default. To prevent a [Tween] from autostarting, you can call [method stop] immediately after it is created.
@@ -64,12 +107,20 @@
<return type="Tween" />
<description>
Used to chain two [Tweener]s after [method set_parallel] is called with [code]true[/code].
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = create_tween().set_parallel(true)
tween.tween_property(...)
tween.tween_property(...) # Will run parallelly with above.
tween.chain().tween_property(...) # Will run after two above are finished.
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Tween tween = CreateTween().SetParallel(true);
+ tween.TweenProperty(...);
+ tween.TweenProperty(...); // Will run parallelly with above.
+ tween.Chain().TweenProperty(...); // Will run after two above are finished.
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="custom_step">
@@ -127,12 +178,20 @@
<return type="Tween" />
<description>
Makes the next [Tweener] run parallelly to the previous one. Example:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = create_tween()
tween.tween_property(...)
tween.parallel().tween_property(...)
tween.parallel().tween_property(...)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Tween tween = CreateTween();
+ tween.TweenProperty(...);
+ tween.Parallel().TweenProperty(...);
+ tween.Parallel().TweenProperty(...);
+ [/csharp]
+ [/codeblocks]
All [Tweener]s in the example will run at the same time.
You can make the [Tween] parallel by default by using [method set_parallel].
</description>
@@ -214,16 +273,30 @@
<description>
Creates and appends a [CallbackTweener]. This method can be used to call an arbitrary method in any object. Use [method Callable.bind] to bind additional arguments for the call.
Example: object that keeps shooting every 1 second.
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = get_tree().create_tween().set_loops()
tween.tween_callback(shoot).set_delay(1)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Tween tween = GetTree().CreateTween().SetLoops();
+ tween.TweenCallback(new Callable(Shoot)).SetDelay(1.0f);
+ [/csharp]
+ [/codeblocks]
Example: turning a sprite red and then blue, with 2 second delay.
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = get_tree().create_tween()
tween.tween_callback($Sprite.set_modulate.bind(Color.red)).set_delay(2)
tween.tween_callback($Sprite.set_modulate.bind(Color.blue)).set_delay(2)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Tween tween = GetTree().CreateTween();
+ Sprite2D sprite = GetNode&lt;Sprite2D&gt;("Sprite");
+ tween.TweenCallback(new Callable(() =&gt; sprite.Modulate = Colors.Red)).SetDelay(2.0f);
+ tween.TweenCallback(new Callable(() =&gt; sprite.Modulate = Colors.Blue)).SetDelay(2.0f);
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="tween_interval">
@@ -232,13 +305,21 @@
<description>
Creates and appends an [IntervalTweener]. This method can be used to create delays in the tween animation, as an alternative to using the delay in other [Tweener]s, or when there's no animation (in which case the [Tween] acts as a timer). [param time] is the length of the interval, in seconds.
Example: creating an interval in code execution.
- [codeblock]
+ [codeblocks]
+ [gdscript]
# ... some code
await create_tween().tween_interval(2).finished
# ... more code
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ // ... some code
+ await ToSignal(CreateTween().TweenInterval(2.0f), Tween.SignalName.Finished);
+ // ... more code
+ [/csharp]
+ [/codeblocks]
Example: creating an object that moves back and forth and jumps every few seconds.
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = create_tween().set_loops()
tween.tween_property($Sprite, "position:x", 200.0, 1).as_relative()
tween.tween_callback(jump)
@@ -246,7 +327,17 @@
tween.tween_property($Sprite, "position:x", -200.0, 1).as_relative()
tween.tween_callback(jump)
tween.tween_interval(2)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Tween tween = CreateTween().SetLoops();
+ tween.TweenProperty(GetNode("Sprite"), "position:x", 200.0f, 1.0f).AsRelative();
+ tween.TweenCallback(new Callable(Jump));
+ tween.TweenInterval(2.0f);
+ tween.TweenProperty(GetNode("Sprite"), "position:x", -200.0f, 1.0f).AsRelative();
+ tween.TweenCallback(new Callable(Jump));
+ tween.TweenInterval(2.0f);
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="tween_method">
@@ -258,19 +349,41 @@
<description>
Creates and appends a [MethodTweener]. This method is similar to a combination of [method tween_callback] and [method tween_property]. It calls a method over time with a tweened value provided as an argument. The value is tweened between [param from] and [param to] over the time specified by [param duration], in seconds. Use [method Callable.bind] to bind additional arguments for the call. You can use [method MethodTweener.set_ease] and [method MethodTweener.set_trans] to tweak the easing and transition of the value or [method MethodTweener.set_delay] to delay the tweening.
Example: making a 3D object look from one point to another point.
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = create_tween()
tween.tween_method(look_at.bind(Vector3.UP), Vector3(-1, 0, -1), Vector3(1, 0, -1), 1) # The look_at() method takes up vector as second argument.
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Tween tween = CreateTween();
+ tween.TweenMethod(new Callable(() =&gt; LookAt(Vector3.Up)), new Vector3(-1.0f, 0.0f, -1.0f), new Vector3(1.0f, 0.0f, -1.0f), 1.0f); // The LookAt() method takes up vector as second argument.
+ [/csharp]
+ [/codeblocks]
Example: setting a text of a [Label], using an intermediate method and after a delay.
- [codeblock]
+ [codeblocks]
+ [gdscript]
func _ready():
var tween = create_tween()
tween.tween_method(set_label_text, 0, 10, 1).set_delay(1)
func set_label_text(value: int):
$Label.text = "Counting " + str(value)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ public override void _Ready()
+ {
+ base._Ready();
+
+ Tween tween = CreateTween();
+ tween.TweenMethod(new Callable(SetLabelText), 0.0f, 10.0f, 1.0f).SetDelay(1.0f);
+ }
+
+ private void SetLabelText(int value)
+ {
+ GetNode&lt;Label&gt;("Label").Text = $"Counting {value}";
+ }
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="tween_property">
@@ -281,19 +394,33 @@
<param index="3" name="duration" type="float" />
<description>
Creates and appends a [PropertyTweener]. This method tweens a [param property] of an [param object] between an initial value and [param final_val] in a span of time equal to [param duration], in seconds. The initial value by default is the property's value at the time the tweening of the [PropertyTweener] starts. For example:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = create_tween()
tween.tween_property($Sprite, "position", Vector2(100, 200), 1)
tween.tween_property($Sprite, "position", Vector2(200, 300), 1)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Tween tween = CreateTween();
+ tween.TweenProperty(GetNode("Sprite"), "position", new Vector2(100.0f, 200.0f), 1.0f);
+ tween.TweenProperty(GetNode("Sprite"), "position", new Vector2(200.0f, 300.0f), 1.0f);
+ [/csharp]
+ [/codeblocks]
will move the sprite to position (100, 200) and then to (200, 300). If you use [method PropertyTweener.from] or [method PropertyTweener.from_current], the starting position will be overwritten by the given value instead. See other methods in [PropertyTweener] to see how the tweening can be tweaked further.
[b]Note:[/b] You can find the correct property name by hovering over the property in the Inspector. You can also provide the components of a property directly by using [code]"property:component"[/code] (eg. [code]position:x[/code]), where it would only apply to that particular component.
Example: moving object twice from the same position, with different transition types.
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = create_tween()
tween.tween_property($Sprite, "position", Vector2.RIGHT * 300, 1).as_relative().set_trans(Tween.TRANS_SINE)
tween.tween_property($Sprite, "position", Vector2.RIGHT * 300, 1).as_relative().from_current().set_trans(Tween.TRANS_EXPO)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Tween tween = CreateTween();
+ tween.TweenProperty(GetNode("Sprite"), "position", Vector2.Right * 300.0f, 1.0f).AsRelative().SetTrans(Tween.TransitionType.Sine);
+ tween.TweenProperty(GetNode("Sprite"), "position", Vector2.Right * 300.0f, 1.0f).AsRelative().FromCurrent().SetTrans(Tween.TransitionType.Expo);
+ [/csharp]
+ [/codeblocks]
</description>
</method>
</methods>
diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml
index 3ef59b1c39..7258efbdda 100644
--- a/doc/classes/UndoRedo.xml
+++ b/doc/classes/UndoRedo.xml
@@ -62,12 +62,11 @@
<tutorials>
</tutorials>
<methods>
- <method name="add_do_method" qualifiers="vararg">
+ <method name="add_do_method">
<return type="void" />
- <param index="0" name="object" type="Object" />
- <param index="1" name="method" type="StringName" />
+ <param index="0" name="callable" type="Callable" />
<description>
- Register a [param method] that will be called when the action is committed.
+ Register a [Callable] that will be called when the action is committed.
</description>
</method>
<method name="add_do_property">
@@ -86,12 +85,11 @@
Register a reference for "do" that will be erased if the "do" history is lost. This is useful mostly for new nodes created for the "do" call. Do not use for resources.
</description>
</method>
- <method name="add_undo_method" qualifiers="vararg">
+ <method name="add_undo_method">
<return type="void" />
- <param index="0" name="object" type="Object" />
- <param index="1" name="method" type="StringName" />
+ <param index="0" name="callable" type="Callable" />
<description>
- Register a [param method] that will be called when the action is undone.
+ Register a [Callable] that will be called when the action is undone.
</description>
</method>
<method name="add_undo_property">
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index 2c0a694ef9..c585b54ee1 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -381,7 +381,8 @@
Note that behavior might be different depending on the platform.
</member>
<member name="transparent" type="bool" setter="set_flag" getter="get_flag" default="false">
- If [code]true[/code], the [Window]'s background can be transparent. This is best used with embedded windows. Currently non-embedded [Window] transparency is implemented only for MacOS.
+ If [code]true[/code], the [Window]'s background can be transparent. This is best used with embedded windows.
+ [b]Note:[/b] This flag has no effect if [member ProjectSettings.display/window/per_pixel_transparency/allowed] is set to [code]false[/code].
</member>
<member name="unfocusable" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], the [Window] can't be focused nor interacted with. It can still be visible.
@@ -454,6 +455,11 @@
Emitted when the [constant NOTIFICATION_THEME_CHANGED] notification is sent.
</description>
</signal>
+ <signal name="titlebar_changed">
+ <description>
+ Emitted when window title bar decorations are changed, e.g., macOS window enter/exit full screen mode, or extend-to-title flag is changed.
+ </description>
+ </signal>
<signal name="visibility_changed">
<description>
Emitted when [Window] is made visible or disappears.
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 8d4954136e..0ffede0992 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -198,7 +198,8 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
int item_count = 0;
bool backbuffer_cleared = false;
bool time_used = false;
- bool material_screen_texture_found = false;
+ bool material_screen_texture_cached = false;
+ bool material_screen_texture_mipmaps_cached = false;
Rect2 back_buffer_rect;
bool backbuffer_copy = false;
bool backbuffer_gen_mipmaps = false;
@@ -223,10 +224,12 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
GLES3::CanvasMaterialData *md = static_cast<GLES3::CanvasMaterialData *>(material_storage->material_get_data(material, RS::SHADER_CANVAS_ITEM));
if (md && md->shader_data->valid) {
if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) {
- if (!material_screen_texture_found) {
+ if (!material_screen_texture_cached) {
backbuffer_copy = true;
back_buffer_rect = Rect2();
backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps;
+ } else if (!material_screen_texture_mipmaps_cached) {
+ backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps;
}
}
@@ -287,7 +290,16 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, backbuffer_gen_mipmaps);
backbuffer_copy = false;
- material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
+ backbuffer_gen_mipmaps = false;
+ material_screen_texture_cached = true; // After a backbuffer copy, screen texture makes no further copies.
+ material_screen_texture_mipmaps_cached = backbuffer_gen_mipmaps;
+ }
+
+ if (backbuffer_gen_mipmaps) {
+ texture_storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, back_buffer_rect);
+
+ backbuffer_gen_mipmaps = false;
+ material_screen_texture_mipmaps_cached = true;
}
// just add all items for now
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index dae26b1e5f..85b35639ec 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -683,6 +683,7 @@ void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, cons
light_data_dirty = true;
for (uint32_t i = sky_globals.directional_light_count; i < sky_globals.max_directional_lights; i++) {
sky_globals.directional_lights[i].enabled = false;
+ sky_globals.last_frame_directional_lights[i].enabled = false;
}
}
@@ -1718,7 +1719,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
-void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) {
+void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RenderingMethod::RenderInfo *r_render_info) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
RENDER_TIMESTAMP("Setup 3D Scene");
@@ -2480,7 +2481,7 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
scene_globals.default_shader = material_storage->shader_allocate();
material_storage->shader_initialize(scene_globals.default_shader);
material_storage->shader_set_code(scene_globals.default_shader, R"(
-// Default 3D material shader (clustered).
+// Default 3D material shader.
shader_type spatial;
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 881fc5615c..f0dc972678 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -124,7 +124,7 @@ struct RenderDataGLES3 {
uint32_t spot_light_count = 0;
uint32_t omni_light_count = 0;
- RendererScene::RenderInfo *render_info = nullptr;
+ RenderingMethod::RenderInfo *render_info = nullptr;
};
class RasterizerCanvasGLES3;
@@ -304,12 +304,13 @@ private:
};
enum {
- INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5,
- INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6,
- INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
- INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
- INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
- INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11,
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
+ INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 8,
+ INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 9,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 10,
+ INSTANCE_DATA_FLAG_PARTICLES = 1 << 11,
INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
@@ -711,7 +712,7 @@ public:
void voxel_gi_set_quality(RS::VoxelGIQuality) override;
- void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override;
+ void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) override;
void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) override;
diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h
index f054f0fdc6..8b708116ac 100644
--- a/drivers/gles3/storage/light_storage.h
+++ b/drivers/gles3/storage/light_storage.h
@@ -36,6 +36,7 @@
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
+#include "drivers/gles3/storage/texture_storage.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/storage/light_storage.h"
#include "servers/rendering/storage/utilities.h"
@@ -246,7 +247,7 @@ public:
const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
- return light_owner.owns(light->projector);
+ return TextureStorage::get_singleton()->owns_texture(light->projector);
}
_FORCE_INLINE_ bool light_is_negative(RID p_light) const {
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index 523c9dd8e6..687e98ba58 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1379,9 +1379,9 @@ MaterialStorage::MaterialStorage() {
actions.renames["POINT_SIZE"] = "gl_PointSize";
actions.renames["MODEL_MATRIX"] = "model_matrix";
- actions.renames["CANVAS_MATRIX"] = "canvas_data.canvas_transform";
- actions.renames["SCREEN_MATRIX"] = "canvas_data.screen_transform";
- actions.renames["TIME"] = "canvas_data.time";
+ actions.renames["CANVAS_MATRIX"] = "canvas_transform";
+ actions.renames["SCREEN_MATRIX"] = "screen_transform";
+ actions.renames["TIME"] = "time";
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
@@ -1399,7 +1399,7 @@ MaterialStorage::MaterialStorage() {
actions.renames["SPECULAR_SHININESS"] = "specular_shininess";
actions.renames["SCREEN_UV"] = "screen_uv";
actions.renames["SCREEN_TEXTURE"] = "screen_texture";
- actions.renames["SCREEN_PIXEL_SIZE"] = "canvas_data.screen_pixel_size";
+ actions.renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
actions.renames["POINT_COORD"] = "gl_PointCoord";
actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 8d2f8a7ed6..165de34c71 100644
--- a/drivers/png/image_loader_png.cpp
+++ b/drivers/png/image_loader_png.cpp
@@ -36,7 +36,7 @@
#include <string.h>
-Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
const uint64_t buffer_size = f->get_length();
Vector<uint8_t> file_buffer;
Error err = file_buffer.resize(buffer_size);
diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h
index 91c3c8925f..a247d77310 100644
--- a/drivers/png/image_loader_png.h
+++ b/drivers/png/image_loader_png.h
@@ -40,7 +40,7 @@ private:
static Ref<Image> load_mem_png(const uint8_t *p_png, int p_size);
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderPNG();
};
diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp
index 504ef9843a..53a7f7aa4f 100644
--- a/drivers/register_driver_types.cpp
+++ b/drivers/register_driver_types.cpp
@@ -34,11 +34,11 @@
#include "drivers/png/image_loader_png.h"
#include "drivers/png/resource_saver_png.h"
-static ImageLoaderPNG *image_loader_png;
+static Ref<ImageLoaderPNG> image_loader_png;
static Ref<ResourceSaverPNG> resource_saver_png;
void register_core_driver_types() {
- image_loader_png = memnew(ImageLoaderPNG);
+ image_loader_png.instantiate();
ImageLoader::add_image_format_loader(image_loader_png);
resource_saver_png.instantiate();
@@ -46,9 +46,8 @@ void register_core_driver_types() {
}
void unregister_core_driver_types() {
- if (image_loader_png) {
- memdelete(image_loader_png);
- }
+ ImageLoader::remove_image_format_loader(image_loader_png);
+ image_loader_png.unref();
ResourceSaver::remove_resource_format_saver(resource_saver_png);
resource_saver_png.unref();
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 388ad479b9..300fbcdcfd 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -70,7 +70,7 @@ void FileAccessUnix::check_errors() const {
}
}
-Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) {
_close();
path_src = p_path;
diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h
index 297c34e454..e1311a80f8 100644
--- a/drivers/unix/file_access_unix.h
+++ b/drivers/unix/file_access_unix.h
@@ -54,7 +54,7 @@ class FileAccessUnix : public FileAccess {
public:
static CloseNotificationFunc close_notification_func;
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual String get_path() const override; /// returns the path for the current open file
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index beb2812999..c8a42e925e 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -51,7 +51,6 @@
#include <sys/sysctl.h>
#endif
-#include <assert.h>
#include <dlfcn.h>
#include <errno.h>
#include <poll.h>
@@ -104,10 +103,6 @@ static void _setup_clock() {
}
#endif
-void OS_Unix::debug_break() {
- assert(false);
-}
-
static void handle_interrupt(int sig) {
if (!EngineDebugger::is_active()) {
return;
@@ -194,6 +189,14 @@ String OS_Unix::get_name() const {
return "Unix";
}
+String OS_Unix::get_distribution_name() const {
+ return "";
+}
+
+String OS_Unix::get_version() const {
+ return "";
+}
+
double OS_Unix::get_unix_time() const {
struct timeval tv_now;
gettimeofday(&tv_now, nullptr);
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index b4c844bfef..b35f161524 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -62,6 +62,8 @@ public:
virtual Error set_cwd(const String &p_cwd) override;
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual DateTime get_datetime(bool p_utc) const override;
virtual TimeZoneInfo get_time_zone_info() const override;
@@ -84,7 +86,6 @@ public:
virtual int get_processor_count() const override;
- virtual void debug_break() override;
virtual void initialize_debugging() override;
virtual String get_executable_path() const override;
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 73ae108961..53e9146f85 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -9367,10 +9367,10 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
// NOTE: If adding new project settings here, also duplicate their definition in
// rendering_server.cpp for headless doctool.
- staging_buffer_block_size = GLOBAL_DEF("rendering/vulkan/staging_buffer/block_size_kb", 256);
+ staging_buffer_block_size = GLOBAL_DEF("rendering/rendering_device/staging_buffer/block_size_kb", 256);
staging_buffer_block_size = MAX(4u, staging_buffer_block_size);
staging_buffer_block_size *= 1024; // Kb -> bytes.
- staging_buffer_max_size = GLOBAL_DEF("rendering/vulkan/staging_buffer/max_size_mb", 128);
+ staging_buffer_max_size = GLOBAL_DEF("rendering/rendering_device/staging_buffer/max_size_mb", 128);
staging_buffer_max_size = MAX(1u, staging_buffer_max_size);
staging_buffer_max_size *= 1024 * 1024;
@@ -9378,7 +9378,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
// Validate enough blocks.
staging_buffer_max_size = staging_buffer_block_size * 4;
}
- texture_upload_region_size_px = GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64);
+ texture_upload_region_size_px = GLOBAL_DEF("rendering/rendering_device/staging_buffer/texture_upload_region_size_px", 64);
texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px);
frames_drawn = frame_count; // Start from frame count, so everything else is immediately old.
@@ -9393,7 +9393,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
ERR_CONTINUE(err != OK);
}
- max_descriptors_per_pool = GLOBAL_DEF("rendering/vulkan/descriptor_pools/max_descriptors_per_pool", 64);
+ max_descriptors_per_pool = GLOBAL_DEF("rendering/rendering_device/descriptor_pools/max_descriptors_per_pool", 64);
// Check to make sure DescriptorPoolKey is good.
static_assert(sizeof(uint64_t) * 3 >= UNIFORM_TYPE_MAX * sizeof(uint16_t));
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 1a66d19373..095d936c78 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -58,7 +58,7 @@ void FileAccessWindows::check_errors() const {
}
}
-Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) {
_close();
path_src = p_path;
diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h
index 8629bb936b..d84c400775 100644
--- a/drivers/windows/file_access_windows.h
+++ b/drivers/windows/file_access_windows.h
@@ -51,7 +51,7 @@ class FileAccessWindows : public FileAccess {
void _close();
public:
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual String get_path() const override; /// returns the path for the current open file
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index 219f3fdbe1..3b87b3e65e 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -667,8 +667,8 @@ void AnimationBezierTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) {
void AnimationBezierTrackEdit::set_editor(AnimationTrackEditor *p_editor) {
editor = p_editor;
- connect("clear_selection", Callable(editor, "_clear_selection").bind(false));
- connect("select_key", Callable(editor, "_key_selected"), CONNECT_DEFERRED);
+ connect("clear_selection", callable_mp(editor, &AnimationTrackEditor::_clear_selection).bind(false));
+ connect("select_key", callable_mp(editor, &AnimationTrackEditor::_key_selected), CONNECT_DEFERRED);
}
void AnimationBezierTrackEdit::_play_position_draw() {
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 70b5501692..9529460ab1 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -1445,7 +1445,9 @@ void AnimationTimelineEdit::_anim_loop_pressed() {
default:
break;
}
+ undo_redo->add_do_method(this, "update_values");
undo_redo->add_undo_method(animation.ptr(), "set_loop_mode", animation->get_loop_mode());
+ undo_redo->add_undo_method(this, "update_values");
undo_redo->commit_action();
} else {
String base_path = animation->get_path();
@@ -1913,6 +1915,8 @@ void AnimationTimelineEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag"), PropertyInfo(Variant::BOOL, "timeline_only")));
ADD_SIGNAL(MethodInfo("track_added", PropertyInfo(Variant::INT, "track")));
ADD_SIGNAL(MethodInfo("length_changed", PropertyInfo(Variant::FLOAT, "size")));
+
+ ClassDB::bind_method(D_METHOD("update_values"), &AnimationTimelineEdit::update_values);
}
AnimationTimelineEdit::AnimationTimelineEdit() {
@@ -3420,9 +3424,6 @@ void AnimationTrackEditGroup::_zoom_changed() {
queue_redraw();
}
-void AnimationTrackEditGroup::_bind_methods() {
-}
-
AnimationTrackEditGroup::AnimationTrackEditGroup() {
set_mouse_filter(MOUSE_FILTER_PASS);
}
@@ -6050,10 +6051,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
real_t to_diff = fmod(b - a, Math_TAU);
to_v = a + fmod(2.0 * to_diff, Math_TAU) - to_diff;
}
- Variant delta_v;
- Variant::sub(to_v, from_v, delta_v);
+ Variant delta_v = Animation::subtract_variant(to_v, from_v);
double duration = to_t - from_t;
- double fixed_duration = duration - 0.01; // Prevent to overwrap keys...
+ double fixed_duration = duration - UNIT_EPSILON; // Prevent to overwrap keys...
for (double delta_t = dur_step; delta_t < fixed_duration; delta_t += dur_step) {
Pair<real_t, Variant> keydata;
keydata.first = from_t + delta_t;
@@ -6458,16 +6458,11 @@ void AnimationTrackEditor::_select_all_tracks_for_copy() {
}
void AnimationTrackEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_animation_update"), &AnimationTrackEditor::_animation_update);
- ClassDB::bind_method(D_METHOD("_track_grab_focus"), &AnimationTrackEditor::_track_grab_focus);
- ClassDB::bind_method(D_METHOD("_update_tracks"), &AnimationTrackEditor::_update_tracks);
- ClassDB::bind_method(D_METHOD("_redraw_tracks"), &AnimationTrackEditor::_redraw_tracks);
- ClassDB::bind_method(D_METHOD("_clear_selection_for_anim"), &AnimationTrackEditor::_clear_selection_for_anim);
- ClassDB::bind_method(D_METHOD("_select_at_anim"), &AnimationTrackEditor::_select_at_anim);
-
- ClassDB::bind_method(D_METHOD("_key_selected"), &AnimationTrackEditor::_key_selected); // Still used by some connect_compat.
- ClassDB::bind_method(D_METHOD("_key_deselected"), &AnimationTrackEditor::_key_deselected); // Still used by some connect_compat.
- ClassDB::bind_method(D_METHOD("_clear_selection"), &AnimationTrackEditor::_clear_selection); // Still used by some connect_compat.
+ ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update);
+ ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus);
+ ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim);
+ ClassDB::bind_method("_select_at_anim", &AnimationTrackEditor::_select_at_anim);
+ ClassDB::bind_method("_clear_selection", &AnimationTrackEditor::_clear_selection);
ClassDB::bind_method(D_METHOD("_bezier_track_set_key_handle_mode", "animation", "track_idx", "key_idx", "key_handle_mode", "key_handle_set_mode"), &AnimationTrackEditor::_bezier_track_set_key_handle_mode, DEFVAL(Animation::HANDLE_SET_MODE_NONE));
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index ac69b88e99..5c51921d93 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -280,7 +280,6 @@ class AnimationTrackEditGroup : public Control {
void _zoom_changed();
protected:
- static void _bind_methods();
void _notification(int p_what);
public:
@@ -407,7 +406,6 @@ class AnimationTrackEditor : public VBoxContainer {
void _insert_key_from_track(float p_ofs, int p_track);
void _add_method_key(const String &p_method);
- void _clear_selection(bool p_update = false);
void _clear_selection_for_anim(const Ref<Animation> &p_anim);
void _select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos);
@@ -425,9 +423,6 @@ class AnimationTrackEditor : public VBoxContainer {
RBMap<SelectedKey, KeyInfo> selection;
- void _key_selected(int p_key, bool p_single, int p_track);
- void _key_deselected(int p_key, int p_track);
-
bool moving_selection = false;
float moving_selection_offset = 0.0f;
void _move_selection_begin();
@@ -531,6 +526,11 @@ protected:
void _notification(int p_what);
public:
+ // Public for use with callable_mp.
+ void _clear_selection(bool p_update = false);
+ void _key_selected(int p_key, bool p_single, int p_track);
+ void _key_deselected(int p_key, int p_track);
+
enum {
EDIT_COPY_TRACKS,
EDIT_COPY_TRACKS_CONFIRM,
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 861d05f17a..ddeb8643b8 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -238,6 +238,12 @@ void ConnectDialog::_notification(int p_what) {
String type_name = Variant::get_type_name((Variant::Type)type_list->get_item_id(i));
type_list->set_item_icon(i, get_theme_icon(type_name, SNAME("EditorIcons")));
}
+
+ Ref<StyleBox> style = get_theme_stylebox("normal", "LineEdit")->duplicate();
+ if (style.is_valid()) {
+ style->set_default_margin(SIDE_TOP, style->get_default_margin(SIDE_TOP) + 1.0);
+ from_signal->add_theme_style_override("normal", style);
+ }
} break;
}
}
@@ -361,6 +367,10 @@ void ConnectDialog::popup_dialog(const String &p_for_signal) {
error_label->set_visible(!_find_first_script(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root()));
}
+ if (first_popup) {
+ first_popup = false;
+ _advanced_pressed();
+ }
popup_centered();
}
@@ -383,6 +393,7 @@ void ConnectDialog::_advanced_pressed() {
}
_update_ok_enabled();
+ EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "use_advanced_connections", advanced->is_pressed());
popup_centered();
}
@@ -465,30 +476,32 @@ ConnectDialog::ConnectDialog() {
vbc_right->add_margin_child(TTR("Unbind Signal Arguments:"), unbind_count);
- HBoxContainer *dstm_hb = memnew(HBoxContainer);
- vbc_left->add_margin_child(TTR("Receiver Method:"), dstm_hb);
-
dst_method = memnew(LineEdit);
dst_method->set_h_size_flags(Control::SIZE_EXPAND_FILL);
dst_method->connect("text_submitted", callable_mp(this, &ConnectDialog::_text_submitted));
- dstm_hb->add_child(dst_method);
+ vbc_left->add_margin_child(TTR("Receiver Method:"), dst_method);
advanced = memnew(CheckButton);
- dstm_hb->add_child(advanced);
+ vbc_left->add_child(advanced);
advanced->set_text(TTR("Advanced"));
+ advanced->set_h_size_flags(Control::SIZE_SHRINK_BEGIN | Control::SIZE_EXPAND);
+ advanced->set_pressed(EditorSettings::get_singleton()->get_project_metadata("editor_metadata", "use_advanced_connections", false));
advanced->connect("pressed", callable_mp(this, &ConnectDialog::_advanced_pressed));
+ HBoxContainer *hbox = memnew(HBoxContainer);
+ vbc_right->add_child(hbox);
+
deferred = memnew(CheckBox);
deferred->set_h_size_flags(0);
deferred->set_text(TTR("Deferred"));
deferred->set_tooltip_text(TTR("Defers the signal, storing it in a queue and only firing it at idle time."));
- vbc_right->add_child(deferred);
+ hbox->add_child(deferred);
one_shot = memnew(CheckBox);
one_shot->set_h_size_flags(0);
- one_shot->set_text(TTR("Oneshot"));
+ one_shot->set_text(TTR("One Shot"));
one_shot->set_tooltip_text(TTR("Disconnects the signal after its first emission."));
- vbc_right->add_child(one_shot);
+ hbox->add_child(one_shot);
cdbinds = memnew(ConnectDialogBinds);
@@ -810,7 +823,7 @@ void ConnectionsDock::_go_to_script(TreeItem &p_item) {
}
if (script.is_valid() && ScriptEditor::get_singleton()->script_goto_method(script, cd.method)) {
- EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
+ EditorNode::get_singleton()->editor_select(EditorNode::EDITOR_SCRIPT);
}
}
diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h
index e37246e7a0..db2f855617 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -112,6 +112,7 @@ private:
LineEdit *dst_method = nullptr;
ConnectDialogBinds *cdbinds = nullptr;
bool edit_mode = false;
+ bool first_popup = true;
NodePath dst_path;
VBoxContainer *vbc_right = nullptr;
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index 9f655ab00a..7d6eb186dc 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -1162,13 +1162,11 @@ Error DocTools::_load(Ref<XMLParser> parser) {
}
if (parser->has_attribute("is_deprecated")) {
- String result = parser->get_attribute_value("is_deprecated");
- c.is_deprecated = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ c.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- String result = parser->get_attribute_value("is_experimental");
- c.is_experimental = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ c.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
}
while (parser->read() == OK) {
@@ -1315,12 +1313,10 @@ Error DocTools::_load(Ref<XMLParser> parser) {
constant2.is_bitfield = parser->get_attribute_value("is_bitfield").to_lower() == "true";
}
if (parser->has_attribute("is_deprecated")) {
- String result = parser->get_attribute_value("is_deprecated");
- constant2.is_deprecated = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ constant2.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- String result = parser->get_attribute_value("is_experimental");
- constant2.is_experimental = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ constant2.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
}
if (!parser->is_empty()) {
parser->read();
@@ -1376,10 +1372,10 @@ static void _write_method_doc(Ref<FileAccess> f, const String &p_name, Vector<Do
String additional_attributes;
if (m.is_deprecated) {
- additional_attributes += " is_deprecated=\"True\"";
+ additional_attributes += " is_deprecated=\"true\"";
}
if (m.is_experimental) {
- additional_attributes += " is_experimental=\"True\"";
+ additional_attributes += " is_experimental=\"true\"";
}
_write_string(f, 2, "<" + p_name + " name=\"" + m.name.xml_escape() + "\"" + qualifiers + additional_attributes + ">");
@@ -1446,10 +1442,10 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
if (!c.inherits.is_empty()) {
header += " inherits=\"" + c.inherits + "\"";
if (c.is_deprecated) {
- header += " is_deprecated=\"True\"";
+ header += " is_deprecated=\"true\"";
}
if (c.is_experimental) {
- header += " is_experimental=\"True\"";
+ header += " is_experimental=\"true\"";
}
}
header += String(" version=\"") + VERSION_BRANCH + "\"";
@@ -1495,10 +1491,10 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
additional_attributes += " default=\"" + c.properties[i].default_value.xml_escape(true) + "\"";
}
if (c.properties[i].is_deprecated) {
- additional_attributes += " is_deprecated=\"True\"";
+ additional_attributes += " is_deprecated=\"true\"";
}
if (c.properties[i].is_experimental) {
- additional_attributes += " is_experimental=\"True\"";
+ additional_attributes += " is_experimental=\"true\"";
}
const DocData::PropertyDoc &p = c.properties[i];
@@ -1523,10 +1519,10 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
String additional_attributes;
if (c.constants[i].is_deprecated) {
- additional_attributes += " is_deprecated=\"True\"";
+ additional_attributes += " is_deprecated=\"true\"";
}
if (c.constants[i].is_experimental) {
- additional_attributes += " is_experimental=\"True\"";
+ additional_attributes += " is_experimental=\"true\"";
}
if (k.is_value_valid) {
diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp
index ba1f2fd6af..a0913265eb 100644
--- a/editor/editor_command_palette.cpp
+++ b/editor/editor_command_palette.cpp
@@ -130,7 +130,7 @@ void EditorCommandPalette::_update_command_search(const String &search_text) {
ti->set_metadata(0, entries[i].key_name);
ti->set_text_alignment(1, HORIZONTAL_ALIGNMENT_RIGHT);
ti->set_text(1, shortcut_text);
- Color c = Color(1, 1, 1, 0.5);
+ Color c = get_theme_color(SNAME("font_color"), SNAME("Editor")) * Color(1, 1, 1, 0.5);
ti->set_custom_color(1, c);
}
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index 708173ea26..9549ffb09b 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -763,7 +763,7 @@ void EditorFeatureProfileManager::_update_selected_profile() {
TreeItem *root = class_list->create_item();
TreeItem *features = class_list->create_item(root);
- TreeItem *last_feature;
+ TreeItem *last_feature = nullptr;
features->set_text(0, TTR("Main Features:"));
for (int i = 0; i < EditorFeatureProfile::FEATURE_MAX; i++) {
TreeItem *feature;
diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h
index 6d11cb10ed..2e7302aaf9 100644
--- a/editor/editor_file_dialog.h
+++ b/editor/editor_file_dialog.h
@@ -202,7 +202,6 @@ private:
void _select_drive(int p_idx);
void _dir_submitted(String p_dir);
- void _file_submitted(const String &p_file);
void _action_pressed();
void _save_confirm_pressed();
void _cancel_pressed();
@@ -240,6 +239,9 @@ protected:
static void _bind_methods();
public:
+ // Public for use with callable_mp.
+ void _file_submitted(const String &p_file);
+
void popup_file_dialog();
void clear_filters();
void add_filter(const String &p_filter, const String &p_description = "");
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 177bc6d2b2..b89bd23859 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -690,7 +690,6 @@ void EditorFileSystem::scan() {
_update_extensions();
- abort_scan = false;
if (!use_threads) {
scanning = true;
scan_total = 0;
@@ -1162,8 +1161,6 @@ void EditorFileSystem::scan_changes() {
scanning_changes = true;
scanning_changes_done = false;
- abort_scan = false;
-
if (!use_threads) {
if (filesystem) {
EditorProgressBG pr("sources", TTR("ScanSources"), 1000);
@@ -1195,8 +1192,6 @@ void EditorFileSystem::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
Thread &active_thread = thread.is_started() ? thread : thread_sources;
if (use_threads && active_thread.is_started()) {
- //abort thread if in progress
- abort_scan = true;
while (scanning) {
OS::get_singleton()->delay_usec(1000);
}
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index f4e69b95e7..e06c6e4593 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -168,7 +168,6 @@ class EditorFileSystem : public Node {
EditorFileSystemDirectory *new_filesystem = nullptr;
- bool abort_scan = false;
bool scanning = false;
bool importing = false;
bool first_scan = true;
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index fffe77f1c4..c31d13d122 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -96,6 +96,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)EditorSettings::get_singleton()->get("interface/editor/font_subpixel_positioning");
TextServer::Hinting font_hinting;
+ TextServer::Hinting font_mono_hinting;
switch (font_hinting_setting) {
case 0:
// The "Auto" setting uses the setting that best matches the OS' font rendering:
@@ -104,18 +105,23 @@ void editor_register_fonts(Ref<Theme> p_theme) {
// - Linux has configurable font hinting, but most distributions including Ubuntu default to "Light".
#ifdef MACOS_ENABLED
font_hinting = TextServer::HINTING_NONE;
+ font_mono_hinting = TextServer::HINTING_NONE;
#else
font_hinting = TextServer::HINTING_LIGHT;
+ font_mono_hinting = TextServer::HINTING_LIGHT;
#endif
break;
case 1:
font_hinting = TextServer::HINTING_NONE;
+ font_mono_hinting = TextServer::HINTING_NONE;
break;
case 2:
font_hinting = TextServer::HINTING_LIGHT;
+ font_mono_hinting = TextServer::HINTING_LIGHT;
break;
default:
font_hinting = TextServer::HINTING_NORMAL;
+ font_mono_hinting = TextServer::HINTING_LIGHT;
break;
}
@@ -163,7 +169,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
default_font_bold->set_fallbacks(fallbacks_bold);
default_font_bold_msdf->set_fallbacks(fallbacks_bold);
- Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning);
+ Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_mono_hinting, font_antialiasing, true, font_subpixel_positioning);
default_font_mono->set_fallbacks(fallbacks);
// Init base font configs and load custom fonts.
@@ -260,7 +266,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> mono_fc;
mono_fc.instantiate();
if (custom_font_path_source.length() > 0 && dir->file_exists(custom_font_path_source)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path_source, font_hinting, font_antialiasing, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path_source, font_mono_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_mono);
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index 7e7d7ca418..1b8146a0f0 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -324,11 +324,16 @@ bool EditorHelpSearch::Runner::_phase_match_classes_init() {
}
bool EditorHelpSearch::Runner::_phase_match_classes() {
+ if (!iterator_doc) {
+ return true;
+ }
+
DocData::ClassDoc &class_doc = iterator_doc->value;
if (class_doc.name.is_empty()) {
++iterator_doc;
return false;
}
+
if (!_is_class_disabled_by_feature_profile(class_doc.name)) {
ClassMatch match;
match.doc = &class_doc;
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index f001887ef9..5de205153d 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -426,6 +426,9 @@ void EditorProperty::_set_read_only(bool p_read_only) {
void EditorProperty::set_read_only(bool p_read_only) {
read_only = p_read_only;
+ if (GDVIRTUAL_CALL(_set_read_only, p_read_only)) {
+ return;
+ }
_set_read_only(p_read_only);
}
@@ -458,7 +461,7 @@ StringName EditorProperty::_get_revert_property() const {
return property;
}
-void EditorProperty::update_revert_and_pin_status() {
+void EditorProperty::update_editor_property_status() {
if (property == StringName()) {
return; //no property, so nothing to do
}
@@ -469,15 +472,26 @@ void EditorProperty::update_revert_and_pin_status() {
CRASH_COND(!node);
new_pinned = node->is_property_pinned(property);
}
+
Variant current = object->get(_get_revert_property());
bool new_can_revert = EditorPropertyRevert::can_property_revert(object, property, &current) && !is_read_only();
- if (new_can_revert != can_revert || new_pinned != pinned) {
+ bool new_checked = checked;
+ if (checkable) { // for properties like theme overrides.
+ bool valid = false;
+ Variant value = object->get(property, &valid);
+ if (valid) {
+ new_checked = value.get_type() != Variant::NIL;
+ }
+ }
+
+ if (new_can_revert != can_revert || new_pinned != pinned || new_checked != checked) {
if (new_can_revert != can_revert) {
emit_signal(SNAME("property_can_revert_changed"), property, new_can_revert);
}
can_revert = new_can_revert;
pinned = new_pinned;
+ checked = new_checked;
queue_redraw();
}
}
@@ -974,7 +988,9 @@ void EditorProperty::_bind_methods() {
ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "focusable_idx")));
GDVIRTUAL_BIND(_update_property)
- ClassDB::bind_method(D_METHOD("_update_revert_and_pin_status"), &EditorProperty::update_revert_and_pin_status);
+ GDVIRTUAL_BIND(_set_read_only, "read_only")
+
+ ClassDB::bind_method(D_METHOD("_update_editor_property_status"), &EditorProperty::update_editor_property_status);
}
EditorProperty::EditorProperty() {
@@ -1127,11 +1143,10 @@ Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) cons
}
Size2 EditorInspectorCategory::get_minimum_size() const {
- Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Tree"));
- int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Tree"));
+ Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
+ int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
Size2 ms;
- ms.width = 1;
ms.height = font->get_height(font_size);
if (icon.is_valid()) {
ms.height = MAX(icon->get_height(), ms.height);
@@ -1651,6 +1666,10 @@ void EditorInspectorArray::_panel_draw(int p_index) {
void EditorInspectorArray::_panel_gui_input(Ref<InputEvent> p_event, int p_index) {
ERR_FAIL_INDEX(p_index, (int)array_elements.size());
+ if (read_only) {
+ return;
+ }
+
Ref<InputEventKey> key_ref = p_event;
if (key_ref.is_valid()) {
const InputEventKey &key = **key_ref;
@@ -2151,7 +2170,7 @@ void EditorInspectorArray::drop_data_fw(const Point2 &p_point, const Variant &p_
}
bool EditorInspectorArray::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
- if (!movable) {
+ if (!movable || read_only) {
return false;
}
// First, update drawing.
@@ -2271,7 +2290,9 @@ VBoxContainer *EditorInspectorArray::get_vbox(int p_index) {
}
}
-EditorInspectorArray::EditorInspectorArray() {
+EditorInspectorArray::EditorInspectorArray(bool p_read_only) {
+ read_only = p_read_only;
+
set_mouse_filter(Control::MOUSE_FILTER_STOP);
odd_style.instantiate();
@@ -2297,6 +2318,7 @@ EditorInspectorArray::EditorInspectorArray() {
add_button = EditorInspector::create_inspector_action_button(TTR("Add Element"));
add_button->connect("pressed", callable_mp(this, &EditorInspectorArray::_add_button_pressed));
+ add_button->set_disabled(read_only);
vbox->add_child(add_button);
control_dropping = memnew(Control);
@@ -2317,6 +2339,7 @@ EditorInspectorArray::EditorInspectorArray() {
new_size_spin_box->set_max(16384);
new_size_spin_box->connect("value_changed", callable_mp(this, &EditorInspectorArray::_new_size_spin_box_value_changed));
new_size_spin_box->get_line_edit()->connect("text_submitted", callable_mp(this, &EditorInspectorArray::_new_size_spin_box_text_submitted));
+ new_size_spin_box->set_editable(!read_only);
resize_dialog_vbox->add_margin_child(TTRC("New Size:"), new_size_spin_box);
vbox->connect("visibility_changed", callable_mp(this, &EditorInspectorArray::_vbox_visibility_changed));
@@ -2544,7 +2567,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, EditorIn
ep->set_read_only(read_only);
ep->update_property();
ep->_update_pin_flags();
- ep->update_revert_and_pin_status();
+ ep->update_editor_property_status();
ep->set_deletable(deletable_properties);
ep->update_cache();
}
@@ -3030,7 +3053,7 @@ void EditorInspector::update_tree() {
bool movable = true;
bool numbered = false;
bool foldable = use_folding;
- String add_button_text;
+ String add_button_text = TTR("Add Element");
String swap_method;
for (int i = (p.type == Variant::NIL ? 1 : 2); i < class_name_components.size(); i++) {
if (class_name_components[i].begins_with("page_size") && class_name_components[i].get_slice_count("=") == 2) {
@@ -3051,7 +3074,7 @@ void EditorInspector::update_tree() {
if (p.type == Variant::NIL) {
// Setup the array to use a method to create/move/delete elements.
array_element_prefix = class_name_components[0];
- editor_inspector_array = memnew(EditorInspectorArray);
+ editor_inspector_array = memnew(EditorInspectorArray(all_read_only));
String array_label = path.contains("/") ? path.substr(path.rfind("/") + 1) : path;
array_label = EditorPropertyNameProcessor::get_singleton()->process_name(property_label_string, property_name_style);
@@ -3063,7 +3086,7 @@ void EditorInspector::update_tree() {
// Setup the array to use the count property and built-in functions to create/move/delete elements.
if (class_name_components.size() >= 2) {
array_element_prefix = class_name_components[1];
- editor_inspector_array = memnew(EditorInspectorArray);
+ editor_inspector_array = memnew(EditorInspectorArray(all_read_only));
int page = per_array_page.has(array_element_prefix) ? per_array_page[array_element_prefix] : 0;
editor_inspector_array->setup_with_count_property(object, class_name_components[0], p.name, array_element_prefix, page, c, foldable, movable, numbered, page_size, add_button_text, swap_method);
@@ -3203,6 +3226,7 @@ void EditorInspector::update_tree() {
// Use the existing one.
ep->set_label(property_label_string);
}
+
for (int j = 0; j < properties.size(); j++) {
String prop = properties[j];
@@ -3250,7 +3274,7 @@ void EditorInspector::update_tree() {
ep->set_doc_path(doc_info.path);
ep->update_property();
ep->_update_pin_flags();
- ep->update_revert_and_pin_status();
+ ep->update_editor_property_status();
ep->update_cache();
if (current_selected && ep->property == current_selected) {
@@ -3289,7 +3313,7 @@ void EditorInspector::update_property(const String &p_prop) {
for (EditorProperty *E : editor_property_map[p_prop]) {
E->update_property();
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
E->update_cache();
}
}
@@ -3632,7 +3656,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
if (editor_property_map.has(p_name)) {
for (EditorProperty *E : editor_property_map[p_name]) {
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
}
}
}
@@ -3746,7 +3770,7 @@ void EditorInspector::_property_checked(const String &p_path, bool p_checked) {
for (EditorProperty *E : editor_property_map[p_path]) {
E->set_checked(p_checked);
E->update_property();
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
E->update_cache();
}
}
@@ -3770,8 +3794,8 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) {
undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned);
if (editor_property_map.has(p_path)) {
for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
- undo_redo->add_do_method(E->get(), "_update_revert_and_pin_status");
- undo_redo->add_undo_method(E->get(), "_update_revert_and_pin_status");
+ undo_redo->add_do_method(E->get(), "_update_editor_property_status");
+ undo_redo->add_undo_method(E->get(), "_update_editor_property_status");
}
}
undo_redo->commit_action();
@@ -3779,7 +3803,7 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) {
node->set_property_pinned(p_path, p_pinned);
if (editor_property_map.has(p_path)) {
for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
- E->get()->update_revert_and_pin_status();
+ E->get()->update_editor_property_status();
}
}
}
@@ -3860,7 +3884,7 @@ void EditorInspector::_notification(int p_what) {
for (EditorProperty *E : F.value) {
if (E && !E->is_cache_valid()) {
E->update_property();
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
E->update_cache();
}
}
@@ -3882,7 +3906,7 @@ void EditorInspector::_notification(int p_what) {
if (editor_property_map.has(prop)) {
for (EditorProperty *E : editor_property_map[prop]) {
E->update_property();
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
E->update_cache();
}
}
@@ -3975,13 +3999,7 @@ void EditorInspector::_check_meta_name(const String &p_name) {
} else if (!p_name.is_valid_identifier()) {
error = TTR("Metadata name must be a valid identifier.");
} else if (object->has_meta(p_name)) {
- Node *node = Object::cast_to<Node>(object);
- if (node) {
- error = vformat(TTR("Metadata with name \"%s\" already exists on \"%s\"."), p_name, node->get_name());
- } else {
- // This should normally never be reached, but the error is set just in case.
- error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name, node->get_name());
- }
+ error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name);
} else if (p_name[0] == '_') {
error = TTR("Names starting with _ are reserved for editor-only metadata.");
}
@@ -4001,14 +4019,6 @@ void EditorInspector::_show_add_meta_dialog() {
if (!add_meta_dialog) {
add_meta_dialog = memnew(ConfirmationDialog);
- Node *node = Object::cast_to<Node>(object);
- if (node) {
- add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), node->get_name()));
- } else {
- // This should normally never be reached, but the title is set just in case.
- add_meta_dialog->set_title(vformat(TTR("Add Metadata Property"), node->get_name()));
- }
-
VBoxContainer *vbc = memnew(VBoxContainer);
add_meta_dialog->add_child(vbc);
HBoxContainer *hbc = memnew(HBoxContainer);
@@ -4038,6 +4048,14 @@ void EditorInspector::_show_add_meta_dialog() {
add_meta_name->connect("text_changed", callable_mp(this, &EditorInspector::_check_meta_name));
}
+ Node *node = Object::cast_to<Node>(object);
+ if (node) {
+ add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), node->get_name()));
+ } else {
+ // This should normally be reached when the object is derived from Resource.
+ add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), object->get_class()));
+ }
+
add_meta_dialog->popup_centered();
add_meta_name->set_text("");
_check_meta_name("");
@@ -4046,6 +4064,7 @@ void EditorInspector::_show_add_meta_dialog() {
void EditorInspector::_bind_methods() {
ClassDB::bind_method("_edit_request_change", &EditorInspector::_edit_request_change);
+ ClassDB::bind_method("get_selected_path", &EditorInspector::get_selected_path);
ADD_SIGNAL(MethodInfo("property_selected", PropertyInfo(Variant::STRING, "property")));
ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::BOOL, "advance")));
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index d634eae23f..872007e637 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -120,6 +120,8 @@ private:
HashMap<StringName, Variant> cache;
GDVIRTUAL0(_update_property)
+ GDVIRTUAL1(_set_read_only, bool)
+
void _update_pin_flags();
protected:
@@ -151,7 +153,7 @@ public:
void set_doc_path(const String &p_doc_path);
virtual void update_property();
- void update_revert_and_pin_status();
+ void update_editor_property_status();
virtual bool use_keying_next() const;
@@ -333,6 +335,7 @@ class EditorInspectorArray : public EditorInspectorSection {
int begin_array_index = 0;
int end_array_index = 0;
+ bool read_only = false;
bool movable = true;
bool numbered = false;
@@ -404,7 +407,7 @@ public:
void setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = "");
VBoxContainer *get_vbox(int p_index);
- EditorInspectorArray();
+ EditorInspectorArray(bool p_read_only);
};
class EditorPaginator : public HBoxContainer {
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 804722299c..28768b7f34 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -429,7 +429,7 @@ void EditorNode::_version_control_menu_option(int p_idx) {
void EditorNode::_update_title() {
const String appname = ProjectSettings::get_singleton()->get("application/config/name");
- String title = (appname.is_empty() ? TTR("Unnamed Project") : appname) + String(" - ") + VERSION_NAME;
+ String title = (appname.is_empty() ? TTR("Unnamed Project") : appname);
const String edited = editor_data.get_edited_scene_root() ? editor_data.get_edited_scene_root()->get_scene_file_path() : String();
if (!edited.is_empty()) {
// Display the edited scene name before the program name so that it can be seen in the OS task bar.
@@ -439,8 +439,10 @@ void EditorNode::_update_title() {
// Display the "modified" mark before anything else so that it can always be seen in the OS task bar.
title = vformat("(*) %s", title);
}
-
- DisplayServer::get_singleton()->window_set_title(title);
+ DisplayServer::get_singleton()->window_set_title(title + String(" - ") + VERSION_NAME);
+ if (project_title) {
+ project_title->set_text(title);
+ }
}
void EditorNode::shortcut_input(const Ref<InputEvent> &p_event) {
@@ -465,15 +467,15 @@ void EditorNode::shortcut_input(const Ref<InputEvent> &p_event) {
}
if (ED_IS_SHORTCUT("editor/editor_2d", p_event)) {
- _editor_select(EDITOR_2D);
+ editor_select(EDITOR_2D);
} else if (ED_IS_SHORTCUT("editor/editor_3d", p_event)) {
- _editor_select(EDITOR_3D);
+ editor_select(EDITOR_3D);
} else if (ED_IS_SHORTCUT("editor/editor_script", p_event)) {
- _editor_select(EDITOR_SCRIPT);
+ editor_select(EDITOR_SCRIPT);
} else if (ED_IS_SHORTCUT("editor/editor_help", p_event)) {
emit_signal(SNAME("request_help_search"), "");
} else if (ED_IS_SHORTCUT("editor/editor_assetlib", p_event) && AssetLibraryEditorPlugin::is_available()) {
- _editor_select(EDITOR_ASSETLIB);
+ editor_select(EDITOR_ASSETLIB);
} else if (ED_IS_SHORTCUT("editor/editor_next", p_event)) {
_editor_select_next();
} else if (ED_IS_SHORTCUT("editor/editor_prev", p_event)) {
@@ -584,7 +586,7 @@ void EditorNode::_update_from_settings() {
void EditorNode::_select_default_main_screen_plugin() {
if (EDITOR_3D < main_editor_buttons.size() && main_editor_buttons[EDITOR_3D]->is_visible()) {
// If the 3D editor is enabled, use this as the default.
- _editor_select(EDITOR_3D);
+ editor_select(EDITOR_3D);
return;
}
@@ -593,12 +595,12 @@ void EditorNode::_select_default_main_screen_plugin() {
for (int i = 0; i < main_editor_buttons.size(); i++) {
Button *editor_button = main_editor_buttons[i];
if (editor_button->is_visible()) {
- _editor_select(i);
+ editor_select(i);
return;
}
}
- _editor_select(-1);
+ editor_select(-1);
}
void EditorNode::_notification(int p_what) {
@@ -659,6 +661,12 @@ void EditorNode::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
Engine::get_singleton()->set_editor_hint(true);
+ Window *window = static_cast<Window *>(get_tree()->get_root());
+ if (window) {
+ // Handle macOS fullscreen and extend-to-title changes.
+ window->connect("titlebar_changed", callable_mp(this, &EditorNode::_titlebar_resized));
+ }
+
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec")));
get_tree()->get_root()->set_as_audio_listener_3d(false);
get_tree()->get_root()->set_as_audio_listener_2d(false);
@@ -713,6 +721,8 @@ void EditorNode::_notification(int p_what) {
ProjectSettings::get_singleton()->save();
}
+ _titlebar_resized();
+
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
@@ -750,7 +760,8 @@ void EditorNode::_notification(int p_what) {
EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/theme") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/font") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/main_font") ||
- EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/code_font");
+ EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/code_font") ||
+ EditorSettings::get_singleton()->check_changed_settings_in_group("filesystem/file_dialog/thumbnail_size");
if (theme_changed) {
theme = create_custom_theme(theme_base->get_theme());
@@ -1169,6 +1180,18 @@ void EditorNode::_reload_project_settings() {
void EditorNode::_vp_resized() {
}
+void EditorNode::_titlebar_resized() {
+ const Size2 &margin = DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID);
+ if (left_menu_spacer) {
+ int w = (gui_base->is_layout_rtl()) ? margin.y : margin.x;
+ left_menu_spacer->set_custom_minimum_size(Size2(w, 0));
+ }
+ if (right_menu_spacer) {
+ int w = (gui_base->is_layout_rtl()) ? margin.x : margin.y;
+ right_menu_spacer->set_custom_minimum_size(Size2(w, 0));
+ }
+}
+
void EditorNode::_version_button_pressed() {
DisplayServer::get_singleton()->clipboard_set(version_btn->get_meta(META_TEXT_TO_COPY));
}
@@ -1190,7 +1213,7 @@ void EditorNode::_editor_select_next() {
}
} while (!main_editor_buttons[editor]->is_visible());
- _editor_select(editor);
+ editor_select(editor);
}
void EditorNode::_open_command_palette() {
@@ -1208,7 +1231,7 @@ void EditorNode::_editor_select_prev() {
}
} while (!main_editor_buttons[editor]->is_visible());
- _editor_select(editor);
+ editor_select(editor);
}
Error EditorNode::load_resource(const String &p_resource, bool p_ignore_broken_deps) {
@@ -2390,7 +2413,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
else if (main_plugin != editor_plugin_screen && (!ScriptEditor::get_singleton() || !ScriptEditor::get_singleton()->is_visible_in_tree() || ScriptEditor::get_singleton()->can_take_away_focus())) {
// Update screen main_plugin.
- _editor_select(plugin_index);
+ editor_select(plugin_index);
main_plugin->edit(current_obj);
} else {
editor_plugin_screen->edit(current_obj);
@@ -2450,7 +2473,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
write_movie_file = GLOBAL_GET("editor/movie_writer/movie_file");
}
if (write_movie_file == String()) {
- show_accept(TTR("Movie Maker mode is enabled, but no movie file path has been specified.\nA default movie file path can be specified in the project settings under the 'Editor/Movie Writer' category.\nAlternatively, for running single scenes, a 'movie_path' metadata can be added to the root node,\nspecifying the path to a movie file that will be used when recording that scene."), TTR("OK"));
+ show_accept(TTR("Movie Maker mode is enabled, but no movie file path has been specified.\nA default movie file path can be specified in the project settings under the Editor > Movie Writer category.\nAlternatively, for running single scenes, a `movie_file` string metadata can be added to the root node,\nspecifying the path to a movie file that will be used when recording that scene."), TTR("OK"));
return;
}
}
@@ -2763,18 +2786,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
} else if (extensions.size()) {
String root_name = scene->get_name();
- // Very similar to node naming logic.
- switch (ProjectSettings::get_singleton()->get("editor/scene/scene_naming").operator int()) {
- case SCENE_NAME_CASING_AUTO:
- // Use casing of the root node.
- break;
- case SCENE_NAME_CASING_PASCAL_CASE: {
- root_name = root_name.to_pascal_case();
- } break;
- case SCENE_NAME_CASING_SNAKE_CASE:
- root_name = root_name.replace("-", "_").to_snake_case();
- break;
- }
+ root_name = EditorNode::adjust_scene_name_casing(root_name);
file->set_current_path(root_name + "." + extensions.front()->get().to_lower());
}
file->popup_file_dialog();
@@ -3080,8 +3092,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case HELP_SUPPORT_GODOT_DEVELOPMENT: {
OS::get_singleton()->shell_open("https://godotengine.org/donate");
} break;
- case SET_RENDERING_DRIVER_SAVE_AND_RESTART: {
- ProjectSettings::get_singleton()->set("rendering/driver/driver_name", rendering_driver_request);
+ case SET_RENDERER_NAME_SAVE_AND_RESTART: {
+ ProjectSettings::get_singleton()->set("rendering/renderer/rendering_method", renderer_request);
ProjectSettings::get_singleton()->save();
save_all_scenes();
@@ -3090,6 +3102,19 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
}
+String EditorNode::adjust_scene_name_casing(const String &root_name) {
+ switch (ProjectSettings::get_singleton()->get("editor/scene/scene_naming").operator int()) {
+ case SCENE_NAME_CASING_AUTO:
+ // Use casing of the root node.
+ break;
+ case SCENE_NAME_CASING_PASCAL_CASE:
+ return root_name.to_pascal_case();
+ case SCENE_NAME_CASING_SNAKE_CASE:
+ return root_name.replace("-", "_").to_snake_case();
+ }
+ return root_name;
+}
+
void EditorNode::_request_screenshot() {
_screenshot();
}
@@ -3303,7 +3328,7 @@ VBoxContainer *EditorNode::get_main_screen_control() {
return main_screen_vbox;
}
-void EditorNode::_editor_select(int p_which) {
+void EditorNode::editor_select(int p_which) {
static bool selecting = false;
if (selecting || changing_scene) {
return;
@@ -3357,7 +3382,7 @@ void EditorNode::select_editor_by_name(const String &p_name) {
for (int i = 0; i < main_editor_buttons.size(); i++) {
if (main_editor_buttons[i]->get_text() == p_name) {
- _editor_select(i);
+ editor_select(i);
return;
}
}
@@ -3370,7 +3395,7 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed
Button *tb = memnew(Button);
tb->set_flat(true);
tb->set_toggle_mode(true);
- tb->connect("pressed", callable_mp(singleton, &EditorNode::_editor_select).bind(singleton->main_editor_buttons.size()));
+ tb->connect("pressed", callable_mp(singleton, &EditorNode::editor_select).bind(singleton->main_editor_buttons.size()));
tb->set_name(p_editor->get_name());
tb->set_text(p_editor->get_name());
@@ -3387,7 +3412,7 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed
tb->add_theme_font_size_override("font_size", singleton->gui_base->get_theme_font_size(SNAME("main_button_font_size"), SNAME("EditorFonts")));
singleton->main_editor_buttons.push_back(tb);
- singleton->main_editor_button_vb->add_child(tb);
+ singleton->main_editor_button_hb->add_child(tb);
singleton->editor_table.push_back(p_editor);
singleton->distraction_free->move_to_front();
@@ -3404,7 +3429,7 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_chan
for (int i = 0; i < singleton->main_editor_buttons.size(); i++) {
if (p_editor->get_name() == singleton->main_editor_buttons[i]->get_text()) {
if (singleton->main_editor_buttons[i]->is_pressed()) {
- singleton->_editor_select(EDITOR_SCRIPT);
+ singleton->editor_select(EDITOR_SCRIPT);
}
memdelete(singleton->main_editor_buttons[i]);
@@ -3628,7 +3653,7 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
int index = p_state["editor_index"];
if (current < 2) { // If currently in spatial/2d, only switch to spatial/2d. If currently in script, stay there.
if (index < 2 || !get_edited_scene()) {
- _editor_select(index);
+ editor_select(index);
}
}
}
@@ -3639,9 +3664,9 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
int n2d = 0, n3d = 0;
_find_node_types(get_edited_scene(), n2d, n3d);
if (n2d > n3d) {
- _editor_select(EDITOR_2D);
+ editor_select(EDITOR_2D);
} else if (n3d > n2d) {
- _editor_select(EDITOR_3D);
+ editor_select(EDITOR_3D);
}
}
}
@@ -3668,10 +3693,6 @@ bool EditorNode::is_changing_scene() const {
return changing_scene;
}
-void EditorNode::_clear_undo_history() {
- get_undo_redo()->clear_history(false);
-}
-
void EditorNode::set_current_scene(int p_idx) {
// Save the folding in case the scene gets reloaded.
if (editor_data.get_scene_path(p_idx) != "" && editor_data.get_edited_scene_root(p_idx)) {
@@ -3932,7 +3953,7 @@ void EditorNode::edit_foreign_resource(Ref<Resource> p_resource) {
InspectorDock::get_singleton()->call_deferred("edit_resource", p_resource);
}
-bool EditorNode::is_resource_read_only(Ref<Resource> p_resource) {
+bool EditorNode::is_resource_read_only(Ref<Resource> p_resource, bool p_foreign_resources_are_writable) {
ERR_FAIL_COND_V(p_resource.is_null(), false);
String path = p_resource->get_path();
@@ -3944,7 +3965,11 @@ bool EditorNode::is_resource_read_only(Ref<Resource> p_resource) {
// If the base resource is a packed scene, we treat it as read-only if it is not the currently edited scene.
if (ResourceLoader::get_resource_type(base) == "PackedScene") {
if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
- return true;
+ // If we have not flagged foreign resources as writable or the base scene the resource is
+ // part was imported, it can be considered read-only.
+ if (!p_foreign_resources_are_writable || FileAccess::exists(base + ".import")) {
+ return true;
+ }
}
} else {
// If a corresponding .import file exists for the base file, we assume it to be imported and should therefore treated as read-only.
@@ -5878,27 +5903,27 @@ void EditorNode::_bottom_panel_raise_toggled(bool p_pressed) {
top_split->set_visible(!p_pressed);
}
-void EditorNode::_update_rendering_driver_color() {
- if (rendering_driver->get_text() == "opengl3") {
- rendering_driver->add_theme_color_override("font_color", Color::hex(0x5586a4ff));
- } else if (rendering_driver->get_text() == "vulkan") {
- rendering_driver->add_theme_color_override("font_color", theme_base->get_theme_color(SNAME("vulkan_color"), SNAME("Editor")));
+void EditorNode::_update_renderer_color() {
+ if (renderer->get_text() == "gl_compatibility") {
+ renderer->add_theme_color_override("font_color", Color::hex(0x5586a4ff));
+ } else if (renderer->get_text() == "forward_plus" || renderer->get_text() == "mobile") {
+ renderer->add_theme_color_override("font_color", theme_base->get_theme_color(SNAME("vulkan_color"), SNAME("Editor")));
}
}
-void EditorNode::_rendering_driver_selected(int p_which) {
- String driver = rendering_driver->get_item_metadata(p_which);
+void EditorNode::_renderer_selected(int p_which) {
+ String rendering_method = renderer->get_item_metadata(p_which);
- String current_driver = OS::get_singleton()->get_current_rendering_driver_name();
+ String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method");
- if (driver == current_driver) {
+ if (rendering_method == current_renderer) {
return;
}
- rendering_driver_request = driver;
+ renderer_request = rendering_method;
video_restart_dialog->popup_centered();
- rendering_driver->select(rendering_driver_current);
- _update_rendering_driver_color();
+ renderer->select(renderer_current);
+ _update_renderer_color();
}
void EditorNode::_resource_saved(Ref<Resource> p_resource, const String &p_path) {
@@ -5933,7 +5958,7 @@ void EditorNode::_feature_profile_changed() {
if ((profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D) && singleton->main_editor_buttons[EDITOR_3D]->is_pressed()) ||
(profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT) && singleton->main_editor_buttons[EDITOR_SCRIPT]->is_pressed()) ||
(AssetLibraryEditorPlugin::is_available() && profile->is_feature_disabled(EditorFeatureProfile::FEATURE_ASSET_LIB) && singleton->main_editor_buttons[EDITOR_ASSETLIB]->is_pressed())) {
- _editor_select(EDITOR_2D);
+ editor_select(EDITOR_2D);
}
} else {
import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), false);
@@ -5956,19 +5981,14 @@ void EditorNode::_bind_methods() {
GLOBAL_DEF("editor/scene/scene_naming", SCENE_NAME_CASING_SNAKE_CASE);
ProjectSettings::get_singleton()->set_custom_property_info("editor/scene/scene_naming", PropertyInfo(Variant::INT, "editor/scene/scene_naming", PROPERTY_HINT_ENUM, "Auto,PascalCase,snake_case"));
ClassDB::bind_method("edit_current", &EditorNode::edit_current);
- ClassDB::bind_method("_editor_select", &EditorNode::_editor_select);
- ClassDB::bind_method("_node_renamed", &EditorNode::_node_renamed);
ClassDB::bind_method("edit_node", &EditorNode::edit_node);
ClassDB::bind_method(D_METHOD("push_item", "object", "property", "inspector_only"), &EditorNode::push_item, DEFVAL(""), DEFVAL(false));
- ClassDB::bind_method("_get_scene_metadata", &EditorNode::_get_scene_metadata);
ClassDB::bind_method("set_edited_scene", &EditorNode::set_edited_scene);
ClassDB::bind_method("open_request", &EditorNode::open_request);
ClassDB::bind_method("edit_foreign_resource", &EditorNode::edit_foreign_resource);
ClassDB::bind_method("is_resource_read_only", &EditorNode::is_resource_read_only);
- ClassDB::bind_method("_close_messages", &EditorNode::_close_messages);
- ClassDB::bind_method("_show_messages", &EditorNode::_show_messages);
ClassDB::bind_method("stop_child_process", &EditorNode::stop_child_process);
@@ -5977,19 +5997,10 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state);
ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes);
- ClassDB::bind_method("_clear_undo_history", &EditorNode::_clear_undo_history);
-
ClassDB::bind_method("edit_item_resource", &EditorNode::edit_item_resource);
ClassDB::bind_method(D_METHOD("get_gui_base"), &EditorNode::get_gui_base);
- ClassDB::bind_method(D_METHOD("_on_plugin_ready"), &EditorNode::_on_plugin_ready); // Still used by some connect_compat.
-
- ClassDB::bind_method("_screenshot", &EditorNode::_screenshot);
- ClassDB::bind_method("_save_screenshot", &EditorNode::_save_screenshot);
-
- ClassDB::bind_method("_version_button_pressed", &EditorNode::_version_button_pressed);
-
ADD_SIGNAL(MethodInfo("play_pressed"));
ADD_SIGNAL(MethodInfo("pause_pressed"));
ADD_SIGNAL(MethodInfo("stop_pressed"));
@@ -6601,14 +6612,14 @@ EditorNode::EditorNode() {
if (can_expand) {
// Add spacer to avoid other controls under window minimize/maximize/close buttons (left side).
- Control *menu_spacer = memnew(Control);
- menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
- menu_spacer->set_custom_minimum_size(Size2(DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID).x, 0));
- menu_hb->add_child(menu_spacer);
+ left_menu_spacer = memnew(Control);
+ left_menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_hb->add_child(left_menu_spacer);
}
main_menu = memnew(MenuBar);
menu_hb->add_child(main_menu);
+
main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
main_menu->set_flat(true);
main_menu->set_start_index(0); // Main menu, add to the start of global menu.
@@ -6777,22 +6788,30 @@ EditorNode::EditorNode() {
project_menu->add_shortcut(ED_GET_SHORTCUT("editor/quit_to_project_list"), RUN_PROJECT_MANAGER, true);
// Spacer to center 2D / 3D / Script buttons.
- Control *left_spacer = memnew(Control);
+ HBoxContainer *left_spacer = memnew(HBoxContainer);
left_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ left_spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
menu_hb->add_child(left_spacer);
- menu_hb->add_spacer();
+ if (can_expand && global_menu) {
+ project_title = memnew(Label);
+ project_title->add_theme_font_override("font", gui_base->get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
+ project_title->add_theme_font_size_override("font_size", gui_base->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")));
+ project_title->set_focus_mode(Control::FOCUS_NONE);
+ project_title->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
+ project_title->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
+ project_title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ left_spacer->add_child(project_title);
+ }
- main_editor_button_vb = memnew(HBoxContainer);
- menu_hb->add_child(main_editor_button_vb);
+ main_editor_button_hb = memnew(HBoxContainer);
+ menu_hb->add_child(main_editor_button_hb);
// Options are added and handled by DebuggerEditorPlugin.
debug_menu = memnew(PopupMenu);
debug_menu->set_name(TTR("Debug"));
main_menu->add_child(debug_menu);
- menu_hb->add_spacer();
-
settings_menu = memnew(PopupMenu);
settings_menu->set_name(TTR("Editor"));
main_menu->add_child(settings_menu);
@@ -6866,6 +6885,7 @@ EditorNode::EditorNode() {
// Spacer to center 2D / 3D / Script buttons.
Control *right_spacer = memnew(Control);
right_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ right_spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
menu_hb->add_child(right_spacer);
launch_pad = memnew(PanelContainer);
@@ -6881,23 +6901,24 @@ EditorNode::EditorNode() {
play_button->set_toggle_mode(true);
play_button->set_focus_mode(Control::FOCUS_NONE);
play_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY));
+ play_button->set_tooltip_text(TTR("Run the project's default scene."));
- ED_SHORTCUT_AND_COMMAND("editor/play", TTR("Play"), Key::F5);
- ED_SHORTCUT_OVERRIDE("editor/play", "macos", KeyModifierMask::META | Key::B);
- play_button->set_shortcut(ED_GET_SHORTCUT("editor/play"));
+ ED_SHORTCUT_AND_COMMAND("editor/run_project", TTR("Run Project"), Key::F5);
+ ED_SHORTCUT_OVERRIDE("editor/run_project", "macos", KeyModifierMask::META | Key::B);
+ play_button->set_shortcut(ED_GET_SHORTCUT("editor/run_project"));
pause_button = memnew(Button);
pause_button->set_flat(true);
pause_button->set_toggle_mode(true);
pause_button->set_icon(gui_base->get_theme_icon(SNAME("Pause"), SNAME("EditorIcons")));
pause_button->set_focus_mode(Control::FOCUS_NONE);
- pause_button->set_tooltip_text(TTR("Pause the scene execution for debugging."));
+ pause_button->set_tooltip_text(TTR("Pause the running project's execution for debugging."));
pause_button->set_disabled(true);
launch_pad_hb->add_child(pause_button);
- ED_SHORTCUT("editor/pause_scene", TTR("Pause Scene"), Key::F7);
- ED_SHORTCUT_OVERRIDE("editor/pause_scene", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::Y);
- pause_button->set_shortcut(ED_GET_SHORTCUT("editor/pause_scene"));
+ ED_SHORTCUT("editor/pause_running_project", TTR("Pause Running Project"), Key::F7);
+ ED_SHORTCUT_OVERRIDE("editor/pause_running_project", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::Y);
+ pause_button->set_shortcut(ED_GET_SHORTCUT("editor/pause_running_project"));
stop_button = memnew(Button);
stop_button->set_flat(true);
@@ -6905,12 +6926,12 @@ EditorNode::EditorNode() {
stop_button->set_focus_mode(Control::FOCUS_NONE);
stop_button->set_icon(gui_base->get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
stop_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_STOP));
- stop_button->set_tooltip_text(TTR("Stop the scene."));
+ stop_button->set_tooltip_text(TTR("Stop the currently running project."));
stop_button->set_disabled(true);
- ED_SHORTCUT("editor/stop", TTR("Stop"), Key::F8);
- ED_SHORTCUT_OVERRIDE("editor/stop", "macos", KeyModifierMask::META | Key::PERIOD);
- stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop"));
+ ED_SHORTCUT("editor/stop_running_project", TTR("Stop Running Project"), Key::F8);
+ ED_SHORTCUT_OVERRIDE("editor/stop_running_project", "macos", KeyModifierMask::META | Key::PERIOD);
+ stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop_running_project"));
run_native = memnew(EditorRunNative);
launch_pad_hb->add_child(run_native);
@@ -6922,10 +6943,11 @@ EditorNode::EditorNode() {
play_scene_button->set_toggle_mode(true);
play_scene_button->set_focus_mode(Control::FOCUS_NONE);
play_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_SCENE));
+ play_scene_button->set_tooltip_text(TTR("Run the currently edited scene."));
- ED_SHORTCUT_AND_COMMAND("editor/play_scene", TTR("Play Scene"), Key::F6);
- ED_SHORTCUT_OVERRIDE("editor/play_scene", "macos", KeyModifierMask::META | Key::R);
- play_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_scene"));
+ ED_SHORTCUT_AND_COMMAND("editor/run_current_scene", TTR("Run Current Scene"), Key::F6);
+ ED_SHORTCUT_OVERRIDE("editor/run_current_scene", "macos", KeyModifierMask::META | Key::R);
+ play_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_current_scene"));
play_custom_scene_button = memnew(Button);
play_custom_scene_button->set_flat(true);
@@ -6933,12 +6955,11 @@ EditorNode::EditorNode() {
play_custom_scene_button->set_toggle_mode(true);
play_custom_scene_button->set_focus_mode(Control::FOCUS_NONE);
play_custom_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_CUSTOM_SCENE));
+ play_custom_scene_button->set_tooltip_text(TTR("Run a specific scene."));
- _reset_play_buttons();
-
- ED_SHORTCUT_AND_COMMAND("editor/play_custom_scene", TTR("Play Custom Scene"), KeyModifierMask::CTRL | KeyModifierMask::SHIFT | Key::F5);
- ED_SHORTCUT_OVERRIDE("editor/play_custom_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R);
- play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_custom_scene"));
+ ED_SHORTCUT_AND_COMMAND("editor/run_specific_scene", TTR("Run Specific Scene"), KeyModifierMask::META | KeyModifierMask::SHIFT | Key::F5);
+ ED_SHORTCUT_OVERRIDE("editor/run_specific_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R);
+ play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_specific_scene"));
write_movie_panel = memnew(PanelContainer);
write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles")));
@@ -6962,58 +6983,54 @@ EditorNode::EditorNode() {
HBoxContainer *right_menu_hb = memnew(HBoxContainer);
menu_hb->add_child(right_menu_hb);
- rendering_driver = memnew(OptionButton);
-
+ renderer = memnew(OptionButton);
// Hide the renderer selection dropdown until OpenGL support is more mature.
// The renderer can still be changed in the project settings or using `--rendering-driver opengl3`.
- rendering_driver->set_visible(false);
-
- rendering_driver->set_flat(true);
- rendering_driver->set_focus_mode(Control::FOCUS_NONE);
- rendering_driver->connect("item_selected", callable_mp(this, &EditorNode::_rendering_driver_selected));
- rendering_driver->add_theme_font_override("font", gui_base->get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
- rendering_driver->add_theme_font_size_override("font_size", gui_base->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")));
+ renderer->set_visible(false);
+ renderer->set_flat(true);
+ renderer->set_focus_mode(Control::FOCUS_NONE);
+ renderer->connect("item_selected", callable_mp(this, &EditorNode::_renderer_selected));
+ renderer->add_theme_font_override("font", gui_base->get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
+ renderer->add_theme_font_size_override("font_size", gui_base->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")));
- right_menu_hb->add_child(rendering_driver);
+ right_menu_hb->add_child(renderer);
if (can_expand) {
// Add spacer to avoid other controls under the window minimize/maximize/close buttons (right side).
- Control *menu_spacer = memnew(Control);
- menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
- menu_spacer->set_custom_minimum_size(Size2(DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID).y, 0));
- menu_hb->add_child(menu_spacer);
+ right_menu_spacer = memnew(Control);
+ right_menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_hb->add_child(right_menu_spacer);
}
- // Only display the render drivers that are available for this display driver.
- int display_driver_idx = OS::get_singleton()->get_display_driver_id();
- Vector<String> render_drivers = DisplayServer::get_create_function_rendering_drivers(display_driver_idx);
- String current_rendering_driver = OS::get_singleton()->get_current_rendering_driver_name();
+ String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method");
+
+ PackedStringArray renderers = ProjectSettings::get_singleton()->get_custom_property_info().get(StringName("rendering/renderer/rendering_method")).hint_string.split(",", false);
// As we are doing string comparisons, keep in standard case to prevent problems with capitals
// "vulkan" in particular uses lowercase "v" in the code, and uppercase in the UI.
- current_rendering_driver = current_rendering_driver.to_lower();
+ current_renderer = current_renderer.to_lower();
- for (int i = 0; i < render_drivers.size(); i++) {
- String driver = render_drivers[i];
+ for (int i = 0; i < renderers.size(); i++) {
+ String rendering_method = renderers[i];
- // Add the driver to the UI.
- rendering_driver->add_item(driver);
- rendering_driver->set_item_metadata(i, driver);
+ // Add the renderers name to the UI.
+ renderer->add_item(rendering_method);
+ renderer->set_item_metadata(i, rendering_method);
// Lowercase for standard comparison.
- driver = driver.to_lower();
+ rendering_method = rendering_method.to_lower();
- if (current_rendering_driver == driver) {
- rendering_driver->select(i);
- rendering_driver_current = i;
+ if (current_renderer == rendering_method) {
+ renderer->select(i);
+ renderer_current = i;
}
}
- _update_rendering_driver_color();
+ _update_renderer_color();
video_restart_dialog = memnew(ConfirmationDialog);
- video_restart_dialog->set_text(TTR("Changing the video driver requires restarting the editor."));
+ video_restart_dialog->set_text(TTR("Changing the renderer requires restarting the editor."));
video_restart_dialog->set_ok_button_text(TTR("Save & Restart"));
- video_restart_dialog->connect("confirmed", callable_mp(this, &EditorNode::_menu_option).bind(SET_RENDERING_DRIVER_SAVE_AND_RESTART));
+ video_restart_dialog->connect("confirmed", callable_mp(this, &EditorNode::_menu_option).bind(SET_RENDERER_NAME_SAVE_AND_RESTART));
gui_base->add_child(video_restart_dialog);
progress_hb = memnew(BackgroundProgress);
@@ -7537,12 +7554,13 @@ EditorNode::EditorNode() {
screenshot_timer->set_owner(get_owner());
// Adjust spacers to center 2D / 3D / Script buttons.
- int max_w = MAX(launch_pad_hb->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x);
+ int max_w = MAX(launch_pad->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x);
left_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - main_menu->get_minimum_size().x), 0));
- right_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - launch_pad_hb->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0));
+ right_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - launch_pad->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0));
// Extend menu bar to window title.
if (can_expand) {
+ DisplayServer::get_singleton()->window_set_window_buttons_offset(Vector2i(menu_hb->get_minimum_size().y / 2, menu_hb->get_minimum_size().y / 2), DisplayServer::MAIN_WINDOW_ID);
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE, true, DisplayServer::MAIN_WINDOW_ID);
menu_hb->set_can_move_window(true);
}
diff --git a/editor/editor_node.h b/editor/editor_node.h
index df3d2ae0f8..fab280bc14 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -125,6 +125,12 @@ public:
EDITOR_ASSETLIB
};
+ enum SceneNameCasing {
+ SCENE_NAME_CASING_AUTO,
+ SCENE_NAME_CASING_PASCAL_CASE,
+ SCENE_NAME_CASING_SNAKE_CASE
+ };
+
struct ExecuteThreadArgs {
String path;
List<String> args;
@@ -218,7 +224,7 @@ private:
HELP_ABOUT,
HELP_SUPPORT_GODOT_DEVELOPMENT,
- SET_RENDERING_DRIVER_SAVE_AND_RESTART,
+ SET_RENDERER_NAME_SAVE_AND_RESTART,
GLOBAL_NEW_WINDOW,
GLOBAL_SCENE,
@@ -233,12 +239,6 @@ private:
MAX_BUILD_CALLBACKS = 128
};
- enum ScriptNameCasing {
- SCENE_NAME_CASING_AUTO,
- SCENE_NAME_CASING_PASCAL_CASE,
- SCENE_NAME_CASING_SNAKE_CASE
- };
-
struct BottomPanelItem {
String name;
Control *control = nullptr;
@@ -286,12 +286,12 @@ private:
Control *theme_base = nullptr;
Control *gui_base = nullptr;
VBoxContainer *main_vbox = nullptr;
- OptionButton *rendering_driver = nullptr;
+ OptionButton *renderer = nullptr;
ConfirmationDialog *video_restart_dialog = nullptr;
- int rendering_driver_current = 0;
- String rendering_driver_request;
+ int renderer_current = 0;
+ String renderer_request;
// Split containers.
HSplitContainer *left_l_hsplit = nullptr;
@@ -322,6 +322,9 @@ private:
HBoxContainer *bottom_hb = nullptr;
Control *vp_base = nullptr;
+ Label *project_title = nullptr;
+ Control *left_menu_spacer = nullptr;
+ Control *right_menu_spacer = nullptr;
EditorTitleBar *menu_hb = nullptr;
VBoxContainer *main_screen_vbox = nullptr;
MenuBar *main_menu = nullptr;
@@ -397,7 +400,7 @@ private:
String current_path;
MenuButton *update_spinner = nullptr;
- HBoxContainer *main_editor_button_vb = nullptr;
+ HBoxContainer *main_editor_button_hb = nullptr;
Vector<Button *> main_editor_buttons;
Vector<EditorPlugin *> editor_table;
@@ -543,7 +546,6 @@ private:
void _update_file_menu_opened();
void _update_file_menu_closed();
- void _on_plugin_ready(Object *p_script, const String &p_activate_name);
void _remove_plugin_from_enabled(const String &p_name);
void _fs_changed();
@@ -553,7 +555,6 @@ private:
void _node_renamed();
void _editor_select_next();
void _editor_select_prev();
- void _editor_select(int p_which);
void _set_scene_metadata(const String &p_file, int p_idx = -1);
void _get_scene_metadata(const String &p_file);
void _update_title();
@@ -562,6 +563,7 @@ private:
void _close_messages();
void _show_messages();
void _vp_resized();
+ void _titlebar_resized();
void _version_button_pressed();
int _save_external_resources();
@@ -599,8 +601,8 @@ private:
void _update_from_settings();
- void _rendering_driver_selected(int);
- void _update_rendering_driver_color();
+ void _renderer_selected(int);
+ void _update_renderer_color();
void _exit_editor(int p_exit_code);
@@ -658,8 +660,6 @@ private:
void _update_layouts_menu();
void _layout_menu_option(int p_id);
- void _clear_undo_history();
-
void _update_addon_config();
void _toggle_distraction_free_mode();
@@ -703,7 +703,11 @@ protected:
void set_current_tab(int p_tab);
public:
- void set_visible_editor(EditorTable p_table) { _editor_select(p_table); }
+ // Public for use with callable_mp.
+ void _on_plugin_ready(Object *p_script, const String &p_activate_name);
+
+ void editor_select(int p_which);
+ void set_visible_editor(EditorTable p_table) { editor_select(p_table); }
bool call_build();
@@ -720,6 +724,8 @@ public:
static HBoxContainer *get_menu_hb() { return singleton->menu_hb; }
static VSplitContainer *get_top_split() { return singleton->top_split; }
+ static String adjust_scene_name_casing(const String &root_name);
+
static bool has_unsaved_changes() { return singleton->unsaved_cache; }
static void disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames);
static void add_io_error(const String &p_error);
@@ -784,7 +790,7 @@ public:
void open_request(const String &p_path);
void edit_foreign_resource(Ref<Resource> p_resource);
- bool is_resource_read_only(Ref<Resource> p_resource);
+ bool is_resource_read_only(Ref<Resource> p_resource, bool p_foreign_resources_are_writable = false);
bool is_changing_scene() const;
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index a8df486381..bd19df41fe 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -46,7 +46,7 @@ void EditorPluginSettings::_notification(int p_what) {
} break;
case Node::NOTIFICATION_READY: {
- plugin_config_dialog->connect("plugin_ready", Callable(EditorNode::get_singleton(), "_on_plugin_ready"));
+ plugin_config_dialog->connect("plugin_ready", callable_mp(EditorNode::get_singleton(), &EditorNode::_on_plugin_ready));
plugin_list->connect("button_clicked", callable_mp(this, &EditorPluginSettings::_cell_button_pressed));
} break;
}
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 7364258a07..3b99962435 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -1758,7 +1758,7 @@ void EditorPropertyVector2::_value_changed(double val, const String &p_name) {
Vector2 v2;
v2.x = spin[0]->get_value();
v2.y = spin[1]->get_value();
- emit_changed(get_edited_property(), v2, p_name);
+ emit_changed(get_edited_property(), v2, linked->is_pressed() ? "" : p_name);
}
void EditorPropertyVector2::update_property() {
@@ -2005,7 +2005,7 @@ void EditorPropertyVector3::_value_changed(double val, const String &p_name) {
v3.y = Math::deg_to_rad(v3.y);
v3.z = Math::deg_to_rad(v3.z);
}
- emit_changed(get_edited_property(), v3, p_name);
+ emit_changed(get_edited_property(), v3, linked->is_pressed() ? "" : p_name);
}
void EditorPropertyVector3::update_property() {
@@ -2171,7 +2171,7 @@ void EditorPropertyVector2i::_value_changed(double val, const String &p_name) {
Vector2i v2;
v2.x = spin[0]->get_value();
v2.y = spin[1]->get_value();
- emit_changed(get_edited_property(), v2, p_name);
+ emit_changed(get_edited_property(), v2, linked->is_pressed() ? "" : p_name);
}
void EditorPropertyVector2i::update_property() {
@@ -2413,7 +2413,7 @@ void EditorPropertyVector3i::_value_changed(double val, const String &p_name) {
v3.x = spin[0]->get_value();
v3.y = spin[1]->get_value();
v3.z = spin[2]->get_value();
- emit_changed(get_edited_property(), v3, p_name);
+ emit_changed(get_edited_property(), v3, linked->is_pressed() ? "" : p_name);
}
void EditorPropertyVector3i::update_property() {
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index ad84b30689..728a3b0f80 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -268,6 +268,7 @@ void EditorPropertyArray::update_property() {
size_slider->set_step(1);
size_slider->set_max(1000000);
size_slider->set_h_size_flags(SIZE_EXPAND_FILL);
+ size_slider->set_read_only(is_read_only());
size_slider->connect("value_changed", callable_mp(this, &EditorPropertyArray::_length_changed));
hbox->add_child(size_slider);
@@ -278,6 +279,7 @@ void EditorPropertyArray::update_property() {
button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Element"));
button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
button_add_item->connect(SNAME("pressed"), callable_mp(this, &EditorPropertyArray::_add_element));
+ button_add_item->set_disabled(is_read_only());
vbox->add_child(button_add_item);
paginator = memnew(EditorPaginator);
@@ -328,6 +330,7 @@ void EditorPropertyArray::update_property() {
Button *reorder_button = memnew(Button);
reorder_button->set_icon(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons")));
reorder_button->set_default_cursor_shape(Control::CURSOR_MOVE);
+ reorder_button->set_disabled(is_read_only());
reorder_button->connect("gui_input", callable_mp(this, &EditorPropertyArray::_reorder_button_gui_input));
reorder_button->connect("button_down", callable_mp(this, &EditorPropertyArray::_reorder_button_down).bind(i + offset));
reorder_button->connect("button_up", callable_mp(this, &EditorPropertyArray::_reorder_button_up));
@@ -358,6 +361,7 @@ void EditorPropertyArray::update_property() {
prop->connect("property_changed", callable_mp(this, &EditorPropertyArray::_property_changed));
prop->connect("object_id_selected", callable_mp(this, &EditorPropertyArray::_object_id_selected));
prop->set_h_size_flags(SIZE_EXPAND_FILL);
+ prop->set_read_only(is_read_only());
hbox->add_child(prop);
bool is_untyped_array = array.get_type() == Variant::ARRAY && subtype == Variant::NIL;
@@ -366,10 +370,12 @@ void EditorPropertyArray::update_property() {
Button *edit = memnew(Button);
edit->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
hbox->add_child(edit);
+ edit->set_disabled(is_read_only());
edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_change_type).bind(edit, i + offset));
} else {
Button *remove = memnew(Button);
remove->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ remove->set_disabled(is_read_only());
remove->connect("pressed", callable_mp(this, &EditorPropertyArray::_remove_pressed).bind(i + offset));
hbox->add_child(remove);
}
@@ -409,6 +415,10 @@ void EditorPropertyArray::_button_draw() {
}
bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
+ if (is_read_only()) {
+ return false;
+ }
+
String allowed_type = Variant::get_type_name(subtype);
// When the subtype is of type Object, an additional subtype may be specified in the hint string
@@ -609,7 +619,7 @@ void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint
}
void EditorPropertyArray::_reorder_button_gui_input(const Ref<InputEvent> &p_event) {
- if (reorder_from_index < 0) {
+ if (reorder_from_index < 0 || is_read_only()) {
return;
}
@@ -646,6 +656,10 @@ void EditorPropertyArray::_reorder_button_gui_input(const Ref<InputEvent> &p_eve
}
void EditorPropertyArray::_reorder_button_down(int p_index) {
+ if (is_read_only()) {
+ return;
+ }
+
reorder_from_index = p_index;
reorder_to_index = p_index;
reorder_selected_element_hbox = Object::cast_to<HBoxContainer>(property_vbox->get_child(p_index % page_length));
@@ -656,6 +670,10 @@ void EditorPropertyArray::_reorder_button_down(int p_index) {
}
void EditorPropertyArray::_reorder_button_up() {
+ if (is_read_only()) {
+ return;
+ }
+
if (reorder_from_index != reorder_to_index) {
// Move the element.
Variant array = object->get_array();
@@ -1097,6 +1115,10 @@ void EditorPropertyDictionary::update_property() {
}
}
+ ERR_FAIL_COND(!prop);
+
+ prop->set_read_only(is_read_only());
+
if (i == amount) {
PanelContainer *pc = memnew(PanelContainer);
property_vbox->add_child(pc);
@@ -1135,6 +1157,7 @@ void EditorPropertyDictionary::update_property() {
prop->set_h_size_flags(SIZE_EXPAND_FILL);
Button *edit = memnew(Button);
edit->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ edit->set_disabled(is_read_only());
hbox->add_child(edit);
edit->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_change_type).bind(edit, change_index));
@@ -1143,6 +1166,7 @@ void EditorPropertyDictionary::update_property() {
if (i == amount + 1) {
button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Key/Value Pair"));
button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ button_add_item->set_disabled(is_read_only());
button_add_item->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_add_key_value));
add_vbox->add_child(button_add_item);
}
diff --git a/editor/editor_quick_open.cpp b/editor/editor_quick_open.cpp
index 539cb7cd8a..b4ec3bca15 100644
--- a/editor/editor_quick_open.cpp
+++ b/editor/editor_quick_open.cpp
@@ -31,6 +31,7 @@
#include "editor_quick_open.h"
#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
void EditorQuickOpen::popup_dialog(const StringName &p_base, bool p_enable_multi, bool p_dontclear) {
base_type = p_base;
@@ -57,17 +58,29 @@ void EditorQuickOpen::_build_search_cache(EditorFileSystemDirectory *p_efsd) {
Vector<String> base_types = String(base_type).split(String(","));
for (int i = 0; i < p_efsd->get_file_count(); i++) {
- String file_type = p_efsd->get_file_type(i);
+ String file = p_efsd->get_file_path(i);
+ String engine_type = p_efsd->get_file_type(i);
+ // TODO: Fix lack of caching for resource's script's global class name (if applicable).
+ String script_type;
+ if (_load_resources) {
+ Ref<Resource> res = ResourceLoader::load(file);
+ if (res.is_valid()) {
+ Ref<Script> scr = res->get_script();
+ if (scr.is_valid()) {
+ script_type = scr->get_language()->get_global_class_name(file);
+ }
+ }
+ }
+ String actual_type = script_type.is_empty() ? engine_type : script_type;
// Iterate all possible base types.
for (String &parent_type : base_types) {
- if (ClassDB::is_parent_class(file_type, parent_type)) {
- String file = p_efsd->get_file_path(i);
+ if (ClassDB::is_parent_class(engine_type, parent_type) || EditorNode::get_editor_data().script_class_is_parent(script_type, parent_type)) {
files.push_back(file.substr(6, file.length()));
// Store refs to used icons.
String ext = file.get_extension();
if (!icons.has(ext)) {
- icons.insert(ext, get_theme_icon((has_theme_icon(file_type, SNAME("EditorIcons")) ? file_type : String("Object")), SNAME("EditorIcons")));
+ icons.insert(ext, get_theme_icon((has_theme_icon(actual_type, SNAME("EditorIcons")) ? actual_type : String("Object")), SNAME("EditorIcons")));
}
// Stop testing base types as soon as we got a match.
diff --git a/editor/editor_quick_open.h b/editor/editor_quick_open.h
index e41a8c7e75..83cbbd7cac 100644
--- a/editor/editor_quick_open.h
+++ b/editor/editor_quick_open.h
@@ -43,6 +43,7 @@ class EditorQuickOpen : public ConfirmationDialog {
Tree *search_options = nullptr;
StringName base_type;
bool allow_multi_select = false;
+ bool _load_resources = false; // Prohibitively slow for now.
Vector<String> files;
OAHashMap<String, Ref<Texture2D>> icons;
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 5346052f4d..de8259c25c 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -53,6 +53,7 @@ void EditorResourcePicker::_update_resource() {
if (edited_resource.is_valid() && edited_resource->get_path().is_resource_file()) {
resource_path = edited_resource->get_path() + "\n";
}
+ String class_name = _get_resource_type(edited_resource);
if (preview_rect) {
preview_rect->set_texture(Ref<Texture2D>());
@@ -64,16 +65,20 @@ void EditorResourcePicker::_update_resource() {
assign_button->set_text(TTR("<empty>"));
assign_button->set_tooltip_text("");
} else {
- assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), "Object"));
+ assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), SNAME("Object")));
if (!edited_resource->get_name().is_empty()) {
assign_button->set_text(edited_resource->get_name());
} else if (edited_resource->get_path().is_resource_file()) {
assign_button->set_text(edited_resource->get_path().get_file());
} else {
- assign_button->set_text(edited_resource->get_class());
+ assign_button->set_text(class_name);
}
- assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + edited_resource->get_class());
+
+ if (edited_resource->get_path().is_resource_file()) {
+ resource_path = edited_resource->get_path() + "\n";
+ }
+ assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + class_name);
// Preview will override the above, so called at the end.
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(edited_resource, this, "_update_resource_preview", edited_resource->get_instance_id());
@@ -134,16 +139,29 @@ void EditorResourcePicker::_file_selected(const String &p_path) {
if (!base_type.is_empty()) {
bool any_type_matches = false;
+ String res_type = loaded_resource->get_class();
+ Ref<Script> res_script = loaded_resource->get_script();
+ bool is_global_class = false;
+ if (res_script.is_valid()) {
+ String script_type = EditorNode::get_editor_data().script_class_get_name(res_script->get_path());
+ if (!script_type.is_empty()) {
+ is_global_class = true;
+ res_type = script_type;
+ }
+ }
+
for (int i = 0; i < base_type.get_slice_count(","); i++) {
String base = base_type.get_slice(",", i);
- if (loaded_resource->is_class(base)) {
- any_type_matches = true;
+
+ any_type_matches = is_global_class ? EditorNode::get_editor_data().script_class_is_parent(res_type, base) : loaded_resource->is_class(base);
+
+ if (!any_type_matches) {
break;
}
}
if (!any_type_matches) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("The selected resource (%s) does not match any type expected for this property (%s)."), loaded_resource->get_class(), base_type));
+ EditorNode::get_singleton()->show_warning(vformat(TTR("The selected resource (%s) does not match any type expected for this property (%s)."), res_type, base_type));
return;
}
}
@@ -186,7 +204,7 @@ void EditorResourcePicker::_update_menu_items() {
// Add options for changing existing value of the resource.
if (edited_resource.is_valid()) {
// Determine if the edited resource is part of another scene (foreign) which was imported
- bool is_edited_resource_foreign_import = EditorNode::get_singleton()->is_resource_read_only(edited_resource);
+ bool is_edited_resource_foreign_import = EditorNode::get_singleton()->is_resource_read_only(edited_resource, true);
// If the resource is determined to be foreign and imported, change the menu entry's description to 'inspect' rather than 'edit'
// since will only be able to view its properties in read-only mode.
@@ -227,16 +245,19 @@ void EditorResourcePicker::_update_menu_items() {
// Add options to copy/paste resource.
Ref<Resource> cb = EditorSettings::get_singleton()->get_resource_clipboard();
bool paste_valid = false;
- if (is_editable()) {
- if (cb.is_valid()) {
- if (base_type.is_empty()) {
- paste_valid = true;
- } else {
- for (int i = 0; i < base_type.get_slice_count(","); i++) {
- if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) {
- paste_valid = true;
- break;
- }
+ if (is_editable() && cb.is_valid()) {
+ if (base_type.is_empty()) {
+ paste_valid = true;
+ } else {
+ String res_type = _get_resource_type(cb);
+
+ for (int i = 0; i < base_type.get_slice_count(","); i++) {
+ String base = base_type.get_slice(",", i);
+
+ paste_valid = ClassDB::is_parent_class(res_type, base) || EditorNode::get_editor_data().script_class_is_parent(res_type, base);
+
+ if (!paste_valid) {
+ break;
}
}
}
@@ -281,6 +302,9 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
for (int i = 0; i < base_type.get_slice_count(","); i++) {
String base = base_type.get_slice(",", i);
ResourceLoader::get_recognized_extensions_for_type(base, &extensions);
+ if (ScriptServer::is_global_class(base)) {
+ ResourceLoader::get_recognized_extensions_for_type(ScriptServer::get_global_class_native_base(base), &extensions);
+ }
}
HashSet<String> valid_extensions;
@@ -408,13 +432,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
Variant obj;
if (ScriptServer::is_global_class(intype)) {
- obj = ClassDB::instantiate(ScriptServer::get_global_class_native_base(intype));
- if (obj) {
- Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(intype));
- if (script.is_valid()) {
- ((Object *)obj)->set_script(script);
- }
- }
+ obj = EditorNode::get_editor_data().script_class_instance(intype);
} else {
obj = ClassDB::instantiate(intype);
}
@@ -512,23 +530,40 @@ void EditorResourcePicker::_button_draw() {
void EditorResourcePicker::_button_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
- // Only attempt to update and show the menu if we have
- // a valid resource or the Picker is editable, as
- // there will otherwise be nothing to display.
- if (edited_resource.is_valid() || is_editable()) {
- _update_menu_items();
-
- Vector2 pos = get_screen_position() + mb->get_position();
- edit_menu->reset_size();
- edit_menu->set_position(pos);
- edit_menu->popup();
- }
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
+ // Only attempt to update and show the menu if we have
+ // a valid resource or the Picker is editable, as
+ // there will otherwise be nothing to display.
+ if (edited_resource.is_valid() || is_editable()) {
+ _update_menu_items();
+
+ Vector2 pos = get_screen_position() + mb->get_position();
+ edit_menu->reset_size();
+ edit_menu->set_position(pos);
+ edit_menu->popup();
}
}
}
+String EditorResourcePicker::_get_resource_type(const Ref<Resource> &p_resource) const {
+ if (p_resource.is_null()) {
+ return String();
+ }
+ String res_type = p_resource->get_class();
+
+ Ref<Script> res_script = p_resource->get_script();
+ if (res_script.is_null()) {
+ return res_type;
+ }
+
+ // TODO: Replace with EditorFileSystem when PR #60606 is merged to use cached resource type.
+ String script_type = EditorNode::get_editor_data().script_class_get_name(res_script->get_path());
+ if (!script_type.is_empty()) {
+ res_type = script_type;
+ }
+ return res_type;
+}
+
void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<String> *p_vector) const {
Vector<String> allowed_types = base_type.split(",");
int size = allowed_types.size();
@@ -550,7 +585,9 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<Strin
List<StringName> allowed_subtypes;
List<StringName> inheriters;
- ClassDB::get_inheriters_from_class(base, &inheriters);
+ if (!ScriptServer::is_global_class(base)) {
+ ClassDB::get_inheriters_from_class(base, &inheriters);
+ }
for (const StringName &subtype_name : inheriters) {
p_vector->insert(subtype_name);
allowed_subtypes.push_back(subtype_name);
@@ -602,32 +639,29 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const {
}
} else if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
res = drag_data["resource"];
+ } else if (drag_data.has("type") && String(drag_data["type"]) == "files") {
+ Vector<String> files = drag_data["files"];
+
+ // TODO: Extract the typename of the dropped filepath's resource in a more performant way, without fully loading it.
+ if (files.size() == 1) {
+ String file = files[0];
+ res = ResourceLoader::load(file);
+ }
}
HashSet<String> allowed_types;
_get_allowed_types(true, &allowed_types);
- if (res.is_valid() && _is_type_valid(res->get_class(), allowed_types)) {
- return true;
- }
+ if (res.is_valid()) {
+ String res_type = _get_resource_type(res);
- if (res.is_valid() && res->get_script()) {
- StringName custom_class = EditorNode::get_singleton()->get_object_custom_type_name(res->get_script());
- if (_is_type_valid(custom_class, allowed_types)) {
+ if (_is_type_valid(res_type, allowed_types)) {
return true;
}
- }
-
- if (drag_data.has("type") && String(drag_data["type"]) == "files") {
- Vector<String> files = drag_data["files"];
-
- if (files.size() == 1) {
- String file = files[0];
- String file_type = EditorFileSystem::get_singleton()->get_file_type(file);
- if (!file_type.is_empty() && _is_type_valid(file_type, allowed_types)) {
- return true;
- }
+ StringName custom_class = EditorNode::get_singleton()->get_object_custom_type_name(res.ptr());
+ if (_is_type_valid(custom_class, allowed_types)) {
+ return true;
}
}
@@ -685,8 +719,10 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_
HashSet<String> allowed_types;
_get_allowed_types(false, &allowed_types);
+ String res_type = _get_resource_type(dropped_resource);
+
// If the accepted dropped resource is from the extended list, it requires conversion.
- if (!_is_type_valid(dropped_resource->get_class(), allowed_types)) {
+ if (!_is_type_valid(res_type, allowed_types)) {
for (const String &E : allowed_types) {
String at = E.strip_edges();
diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h
index 3d6127e656..d1a20f04b7 100644
--- a/editor/editor_resource_picker.h
+++ b/editor/editor_resource_picker.h
@@ -91,6 +91,7 @@ class EditorResourcePicker : public HBoxContainer {
void _button_draw();
void _button_input(const Ref<InputEvent> &p_event);
+ String _get_resource_type(const Ref<Resource> &p_resource) const;
void _get_allowed_types(bool p_with_convert, HashSet<String> *p_vector) const;
bool _is_drop_valid(const Dictionary &p_drag_data) const;
bool _is_type_valid(const String p_type_name, HashSet<String> p_allowed_types) const;
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index ec67cde112..2c09543d92 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -416,45 +416,50 @@ void EditorSettingsDialog::_update_shortcuts() {
List<String> slist;
EditorSettings::get_singleton()->get_shortcut_list(&slist);
+ slist.sort(); // Sort alphabetically.
const EditorPropertyNameProcessor::Style name_style = EditorPropertyNameProcessor::get_settings_style();
const EditorPropertyNameProcessor::Style tooltip_style = EditorPropertyNameProcessor::get_tooltip_style(name_style);
+ // Create all sections first.
for (const String &E : slist) {
Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(E);
- if (!sc->has_meta("original")) {
+ String section_name = E.get_slice("/", 0);
+
+ if (sections.has(section_name)) {
continue;
}
- // Shortcut Section
+ TreeItem *section = shortcuts->create_item(root);
- TreeItem *section;
- String section_name = E.get_slice("/", 0);
+ const String item_name = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, name_style);
+ const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style);
- if (sections.has(section_name)) {
- section = sections[section_name];
- } else {
- section = shortcuts->create_item(root);
-
- const String item_name = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, name_style);
- const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style);
-
- section->set_text(0, item_name);
- section->set_tooltip_text(0, tooltip);
- section->set_selectable(0, false);
- section->set_selectable(1, false);
- section->set_custom_bg_color(0, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
- section->set_custom_bg_color(1, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
-
- if (collapsed.has(item_name)) {
- section->set_collapsed(collapsed[item_name]);
- }
+ section->set_text(0, item_name);
+ section->set_tooltip_text(0, tooltip);
+ section->set_selectable(0, false);
+ section->set_selectable(1, false);
+ section->set_custom_bg_color(0, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
+ section->set_custom_bg_color(1, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
- sections[section_name] = section;
+ if (collapsed.has(item_name)) {
+ section->set_collapsed(collapsed[item_name]);
}
- // Shortcut Item
+ sections[section_name] = section;
+ }
+ // Add shortcuts to sections.
+ for (const String &E : slist) {
+ Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(E);
+ if (!sc->has_meta("original")) {
+ continue;
+ }
+
+ String section_name = E.get_slice("/", 0);
+ TreeItem *section = sections[section_name];
+
+ // Shortcut Item
if (!shortcut_filter.is_subsequence_ofn(sc->get_name())) {
continue;
}
@@ -552,6 +557,10 @@ void EditorSettingsDialog::_shortcut_cell_double_clicked() {
const ShortcutButton edit_btn_id = EditorSettingsDialog::SHORTCUT_EDIT;
const int edit_btn_col = 1;
TreeItem *ti = shortcuts->get_selected();
+ if (ti == nullptr) {
+ return;
+ }
+
String type = ti->get_meta("type");
int col = shortcuts->get_selected_column();
if (type == "shortcut" && col == 0) {
@@ -763,6 +772,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
shortcut_editor = memnew(InputEventConfigurationDialog);
shortcut_editor->connect("confirmed", callable_mp(this, &EditorSettingsDialog::_event_config_confirmed));
shortcut_editor->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_KEY);
+ shortcut_editor->set_close_on_escape(false);
add_child(shortcut_editor);
set_hide_on_ok(true);
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index edbd2dd62f..486a1f5a84 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -42,10 +42,15 @@
#include "modules/svg/image_loader_svg.h"
#endif
-HashMap<Color, Color> EditorColorMap::editor_color_map;
+HashMap<Color, Color> EditorColorMap::color_conversion_map;
+HashSet<StringName> EditorColorMap::color_conversion_exceptions;
-void EditorColorMap::add_color_pair(const String p_from_color, const String p_to_color) {
- editor_color_map[Color::html(p_from_color)] = Color::html(p_to_color);
+void EditorColorMap::add_conversion_color_pair(const String p_from_color, const String p_to_color) {
+ color_conversion_map[Color::html(p_from_color)] = Color::html(p_to_color);
+}
+
+void EditorColorMap::add_conversion_exception(const StringName p_icon_name) {
+ color_conversion_exceptions.insert(p_icon_name);
}
void EditorColorMap::create() {
@@ -53,105 +58,139 @@ void EditorColorMap::create() {
// This can be a basis for proper palette validation later.
// Convert: FROM TO
- add_color_pair("#478cbf", "#478cbf"); // Godot Blue
- add_color_pair("#414042", "#414042"); // Godot Gray
+ add_conversion_color_pair("#478cbf", "#478cbf"); // Godot Blue
+ add_conversion_color_pair("#414042", "#414042"); // Godot Gray
- add_color_pair("#ffffff", "#414141"); // Pure white
- add_color_pair("#000000", "#bfbfbf"); // Pure black
+ add_conversion_color_pair("#ffffff", "#414141"); // Pure white
+ add_conversion_color_pair("#000000", "#bfbfbf"); // Pure black
// Keep pure RGB colors as is, but list them for explicitly.
- add_color_pair("#ff0000", "#ff0000"); // Pure red
- add_color_pair("#00ff00", "#00ff00"); // Pure green
- add_color_pair("#0000ff", "#0000ff"); // Pure blue
+ add_conversion_color_pair("#ff0000", "#ff0000"); // Pure red
+ add_conversion_color_pair("#00ff00", "#00ff00"); // Pure green
+ add_conversion_color_pair("#0000ff", "#0000ff"); // Pure blue
// GUI Colors
- add_color_pair("#e0e0e0", "#5a5a5a"); // Common icon color
- add_color_pair("#fefefe", "#fefefe"); // Forced light color
- add_color_pair("#808080", "#808080"); // GUI disabled color
- add_color_pair("#b3b3b3", "#363636"); // GUI disabled light color
- add_color_pair("#699ce8", "#699ce8"); // GUI highlight color
- add_color_pair("#f9f9f9", "#606060"); // Scrollbar grabber highlight color
-
- add_color_pair("#c38ef1", "#a85de9"); // Animation
- add_color_pair("#fc7f7f", "#cd3838"); // Spatial
- add_color_pair("#8da5f3", "#3d64dd"); // 2D
- add_color_pair("#4b70ea", "#1a3eac"); // 2D Dark
- add_color_pair("#8eef97", "#2fa139"); // Control
-
- add_color_pair("#5fb2ff", "#0079f0"); // Selection (blue)
- add_color_pair("#003e7a", "#2b74bb"); // Selection (darker blue)
- add_color_pair("#f7f5cf", "#615f3a"); // Gizmo (yellow)
+ add_conversion_color_pair("#e0e0e0", "#5a5a5a"); // Common icon color
+ add_conversion_color_pair("#fefefe", "#fefefe"); // Forced light color
+ add_conversion_color_pair("#808080", "#808080"); // GUI disabled color
+ add_conversion_color_pair("#b3b3b3", "#363636"); // GUI disabled light color
+ add_conversion_color_pair("#699ce8", "#699ce8"); // GUI highlight color
+ add_conversion_color_pair("#f9f9f9", "#606060"); // Scrollbar grabber highlight color
+
+ add_conversion_color_pair("#c38ef1", "#a85de9"); // Animation
+ add_conversion_color_pair("#fc7f7f", "#cd3838"); // Spatial
+ add_conversion_color_pair("#8da5f3", "#3d64dd"); // 2D
+ add_conversion_color_pair("#4b70ea", "#1a3eac"); // 2D Dark
+ add_conversion_color_pair("#8eef97", "#2fa139"); // Control
+
+ add_conversion_color_pair("#5fb2ff", "#0079f0"); // Selection (blue)
+ add_conversion_color_pair("#003e7a", "#2b74bb"); // Selection (darker blue)
+ add_conversion_color_pair("#f7f5cf", "#615f3a"); // Gizmo (yellow)
// Rainbow
- add_color_pair("#ff4545", "#ff2929"); // Red
- add_color_pair("#ffe345", "#ffe337"); // Yellow
- add_color_pair("#80ff45", "#74ff34"); // Green
- add_color_pair("#45ffa2", "#2cff98"); // Aqua
- add_color_pair("#45d7ff", "#22ccff"); // Blue
- add_color_pair("#8045ff", "#702aff"); // Purple
- add_color_pair("#ff4596", "#ff2781"); // Pink
+ add_conversion_color_pair("#ff4545", "#ff2929"); // Red
+ add_conversion_color_pair("#ffe345", "#ffe337"); // Yellow
+ add_conversion_color_pair("#80ff45", "#74ff34"); // Green
+ add_conversion_color_pair("#45ffa2", "#2cff98"); // Aqua
+ add_conversion_color_pair("#45d7ff", "#22ccff"); // Blue
+ add_conversion_color_pair("#8045ff", "#702aff"); // Purple
+ add_conversion_color_pair("#ff4596", "#ff2781"); // Pink
// Audio gradients
- add_color_pair("#e1da5b", "#d6cf4b"); // Yellow
+ add_conversion_color_pair("#e1da5b", "#d6cf4b"); // Yellow
- add_color_pair("#62aeff", "#1678e0"); // Frozen gradient top
- add_color_pair("#75d1e6", "#41acc5"); // Frozen gradient middle
- add_color_pair("#84ffee", "#49ccba"); // Frozen gradient bottom
+ add_conversion_color_pair("#62aeff", "#1678e0"); // Frozen gradient top
+ add_conversion_color_pair("#75d1e6", "#41acc5"); // Frozen gradient middle
+ add_conversion_color_pair("#84ffee", "#49ccba"); // Frozen gradient bottom
- add_color_pair("#f70000", "#c91616"); // Color track red
- add_color_pair("#eec315", "#d58c0b"); // Color track orange
- add_color_pair("#dbee15", "#b7d10a"); // Color track yellow
- add_color_pair("#288027", "#218309"); // Color track green
+ add_conversion_color_pair("#f70000", "#c91616"); // Color track red
+ add_conversion_color_pair("#eec315", "#d58c0b"); // Color track orange
+ add_conversion_color_pair("#dbee15", "#b7d10a"); // Color track yellow
+ add_conversion_color_pair("#288027", "#218309"); // Color track green
// Resource groups
- add_color_pair("#ffca5f", "#fea900"); // Mesh resource (orange)
- add_color_pair("#2998ff", "#68b6ff"); // Shape resource (blue)
- add_color_pair("#a2d2ff", "#4998e3"); // Shape resource (light blue)
+ add_conversion_color_pair("#ffca5f", "#fea900"); // Mesh resource (orange)
+ add_conversion_color_pair("#2998ff", "#68b6ff"); // Shape resource (blue)
+ add_conversion_color_pair("#a2d2ff", "#4998e3"); // Shape resource (light blue)
// Animation editor tracks
// The property track icon color is set by the common icon color.
- add_color_pair("#ea7940", "#bd5e2c"); // 3D Position track
- add_color_pair("#ff2b88", "#bd165f"); // 3D Rotation track
- add_color_pair("#eac840", "#bd9d1f"); // 3D Scale track
- add_color_pair("#3cf34e", "#16a827"); // Call Method track
- add_color_pair("#2877f6", "#236be6"); // Bezier Curve track
- add_color_pair("#eae440", "#9f9722"); // Audio Playback track
- add_color_pair("#a448f0", "#9853ce"); // Animation Playback track
- add_color_pair("#5ad5c4", "#0a9c88"); // Blend Shape track
+ add_conversion_color_pair("#ea7940", "#bd5e2c"); // 3D Position track
+ add_conversion_color_pair("#ff2b88", "#bd165f"); // 3D Rotation track
+ add_conversion_color_pair("#eac840", "#bd9d1f"); // 3D Scale track
+ add_conversion_color_pair("#3cf34e", "#16a827"); // Call Method track
+ add_conversion_color_pair("#2877f6", "#236be6"); // Bezier Curve track
+ add_conversion_color_pair("#eae440", "#9f9722"); // Audio Playback track
+ add_conversion_color_pair("#a448f0", "#9853ce"); // Animation Playback track
+ add_conversion_color_pair("#5ad5c4", "#0a9c88"); // Blend Shape track
// Control layouts
- add_color_pair("#d6d6d6", "#474747"); // Highlighted part
- add_color_pair("#474747", "#d6d6d6"); // Background part
- add_color_pair("#919191", "#6e6e6e"); // Border part
+ add_conversion_color_pair("#d6d6d6", "#474747"); // Highlighted part
+ add_conversion_color_pair("#474747", "#d6d6d6"); // Background part
+ add_conversion_color_pair("#919191", "#6e6e6e"); // Border part
// TileSet editor icons
- add_color_pair("#fce00e", "#aa8d24"); // New Single Tile
- add_color_pair("#0e71fc", "#0350bd"); // New Autotile
- add_color_pair("#c6ced4", "#828f9b"); // New Atlas
+ add_conversion_color_pair("#fce00e", "#aa8d24"); // New Single Tile
+ add_conversion_color_pair("#0e71fc", "#0350bd"); // New Autotile
+ add_conversion_color_pair("#c6ced4", "#828f9b"); // New Atlas
// Visual script
- add_color_pair("#41ecad", "#25e3a0"); // VisualScript variant
- add_color_pair("#6f91f0", "#6d8eeb"); // VisualScript bool
- add_color_pair("#5abbef", "#4fb2e9"); // VisualScript int
- add_color_pair("#35d4f4", "#27ccf0"); // VisualScript float
- add_color_pair("#4593ec", "#4690e7"); // VisualScript String
- add_color_pair("#ac73f1", "#ad76ee"); // VisualScript Vector2
- add_color_pair("#f1738f", "#ee758e"); // VisualScript Rect2
- add_color_pair("#de66f0", "#dc6aed"); // VisualScript Vector3
- add_color_pair("#b9ec41", "#96ce1a"); // VisualScript Transform2D
- add_color_pair("#f74949", "#f77070"); // VisualScript Plane
- add_color_pair("#ec418e", "#ec69a3"); // VisualScript Quat
- add_color_pair("#ee5677", "#ee7991"); // VisualScript AABB
- add_color_pair("#e1ec41", "#b2bb19"); // VisualScript Basis
- add_color_pair("#f68f45", "#f49047"); // VisualScript Transform
- add_color_pair("#417aec", "#6993ec"); // VisualScript NodePath
- add_color_pair("#41ec80", "#2ce573"); // VisualScript RID
- add_color_pair("#55f3e3", "#12d5c3"); // VisualScript Object
- add_color_pair("#54ed9e", "#57e99f"); // VisualScript Dictionary
+ add_conversion_color_pair("#41ecad", "#25e3a0"); // VisualScript variant
+ add_conversion_color_pair("#6f91f0", "#6d8eeb"); // VisualScript bool
+ add_conversion_color_pair("#5abbef", "#4fb2e9"); // VisualScript int
+ add_conversion_color_pair("#35d4f4", "#27ccf0"); // VisualScript float
+ add_conversion_color_pair("#4593ec", "#4690e7"); // VisualScript String
+ add_conversion_color_pair("#ac73f1", "#ad76ee"); // VisualScript Vector2
+ add_conversion_color_pair("#f1738f", "#ee758e"); // VisualScript Rect2
+ add_conversion_color_pair("#de66f0", "#dc6aed"); // VisualScript Vector3
+ add_conversion_color_pair("#b9ec41", "#96ce1a"); // VisualScript Transform2D
+ add_conversion_color_pair("#f74949", "#f77070"); // VisualScript Plane
+ add_conversion_color_pair("#ec418e", "#ec69a3"); // VisualScript Quat
+ add_conversion_color_pair("#ee5677", "#ee7991"); // VisualScript AABB
+ add_conversion_color_pair("#e1ec41", "#b2bb19"); // VisualScript Basis
+ add_conversion_color_pair("#f68f45", "#f49047"); // VisualScript Transform
+ add_conversion_color_pair("#417aec", "#6993ec"); // VisualScript NodePath
+ add_conversion_color_pair("#41ec80", "#2ce573"); // VisualScript RID
+ add_conversion_color_pair("#55f3e3", "#12d5c3"); // VisualScript Object
+ add_conversion_color_pair("#54ed9e", "#57e99f"); // VisualScript Dictionary
// Visual shaders
- add_color_pair("#77ce57", "#67c046"); // Vector funcs
- add_color_pair("#ea686c", "#d95256"); // Vector transforms
- add_color_pair("#eac968", "#d9b64f"); // Textures and cubemaps
- add_color_pair("#cf68ea", "#c050dd"); // Functions and expressions
+ add_conversion_color_pair("#77ce57", "#67c046"); // Vector funcs
+ add_conversion_color_pair("#ea686c", "#d95256"); // Vector transforms
+ add_conversion_color_pair("#eac968", "#d9b64f"); // Textures and cubemaps
+ add_conversion_color_pair("#cf68ea", "#c050dd"); // Functions and expressions
+
+ // These icons should not be converted.
+ add_conversion_exception("EditorPivot");
+ add_conversion_exception("EditorHandle");
+ add_conversion_exception("Editor3DHandle");
+ add_conversion_exception("EditorBoneHandle");
+ add_conversion_exception("Godot");
+ add_conversion_exception("Sky");
+ add_conversion_exception("EditorControlAnchor");
+ add_conversion_exception("DefaultProjectIcon");
+ add_conversion_exception("GuiChecked");
+ add_conversion_exception("GuiRadioChecked");
+ add_conversion_exception("GuiIndeterminate");
+ add_conversion_exception("GuiCloseCustomizable");
+ add_conversion_exception("GuiGraphNodePort");
+ add_conversion_exception("GuiResizer");
+ add_conversion_exception("ZoomMore");
+ add_conversion_exception("ZoomLess");
+ add_conversion_exception("ZoomReset");
+ add_conversion_exception("LockViewport");
+ add_conversion_exception("GroupViewport");
+ add_conversion_exception("StatusError");
+ add_conversion_exception("StatusSuccess");
+ add_conversion_exception("StatusWarning");
+ add_conversion_exception("OverbrightIndicator");
+ add_conversion_exception("GuiMiniCheckerboard");
+
+ /// Code Editor.
+ add_conversion_exception("GuiTab");
+ add_conversion_exception("GuiSpace");
+ add_conversion_exception("CodeFoldedRightArrow");
+ add_conversion_exception("CodeFoldDownArrow");
+ add_conversion_exception("TextEditorPlay");
+ add_conversion_exception("Breakpoint");
}
static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) {
@@ -206,67 +245,49 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, float p_scale, float
img->adjust_bcs(1.0, 1.0, p_saturation);
}
- // In this case filter really helps.
return ImageTexture::create_from_image(img);
}
#endif
-void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = true, int p_thumb_size = 32, bool p_only_thumbs = false, float p_icon_saturation = 1.0) {
+void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme, float p_icon_saturation, int p_thumb_size, bool p_only_thumbs = false) {
#ifdef MODULE_SVG_ENABLED
- HashMap<Color, Color> icon_color_map;
-
- // The names of the icons to never convert, even if one of their colors
- // are contained in the dictionary above.
- HashSet<StringName> exceptions;
-
+ // Before we register the icons, we adjust their colors and saturation.
+ // Most icons follow the standard rules for color conversion to follow the editor
+ // theme's polarity (dark/light). We also adjust the saturation for most icons,
+ // following the editor setting.
+ // Some icons are excluded from this conversion, and instead use the configured
+ // accent color to replace their innate accent color to match the editor theme.
+ // And then some icons are completely excluded from the conversion.
+
+ // Standard color conversion map.
+ HashMap<Color, Color> color_conversion_map;
+ // Icons by default are set up for the dark theme, so if the theme is light,
+ // we apply the dark-to-light color conversion map.
if (!p_dark_theme) {
- for (KeyValue<Color, Color> &E : EditorColorMap::get()) {
- icon_color_map[E.key] = E.value;
+ for (KeyValue<Color, Color> &E : EditorColorMap::get_color_conversion_map()) {
+ color_conversion_map[E.key] = E.value;
}
-
- exceptions.insert("EditorPivot");
- exceptions.insert("EditorHandle");
- exceptions.insert("Editor3DHandle");
- exceptions.insert("EditorBoneHandle");
- exceptions.insert("Godot");
- exceptions.insert("Sky");
- exceptions.insert("EditorControlAnchor");
- exceptions.insert("DefaultProjectIcon");
- exceptions.insert("GuiChecked");
- exceptions.insert("GuiRadioChecked");
- exceptions.insert("GuiIndeterminate");
- exceptions.insert("GuiCloseCustomizable");
- exceptions.insert("GuiGraphNodePort");
- exceptions.insert("GuiResizer");
- exceptions.insert("ZoomMore");
- exceptions.insert("ZoomLess");
- exceptions.insert("ZoomReset");
- exceptions.insert("LockViewport");
- exceptions.insert("GroupViewport");
- exceptions.insert("StatusError");
- exceptions.insert("StatusSuccess");
- exceptions.insert("StatusWarning");
- exceptions.insert("OverbrightIndicator");
- exceptions.insert("GuiMiniCheckerboard");
-
- // Prevents Code Editor icons from changing
- exceptions.insert("GuiTab");
- exceptions.insert("GuiSpace");
- exceptions.insert("CodeFoldedRightArrow");
- exceptions.insert("CodeFoldDownArrow");
- exceptions.insert("TextEditorPlay");
- exceptions.insert("Breakpoint");
}
-
- // These ones should be converted even if we are using a dark theme.
+ // These colors should be converted even if we are using a dark theme.
const Color error_color = p_theme->get_color(SNAME("error_color"), SNAME("Editor"));
const Color success_color = p_theme->get_color(SNAME("success_color"), SNAME("Editor"));
const Color warning_color = p_theme->get_color(SNAME("warning_color"), SNAME("Editor"));
- icon_color_map[Color::html("#ff5f5f")] = error_color;
- icon_color_map[Color::html("#5fff97")] = success_color;
- icon_color_map[Color::html("#ffdd65")] = warning_color;
-
- // Use the accent color for some icons (checkbox, radio, toggle, etc.).
+ color_conversion_map[Color::html("#ff5f5f")] = error_color;
+ color_conversion_map[Color::html("#5fff97")] = success_color;
+ color_conversion_map[Color::html("#ffdd65")] = warning_color;
+
+ // The names of the icons to exclude from the standard color conversion.
+ HashSet<StringName> conversion_exceptions = EditorColorMap::get_color_conversion_exceptions();
+
+ // The names of the icons to exclude when adjusting for saturation.
+ HashSet<StringName> saturation_exceptions;
+ saturation_exceptions.insert("DefaultProjectIcon");
+ saturation_exceptions.insert("Godot");
+ saturation_exceptions.insert("Logo");
+
+ // Accent color conversion map.
+ // It is used on soem icons (checkbox, radio, toggle, etc.), regardless of the dark
+ // or light mode.
HashMap<Color, Color> accent_color_map;
HashSet<StringName> accent_color_icons;
@@ -292,16 +313,14 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
icon = editor_generate_icon(i, EDSCALE, 1.0, accent_color_map);
} else {
float saturation = p_icon_saturation;
-
- if (strcmp(editor_icons_names[i], "DefaultProjectIcon") == 0 || strcmp(editor_icons_names[i], "Godot") == 0 || strcmp(editor_icons_names[i], "Logo") == 0) {
+ if (saturation_exceptions.has(editor_icons_names[i])) {
saturation = 1.0;
}
- const int is_exception = exceptions.has(editor_icons_names[i]);
- if (is_exception) {
+ if (conversion_exceptions.has(editor_icons_names[i])) {
icon = editor_generate_icon(i, EDSCALE, saturation);
} else {
- icon = editor_generate_icon(i, EDSCALE, saturation, icon_color_map);
+ icon = editor_generate_icon(i, EDSCALE, saturation, color_conversion_map);
}
}
@@ -310,19 +329,26 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
}
// Generate thumbnail icons with the given thumbnail size.
- // We don't need filtering when generating at one of the default resolutions.
- const bool force_filter = p_thumb_size != 64 && p_thumb_size != 32;
+ // See editor\icons\editor_icons_builders.py for the code that determines which icons are thumbnails.
if (p_thumb_size >= 64) {
const float scale = (float)p_thumb_size / 64.0 * EDSCALE;
for (int i = 0; i < editor_bg_thumbs_count; i++) {
const int index = editor_bg_thumbs_indices[i];
- const int is_exception = exceptions.has(editor_icons_names[index]);
-
Ref<ImageTexture> icon;
- if (!p_dark_theme && !is_exception) {
- icon = editor_generate_icon(index, scale, force_filter, icon_color_map);
+
+ if (accent_color_icons.has(editor_icons_names[index])) {
+ icon = editor_generate_icon(index, scale, 1.0, accent_color_map);
} else {
- icon = editor_generate_icon(index, scale, force_filter);
+ float saturation = p_icon_saturation;
+ if (saturation_exceptions.has(editor_icons_names[index])) {
+ saturation = 1.0;
+ }
+
+ if (conversion_exceptions.has(editor_icons_names[index])) {
+ icon = editor_generate_icon(index, scale, saturation);
+ } else {
+ icon = editor_generate_icon(index, scale, saturation, color_conversion_map);
+ }
}
p_theme->set_icon(editor_icons_names[index], SNAME("EditorIcons"), icon);
@@ -331,13 +357,21 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
const float scale = (float)p_thumb_size / 32.0 * EDSCALE;
for (int i = 0; i < editor_md_thumbs_count; i++) {
const int index = editor_md_thumbs_indices[i];
- const bool is_exception = exceptions.has(editor_icons_names[index]);
-
Ref<ImageTexture> icon;
- if (!p_dark_theme && !is_exception) {
- icon = editor_generate_icon(index, scale, force_filter, icon_color_map);
+
+ if (accent_color_icons.has(editor_icons_names[index])) {
+ icon = editor_generate_icon(index, scale, 1.0, accent_color_map);
} else {
- icon = editor_generate_icon(index, scale, force_filter);
+ float saturation = p_icon_saturation;
+ if (saturation_exceptions.has(editor_icons_names[index])) {
+ saturation = 1.0;
+ }
+
+ if (conversion_exceptions.has(editor_icons_names[index])) {
+ icon = editor_generate_icon(index, scale, saturation);
+ } else {
+ icon = editor_generate_icon(index, scale, saturation, color_conversion_map);
+ }
}
p_theme->set_icon(editor_icons_names[index], SNAME("EditorIcons"), icon);
@@ -432,7 +466,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
if (dark_theme) {
ImageLoaderSVG::set_forced_color_map(HashMap<Color, Color>());
} else {
- ImageLoaderSVG::set_forced_color_map(EditorColorMap::get());
+ ImageLoaderSVG::set_forced_color_map(EditorColorMap::get_color_conversion_map());
}
#endif
@@ -475,9 +509,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color highlight_color = Color(accent_color.r, accent_color.g, accent_color.b, 0.275);
const Color disabled_highlight_color = highlight_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5);
- float prev_icon_saturation = theme->has_color(SNAME("icon_saturation"), SNAME("Editor")) ? theme->get_color(SNAME("icon_saturation"), SNAME("Editor")).r : 1.0;
-
- theme->set_color("icon_saturation", "Editor", Color(icon_saturation, icon_saturation, icon_saturation)); // can't save single float in theme, so using color
+ // Can't save single float in theme, so using Color.
+ theme->set_color("icon_saturation", "Editor", Color(icon_saturation, icon_saturation, icon_saturation));
theme->set_color("accent_color", "Editor", accent_color);
theme->set_color("highlight_color", "Editor", highlight_color);
theme->set_color("disabled_highlight_color", "Editor", disabled_highlight_color);
@@ -518,7 +551,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Color readonly_warning_color = error_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.25);
if (!dark_theme) {
- // Darken some colors to be readable on a light background
+ // Darken some colors to be readable on a light background.
success_color = success_color.lerp(mono_color, 0.35);
warning_color = warning_color.lerp(mono_color, 0.35);
error_color = error_color.lerp(mono_color, 0.25);
@@ -541,22 +574,43 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("dark_theme", "Editor", dark_theme);
theme->set_constant("color_picker_button_height", "Editor", 28 * EDSCALE);
- // Register icons + font
+ // Register editor icons.
+ // If the settings are comparable to the old theme, then just copy them over.
+ // Otherwise, regenerate them. Also check if we need to regenerate "thumb" icons.
+ bool keep_old_icons = false;
+ bool regenerate_thumb_icons = true;
+ if (p_theme != nullptr) {
+ // We check editor scale, theme dark/light mode, icon saturation, and accent color.
+
+ // That doesn't really work as expected, since theme constants are integers, and scales are floats.
+ // So this check will never work when changing between 100-199% values.
+ const float prev_scale = (float)p_theme->get_constant(SNAME("scale"), SNAME("Editor"));
+ const bool prev_dark_theme = (bool)p_theme->get_constant(SNAME("dark_theme"), SNAME("Editor"));
+ const Color prev_accent_color = p_theme->get_color(SNAME("accent_color"), SNAME("Editor"));
+ const float prev_icon_saturation = p_theme->get_color(SNAME("icon_saturation"), SNAME("Editor")).r;
+
+ keep_old_icons = (Math::is_equal_approx(prev_scale, EDSCALE) &&
+ prev_dark_theme == dark_theme &&
+ prev_accent_color == accent_color &&
+ prev_icon_saturation == icon_saturation);
+
+ const double prev_thumb_size = (double)p_theme->get_constant(SNAME("thumb_size"), SNAME("Editor"));
+
+ regenerate_thumb_icons = !Math::is_equal_approx(prev_thumb_size, thumb_size);
+ }
- // The editor scale, icon color (dark_theme bool), icon saturation, and accent color has not changed, so we do not regenerate the icons.
- if (p_theme != nullptr && fabs(p_theme->get_constant(SNAME("scale"), SNAME("Editor")) - EDSCALE) < 0.00001 && (bool)p_theme->get_constant(SNAME("dark_theme"), SNAME("Editor")) == dark_theme && prev_icon_saturation == icon_saturation && p_theme->get_color(SNAME("accent_color"), SNAME("Editor")) == accent_color) {
- // Register already generated icons.
+ if (keep_old_icons) {
for (int i = 0; i < editor_icons_count; i++) {
theme->set_icon(editor_icons_names[i], SNAME("EditorIcons"), p_theme->get_icon(editor_icons_names[i], SNAME("EditorIcons")));
}
} else {
- editor_register_and_generate_icons(theme, dark_theme, thumb_size, false, icon_saturation);
+ editor_register_and_generate_icons(theme, dark_theme, icon_saturation, thumb_size, false);
}
- // Thumbnail size has changed, so we regenerate the medium sizes
- if (p_theme != nullptr && fabs((double)p_theme->get_constant(SNAME("thumb_size"), SNAME("Editor")) - thumb_size) > 0.00001) {
- editor_register_and_generate_icons(p_theme, dark_theme, thumb_size, true);
+ if (regenerate_thumb_icons) {
+ editor_register_and_generate_icons(theme, dark_theme, icon_saturation, thumb_size, true);
}
+ // Register editor fonts.
editor_register_fonts(theme);
// Ensure borders are visible when using an editor scale below 100%.
diff --git a/editor/editor_themes.h b/editor/editor_themes.h
index 37db8160fa..da5db95d0e 100644
--- a/editor/editor_themes.h
+++ b/editor/editor_themes.h
@@ -39,13 +39,18 @@
class EditorColorMap {
// Godot Color values are used to avoid the ambiguity of strings
// (where "#ffffff", "fff", and "white" are all equivalent).
- static HashMap<Color, Color> editor_color_map;
+ static HashMap<Color, Color> color_conversion_map;
+ // The names of the icons to never convert, even if one of their colors
+ // are contained in the color map from above.
+ static HashSet<StringName> color_conversion_exceptions;
public:
static void create();
- static void add_color_pair(const String p_from_color, const String p_to_color);
+ static void add_conversion_color_pair(const String p_from_color, const String p_to_color);
+ static void add_conversion_exception(const StringName p_icon_name);
- static HashMap<Color, Color> &get() { return editor_color_map; };
+ static HashMap<Color, Color> &get_color_conversion_map() { return color_conversion_map; };
+ static HashSet<StringName> &get_color_conversion_exceptions() { return color_conversion_exceptions; };
};
Ref<Theme> create_editor_theme(Ref<Theme> p_theme = nullptr);
diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp
index 8c04a4d595..064448fd96 100644
--- a/editor/editor_undo_redo_manager.cpp
+++ b/editor/editor_undo_redo_manager.cpp
@@ -131,12 +131,12 @@ void EditorUndoRedoManager::create_action(const String &p_name, UndoRedo::MergeM
void EditorUndoRedoManager::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
- undo_redo->add_do_methodp(p_object, p_method, p_args, p_argcount);
+ undo_redo->add_do_method(Callable(p_object, p_method).bindp(p_args, p_argcount));
}
void EditorUndoRedoManager::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
- undo_redo->add_undo_methodp(p_object, p_method, p_args, p_argcount);
+ undo_redo->add_undo_method(Callable(p_object, p_method).bindp(p_args, p_argcount));
}
void EditorUndoRedoManager::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index bcc85570ed..13ab5cebf6 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -710,7 +710,7 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector
if (type == "PackedScene") { // Its a scene.
Ref<PackedScene> ps = ResourceLoader::load(p_path, "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE);
ERR_FAIL_COND_V(ps.is_null(), p_path);
- Node *node = ps->instantiate();
+ Node *node = ps->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); // Make sure the child scene root gets the correct inheritance chain.
ERR_FAIL_COND_V(node == nullptr, p_path);
if (customize_scenes_plugins.size()) {
for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) {
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index 8c67885971..43aac5e981 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -865,10 +865,10 @@ void ProjectExportDialog::_validate_export_path(const String &p_path) {
if (invalid_path) {
export_project->get_ok_button()->set_disabled(true);
- export_project->get_line_edit()->disconnect("text_submitted", Callable(export_project, "_file_submitted"));
+ export_project->get_line_edit()->disconnect("text_submitted", callable_mp(export_project, &EditorFileDialog::_file_submitted));
} else {
export_project->get_ok_button()->set_disabled(false);
- export_project->get_line_edit()->connect("text_submitted", Callable(export_project, "_file_submitted"));
+ export_project->get_line_edit()->connect("text_submitted", callable_mp(export_project, &EditorFileDialog::_file_submitted));
}
}
@@ -901,9 +901,9 @@ void ProjectExportDialog::_export_project() {
// with _validate_export_path.
// FIXME: This is a hack, we should instead change EditorFileDialog to allow
// disabling validation by the "text_submitted" signal.
- if (!export_project->get_line_edit()->is_connected("text_submitted", Callable(export_project, "_file_submitted"))) {
+ if (!export_project->get_line_edit()->is_connected("text_submitted", callable_mp(export_project, &EditorFileDialog::_file_submitted))) {
export_project->get_ok_button()->set_disabled(false);
- export_project->get_line_edit()->connect("text_submitted", Callable(export_project, "_file_submitted"));
+ export_project->get_line_edit()->connect("text_submitted", callable_mp(export_project, &EditorFileDialog::_file_submitted));
}
export_project->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 19b4932d3d..424eab2f02 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1751,22 +1751,7 @@ void FileSystemDock::_tree_rmb_option(int p_option) {
case FOLDER_COLLAPSE_ALL: {
// Expand or collapse the folder
if (selected_strings.size() == 1) {
- bool is_collapsed = (p_option == FOLDER_COLLAPSE_ALL);
-
- Vector<TreeItem *> needs_check;
- needs_check.push_back(tree->get_selected());
-
- while (needs_check.size()) {
- needs_check[0]->set_collapsed(is_collapsed);
-
- TreeItem *child = needs_check[0]->get_first_child();
- while (child) {
- needs_check.push_back(child);
- child = child->get_next();
- }
-
- needs_check.remove_at(0);
- }
+ tree->get_selected()->set_collapsed_recursive(p_option == FOLDER_COLLAPSE_ALL);
}
} break;
default: {
diff --git a/editor/icons/MemberAnnotation.svg b/editor/icons/MemberAnnotation.svg
index c73ebf7b9b..39bef6d9ee 100644
--- a/editor/icons/MemberAnnotation.svg
+++ b/editor/icons/MemberAnnotation.svg
@@ -1 +1 @@
-<svg width="16" height="16" version="1.0" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><script id="custom-useragent-string-page-script"/><path d="m13.821 12.756c-5.0033 3.9148-12.551 2.248-12.49-4.538 0.67424-11.471 17.312-7.4502 12.446 2.1173-1.0549 1.1955-2.0737 1.4617-3.1983 0.4329-0.21023-0.19282-0.44783-1.1594-0.3819-1.5089 0.35827-1.8946 1.0885-4.0778-0.72151-4.7234-2.4171-0.86457-4.5592 1.6495-4.9697 4.0193-0.47396 2.7343 2.284 3.3749 4.1487 1.9879 0.4553-0.36324 1.6433-1.3796 1.6806-1.9742" fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="1.4928"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13.821 12.756c-5.0033 3.9148-12.551 2.248-12.49-4.538.67424-11.471 17.312-7.4502 12.446 2.1173-1.0549 1.1955-2.0737 1.4617-3.1983.4329-.21023-.19282-.44783-1.1594-.3819-1.5089.35827-1.8946 1.0885-4.0778-.72151-4.7234-2.4171-.86457-4.5592 1.6495-4.9697 4.0193-.47396 2.7343 2.284 3.3749 4.1487 1.9879.4553-.36324 1.6433-1.3796 1.6806-1.9742" fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="1.4928"/></svg>
diff --git a/editor/icons/MethodOverride.svg b/editor/icons/MethodOverride.svg
new file mode 100644
index 0000000000..004b9bf283
--- /dev/null
+++ b/editor/icons/MethodOverride.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 4.2333332 4.2333332" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m.49005985 3.3580432.83285685-.0000001v-.7093212c.0027125-.6681099.2054076-1.1321001 1.0021593-1.1328214h.3207573v-.79375l1.3229167 1.0648649-1.3229167 1.0518017v-.79375h-.3364788c-.2888876 0-.4514151.2436282-.4573001.5980603 0 .2833012.0000193.4455045.0000289.7134508h.79375v.4907171l-2.15577345.00147z" fill="#5fb2ff"/></svg>
diff --git a/editor/icons/MethodOverrideAndSlot.svg b/editor/icons/MethodOverrideAndSlot.svg
new file mode 100644
index 0000000000..d3bd9f0253
--- /dev/null
+++ b/editor/icons/MethodOverrideAndSlot.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 4.2333332 4.2333332" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m.15761184 3.636193h.37155483l.004252-.7093212c.0027092-.6681099.12999225-1.1321001.92674393-1.1328214h.1273374l.0042585-.7357171 1.3186582 1.006832-1.3229167 1.0700676v-.8531081h-.1260545c-.2888876 0-.3972562.2847204-.4031411.6391525 0 .2833012.0000193.4455045.0000289.7134508h1.2412654v.4907171h-2.14198686z" fill="#5fb2ff"/><path d="m2.38125.79375h1.5875v2.6458333h-1.5875v-.5291666h1.0583333v-1.5875h-1.0583333z" fill="#5fff97"/></svg>
diff --git a/editor/icons/VisualScriptComment.svg b/editor/icons/VisualScriptComment.svg
deleted file mode 100644
index 3887853b58..0000000000
--- a/editor/icons/VisualScriptComment.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="14" viewBox="0 0 14 14" width="14" xmlns="http://www.w3.org/2000/svg"><path d="m3 1v2h-2v2h2v4h-2v2h2v2h2v-2h4v2h2v-2h2v-2h-2v-4h2v-2h-2v-2h-2v2h-4v-2zm2 4h4v4h-4z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/VisualScriptExpression.svg b/editor/icons/VisualScriptExpression.svg
deleted file mode 100644
index d6a3c2d9a8..0000000000
--- a/editor/icons/VisualScriptExpression.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m4.859536 3.0412379c-2.0539867 0-3.7190721 1.6650852-3.7190721 3.719072v6.1984521h2.4793814v-2.479381h2.4793814v-2.4793803h-2.4793814v-1.2396908c0-.6846622.5550285-1.2396907 1.2396907-1.2396907h1.2396907v-2.4793813z"/><path d="m7.5889175 3.0000003 2.5000005 4.9999997-2.5000005 5h2.5000005l1.135249-2.727 1.36475 2.727h2.499999l-2.499999-5 2.499999-4.9999997h-2.499999l-1.13525 2.7269998-1.364749-2.7269998zm7.4999985 9.9999997v-6.25z"/></g></svg>
diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp
index d1f37179f3..1e0f45419f 100644
--- a/editor/import/dynamic_font_import_settings.cpp
+++ b/editor/import/dynamic_font_import_settings.cpp
@@ -302,6 +302,7 @@ static UniRange unicode_ranges[] = {
{ 0x10D00, 0x10D3F, U"Hanifi Rohingya" },
{ 0x10E60, 0x10E7F, U"Rumi Numeral Symbols" },
{ 0x10E80, 0x10EBF, U"Yezidi" },
+ { 0x10EC0, 0x10EFF, U"Arabic Extended-C" },
{ 0x10F00, 0x10F2F, U"Old Sogdian" },
{ 0x10F30, 0x10F6F, U"Sogdian" },
{ 0x10F70, 0x10FAF, U"Old Uyghur" },
@@ -333,11 +334,13 @@ static UniRange unicode_ranges[] = {
{ 0x11A50, 0x11AAF, U"Soyombo" },
{ 0x11AB0, 0x11ABF, U"Unified Canadian Aboriginal Syllabics Extended-A" },
{ 0x11AC0, 0x11AFF, U"Pau Cin Hau" },
+ { 0x11B00, 0x11B5F, U"Devanagari Extended-A" },
{ 0x11C00, 0x11C6F, U"Bhaiksuki" },
{ 0x11C70, 0x11CBF, U"Marchen" },
{ 0x11D00, 0x11D5F, U"Masaram Gondi" },
{ 0x11D60, 0x11DAF, U"Gunjala Gondi" },
{ 0x11EE0, 0x11EFF, U"Makasar" },
+ { 0x11F00, 0x11F5F, U"Kawi" },
{ 0x11FB0, 0x11FBF, U"Lisu Supplement" },
{ 0x11FC0, 0x11FFF, U"Tamil Supplement" },
{ 0x12000, 0x123FF, U"Cuneiform" },
@@ -370,6 +373,7 @@ static UniRange unicode_ranges[] = {
{ 0x1D000, 0x1D0FF, U"Byzantine Musical Symbols" },
{ 0x1D100, 0x1D1FF, U"Musical Symbols" },
{ 0x1D200, 0x1D24F, U"Ancient Greek Musical Notation" },
+ { 0x1D2C0, 0x1D2DF, U"Kaktovik Numerals" },
{ 0x1D2E0, 0x1D2FF, U"Mayan Numerals" },
{ 0x1D300, 0x1D35F, U"Tai Xuan Jing Symbols" },
{ 0x1D360, 0x1D37F, U"Counting Rod Numerals" },
@@ -377,9 +381,11 @@ static UniRange unicode_ranges[] = {
{ 0x1D800, 0x1DAAF, U"Sutton SignWriting" },
{ 0x1DF00, 0x1DFFF, U"Latin Extended-G" },
{ 0x1E000, 0x1E02F, U"Glagolitic Supplement" },
+ { 0x1E030, 0x1E08F, U"Cyrillic Extended-D" },
{ 0x1E100, 0x1E14F, U"Nyiakeng Puachue Hmong" },
{ 0x1E290, 0x1E2BF, U"Toto" },
{ 0x1E2C0, 0x1E2FF, U"Wancho" },
+ { 0x1E4D0, 0x1E4FF, U"Nag Mundari" },
{ 0x1E7E0, 0x1E7FF, U"Ethiopic Extended-B" },
{ 0x1E800, 0x1E8DF, U"Mende Kikakui" },
{ 0x1E900, 0x1E95F, U"Adlam" },
@@ -409,6 +415,7 @@ static UniRange unicode_ranges[] = {
{ 0x2CEB0, 0x2EBEF, U"CJK Unified Ideographs Extension F" },
{ 0x2F800, 0x2FA1F, U"CJK Compatibility Ideographs Supplement" },
{ 0x30000, 0x3134F, U"CJK Unified Ideographs Extension G" },
+ { 0x31350, 0x323AF, U"CJK Unified Ideographs Extension H" },
//{ 0xE0000, 0xE007F, U"Tags" },
//{ 0xE0100, 0xE01EF, U"Variation Selectors Supplement" },
{ 0xF0000, 0xFFFFF, U"Supplementary Private Use Area-A" },
@@ -1002,6 +1009,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
vars_list_root = vars_list->create_item();
+ import_settings_data->settings.clear();
import_settings_data->defaults.clear();
for (List<ResourceImporter::ImportOption>::Element *E = options_general.front(); E; E = E->next()) {
import_settings_data->defaults[E->get().option.name] = E->get().default_value;
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 41061c3fc3..b5798a5784 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -1891,6 +1891,39 @@ void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_
}
}
+Array ResourceImporterScene::_get_skinned_pose_transforms(ImporterMeshInstance3D *p_src_mesh_node) {
+ Array skin_pose_transform_array;
+
+ const Ref<Skin> skin = p_src_mesh_node->get_skin();
+ if (skin.is_valid()) {
+ NodePath skeleton_path = p_src_mesh_node->get_skeleton_path();
+ const Node *node = p_src_mesh_node->get_node_or_null(skeleton_path);
+ const Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
+ if (skeleton) {
+ int bind_count = skin->get_bind_count();
+
+ for (int i = 0; i < bind_count; i++) {
+ Transform3D bind_pose = skin->get_bind_pose(i);
+ String bind_name = skin->get_bind_name(i);
+
+ int bone_idx = bind_name.is_empty() ? skin->get_bind_bone(i) : skeleton->find_bone(bind_name);
+ ERR_FAIL_COND_V(bone_idx >= skeleton->get_bone_count(), Array());
+
+ Transform3D bp_global_rest;
+ if (bone_idx >= 0) {
+ bp_global_rest = skeleton->get_bone_global_pose(bone_idx);
+ } else {
+ bp_global_rest = skeleton->get_bone_global_pose(i);
+ }
+
+ skin_pose_transform_array.push_back(bp_global_rest * bind_pose);
+ }
+ }
+ }
+
+ return skin_pose_transform_array;
+}
+
void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches) {
ImporterMeshInstance3D *src_mesh_node = Object::cast_to<ImporterMeshInstance3D>(p_node);
if (src_mesh_node) {
@@ -2007,7 +2040,8 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m
}
if (generate_lods) {
- src_mesh_node->get_mesh()->generate_lods(merge_angle, split_angle);
+ Array skin_pose_transform_array = _get_skinned_pose_transforms(src_mesh_node);
+ src_mesh_node->get_mesh()->generate_lods(merge_angle, split_angle, skin_pose_transform_array);
}
if (create_shadow_meshes) {
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index da37893cc5..386519bc59 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -34,11 +34,14 @@
#include "core/error/error_macros.h"
#include "core/io/resource_importer.h"
#include "core/variant/dictionary.h"
-#include "scene/3d/node_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/resources/animation.h"
+#include "scene/resources/box_shape_3d.h"
+#include "scene/resources/capsule_shape_3d.h"
+#include "scene/resources/cylinder_shape_3d.h"
#include "scene/resources/mesh.h"
#include "scene/resources/shape_3d.h"
-#include "scene/resources/skin.h"
+#include "scene/resources/sphere_shape_3d.h"
class Material;
class AnimationPlayer;
@@ -208,6 +211,7 @@ class ResourceImporterScene : public ResourceImporter {
SHAPE_TYPE_CAPSULE,
};
+ Array _get_skinned_pose_transforms(ImporterMeshInstance3D *p_src_mesh_node);
void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner);
void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches);
void _add_shapes(Node *p_node, const Vector<Ref<Shape3D>> &p_shapes);
@@ -309,11 +313,6 @@ public:
virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
};
-#include "scene/resources/box_shape_3d.h"
-#include "scene/resources/capsule_shape_3d.h"
-#include "scene/resources/cylinder_shape_3d.h"
-#include "scene/resources/sphere_shape_3d.h"
-
template <class M>
Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh> &p_mesh, const M &p_options) {
ShapeType generate_shape_type = SHAPE_TYPE_DECOMPOSE_CONVEX;
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index f4b8646e18..ca7b2d0015 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -101,13 +101,13 @@ void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_propert
undo_redo->create_action(TTR("Parameter Changed:") + " " + String(p_property), UndoRedo::MERGE_ENDS);
undo_redo->add_do_property(tree, p_property, p_value);
undo_redo->add_undo_property(tree, p_property, tree->get(p_property));
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
updating = false;
}
-void AnimationNodeBlendTreeEditor::_update_graph() {
+void AnimationNodeBlendTreeEditor::update_graph() {
if (updating || blend_tree.is_null()) {
return;
}
@@ -364,8 +364,8 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
to_slot = -1;
}
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
}
@@ -416,8 +416,8 @@ void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Ve
undo_redo->create_action(TTR("Node Moved"));
undo_redo->add_do_method(blend_tree.ptr(), "set_node_position", p_which, p_to / EDSCALE);
undo_redo->add_undo_method(blend_tree.ptr(), "set_node_position", p_which, p_from / EDSCALE);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
updating = false;
}
@@ -437,8 +437,8 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int
undo_redo->create_action(TTR("Nodes Connected"));
undo_redo->add_do_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from);
undo_redo->add_undo_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
}
@@ -453,8 +453,8 @@ void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from,
undo_redo->create_action(TTR("Nodes Disconnected"));
undo_redo->add_do_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index);
undo_redo->add_undo_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
updating = false;
}
@@ -468,8 +468,8 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options,
undo_redo->create_action(TTR("Set Animation"));
undo_redo->add_do_method(anim.ptr(), "set_animation", option);
undo_redo->add_undo_method(anim.ptr(), "set_animation", anim->get_animation());
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
}
@@ -491,8 +491,8 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
}
}
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
}
@@ -819,7 +819,7 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
_update_theme();
if (is_visible_in_tree()) {
- _update_graph();
+ update_graph();
}
} break;
@@ -900,12 +900,23 @@ void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) {
}
void AnimationNodeBlendTreeEditor::_bind_methods() {
- ClassDB::bind_method("_update_graph", &AnimationNodeBlendTreeEditor::_update_graph);
+ ClassDB::bind_method("update_graph", &AnimationNodeBlendTreeEditor::update_graph);
ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters);
}
AnimationNodeBlendTreeEditor *AnimationNodeBlendTreeEditor::singleton = nullptr;
+// AnimationNode's "node_changed" signal means almost update_input.
+void AnimationNodeBlendTreeEditor::_node_changed(const StringName &p_node_name) {
+ // TODO:
+ // Here is executed during the commit of EditorNode::undo_redo, it is not possible to create an undo_redo action here.
+ // The disconnect when the number of enabled inputs decreases is done in AnimationNodeBlendTree and update_graph().
+ // This means that there is no place to register undo_redo actions.
+ // In order to implement undo_redo correctly, we may need to implement AnimationNodeEdit such as AnimationTrackKeyEdit
+ // and add it to _node_selected() with EditorNode::get_singleton()->push_item(AnimationNodeEdit).
+ update_graph();
+}
+
void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<AnimationNode> p_node) {
if (blend_tree.is_null()) {
return;
@@ -940,8 +951,8 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name);
undo_redo->add_do_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + prev_name, base_path + name);
undo_redo->add_undo_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + name, base_path + prev_name);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
updating = false;
gn->set_name(new_name);
@@ -979,7 +990,7 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
}
}
- _update_graph(); // Needed to update the signal connections with the new name.
+ update_graph(); // Needed to update the signal connections with the new name.
}
void AnimationNodeBlendTreeEditor::_node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node) {
@@ -996,6 +1007,7 @@ bool AnimationNodeBlendTreeEditor::can_edit(const Ref<AnimationNode> &p_node) {
void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
if (blend_tree.is_valid()) {
+ blend_tree->disconnect("node_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_changed));
blend_tree->disconnect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph));
}
@@ -1008,9 +1020,10 @@ void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
} else {
read_only = EditorNode::get_singleton()->is_resource_read_only(blend_tree);
+ blend_tree->connect("node_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_changed));
blend_tree->connect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph));
- _update_graph();
+ update_graph();
}
add_node->set_disabled(read_only);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index 30a54930a2..46e0d18c69 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -71,8 +71,6 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
int to_slot = -1;
String from_node = "";
- void _update_graph();
-
struct AddOption {
String name;
String type;
@@ -95,6 +93,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which);
void _node_renamed(const String &p_text, Ref<AnimationNode> p_node);
void _node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node);
+ void _node_changed(const StringName &p_node_name);
bool updating;
@@ -150,6 +149,8 @@ public:
virtual bool can_edit(const Ref<AnimationNode> &p_node) override;
virtual void edit(const Ref<AnimationNode> &p_node) override;
+ void update_graph();
+
AnimationNodeBlendTreeEditor();
};
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index ed231c446b..1de4fbaabc 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -50,10 +50,18 @@
#include "scene/scene_string_names.h"
void AnimationTreeEditor::edit(AnimationTree *p_tree) {
+ if (p_tree && !p_tree->is_connected("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) {
+ p_tree->connect("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed), CONNECT_DEFERRED);
+ }
+
if (tree == p_tree) {
return;
}
+ if (tree && tree->is_connected("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) {
+ tree->disconnect("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed));
+ }
+
tree = p_tree;
Vector<String> path;
@@ -73,6 +81,13 @@ void AnimationTreeEditor::_path_button_pressed(int p_path) {
}
}
+void AnimationTreeEditor::_animation_list_changed() {
+ AnimationNodeBlendTreeEditor *bte = AnimationNodeBlendTreeEditor::get_singleton();
+ if (bte) {
+ bte->update_graph();
+ }
+}
+
void AnimationTreeEditor::_update_path() {
while (path_hb->get_child_count() > 1) {
memdelete(path_hb->get_child(1));
diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h
index a33d97f62f..9ef9fff8cd 100644
--- a/editor/plugins/animation_tree_editor_plugin.h
+++ b/editor/plugins/animation_tree_editor_plugin.h
@@ -65,6 +65,7 @@ class AnimationTreeEditor : public VBoxContainer {
ObjectID current_root;
void _path_button_pressed(int p_path);
+ void _animation_list_changed();
static Vector<String> get_animation_list();
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 070834b33b..8dc08e3a93 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -4715,12 +4715,10 @@ void CanvasItemEditor::_reset_drag() {
}
void CanvasItemEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_override_camera_button", "game_running"), &CanvasItemEditor::_update_override_camera_button);
ClassDB::bind_method("_get_editor_data", &CanvasItemEditor::_get_editor_data);
ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state);
ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport);
- ClassDB::bind_method(D_METHOD("_zoom_on_position"), &CanvasItemEditor::_zoom_on_position);
ClassDB::bind_method("_set_owner_for_node_and_children", &CanvasItemEditor::_set_owner_for_node_and_children);
@@ -4984,8 +4982,8 @@ CanvasItemEditor::CanvasItemEditor() {
SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created));
SceneTreeDock::get_singleton()->connect("add_node_used", callable_mp(this, &CanvasItemEditor::_reset_create_position));
- EditorNode::get_singleton()->call_deferred(SNAME("connect"), "play_pressed", Callable(this, "_update_override_camera_button").bind(true));
- EditorNode::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", Callable(this, "_update_override_camera_button").bind(false));
+ EditorNode::get_singleton()->call_deferred(SNAME("connect"), callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true));
+ EditorNode::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false));
// A fluid container for all toolbars.
HFlowContainer *main_flow = memnew(HFlowContainer);
@@ -5883,9 +5881,6 @@ void CanvasItemEditorViewport::_notification(int p_what) {
}
}
-void CanvasItemEditorViewport::_bind_methods() {
-}
-
CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_item_editor) {
default_texture_node_type = "Sprite2D";
// Node2D
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 0a840d6fd6..b731d3cc7d 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -618,8 +618,6 @@ class CanvasItemEditorViewport : public Control {
void _show_resource_type_selector();
void _update_theme();
- static void _bind_methods();
-
protected:
void _notification(int p_what);
diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp
index 2df951518e..ba11479714 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -622,6 +622,16 @@ void EditorPropertyOTFeatures::update_property() {
supported = fd->get_supported_feature_list();
}
+ if (supported.is_empty()) {
+ edit->set_text(vformat(TTR("No supported features")));
+ if (container) {
+ set_bottom_editor(nullptr);
+ memdelete(container);
+ button_add = nullptr;
+ container = nullptr;
+ }
+ return;
+ }
edit->set_text(vformat(TTR("Features (%d of %d set)"), dict.size(), supported.size()));
bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property());
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index c8b49678d2..33aad0ac61 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -7645,6 +7645,7 @@ void Node3DEditor::_update_preview_environment() {
preview_sun->get_parent()->remove_child(preview_sun);
sun_state->show();
sun_vb->hide();
+ preview_sun_dangling = true;
}
if (directional_light_count > 0) {
@@ -7658,6 +7659,7 @@ void Node3DEditor::_update_preview_environment() {
add_child(preview_sun, true);
sun_state->hide();
sun_vb->show();
+ preview_sun_dangling = false;
}
}
@@ -7673,6 +7675,7 @@ void Node3DEditor::_update_preview_environment() {
preview_environment->get_parent()->remove_child(preview_environment);
environ_state->show();
environ_vb->hide();
+ preview_env_dangling = true;
}
if (world_env_count > 0) {
environ_state->set_text(TTR("Scene contains\nWorldEnvironment.\nPreview disabled."));
@@ -7685,6 +7688,7 @@ void Node3DEditor::_update_preview_environment() {
add_child(preview_environment);
environ_state->hide();
environ_vb->show();
+ preview_env_dangling = false;
}
}
}
@@ -7854,7 +7858,6 @@ Node3DEditor::Node3DEditor() {
sun_button->set_toggle_mode(true);
sun_button->set_flat(true);
sun_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED);
- sun_button->set_disabled(true);
// Preview is enabled by default - ensure this applies on editor startup when there is no state yet.
sun_button->set_pressed(true);
@@ -7865,7 +7868,6 @@ Node3DEditor::Node3DEditor() {
environ_button->set_toggle_mode(true);
environ_button->set_flat(true);
environ_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED);
- environ_button->set_disabled(true);
// Preview is enabled by default - ensure this applies on editor startup when there is no state yet.
environ_button->set_pressed(true);
@@ -8333,6 +8335,12 @@ void fragment() {
}
Node3DEditor::~Node3DEditor() {
memdelete(preview_node);
+ if (preview_sun_dangling && preview_sun) {
+ memdelete(preview_sun);
+ }
+ if (preview_env_dangling && preview_environment) {
+ memdelete(preview_environment);
+ }
}
void Node3DEditorPlugin::make_visible(bool p_visible) {
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 580cb878ce..c76f534c22 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -763,7 +763,9 @@ private:
Button *sun_environ_settings = nullptr;
DirectionalLight3D *preview_sun = nullptr;
+ bool preview_sun_dangling = false;
WorldEnvironment *preview_environment = nullptr;
+ bool preview_env_dangling = false;
Ref<Environment> environment;
Ref<CameraAttributesPhysical> camera_attributes;
Ref<ProceduralSkyMaterial> sky_material;
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 0a111aeb49..3679657567 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -227,6 +227,7 @@ void ScriptEditorBase::_bind_methods() {
// TODO: This signal is no use for VisualScript.
ADD_SIGNAL(MethodInfo("search_in_files_requested", PropertyInfo(Variant::STRING, "text")));
ADD_SIGNAL(MethodInfo("replace_in_files_requested", PropertyInfo(Variant::STRING, "text")));
+ ADD_SIGNAL(MethodInfo("go_to_method", PropertyInfo(Variant::OBJECT, "script"), PropertyInfo(Variant::STRING, "method")));
}
class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache {
@@ -2380,6 +2381,7 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
se->connect("request_save_history", callable_mp(this, &ScriptEditor::_save_history));
se->connect("search_in_files_requested", callable_mp(this, &ScriptEditor::_on_find_in_files_requested));
se->connect("replace_in_files_requested", callable_mp(this, &ScriptEditor::_on_replace_in_files_requested));
+ se->connect("go_to_method", callable_mp(this, &ScriptEditor::script_goto_method));
//test for modification, maybe the script was not edited but was loaded
@@ -2544,7 +2546,7 @@ void ScriptEditor::apply_scripts() const {
}
}
-void ScriptEditor::reload_scripts() {
+void ScriptEditor::reload_scripts(bool p_refresh_only) {
for (int i = 0; i < tab_container->get_tab_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
@@ -2557,30 +2559,33 @@ void ScriptEditor::reload_scripts() {
continue; //internal script, who cares
}
- uint64_t last_date = edited_res->get_last_modified_time();
- uint64_t date = FileAccess::get_modified_time(edited_res->get_path());
+ if (!p_refresh_only) {
+ uint64_t last_date = edited_res->get_last_modified_time();
+ uint64_t date = FileAccess::get_modified_time(edited_res->get_path());
- if (last_date == date) {
- continue;
- }
+ if (last_date == date) {
+ continue;
+ }
- Ref<Script> script = edited_res;
- if (script != nullptr) {
- Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
- ERR_CONTINUE(!rel_script.is_valid());
- script->set_source_code(rel_script->get_source_code());
- script->set_last_modified_time(rel_script->get_last_modified_time());
- script->reload(true);
- }
+ Ref<Script> script = edited_res;
+ if (script != nullptr) {
+ Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_CONTINUE(!rel_script.is_valid());
+ script->set_source_code(rel_script->get_source_code());
+ script->set_last_modified_time(rel_script->get_last_modified_time());
+ script->reload(true);
+ }
- Ref<TextFile> text_file = edited_res;
- if (text_file != nullptr) {
- Error err;
- Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err);
- ERR_CONTINUE(!rel_text_file.is_valid());
- text_file->set_text(rel_text_file->get_text());
- text_file->set_last_modified_time(rel_text_file->get_last_modified_time());
+ Ref<TextFile> text_file = edited_res;
+ if (text_file != nullptr) {
+ Error err;
+ Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err);
+ ERR_CONTINUE(!rel_text_file.is_valid());
+ text_file->set_text(rel_text_file->get_text());
+ text_file->set_last_modified_time(rel_text_file->get_last_modified_time());
+ }
}
+
se->reload_text();
}
@@ -3059,26 +3064,15 @@ void ScriptEditor::shortcut_input(const Ref<InputEvent> &p_event) {
}
}
-void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) {
- Ref<InputEventMouseButton> mb = ev;
- if (mb.is_valid() && mb->is_pressed()) {
- switch (mb->get_button_index()) {
- case MouseButton::MIDDLE: {
- // Right-click selects automatically; middle-click does not.
- int idx = script_list->get_item_at_position(mb->get_position(), true);
- if (idx >= 0) {
- script_list->select(idx);
- _script_selected(idx);
- _menu_option(FILE_CLOSE);
- }
- } break;
+void ScriptEditor::_script_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index) {
+ if (p_mouse_button_index == MouseButton::MIDDLE) {
+ script_list->select(p_item);
+ _script_selected(p_item);
+ _menu_option(FILE_CLOSE);
+ }
- case MouseButton::RIGHT: {
- _make_script_list_context_menu();
- } break;
- default:
- break;
- }
+ if (p_mouse_button_index == MouseButton::RIGHT) {
+ _make_script_list_context_menu();
}
}
@@ -3688,7 +3682,7 @@ ScriptEditor::ScriptEditor() {
script_list->set_v_size_flags(SIZE_EXPAND_FILL);
script_split->set_split_offset(70 * EDSCALE);
_sort_list_on_update = true;
- script_list->connect("gui_input", callable_mp(this, &ScriptEditor::_script_list_gui_input), CONNECT_DEFERRED);
+ script_list->connect("item_clicked", callable_mp(this, &ScriptEditor::_script_list_clicked), CONNECT_DEFERRED);
script_list->set_allow_rmb_select(true);
script_list->set_drag_forwarding(this);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index a8e6cc6868..1e78dc4ec4 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -426,7 +426,7 @@ class ScriptEditor : public PanelContainer {
virtual void input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
- void _script_list_gui_input(const Ref<InputEvent> &ev);
+ void _script_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index);
void _make_script_list_context_menu();
void _help_search(String p_text);
@@ -477,7 +477,7 @@ public:
bool toggle_scripts_panel();
bool is_scripts_panel_toggled();
void apply_scripts() const;
- void reload_scripts();
+ void reload_scripts(bool p_refresh_only = false);
void open_script_create_dialog(const String &p_base_name, const String &p_base_path);
void open_text_file_create_dialog(const String &p_base_path, const String &p_base_name = "");
Ref<Resource> open_file(const String &p_file);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 42dcfb8b1f..7a57f8a1e2 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -956,10 +956,7 @@ void ScriptTextEditor::_update_connected_methods() {
CodeEdit *text_edit = code_editor->get_text_editor();
text_edit->set_gutter_width(connection_gutter, text_edit->get_line_height());
for (int i = 0; i < text_edit->get_line_count(); i++) {
- if (text_edit->get_line_gutter_metadata(i, connection_gutter) == "") {
- continue;
- }
- text_edit->set_line_gutter_metadata(i, connection_gutter, "");
+ text_edit->set_line_gutter_metadata(i, connection_gutter, Dictionary());
text_edit->set_line_gutter_icon(i, connection_gutter, nullptr);
text_edit->set_line_gutter_clickable(i, connection_gutter, false);
}
@@ -974,6 +971,7 @@ void ScriptTextEditor::_update_connected_methods() {
return;
}
+ // Add connection icons to methods.
Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
HashSet<StringName> methods_found;
for (int i = 0; i < nodes.size(); i++) {
@@ -1002,8 +1000,11 @@ void ScriptTextEditor::_update_connected_methods() {
for (int j = 0; j < functions.size(); j++) {
String name = functions[j].get_slice(":", 0);
if (name == method) {
+ Dictionary line_meta;
+ line_meta["type"] = "connection";
+ line_meta["method"] = method;
line = functions[j].get_slice(":", 1).to_int() - 1;
- text_edit->set_line_gutter_metadata(line, connection_gutter, method);
+ text_edit->set_line_gutter_metadata(line, connection_gutter, line_meta);
text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("Slot"), SNAME("EditorIcons")));
text_edit->set_line_gutter_clickable(line, connection_gutter, true);
methods_found.insert(method);
@@ -1033,6 +1034,58 @@ void ScriptTextEditor::_update_connected_methods() {
}
}
}
+
+ // Add override icons to methods.
+ methods_found.clear();
+ for (int i = 0; i < functions.size(); i++) {
+ StringName name = StringName(functions[i].get_slice(":", 0));
+ if (methods_found.has(name)) {
+ continue;
+ }
+
+ String found_base_class;
+ StringName base_class = script->get_instance_base_type();
+ Ref<Script> inherited_script = script->get_base_script();
+ while (!inherited_script.is_null()) {
+ if (inherited_script->has_method(name)) {
+ found_base_class = "script:" + inherited_script->get_path();
+ break;
+ }
+
+ base_class = inherited_script->get_instance_base_type();
+ inherited_script = inherited_script->get_base_script();
+ }
+
+ if (found_base_class.is_empty() && base_class) {
+ List<MethodInfo> methods;
+ ClassDB::get_method_list(base_class, &methods);
+ for (int j = 0; j < methods.size(); j++) {
+ if (methods[j].name == name) {
+ found_base_class = "builtin:" + base_class;
+ break;
+ }
+ }
+ }
+
+ if (!found_base_class.is_empty()) {
+ int line = functions[i].get_slice(":", 1).to_int() - 1;
+
+ Dictionary line_meta = text_edit->get_line_gutter_metadata(line, connection_gutter);
+ if (line_meta.is_empty()) {
+ // Add override icon to gutter.
+ line_meta["type"] = "inherits";
+ line_meta["method"] = name;
+ line_meta["base_class"] = found_base_class;
+ text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("MethodOverride"), SNAME("EditorIcons")));
+ text_edit->set_line_gutter_clickable(line, connection_gutter, true);
+ } else {
+ // If method is also connected to signal, then merge icons and keep the click behavior of the slot.
+ text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("MethodOverrideAndSlot"), SNAME("EditorIcons")));
+ }
+
+ methods_found.insert(name);
+ }
+ }
}
void ScriptTextEditor::_update_gutter_indexes() {
@@ -1054,18 +1107,40 @@ void ScriptTextEditor::_gutter_clicked(int p_line, int p_gutter) {
return;
}
- String method = code_editor->get_text_editor()->get_line_gutter_metadata(p_line, p_gutter);
- if (method.is_empty()) {
+ Dictionary meta = code_editor->get_text_editor()->get_line_gutter_metadata(p_line, p_gutter);
+ String type = meta.get("type", "");
+ if (type.is_empty()) {
return;
}
- Node *base = get_tree()->get_edited_scene_root();
- if (!base) {
+ // All types currently need a method name.
+ String method = meta.get("method", "");
+ if (method.is_empty()) {
return;
}
- Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
- connection_info_dialog->popup_connections(method, nodes);
+ if (type == "connection") {
+ Node *base = get_tree()->get_edited_scene_root();
+ if (!base) {
+ return;
+ }
+
+ Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
+ connection_info_dialog->popup_connections(method, nodes);
+ } else if (type == "inherits") {
+ String base_class_raw = meta["base_class"];
+ PackedStringArray base_class_split = base_class_raw.split(":", true, 1);
+
+ if (base_class_split[0] == "script") {
+ // Go to function declaration.
+ Ref<Script> base_script = ResourceLoader::load(base_class_split[1]);
+ ERR_FAIL_COND(!base_script.is_valid());
+ emit_signal(SNAME("go_to_method"), base_script, method);
+ } else if (base_class_split[0] == "builtin") {
+ // Open method documentation.
+ emit_signal(SNAME("go_to_help"), "class_method:" + base_class_split[1] + ":" + method);
+ }
+ }
}
void ScriptTextEditor::_edit_option(int p_op) {
@@ -1487,16 +1562,17 @@ bool ScriptTextEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_
}
static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
- if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) {
- return nullptr;
- }
-
- Ref<Script> scr = p_current_node->get_script();
-
- if (scr.is_valid() && scr == script) {
- return p_current_node;
+ // Check scripts only for the nodes belonging to the edited scene.
+ if (p_current_node == p_edited_scene || p_current_node->get_owner() == p_edited_scene) {
+ Ref<Script> scr = p_current_node->get_script();
+ if (scr.is_valid() && scr == script) {
+ return p_current_node;
+ }
}
+ // Traverse all children, even the ones not owned by the edited scene as they
+ // can still have child nodes added within the edited scene and thus owned by
+ // it (e.g. nodes added to subscene's root or to its editable children).
for (int i = 0; i < p_current_node->get_child_count(); i++) {
Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script);
if (n) {
@@ -1558,8 +1634,13 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
}
if (d.has("type") && String(d["type"]) == "nodes") {
- Node *sn = _find_script_node(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root(), script);
+ Node *scene_root = get_tree()->get_edited_scene_root();
+ if (!scene_root) {
+ EditorNode::get_singleton()->show_warning(TTR("Can't drop nodes without an open scene."));
+ return;
+ }
+ Node *sn = _find_script_node(scene_root, scene_root, script);
if (!sn) {
EditorNode::get_singleton()->show_warning(vformat(TTR("Can't drop nodes because script '%s' is not used in this scene."), get_name()));
return;
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 246bc4b183..ae3c578eaa 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -1366,6 +1366,7 @@ void ShaderEditorPlugin::_shader_selected(int p_index) {
edited_shaders[p_index].shader_editor->validate_script();
}
shader_tabs->set_current_tab(p_index);
+ shader_list->select(p_index);
}
void ShaderEditorPlugin::_shader_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index) {
@@ -1375,11 +1376,10 @@ void ShaderEditorPlugin::_shader_list_clicked(int p_item, Vector2 p_local_mouse_
}
void ShaderEditorPlugin::_close_shader(int p_index) {
- int index = shader_tabs->get_current_tab();
- ERR_FAIL_INDEX(index, shader_tabs->get_tab_count());
- Control *c = shader_tabs->get_tab_control(index);
+ ERR_FAIL_INDEX(p_index, shader_tabs->get_tab_count());
+ Control *c = shader_tabs->get_tab_control(p_index);
memdelete(c);
- edited_shaders.remove_at(index);
+ edited_shaders.remove_at(p_index);
_update_shader_list();
EditorNode::get_singleton()->get_undo_redo()->clear_history(); // To prevent undo on deleted graphs.
}
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index ae21aad337..d0a1ddafa1 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -984,11 +984,17 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) {
}
void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
- if (frames == p_frames) {
+ bool new_read_only_state = false;
+ if (p_frames) {
+ new_read_only_state = EditorNode::get_singleton()->is_resource_read_only(p_frames);
+ }
+
+ if (frames == p_frames && new_read_only_state == read_only) {
return;
}
frames = p_frames;
+ read_only = new_read_only_state;
if (p_frames) {
if (!p_frames->has_animation(edited_anim)) {
@@ -1009,6 +1015,20 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
} else {
hide();
}
+
+ new_anim->set_disabled(read_only);
+ remove_anim->set_disabled(read_only);
+ anim_speed->set_editable(!read_only);
+ anim_loop->set_disabled(read_only);
+ load->set_disabled(read_only);
+ load_sheet->set_disabled(read_only);
+ copy->set_disabled(read_only);
+ paste->set_disabled(read_only);
+ empty->set_disabled(read_only);
+ empty2->set_disabled(read_only);
+ move_up->set_disabled(read_only);
+ move_down->set_disabled(read_only);
+ _delete->set_disabled(read_only);
}
void SpriteFramesEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
@@ -1016,6 +1036,10 @@ void SpriteFramesEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
}
Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+ if (read_only) {
+ return false;
+ }
+
if (!frames->has_animation(edited_anim)) {
return false;
}
@@ -1038,6 +1062,10 @@ Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_f
}
bool SpriteFramesEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ if (read_only) {
+ return false;
+ }
+
Dictionary d = p_data;
if (!d.has("type")) {
@@ -1169,6 +1197,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
remove_anim->set_flat(true);
remove_anim->set_tooltip_text(TTR("Remove Animation"));
hbc_animlist->add_child(remove_anim);
+ remove_anim->set_disabled(true);
remove_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_remove));
anim_search_box = memnew(LineEdit);
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index f2530b732f..092f556c63 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -57,6 +57,8 @@ class SpriteFramesEditor : public HSplitContainer {
};
int dominant_param = PARAM_FRAME_COUNT;
+ bool read_only = false;
+
Button *load = nullptr;
Button *load_sheet = nullptr;
Button *_delete = nullptr;
diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp
index 3ea62184c6..4b2f28658a 100644
--- a/editor/plugins/texture_3d_editor_plugin.cpp
+++ b/editor/plugins/texture_3d_editor_plugin.cpp
@@ -138,10 +138,6 @@ void Texture3DEditor::edit(Ref<Texture3D> p_texture) {
}
}
-void Texture3DEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_layer_changed"), &Texture3DEditor::_layer_changed);
-}
-
Texture3DEditor::Texture3DEditor() {
set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
set_custom_minimum_size(Size2(1, 150));
@@ -173,7 +169,7 @@ Texture3DEditor::Texture3DEditor() {
info->add_theme_constant_override("shadow_offset_y", 2);
setting = false;
- layer->connect("value_changed", Callable(this, "_layer_changed"));
+ layer->connect("value_changed", callable_mp(this, &Texture3DEditor::_layer_changed));
}
Texture3DEditor::~Texture3DEditor() {
diff --git a/editor/plugins/texture_3d_editor_plugin.h b/editor/plugins/texture_3d_editor_plugin.h
index 357bdb0845..7795c83c8a 100644
--- a/editor/plugins/texture_3d_editor_plugin.h
+++ b/editor/plugins/texture_3d_editor_plugin.h
@@ -66,8 +66,6 @@ class Texture3DEditor : public Control {
protected:
void _notification(int p_what);
- static void _bind_methods();
-
public:
void edit(Ref<Texture3D> p_texture);
Texture3DEditor();
diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp
index dd8633360e..b0a174c1bc 100644
--- a/editor/plugins/texture_layered_editor_plugin.cpp
+++ b/editor/plugins/texture_layered_editor_plugin.cpp
@@ -214,10 +214,6 @@ void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) {
}
}
-void TextureLayeredEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_layer_changed"), &TextureLayeredEditor::_layer_changed);
-}
-
TextureLayeredEditor::TextureLayeredEditor() {
set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
set_custom_minimum_size(Size2(1, 150));
@@ -249,7 +245,7 @@ TextureLayeredEditor::TextureLayeredEditor() {
info->add_theme_constant_override("shadow_offset_y", 2);
setting = false;
- layer->connect("value_changed", Callable(this, "_layer_changed"));
+ layer->connect("value_changed", callable_mp(this, &TextureLayeredEditor::_layer_changed));
}
TextureLayeredEditor::~TextureLayeredEditor() {
diff --git a/editor/plugins/texture_layered_editor_plugin.h b/editor/plugins/texture_layered_editor_plugin.h
index f49aa83eb2..f4dbc104c8 100644
--- a/editor/plugins/texture_layered_editor_plugin.h
+++ b/editor/plugins/texture_layered_editor_plugin.h
@@ -68,7 +68,6 @@ class TextureLayeredEditor : public Control {
protected:
void _notification(int p_what);
virtual void gui_input(const Ref<InputEvent> &p_event) override;
- static void _bind_methods();
public:
void edit(Ref<TextureLayered> p_texture);
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 1fb9b42449..e2ed8e44c4 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -134,7 +134,7 @@ void ThemeItemImportTree::_update_items_tree() {
data_type_node->set_checked(IMPORT_ITEM_DATA, false);
data_type_node->set_editable(IMPORT_ITEM_DATA, true);
- List<TreeItem *> *item_list;
+ List<TreeItem *> *item_list = nullptr;
switch (dt) {
case Theme::DATA_TYPE_COLOR:
@@ -398,7 +398,7 @@ void ThemeItemImportTree::_restore_selected_item(TreeItem *p_tree_item) {
void ThemeItemImportTree::_update_total_selected(Theme::DataType p_data_type) {
ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
- Label *total_selected_items_label;
+ Label *total_selected_items_label = nullptr;
switch (p_data_type) {
case Theme::DATA_TYPE_COLOR:
total_selected_items_label = total_selected_colors_label;
@@ -562,7 +562,7 @@ void ThemeItemImportTree::_select_all_data_type_pressed(int p_data_type) {
}
Theme::DataType data_type = (Theme::DataType)p_data_type;
- List<TreeItem *> *item_list;
+ List<TreeItem *> *item_list = nullptr;
switch (data_type) {
case Theme::DATA_TYPE_COLOR:
@@ -617,7 +617,7 @@ void ThemeItemImportTree::_select_full_data_type_pressed(int p_data_type) {
}
Theme::DataType data_type = (Theme::DataType)p_data_type;
- List<TreeItem *> *item_list;
+ List<TreeItem *> *item_list = nullptr;
switch (data_type) {
case Theme::DATA_TYPE_COLOR:
@@ -674,7 +674,7 @@ void ThemeItemImportTree::_deselect_all_data_type_pressed(int p_data_type) {
}
Theme::DataType data_type = (Theme::DataType)p_data_type;
- List<TreeItem *> *item_list;
+ List<TreeItem *> *item_list = nullptr;
switch (data_type) {
case Theme::DATA_TYPE_COLOR:
@@ -982,17 +982,17 @@ ThemeItemImportTree::ThemeItemImportTree() {
for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {
Theme::DataType dt = (Theme::DataType)i;
- TextureRect *select_items_icon;
- Label *select_items_label;
- Button *deselect_all_items_button;
- Button *select_all_items_button;
- Button *select_full_items_button;
- Label *total_selected_items_label;
-
- String items_title = "";
- String select_all_items_tooltip = "";
- String select_full_items_tooltip = "";
- String deselect_all_items_tooltip = "";
+ TextureRect *select_items_icon = nullptr;
+ Label *select_items_label = nullptr;
+ Button *deselect_all_items_button = nullptr;
+ Button *select_all_items_button = nullptr;
+ Button *select_full_items_button = nullptr;
+ Label *total_selected_items_label = nullptr;
+
+ String items_title;
+ String select_all_items_tooltip;
+ String select_full_items_tooltip;
+ String deselect_all_items_tooltip;
switch (dt) {
case Theme::DATA_TYPE_COLOR:
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index d9291503cb..c823487279 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -403,6 +403,9 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_
// Update everything.
_update_zoom_and_panning();
+ base_tiles_drawing_root->set_size(_compute_base_tiles_control_size());
+ alternative_tiles_drawing_root->set_size(_compute_alternative_tiles_control_size());
+
// Update.
base_tiles_draw->queue_redraw();
base_tiles_texture_grid->queue_redraw();
@@ -601,7 +604,6 @@ TileAtlasView::TileAtlasView() {
base_tiles_drawing_root = memnew(Control);
base_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
- base_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
base_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
base_tiles_root_control->add_child(base_tiles_drawing_root);
@@ -645,7 +647,6 @@ TileAtlasView::TileAtlasView() {
alternative_tiles_drawing_root = memnew(Control);
alternative_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
- alternative_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
alternative_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
alternative_tiles_root_control->add_child(alternative_tiles_drawing_root);
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 228e475083..45b2a5eb14 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -401,7 +401,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro
if (all_alternatve_id_zero) {
p_list->push_back(PropertyInfo(Variant::NIL, "Animation", PROPERTY_HINT_NONE, "animation_", PROPERTY_USAGE_GROUP));
p_list->push_back(PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, ""));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "animation_separation", PROPERTY_HINT_NONE, "suffix:px"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, "animation_separation", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Frames,animation_frame_"));
// Not optimal, but returns value for the first tile. This is similar to what MultiNodeEdit does.
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index ee8148f00a..7c4326cde1 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -1358,7 +1358,7 @@ void VisualShaderEditor::_update_options_menu() {
Color unsupported_color = get_theme_color(SNAME("error_color"), SNAME("Editor"));
Color supported_color = get_theme_color(SNAME("warning_color"), SNAME("Editor"));
- static bool low_driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "opengl3";
+ static bool low_driver = ProjectSettings::get_singleton()->get("rendering/renderer/rendering_method") == "gl_compatibility";
HashMap<String, TreeItem *> folders;
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 39b30b31fb..f8ba3f0354 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -38,6 +38,7 @@ const int ERROR_CODE = 77;
#include "modules/regex/regex.h"
+#include "core/io/dir_access.h"
#include "core/os/time.h"
#include "core/templates/hash_map.h"
#include "core/templates/list.h"
@@ -216,6 +217,7 @@ static const char *gdscript_function_renames[][2] = {
{ "_get_configuration_warning", "_get_configuration_warnings" }, // Node
{ "_set_current", "set_current" }, // Camera2D
{ "_set_editor_description", "set_editor_description" }, // Node
+ { "_set_playing", "set_playing" }, // AnimatedSprite3D
{ "_toplevel_raise_self", "_top_level_raise_self" }, // CanvasItem
{ "_update_wrap_at", "_update_wrap_at_column" }, // TextEdit
{ "add_animation", "add_animation_library" }, // AnimationPlayer
@@ -230,6 +232,7 @@ static const char *gdscript_function_renames[][2] = {
{ "add_scene_import_plugin", "add_scene_format_importer_plugin" }, //EditorPlugin
{ "add_stylebox_override", "add_theme_stylebox_override" }, // Control
{ "add_torque", "apply_torque" }, //RigidBody2D
+ { "agent_set_neighbor_dist", "agent_set_neighbor_distance" }, // NavigationServer2D, NavigationServer3D
{ "apply_changes", "_apply_changes" }, // EditorPlugin
{ "body_add_force", "body_apply_force" }, // PhysicsServer2D
{ "body_add_torque", "body_apply_torque" }, // PhysicsServer2D
@@ -331,6 +334,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_metakey", "is_meta_pressed" }, // InputEventWithModifiers
{ "get_mid_height", "get_height" }, // CapsuleMesh
{ "get_motion_remainder", "get_remainder" }, // PhysicsTestMotionResult2D
+ { "get_neighbor_dist", "get_neighbor_distance" }, // NavigationAgent2D, NavigationAgent3D
{ "get_network_connected_peers", "get_peers" }, // Multiplayer API
{ "get_network_master", "get_multiplayer_authority" }, // Node
{ "get_network_peer", "get_multiplayer_peer" }, // Multiplayer API
@@ -418,6 +422,7 @@ static const char *gdscript_function_renames[][2] = {
{ "is_normalmap", "is_normal_map" }, // NoiseTexture
{ "is_refusing_new_network_connections", "is_refusing_new_connections" }, // Multiplayer API
{ "is_region", "is_region_enabled" }, // Sprite2D
+ { "is_rotating", "is_ignoring_rotation" }, // Camera2D
{ "is_scancode_unicode", "is_keycode_unicode" }, // OS
{ "is_selectable_when_hidden", "_is_selectable_when_hidden" }, // EditorNode3DGizmoPlugin
{ "is_set_as_toplevel", "is_set_as_top_level" }, // CanvasItem
@@ -510,6 +515,7 @@ static const char *gdscript_function_renames[][2] = {
{ "set_max_atlas_size", "set_max_texture_size" }, // LightmapGI
{ "set_metakey", "set_meta_pressed" }, // InputEventWithModifiers
{ "set_mid_height", "set_height" }, // CapsuleMesh
+ { "set_neighbor_dist", "set_neighbor_distance" }, // NavigationAgent2D, NavigationAgent3D
{ "set_network_master", "set_multiplayer_authority" }, // Node
{ "set_network_peer", "set_multiplayer_peer" }, // Multiplayer API
{ "set_oneshot", "set_one_shot" }, // AnimatedTexture
@@ -650,6 +656,7 @@ static const char *csharp_function_renames[][2] = {
{ "_GetConfigurationWarning", "_GetConfigurationWarnings" }, // Node
{ "_SetCurrent", "SetCurrent" }, // Camera2D
{ "_SetEditorDescription", "SetEditorDescription" }, // Node
+ { "_SetPlaying", "SetPlaying" }, // AnimatedSprite3D
{ "_ToplevelRaiseSelf", "_TopLevelRaiseSelf" }, // CanvasItem
{ "_UpdateWrapAt", "_UpdateWrapAtColumn" }, // TextEdit
{ "AddAnimation", "AddAnimationLibrary" }, // AnimationPlayer
@@ -664,6 +671,7 @@ static const char *csharp_function_renames[][2] = {
{ "AddSceneImportPlugin", "AddSceneFormatImporterPlugin" }, //EditorPlugin
{ "AddStyleboxOverride", "AddThemeStyleboxOverride" }, // Control
{ "AddTorque", "AddConstantTorque" }, //RigidBody2D
+ { "AgentSetNeighborDist", "AgentSetNeighborDistance" }, // NavigationServer2D, NavigationServer3D
{ "BindChildNodeToBone", "SetBoneChildren" }, // Skeleton3D
{ "BumpmapToNormalmap", "BumpMapToNormalMap" }, // Image
{ "CanBeHidden", "_CanBeHidden" }, // EditorNode3DGizmoPlugin
@@ -757,6 +765,7 @@ static const char *csharp_function_renames[][2] = {
{ "GetMetakey", "IsMetaPressed" }, // InputEventWithModifiers
{ "GetMidHeight", "GetHeight" }, // CapsuleMesh
{ "GetMotionRemainder", "GetRemainder" }, // PhysicsTestMotionResult2D
+ { "GetNeighborDist", "GetNeighborDistance" }, // NavigationAgent2D, NavigationAgent3D
{ "GetNetworkConnectedPeers", "GetPeers" }, // Multiplayer API
{ "GetNetworkMaster", "GetMultiplayerAuthority" }, // Node
{ "GetNetworkPeer", "GetMultiplayerPeer" }, // Multiplayer API
@@ -840,6 +849,7 @@ static const char *csharp_function_renames[][2] = {
{ "IsNormalmap", "IsNormalMap" }, // NoiseTexture
{ "IsRefusingNewNetworkConnections", "IsRefusingNewConnections" }, // Multiplayer API
{ "IsRegion", "IsRegionEnabled" }, // Sprite2D
+ { "IsRotating", "IsIgnoringRotation" }, // Camera2D
{ "IsScancodeUnicode", "IsKeycodeUnicode" }, // OS
{ "IsSelectableWhenHidden", "_IsSelectableWhenHidden" }, // EditorNode3DGizmoPlugin
{ "IsSetAsToplevel", "IsSetAsTopLevel" }, // CanvasItem
@@ -926,6 +936,7 @@ static const char *csharp_function_renames[][2] = {
{ "SetMaxAtlasSize", "SetMaxTextureSize" }, // LightmapGI
{ "SetMetakey", "SetMetaPressed" }, // InputEventWithModifiers
{ "SetMidHeight", "SetHeight" }, // CapsuleMesh
+ { "SetNeighborDist", "SetNeighborDistance" }, // NavigationAgent2D, NavigationAgent3D
{ "SetNetworkMaster", "SetMultiplayerAuthority" }, // Node
{ "SetNetworkPeer", "SetMultiplayerPeer" }, // Multiplayer API
{ "SetOneshot", "SetOneShot" }, // AnimatedTexture
@@ -1061,6 +1072,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "focus_neighbour_left", "focus_neighbor_left" }, // Control
{ "focus_neighbour_right", "focus_neighbor_right" }, // Control
{ "focus_neighbour_top", "focus_neighbor_top" }, // Control
+ { "follow_viewport_enable", "follow_viewport_enabled" }, // CanvasItem
{ "file_icon_modulate", "file_icon_color" }, // Theme
{ "files_disabled", "file_disabled_color" }, // Theme
{ "folder_icon_modulate", "folder_icon_color" }, // Theme
@@ -1076,6 +1088,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "margin_right", "offset_right" }, // Control broke NinePatchRect, StyleBox
{ "margin_top", "offset_top" }, // Control broke NinePatchRect, StyleBox
{ "mid_height", "height" }, // CapsuleMesh
+ { "neighbor_dist", "neighbor_distance" }, // NavigationAgent2D, NavigationAgent3D
{ "offset_h", "drag_horizontal_offset" }, // Camera2D
{ "offset_v", "drag_vertical_offset" }, // Camera2D
{ "off", "unchecked" }, // Theme
@@ -1164,6 +1177,7 @@ static const char *csharp_properties_renames[][2] = {
{ "FocusNeighbourLeft", "FocusNeighborLeft" }, // Control
{ "FocusNeighbourRight", "FocusNeighborRight" }, // Control
{ "FocusNeighbourTop", "FocusNeighborTop" }, // Control
+ { "FollowViewportEnable", "FollowViewportEnabled" }, // CanvasItem
{ "GlobalRateScale", "PlaybackSpeedScale" }, // AudioServer
{ "GravityDistanceScale", "GravityPointDistanceScale" }, // Area2D
{ "GravityVec", "GravityDirection" }, // Area2D
@@ -1176,6 +1190,7 @@ static const char *csharp_properties_renames[][2] = {
{ "MarginRight", "OffsetRight" }, // Control broke NinePatchRect, StyleBox
{ "MarginTop", "OffsetTop" }, // Control broke NinePatchRect, StyleBox
{ "MidHeight", "Height" }, // CapsuleMesh
+ { "NeighborDist", "NeighborDistance" }, // NavigationAgent2D, NavigationAgent3D
{ "OffsetH", "DragHorizontalOffset" }, // Camera2D
{ "OffsetV", "DragVerticalOffset" }, // Camera2D
{ "Ofs", "Offset" }, // Theme
@@ -2229,22 +2244,23 @@ Vector<String> ProjectConverter3To4::check_for_files() {
Vector<String> directories_to_check = Vector<String>();
directories_to_check.push_back("res://");
- core_bind::Directory dir = core_bind::Directory();
while (!directories_to_check.is_empty()) {
String path = directories_to_check.get(directories_to_check.size() - 1); // Is there any pop_back function?
- directories_to_check.resize(directories_to_check.size() - 1); // Remove last element.
- if (dir.open(path) == OK) {
- dir.set_include_hidden(true);
- dir.list_dir_begin();
- String current_dir = dir.get_current_dir();
- String file_name = dir.get_next();
+ directories_to_check.resize(directories_to_check.size() - 1); // Remove last element
+
+ Ref<DirAccess> dir = DirAccess::create_for_path(path);
+ if (dir.is_valid()) {
+ dir->set_include_hidden(true);
+ dir->list_dir_begin();
+ String current_dir = dir->get_current_dir();
+ String file_name = dir->_get_next();
while (file_name != "") {
if (file_name == ".git" || file_name == ".import" || file_name == ".godot") {
- file_name = dir.get_next();
+ file_name = dir->_get_next();
continue;
}
- if (dir.current_is_dir()) {
+ if (dir->current_is_dir()) {
directories_to_check.append(current_dir.path_join(file_name) + "/");
} else {
bool proper_extension = false;
@@ -2255,7 +2271,7 @@ Vector<String> ProjectConverter3To4::check_for_files() {
collected_files.append(current_dir.path_join(file_name));
}
}
- file_name = dir.get_next();
+ file_name = dir->_get_next();
}
} else {
print_verbose("Failed to open " + path);
@@ -2331,12 +2347,13 @@ bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
valid = valid && test_conversion_with_regex("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
valid = valid && test_conversion_with_regex("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
- valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true);
+ valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "if Settings.fullscreen:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)\nelse:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide( a, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide_with_snap( a, g, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
@@ -3090,13 +3107,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true);
}
- // OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true)
+ // OS.window_fullscreen = a -> if a: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) else: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
if (line.contains("window_fullscreen")) {
- if (builtin) {
- line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true);
- } else {
- line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true);
- }
+ line = reg_container.reg_os_fullscreen.sub(line, "if $1:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)\nelse:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)", true);
}
// Instantiate
@@ -3144,8 +3157,13 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[5] + "`\n";
}
- line_new += starting_space + base_obj + "move_and_slide()\n";
- line = line_new + line.substr(0, start) + "velocity" + line.substr(end + start);
+ line_new += starting_space + base_obj + "move_and_slide()";
+
+ if (!line.begins_with(starting_space + "move_and_slide")) {
+ line = line_new + "\n" + line.substr(0, start) + "velocity" + line.substr(end + start);
+ } else {
+ line = line_new + line.substr(end + start);
+ }
}
}
}
@@ -3195,8 +3213,13 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[6] + "`\n";
}
- line_new += starting_space + base_obj + "move_and_slide()\n";
- line = line_new + line.substr(0, start) + "velocity" + line.substr(end + start); // move_and_slide used to return velocity
+ line_new += starting_space + base_obj + "move_and_slide()";
+
+ if (!line.begins_with(starting_space + "move_and_slide_with_snap")) {
+ line = line_new + "\n" + line.substr(0, start) + "velocity" + line.substr(end + start);
+ } else {
+ line = line_new + line.substr(end + start);
+ }
}
}
}
@@ -3490,6 +3513,20 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
}
+
+ // set_rotating(true) -> set_ignore_rotation(false)
+ if (line.contains("set_rotating(")) {
+ int start = line.find("set_rotating(");
+ int end = get_end_parenthesis(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 1) {
+ String opposite = parts[0] == "true" ? "false" : "true";
+ line = line.substr(0, start) + "set_ignore_rotation(" + opposite + ")";
+ }
+ }
+ }
+
// OS.get_window_safe_area() -> DisplayServer.get_display_safe_area()
if (line.contains("OS.get_window_safe_area(")) {
int start = line.find("OS.get_window_safe_area(");
@@ -3537,6 +3574,29 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
+ // rotating = true -> ignore_rotation = false # reversed "rotating" for Camera2D
+ if (line.contains("rotating")) {
+ int start = line.find("rotating");
+ bool foundNextEqual = false;
+ String line_to_check = line.substr(start + String("rotating").length());
+ String assigned_value;
+ for (int current_index = 0; line_to_check.length() > current_index; current_index++) {
+ char32_t chr = line_to_check.get(current_index);
+ if (chr == '\t' || chr == ' ') {
+ continue;
+ } else if (chr == '=') {
+ foundNextEqual = true;
+ assigned_value = line.right(current_index).strip_edges();
+ assigned_value = assigned_value == "true" ? "false" : "true";
+ } else {
+ break;
+ }
+ }
+ if (foundNextEqual) {
+ line = line.substr(0, start) + "ignore_rotation =" + assigned_value + " # reversed \"rotating\" for Camera2D";
+ }
+ }
+
// OS -> Time functions
if (line.contains("OS.get_ticks_msec")) {
line = line.replace("OS.get_ticks_msec", "Time.get_ticks_msec");
@@ -3950,6 +4010,8 @@ String ProjectConverter3To4::collect_string_from_vector(Vector<String> &vector)
#else // No RegEx.
+ProjectConverter3To4::ProjectConverter3To4(int _p_maximum_file_size_kb, int _p_maximum_line_length) {}
+
int ProjectConverter3To4::convert() {
ERR_FAIL_V_MSG(ERROR_CODE, "Can't run converter for Godot 3.x projects, because RegEx module is disabled.");
}
diff --git a/editor/project_converter_3_to_4.h b/editor/project_converter_3_to_4.h
index 2cecb9da79..d03e645ac7 100644
--- a/editor/project_converter_3_to_4.h
+++ b/editor/project_converter_3_to_4.h
@@ -31,7 +31,6 @@
#ifndef PROJECT_CONVERTER_3_TO_4_H
#define PROJECT_CONVERTER_3_TO_4_H
-#include "core/core_bind.h"
#include "core/io/file_access.h"
#include "core/object/ref_counted.h"
#include "core/string/ustring.h"
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index f11874a994..673da8872d 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -92,9 +92,9 @@ private:
Container *name_container;
Container *path_container;
Container *install_path_container;
- Container *rasterizer_container;
+ Container *renderer_container;
HBoxContainer *default_files_container;
- Ref<ButtonGroup> rasterizer_button_group;
+ Ref<ButtonGroup> renderer_button_group;
Label *msg;
LineEdit *project_path;
LineEdit *project_name;
@@ -473,16 +473,19 @@ private:
}
PackedStringArray project_features = ProjectSettings::get_required_features();
ProjectSettings::CustomMap initial_settings;
+
// Be sure to change this code if/when renderers are changed.
- int renderer_type = rasterizer_button_group->get_pressed_button()->get_meta(SNAME("driver_name"));
- initial_settings["rendering/vulkan/rendering/back_end"] = renderer_type;
- if (renderer_type == 0) {
- project_features.push_back("Vulkan Clustered");
- } else if (renderer_type == 1) {
- project_features.push_back("Vulkan Mobile");
+ String renderer_type = renderer_button_group->get_pressed_button()->get_meta(SNAME("rendering_method"));
+ initial_settings["rendering/renderer/rendering_method"] = renderer_type;
+
+ if (renderer_type == "forward_plus") {
+ project_features.push_back("Forward Plus");
+ } else if (renderer_type == "mobile") {
+ project_features.push_back("Mobile");
} else {
WARN_PRINT("Unknown renderer type. Please report this as a bug on GitHub.");
}
+
project_features.sort();
initial_settings["application/config/features"] = project_features;
initial_settings["application/config/name"] = project_name->get_text().strip_edges();
@@ -684,7 +687,7 @@ public:
msg->hide();
install_path_container->hide();
install_status_rect->hide();
- rasterizer_container->hide();
+ renderer_container->hide();
default_files_container->hide();
get_ok_button()->set_disabled(false);
@@ -735,7 +738,7 @@ public:
set_ok_button_text(TTR("Import & Edit"));
name_container->hide();
install_path_container->hide();
- rasterizer_container->hide();
+ renderer_container->hide();
default_files_container->hide();
project_path->grab_focus();
@@ -744,7 +747,7 @@ public:
set_ok_button_text(TTR("Create & Edit"));
name_container->show();
install_path_container->hide();
- rasterizer_container->show();
+ renderer_container->show();
default_files_container->show();
project_name->call_deferred(SNAME("grab_focus"));
project_name->call_deferred(SNAME("select_all"));
@@ -755,7 +758,7 @@ public:
project_name->set_text(zip_title);
name_container->show();
install_path_container->hide();
- rasterizer_container->hide();
+ renderer_container->hide();
default_files_container->hide();
project_path->grab_focus();
}
@@ -843,23 +846,23 @@ public:
msg->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
vb->add_child(msg);
- // rasterizer selection
- rasterizer_container = memnew(VBoxContainer);
- vb->add_child(rasterizer_container);
+ // Renderer selection.
+ renderer_container = memnew(VBoxContainer);
+ vb->add_child(renderer_container);
l = memnew(Label);
l->set_text(TTR("Renderer:"));
- rasterizer_container->add_child(l);
- Container *rshb = memnew(HBoxContainer);
- rasterizer_container->add_child(rshb);
- rasterizer_button_group.instantiate();
+ renderer_container->add_child(l);
+ HBoxContainer *rshc = memnew(HBoxContainer);
+ renderer_container->add_child(rshc);
+ renderer_button_group.instantiate();
Container *rvb = memnew(VBoxContainer);
rvb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- rshb->add_child(rvb);
+ rshc->add_child(rvb);
Button *rs_button = memnew(CheckBox);
- rs_button->set_button_group(rasterizer_button_group);
- rs_button->set_text(TTR("Vulkan Clustered"));
- rs_button->set_meta(SNAME("driver_name"), 0); // Vulkan backend "Forward Clustered"
+ rs_button->set_button_group(renderer_button_group);
+ rs_button->set_text(TTR("Forward+"));
+ rs_button->set_meta(SNAME("rendering_method"), "forward_plus");
rs_button->set_pressed(true);
rvb->add_child(rs_button);
l = memnew(Label);
@@ -871,15 +874,15 @@ public:
l->set_modulate(Color(1, 1, 1, 0.7));
rvb->add_child(l);
- rshb->add_child(memnew(VSeparator));
+ rshc->add_child(memnew(VSeparator));
rvb = memnew(VBoxContainer);
rvb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- rshb->add_child(rvb);
+ rshc->add_child(rvb);
rs_button = memnew(CheckBox);
- rs_button->set_button_group(rasterizer_button_group);
- rs_button->set_text(TTR("Vulkan Mobile"));
- rs_button->set_meta(SNAME("driver_name"), 1); // Vulkan backend "Forward Mobile"
+ rs_button->set_button_group(renderer_button_group);
+ rs_button->set_text(TTR("Mobile"));
+ rs_button->set_meta(SNAME("rendering_method"), "mobile");
rvb->add_child(rs_button);
l = memnew(Label);
l->set_text(
@@ -897,7 +900,7 @@ public:
l->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
l->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
l->set_modulate(Color(1, 1, 1, 0.7));
- rasterizer_container->add_child(l);
+ renderer_container->add_child(l);
default_files_container = memnew(HBoxContainer);
vb->add_child(default_files_container);
@@ -2164,9 +2167,11 @@ void ProjectManager::_open_selected_projects_ask() {
return;
}
+ const Size2i popup_min_width = Size2i(600.0 * EDSCALE, 0);
+
if (selected_list.size() > 1) {
- multi_open_ask->set_text(TTR("Are you sure to open more than one project?"));
- multi_open_ask->popup_centered();
+ multi_open_ask->set_text(vformat(TTR("You requested to open %d projects in parallel. Do you confirm?\nNote that usual checks for engine version compatibility will be bypassed."), selected_list.size()));
+ multi_open_ask->popup_centered(popup_min_width);
return;
}
@@ -2175,8 +2180,7 @@ void ProjectManager::_open_selected_projects_ask() {
return;
}
- // Update the project settings or don't open
- const String conf = project.path.path_join("project.godot");
+ // Update the project settings or don't open.
const int config_version = project.version;
PackedStringArray unsupported_features = project.unsupported_features;
@@ -2186,26 +2190,30 @@ void ProjectManager::_open_selected_projects_ask() {
ask_update_settings->get_ok_button()->set_text("OK");
- // Check if the config_version property was empty or 0
+ // Check if the config_version property was empty or 0.
if (config_version == 0) {
- ask_update_settings->set_text(vformat(TTR("The following project settings file does not specify the version of Godot through which it was created.\n\n%s\n\nIf you proceed with opening it, it will be converted to Godot's current configuration file format.\nWarning: You won't be able to open the project with previous versions of the engine anymore."), conf));
- ask_update_settings->popup_centered();
+ ask_update_settings->set_text(vformat(TTR("The selected project \"%s\" does not specify its supported Godot version in its configuration file (\"project.godot\").\n\nProject path: %s\n\nIf you proceed with opening it, it will be converted to Godot's current configuration file format.\n\nWarning: You won't be able to open the project with previous versions of the engine anymore."), project.project_name, project.path));
+ ask_update_settings->popup_centered(popup_min_width);
return;
}
- // Check if we need to convert project settings from an earlier engine version
+ // Check if we need to convert project settings from an earlier engine version.
if (config_version < ProjectSettings::CONFIG_VERSION) {
if (config_version == GODOT4_CONFIG_VERSION - 1 && ProjectSettings::CONFIG_VERSION == GODOT4_CONFIG_VERSION) { // Conversion from Godot 3 to 4.
full_convert_button->show();
+ ask_update_settings->set_text(vformat(TTR("The selected project \"%s\" was generated by Godot 3.x, and needs to be converted for Godot 4.x.\n\nProject path: %s\n\nYou have three options:\n- Convert only the configuration file (\"project.godot\"). Use this to open the project without attempting to convert its scenes, resources and scripts.\n- Convert the entire project including its scenes, resources and scripts (recommended if you are upgrading).\n- Do nothing and go back.\n\nWarning: If you select a conversion option, you won't be able to open the project with previous versions of the engine anymore."), project.project_name, project.path));
+ ask_update_settings->get_ok_button()->set_text(TTR("Convert project.godot Only"));
+ } else {
+ ask_update_settings->set_text(vformat(TTR("The selected project \"%s\" was generated by an older engine version, and needs to be converted for this version.\n\nProject path: %s\n\nDo you want to convert it?\n\nWarning: You won't be able to open the project with previous versions of the engine anymore."), project.project_name, project.path));
+ ask_update_settings->get_ok_button()->set_text(TTR("Convert project.godot"));
}
- ask_update_settings->set_text(vformat(TTR("The following project settings file was generated by an older engine version, and needs to be converted for this version:\n\n%s\n\nDo you want to convert it? You can also convert the entire project (recommended if you are upgrading).\nWarning: You won't be able to open the project with previous versions of the engine anymore."), conf));
- ask_update_settings->get_ok_button()->set_text(TTR("Convert project.godot"));
- ask_update_settings->popup_centered();
+ ask_update_settings->popup_centered(popup_min_width);
+ ask_update_settings->get_cancel_button()->grab_focus(); // To prevent accidents.
return;
}
- // Check if the file was generated by a newer, incompatible engine version
+ // Check if the file was generated by a newer, incompatible engine version.
if (config_version > ProjectSettings::CONFIG_VERSION) {
- dialog_error->set_text(vformat(TTR("Can't open project at '%s'.") + "\n" + TTR("The project settings were created by a newer engine version, whose settings are not compatible with this version."), project.path));
- dialog_error->popup_centered();
+ dialog_error->set_text(vformat(TTR("Can't open project \"%s\" at the following path:\n\n%s\n\nThe project settings were created by a newer engine version, whose settings are not compatible with this version."), project.project_name, project.path));
+ dialog_error->popup_centered(popup_min_width);
return;
}
// Check if the project is using features not supported by this build of Godot.
@@ -2234,14 +2242,20 @@ void ProjectManager::_open_selected_projects_ask() {
warning_message += TTR("Open anyway? Project will be modified.");
ask_update_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
ask_update_settings->set_text(warning_message);
- ask_update_settings->popup_centered();
+ ask_update_settings->popup_centered(popup_min_width);
return;
}
- // Open if the project is up-to-date
+ // Open if the project is up-to-date.
_open_selected_projects();
}
+void ProjectManager::_full_convert_button_pressed() {
+ ask_update_settings->hide();
+ ask_full_convert_dialog->popup_centered(Size2i(600.0 * EDSCALE, 0));
+ ask_full_convert_dialog->get_cancel_button()->grab_focus();
+}
+
void ProjectManager::_perform_full_project_conversion() {
Vector<ProjectList::Item> selected_list = _project_list->get_selected_projects();
if (selected_list.is_empty()) {
@@ -2869,21 +2883,18 @@ ProjectManager::ProjectManager() {
add_child(multi_scan_ask);
ask_update_settings = memnew(ConfirmationDialog);
+ ask_update_settings->set_autowrap(true);
ask_update_settings->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_confirm_update_settings));
- full_convert_button = ask_update_settings->add_button("Perform Full Project Conversion", false);
+ full_convert_button = ask_update_settings->add_button("Convert Full Project", !GLOBAL_GET("gui/common/swap_cancel_ok"));
+ full_convert_button->connect("pressed", callable_mp(this, &ProjectManager::_full_convert_button_pressed));
add_child(ask_update_settings);
ask_full_convert_dialog = memnew(ConfirmationDialog);
ask_full_convert_dialog->set_autowrap(true);
- ask_full_convert_dialog->set_text(TTR(R"(This option will perform full project conversion, updating scenes and scripts from Godot 3.x to work in Godot 4.0. Note that this is a best-effort conversion, i.e. it makes upgrading the project easier, but it will not open out-of-the-box and will still require manual adjustments.
-
-IMPORTANT: Make sure to backup your project before converting, as this operation makes it impossible to open in older versions of Godot.)"));
+ ask_full_convert_dialog->set_text(TTR("This option will perform full project conversion, updating scenes, resources and scripts from Godot 3.x to work in Godot 4.0.\n\nNote that this is a best-effort conversion, i.e. it makes upgrading the project easier, but it will not open out-of-the-box and will still require manual adjustments.\n\nIMPORTANT: Make sure to backup your project before converting, as this operation makes it impossible to open it in older versions of Godot."));
ask_full_convert_dialog->connect("confirmed", callable_mp(this, &ProjectManager::_perform_full_project_conversion));
add_child(ask_full_convert_dialog);
- full_convert_button->connect("pressed", callable_mp((Window *)ask_update_settings, &ConfirmationDialog::hide));
- full_convert_button->connect("pressed", callable_mp((Window *)ask_full_convert_dialog, &ConfirmationDialog::popup_centered_ratio).bind(0.2));
-
npdialog = memnew(ProjectDialog);
npdialog->connect("projects_updated", callable_mp(this, &ProjectManager::_on_projects_updated));
npdialog->connect("project_created", callable_mp(this, &ProjectManager::_on_project_created));
diff --git a/editor/project_manager.h b/editor/project_manager.h
index 0831a63e68..7c05429dde 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -108,6 +108,7 @@ class ProjectManager : public Control {
void _run_project_confirm();
void _open_selected_projects();
void _open_selected_projects_ask();
+ void _full_convert_button_pressed();
void _perform_full_project_conversion();
void _import_project();
void _new_project();
diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp
index 573e57ca04..4563dbb0f7 100644
--- a/editor/scene_create_dialog.cpp
+++ b/editor/scene_create_dialog.cpp
@@ -133,7 +133,7 @@ void SceneCreateDialog::update_dialog() {
root_name = scene_name.get_file().get_basename();
}
- if (!root_name.is_valid_identifier()) {
+ if (root_name.is_empty() || root_name.validate_node_name().size() != root_name.size()) {
update_error(node_error_label, MSG_ERROR, TTR("Invalid root node name."));
is_valid = false;
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index a437245c57..d1dc188be9 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -135,6 +135,8 @@ void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) {
_tool_selected(TOOL_ERASE, true);
} else if (ED_IS_SHORTCUT("scene_tree/copy_node_path", p_event)) {
_tool_selected(TOOL_COPY_NODE_PATH);
+ } else if (ED_IS_SHORTCUT("scene_tree/toggle_unique_name", p_event)) {
+ _tool_selected(TOOL_TOGGLE_SCENE_UNIQUE_NAME);
} else if (ED_IS_SHORTCUT("scene_tree/delete", p_event)) {
_tool_selected(TOOL_ERASE);
} else {
@@ -439,8 +441,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
}
- bool collapsed = _is_collapsed_recursive(selected_item);
- _set_collapsed_recursive(selected_item, !collapsed);
+ bool collapsed = selected_item->is_any_collapsed();
+ selected_item->set_collapsed_recursive(!collapsed);
tree->ensure_cursor_is_visible();
@@ -916,6 +918,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
String existing;
if (extensions.size()) {
String root_name(tocopy->get_name());
+ root_name = EditorNode::adjust_scene_name_casing(root_name);
existing = root_name + "." + extensions.front()->get().to_lower();
}
new_scene_from_dialog->set_current_path(existing);
@@ -1073,6 +1076,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (first_selected == nullptr) {
return;
}
+ if (first_selected->get() == EditorNode::get_singleton()->get_edited_scene()) {
+ // Exclude Root Node. It should never be unique name in its own scene!
+ editor_selection->remove_node(first_selected->get());
+ first_selected = editor_selection->get_selected_node_list().front();
+ if (first_selected == nullptr) {
+ return;
+ }
+ }
bool enabling = !first_selected->get()->is_unique_name_in_owner();
List<Node *> full_selection = editor_selection->get_full_selected_node_list();
@@ -1212,17 +1223,6 @@ void SceneTreeDock::add_root_node(Node *p_node) {
editor_data->get_undo_redo()->commit_action();
}
-void SceneTreeDock::_node_collapsed(Object *p_obj) {
- TreeItem *ti = Object::cast_to<TreeItem>(p_obj);
- if (!ti) {
- return;
- }
-
- if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
- _set_collapsed_recursive(ti, ti->is_collapsed());
- }
-}
-
void SceneTreeDock::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
@@ -1235,14 +1235,14 @@ void SceneTreeDock::_notification(int p_what) {
CanvasItemEditorPlugin *canvas_item_plugin = Object::cast_to<CanvasItemEditorPlugin>(editor_data->get_editor("2D"));
if (canvas_item_plugin) {
- canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", Callable(scene_tree, "_update_tree"));
- canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", Callable(scene_tree, "_update_tree"));
+ canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree));
+ canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree));
scene_tree->connect("node_changed", callable_mp((CanvasItem *)canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), &CanvasItem::queue_redraw));
}
Node3DEditorPlugin *spatial_editor_plugin = Object::cast_to<Node3DEditorPlugin>(editor_data->get_editor("3D"));
- spatial_editor_plugin->get_spatial_editor()->connect("item_lock_status_changed", Callable(scene_tree, "_update_tree"));
- spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", Callable(scene_tree, "_update_tree"));
+ spatial_editor_plugin->get_spatial_editor()->connect("item_lock_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree));
+ spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree));
button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
button_instance->set_icon(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
@@ -1934,48 +1934,6 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
editor_data->get_undo_redo()->commit_action();
}
-bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const {
- bool is_branch_collapsed = false;
-
- List<TreeItem *> needs_check;
- needs_check.push_back(p_item);
-
- while (!needs_check.is_empty()) {
- TreeItem *item = needs_check.back()->get();
- needs_check.pop_back();
-
- TreeItem *child = item->get_first_child();
- is_branch_collapsed = item->is_collapsed() && child;
-
- if (is_branch_collapsed) {
- break;
- }
- while (child) {
- needs_check.push_back(child);
- child = child->get_next();
- }
- }
- return is_branch_collapsed;
-}
-
-void SceneTreeDock::_set_collapsed_recursive(TreeItem *p_item, bool p_collapsed) {
- List<TreeItem *> to_collapse;
- to_collapse.push_back(p_item);
-
- while (!to_collapse.is_empty()) {
- TreeItem *item = to_collapse.back()->get();
- to_collapse.pop_back();
-
- item->set_collapsed(p_collapsed);
-
- TreeItem *child = item->get_first_child();
- while (child) {
- to_collapse.push_back(child);
- child = child->get_next();
- }
- }
-}
-
void SceneTreeDock::_script_created(Ref<Script> p_script) {
List<Node *> selected = editor_selection->get_selected_node_list();
@@ -2865,10 +2823,13 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
}
}
if (all_owned) {
- menu->add_separator();
- menu->add_icon_check_item(get_theme_icon(SNAME("SceneUniqueName"), SNAME("EditorIcons")), TTR("Access as Scene Unique Name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME);
- // Checked based on `selection[0]` because `full_selection` has undesired ordering.
- menu->set_item_checked(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), selection[0]->is_unique_name_in_owner());
+ // Group "toggle_unique_name" with "copy_node_path", if it is available.
+ if (menu->get_item_index(TOOL_COPY_NODE_PATH) == -1) {
+ menu->add_separator();
+ }
+ Node *node = full_selection[0];
+ menu->add_icon_shortcut(get_theme_icon(SNAME("SceneUniqueName"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/toggle_unique_name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME);
+ menu->set_item_text(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), node->is_unique_name_in_owner() ? TTR("Revoke Unique Name") : TTR("Access as Unique Name"));
}
}
@@ -3421,6 +3382,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
ED_SHORTCUT("scene_tree/make_root", TTR("Make Scene Root"));
ED_SHORTCUT("scene_tree/save_branch_as_scene", TTR("Save Branch as Scene"));
ED_SHORTCUT("scene_tree/copy_node_path", TTR("Copy Node Path"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::C);
+ ED_SHORTCUT("scene_tree/toggle_unique_name", TTR("Toggle Access as Unique Name"));
ED_SHORTCUT("scene_tree/delete_no_confirm", TTR("Delete (No Confirm)"), KeyModifierMask::SHIFT | Key::KEY_DELETE);
ED_SHORTCUT("scene_tree/delete", TTR("Delete"), Key::KEY_DELETE);
@@ -3517,7 +3479,6 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
scene_tree->connect("nodes_dragged", callable_mp(this, &SceneTreeDock::_nodes_drag_begin));
scene_tree->get_scene_tree()->connect("item_double_clicked", callable_mp(this, &SceneTreeDock::_focus_node));
- scene_tree->get_scene_tree()->connect("item_collapsed", callable_mp(this, &SceneTreeDock::_node_collapsed));
editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed));
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index dc228e1c93..e48b518252 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -137,7 +137,6 @@ class SceneTreeDock : public VBoxContainer {
HBoxContainer *tool_hbc = nullptr;
void _tool_selected(int p_tool, bool p_confirm_override = false);
void _property_selected(int p_idx);
- void _node_collapsed(Object *p_obj);
Node *property_drop_node = nullptr;
String resource_drop_path;
@@ -188,9 +187,6 @@ class SceneTreeDock : public VBoxContainer {
void _node_reparent(NodePath p_path, bool p_keep_global_xform);
void _do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform);
- bool _is_collapsed_recursive(TreeItem *p_item) const;
- void _set_collapsed_recursive(TreeItem *p_item, bool p_collapsed);
-
void _set_owners(Node *p_owner, const Array &p_nodes);
enum ReplaceOwnerMode {
@@ -228,8 +224,6 @@ class SceneTreeDock : public VBoxContainer {
virtual void input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
- void _import_subscene();
-
void _new_scene_from(String p_file);
void _set_node_owner_recursive(Node *p_node, Node *p_owner);
@@ -292,7 +286,6 @@ public:
void _focus_node();
- void import_subscene();
void add_root_node(Node *p_node);
void set_edited_scene(Node *p_scene);
void instantiate(const String &p_file);
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 137574640e..0b1e9719b7 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -30,6 +30,7 @@
#include "scene_tree_editor.h"
+#include "core/config/project_settings.h"
#include "core/object/message_queue.h"
#include "core/string/print_string.h"
#include "editor/editor_file_system.h"
@@ -835,7 +836,7 @@ void SceneTreeEditor::_notification(int p_what) {
get_tree()->connect("tree_process_mode_changed", callable_mp(this, &SceneTreeEditor::_tree_process_mode_changed));
get_tree()->connect("node_removed", callable_mp(this, &SceneTreeEditor::_node_removed));
get_tree()->connect("node_renamed", callable_mp(this, &SceneTreeEditor::_node_renamed));
- get_tree()->connect("node_configuration_warning_changed", callable_mp(this, &SceneTreeEditor::_warning_changed), CONNECT_DEFERRED);
+ get_tree()->connect("node_configuration_warning_changed", callable_mp(this, &SceneTreeEditor::_warning_changed));
tree->connect("item_collapsed", callable_mp(this, &SceneTreeEditor::_cell_collapsed));
@@ -942,14 +943,16 @@ void SceneTreeEditor::_renamed() {
Node *n = get_node(np);
ERR_FAIL_COND(!n);
- // Empty node names are not allowed, so resets it to previous text and show warning
- if (which->get_text(0).strip_edges().is_empty()) {
- which->set_text(0, n->get_name());
- EditorNode::get_singleton()->show_warning(TTR("No name provided."));
- return;
+ String raw_new_name = which->get_text(0);
+ if (raw_new_name.strip_edges().is_empty()) {
+ // If name is empty, fallback to class name.
+ if (GLOBAL_GET("editor/node_naming/name_casing").operator int() != NAME_CASING_PASCAL_CASE) {
+ raw_new_name = Node::adjust_name_casing(n->get_class());
+ } else {
+ raw_new_name = n->get_class();
+ }
}
- String raw_new_name = which->get_text(0);
String new_name = raw_new_name.validate_node_name();
if (new_name != raw_new_name) {
@@ -1332,7 +1335,7 @@ void SceneTreeEditor::set_connecting_signal(bool p_enable) {
}
void SceneTreeEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_tree"), &SceneTreeEditor::_update_tree, DEFVAL(false)); // Still used by some connect_compat.
+ ClassDB::bind_method(D_METHOD("_update_tree"), &SceneTreeEditor::_update_tree, DEFVAL(false)); // Still used by UndoRedo.
ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node);
ClassDB::bind_method("_test_update_tree", &SceneTreeEditor::_test_update_tree);
diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h
index 28ffa4b11b..8fbc3ab6d6 100644
--- a/editor/scene_tree_editor.h
+++ b/editor/scene_tree_editor.h
@@ -76,7 +76,6 @@ class SceneTreeEditor : public Control {
void _add_nodes(Node *p_node, TreeItem *p_parent);
void _test_update_tree();
- void _update_tree(bool p_scroll_to_selected = false);
bool _update_filter(TreeItem *p_parent = nullptr, bool p_scroll_to_selected = false);
bool _item_matches_all_terms(TreeItem *p_item, PackedStringArray p_terms);
void _tree_changed();
@@ -138,6 +137,9 @@ class SceneTreeEditor : public Control {
Vector<StringName> valid_types;
public:
+ // Public for use with callable_mp.
+ void _update_tree(bool p_scroll_to_selected = false);
+
void set_filter(const String &p_filter);
String get_filter() const;
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index eef0f3eae1..473bbd69d9 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -483,7 +483,7 @@ ShaderGlobalsEditor::ShaderGlobalsEditor() {
inspector->connect("property_deleted", callable_mp(this, &ShaderGlobalsEditor::_variable_deleted), CONNECT_DEFERRED);
interface = memnew(ShaderGlobalsEditorInterface);
- interface->connect("var_changed", Callable(this, "_changed"));
+ interface->connect("var_changed", callable_mp(this, &ShaderGlobalsEditor::_changed));
}
ShaderGlobalsEditor::~ShaderGlobalsEditor() {
diff --git a/main/main.cpp b/main/main.cpp
index a338b71154..aac77c1625 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -141,6 +141,7 @@ static bool _start_success = false;
String tablet_driver = "";
String text_driver = "";
String rendering_driver = "";
+String rendering_method = "";
static int text_driver_idx = -1;
static int display_driver_idx = -1;
static int audio_driver_idx = -1;
@@ -156,6 +157,7 @@ static bool show_help = false;
static bool auto_quit = false;
static OS::ProcessID editor_pid = 0;
#ifdef TOOLS_ENABLED
+static bool found_project = false;
static bool auto_build_solutions = false;
static String debug_server_uri;
static int converter_max_kb_file = 4 * 1024; // 4MB
@@ -353,6 +355,7 @@ void Main::print_help(const char *p_binary) {
}
OS::get_singleton()->print("].\n");
+ OS::get_singleton()->print(" --rendering-method <renderer> Renderer name. Requires driver support.\n");
OS::get_singleton()->print(" --rendering-driver <driver> Rendering driver (depends on display driver).\n");
OS::get_singleton()->print(" --gpu-index <device_index> Use a specific GPU (run with --verbose to get available device list).\n");
OS::get_singleton()->print(" --text-driver <driver> Text driver (Fonts, BiDi, shaping)\n");
@@ -705,9 +708,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
Vector<String> breakpoints;
bool use_custom_res = true;
bool force_res = false;
-#ifdef TOOLS_ENABLED
- bool found_project = false;
-#endif
String default_renderer = "";
String renderer_hints = "";
@@ -757,6 +757,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
if (I->get() == "--audio-driver" ||
I->get() == "--display-driver" ||
+ I->get() == "--rendering-method" ||
I->get() == "--rendering-driver") {
if (I->next()) {
forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get());
@@ -866,43 +867,17 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->print("Missing display driver argument, aborting.\n");
goto error;
}
+ } else if (I->get() == "--rendering-method") {
+ if (I->next()) {
+ rendering_method = I->next()->get();
+ N = I->next()->next();
+ } else {
+ OS::get_singleton()->print("Missing renderer name argument, aborting.\n");
+ goto error;
+ }
} else if (I->get() == "--rendering-driver") {
if (I->next()) {
rendering_driver = I->next()->get();
-
- // as the rendering drivers available may depend on the display driver selected,
- // we can't do an exhaustive check here, but we can look through all the options in
- // all the display drivers for a match
-
- bool found = false;
- for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
- Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i);
-
- for (int d = 0; d < r_drivers.size(); d++) {
- if (rendering_driver == r_drivers[d]) {
- found = true;
- break;
- }
- }
- }
-
- if (!found) {
- OS::get_singleton()->print("Unknown rendering driver '%s', aborting.\nValid options are ",
- rendering_driver.utf8().get_data());
-
- for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
- Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i);
-
- for (int d = 0; d < r_drivers.size(); d++) {
- OS::get_singleton()->print("'%s', ", r_drivers[d].utf8().get_data());
- }
- }
-
- OS::get_singleton()->print(".\n");
-
- goto error;
- }
-
N = I->next()->next();
} else {
OS::get_singleton()->print("Missing rendering driver argument, aborting.\n");
@@ -1485,45 +1460,188 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->set_cmdline(execpath, main_args, user_args);
- // possibly be worth changing the default from vulkan to something lower spec,
- // for the project manager, depending on how smooth the fallback is.
+ {
+ String driver_hints = "";
+#ifdef VULKAN_ENABLED
+ driver_hints = "vulkan";
+#endif
- // this list is hard coded, which makes it more difficult to add new backends.
- // can potentially be changed to more of a plugin system at a later date.
+ String default_driver = driver_hints.get_slice(",", 0);
+
+ // For now everything defaults to vulkan when available. This can change in future updates.
+ GLOBAL_DEF("rendering/rendering_device/driver", default_driver);
+ GLOBAL_DEF("rendering/rendering_device/driver.windows", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.windows",
+ PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.windows", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/rendering_device/driver.linuxbsd", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.linuxbsd",
+ PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.linuxbsd", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/rendering_device/driver.android", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.android",
+ PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.android", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/rendering_device/driver.ios", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.ios",
+ PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.ios", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/rendering_device/driver.macos", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.macos",
+ PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.macos", PROPERTY_HINT_ENUM, driver_hints));
+
+ driver_hints = "";
+#ifdef GLES3_ENABLED
+ driver_hints += "opengl3";
+#endif
- // Start with Vulkan, which will be the default if enabled.
+ default_driver = driver_hints.get_slice(",", 0);
+
+ GLOBAL_DEF("rendering/gl_compatibility/driver", default_driver);
+ GLOBAL_DEF("rendering/gl_compatibility/driver.windows", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.windows",
+ PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.windows", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/gl_compatibility/driver.linuxbsd", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.linuxbsd",
+ PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.linuxbsd", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/gl_compatibility/driver.web", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.web",
+ PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.web", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/gl_compatibility/driver.android", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.android",
+ PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.android", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/gl_compatibility/driver.ios", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.ios",
+ PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.ios", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/gl_compatibility/driver.macos", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.macos",
+ PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.macos", PROPERTY_HINT_ENUM, driver_hints));
+ }
+
+ // Start with RenderingDevice-based backends. Should be included if any RD driver present.
#ifdef VULKAN_ENABLED
- renderer_hints = "vulkan";
+ renderer_hints = "forward_plus,mobile";
#endif
- // And OpenGL3 next, or first if Vulkan is disabled.
+ // And Compatibility next, or first if Vulkan is disabled.
#ifdef GLES3_ENABLED
if (!renderer_hints.is_empty()) {
renderer_hints += ",";
}
- renderer_hints += "opengl3";
+ renderer_hints += "gl_compatibility";
#endif
if (renderer_hints.is_empty()) {
- ERR_PRINT("No rendering driver available.");
+ ERR_PRINT("No renderers available.");
+ }
+
+ if (!rendering_method.is_empty()) {
+ if (rendering_method != "forward_plus" &&
+ rendering_method != "mobile" &&
+ rendering_method != "gl_compatibility") {
+ OS::get_singleton()->print("Unknown renderer name '%s', aborting. Valid options are: %s\n", rendering_method.utf8().get_data(), renderer_hints.utf8().get_data());
+ goto error;
+ }
+ }
+
+ if (!rendering_driver.is_empty()) {
+ // As the rendering drivers available may depend on the display driver and renderer
+ // selected, we can't do an exhaustive check here, but we can look through all
+ // the options in all the display drivers for a match.
+
+ bool found = false;
+ for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
+ Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i);
+
+ for (int d = 0; d < r_drivers.size(); d++) {
+ if (rendering_driver == r_drivers[d]) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ OS::get_singleton()->print("Unknown rendering driver '%s', aborting.\nValid options are ",
+ rendering_driver.utf8().get_data());
+
+ for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
+ Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i);
+
+ for (int d = 0; d < r_drivers.size(); d++) {
+ OS::get_singleton()->print("'%s', ", r_drivers[d].utf8().get_data());
+ }
+ }
+
+ OS::get_singleton()->print(".\n");
+
+ goto error;
+ }
+
+ // Set a default renderer if none selected. Try to choose one that matches the driver.
+ if (rendering_method.is_empty()) {
+ if (rendering_driver == "opengl3") {
+ rendering_method = "gl_compatibility";
+ } else {
+ rendering_method = "forward_plus";
+ }
+ }
+
+ // Now validate whether the selected driver matches with the renderer.
+ bool valid_combination = false;
+ Vector<String> available_drivers;
+ if (rendering_method == "forward_plus" || rendering_method == "mobile") {
+ available_drivers.push_back("vulkan");
+ } else if (rendering_method == "gl_compatibility") {
+ available_drivers.push_back("opengl3");
+ } else {
+ OS::get_singleton()->print("Unknown renderer name '%s', aborting.\n", rendering_method.utf8().get_data());
+ goto error;
+ }
+
+ for (int i = 0; i < available_drivers.size(); i++) {
+ if (rendering_driver == available_drivers[i]) {
+ valid_combination = true;
+ break;
+ }
+ }
+
+ if (!valid_combination) {
+ OS::get_singleton()->print("Invalid renderer/driver combination '%s' and '%s', aborting. %s only supports the following drivers ", rendering_method.utf8().get_data(), rendering_driver.utf8().get_data(), rendering_method.utf8().get_data());
+
+ for (int d = 0; d < available_drivers.size(); d++) {
+ OS::get_singleton()->print("'%s', ", available_drivers[d].utf8().get_data());
+ }
+
+ OS::get_singleton()->print(".\n");
+
+ goto error;
+ }
}
default_renderer = renderer_hints.get_slice(",", 0);
- GLOBAL_DEF_RST("rendering/driver/driver_name", default_renderer);
+ GLOBAL_DEF_RST_BASIC("rendering/renderer/rendering_method", default_renderer);
+ GLOBAL_DEF_RST_BASIC("rendering/renderer/rendering_method.mobile", default_renderer);
+ GLOBAL_DEF_RST_BASIC("rendering/renderer/rendering_method.web", "gl_compatibility"); // This is a bit of a hack until we have WebGPU support.
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/driver/driver_name",
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/renderer/rendering_method",
PropertyInfo(Variant::STRING,
- "rendering/driver/driver_name",
+ "rendering/renderer/rendering_method",
PROPERTY_HINT_ENUM, renderer_hints));
- // if not set on the command line
+ // Default to ProjectSettings default if nothing set on the command line.
+ if (rendering_method.is_empty()) {
+ rendering_method = GLOBAL_GET("rendering/renderer/rendering_method");
+ }
+
if (rendering_driver.is_empty()) {
- rendering_driver = GLOBAL_GET("rendering/driver/driver_name");
+ if (rendering_method == "gl_compatibility") {
+ rendering_driver = GLOBAL_GET("rendering/gl_compatibility/driver");
+ } else {
+ rendering_driver = GLOBAL_GET("rendering/rendering_device/driver");
+ }
}
// note this is the desired rendering driver, it doesn't mean we will get it.
// TODO - make sure this is updated in the case of fallbacks, so that the user interface
// shows the correct driver string.
OS::get_singleton()->set_current_rendering_driver_name(rendering_driver);
+ OS::get_singleton()->set_current_rendering_method(rendering_method);
// always convert to lower case for consistency in the code
rendering_driver = rendering_driver.to_lower();
@@ -1552,13 +1670,19 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (bool(GLOBAL_GET("display/window/size/borderless"))) {
window_flags |= DisplayServer::WINDOW_FLAG_BORDERLESS_BIT;
}
- if (bool(GLOBAL_GET("display/window/size/fullscreen"))) {
- window_mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
- }
-
if (bool(GLOBAL_GET("display/window/size/always_on_top"))) {
window_flags |= DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP_BIT;
}
+ if (bool(GLOBAL_GET("display/window/size/transparent"))) {
+ window_flags |= DisplayServer::WINDOW_FLAG_TRANSPARENT_BIT;
+ }
+ if (bool(GLOBAL_GET("display/window/size/extend_to_title"))) {
+ window_flags |= DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE_BIT;
+ }
+ if (bool(GLOBAL_GET("display/window/size/no_focus"))) {
+ window_flags |= DisplayServer::WINDOW_FLAG_NO_FOCUS_BIT;
+ }
+ window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int());
}
GLOBAL_DEF_RST("internationalization/rendering/force_right_to_left_layout_direction", false);
@@ -1812,6 +1936,13 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
#ifdef TOOLS_ENABLED
if (editor || project_manager || cmdline_tool) {
EditorPaths::create();
+ if (found_project && EditorPaths::get_singleton()->is_self_contained()) {
+ if (ProjectSettings::get_singleton()->get_resource_path() == OS::get_singleton()->get_executable_path().get_base_dir()) {
+ ERR_PRINT("You are trying to run a self-contained editor at the same location as a project. This is not allowed, since editor files will mix with project files.");
+ OS::get_singleton()->set_exit_code(EXIT_FAILURE);
+ return FAILED;
+ }
+ }
}
#endif
diff --git a/methods.py b/methods.py
index 1f49da7ace..97a1e15e35 100644
--- a/methods.py
+++ b/methods.py
@@ -77,44 +77,37 @@ def add_module_version_string(self, s):
self.module_version_string += "." + s
-def update_version(module_version_string=""):
+def get_version_info(module_version_string="", silent=False):
build_name = "custom_build"
if os.getenv("BUILD_NAME") != None:
build_name = str(os.getenv("BUILD_NAME"))
- print("Using custom build name: " + build_name)
+ if not silent:
+ print(f"Using custom build name: '{build_name}'.")
import version
- # NOTE: It is safe to generate this file here, since this is still executed serially
- f = open("core/version_generated.gen.h", "w")
- f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
- f.write("#ifndef VERSION_GENERATED_GEN_H\n")
- f.write("#define VERSION_GENERATED_GEN_H\n")
- f.write('#define VERSION_SHORT_NAME "' + str(version.short_name) + '"\n')
- f.write('#define VERSION_NAME "' + str(version.name) + '"\n')
- f.write("#define VERSION_MAJOR " + str(version.major) + "\n")
- f.write("#define VERSION_MINOR " + str(version.minor) + "\n")
- f.write("#define VERSION_PATCH " + str(version.patch) + "\n")
+ version_info = {
+ "short_name": str(version.short_name),
+ "name": str(version.name),
+ "major": int(version.major),
+ "minor": int(version.minor),
+ "patch": int(version.patch),
+ "status": str(version.status),
+ "build": str(build_name),
+ "module_config": str(version.module_config) + module_version_string,
+ "year": int(version.year),
+ "website": str(version.website),
+ "docs_branch": str(version.docs),
+ }
+
# For dev snapshots (alpha, beta, RC, etc.) we do not commit status change to Git,
# so this define provides a way to override it without having to modify the source.
- godot_status = str(version.status)
if os.getenv("GODOT_VERSION_STATUS") != None:
- godot_status = str(os.getenv("GODOT_VERSION_STATUS"))
- print("Using version status '{}', overriding the original '{}'.".format(godot_status, str(version.status)))
- f.write('#define VERSION_STATUS "' + godot_status + '"\n')
- f.write('#define VERSION_BUILD "' + str(build_name) + '"\n')
- f.write('#define VERSION_MODULE_CONFIG "' + str(version.module_config) + module_version_string + '"\n')
- f.write("#define VERSION_YEAR " + str(version.year) + "\n")
- f.write('#define VERSION_WEBSITE "' + str(version.website) + '"\n')
- f.write('#define VERSION_DOCS_BRANCH "' + str(version.docs) + '"\n')
- f.write('#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH\n')
- f.write("#endif // VERSION_GENERATED_GEN_H\n")
- f.close()
+ version_info["status"] = str(os.getenv("GODOT_VERSION_STATUS"))
+ if not silent:
+ print(f"Using version status '{version_info['status']}', overriding the original '{version.status}'.")
- # NOTE: It is safe to generate this file here, since this is still executed serially
- fhash = open("core/version_hash.gen.cpp", "w")
- fhash.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
- fhash.write('#include "core/version.h"\n')
+ # Parse Git hash if we're in a Git repo.
githash = ""
gitfolder = ".git"
@@ -144,7 +137,49 @@ def update_version(module_version_string=""):
else:
githash = head
- fhash.write('const char *const VERSION_HASH = "' + githash + '";\n')
+ version_info["git_hash"] = githash
+
+ return version_info
+
+
+def generate_version_header(module_version_string=""):
+ version_info = get_version_info(module_version_string)
+
+ # NOTE: It is safe to generate these files here, since this is still executed serially.
+
+ f = open("core/version_generated.gen.h", "w")
+ f.write(
+ """/* THIS FILE IS GENERATED DO NOT EDIT */
+#ifndef VERSION_GENERATED_GEN_H
+#define VERSION_GENERATED_GEN_H
+#define VERSION_SHORT_NAME "{short_name}"
+#define VERSION_NAME "{name}"
+#define VERSION_MAJOR {major}
+#define VERSION_MINOR {minor}
+#define VERSION_PATCH {patch}
+#define VERSION_STATUS "{status}"
+#define VERSION_BUILD "{build}"
+#define VERSION_MODULE_CONFIG "{module_config}"
+#define VERSION_YEAR {year}
+#define VERSION_WEBSITE "{website}"
+#define VERSION_DOCS_BRANCH "{docs_branch}"
+#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
+#endif // VERSION_GENERATED_GEN_H
+""".format(
+ **version_info
+ )
+ )
+ f.close()
+
+ fhash = open("core/version_hash.gen.cpp", "w")
+ fhash.write(
+ """/* THIS FILE IS GENERATED DO NOT EDIT */
+#include "core/version.h"
+const char *const VERSION_HASH = "{git_hash}";
+""".format(
+ **version_info
+ )
+ )
fhash.close()
@@ -811,7 +846,8 @@ def generate_vs_project(env, num_jobs):
add_to_vs_project(env, env.servers_sources)
if env["tests"]:
add_to_vs_project(env, env.tests_sources)
- add_to_vs_project(env, env.editor_sources)
+ if env["tools"]:
+ add_to_vs_project(env, env.editor_sources)
for header in glob_recursive("**/*.h"):
env.vs_incs.append(str(header))
diff --git a/misc/dist/html/editor.html b/misc/dist/html/editor.html
index 7c44dd45a1..ac00270d50 100644
--- a/misc/dist/html/editor.html
+++ b/misc/dist/html/editor.html
@@ -259,31 +259,20 @@
>Web editor documentation</a> for usage instructions and limitations.
</p>
</div>
- <div id="welcome-modal-description-no-cross-origin-isolation" style="display: none">
+ <div id="welcome-modal-missing-description" style="display: none">
<p>
- The web server does not support cross-origin isolation,
- which is required for the Godot Web Editor to function.
- </p>
- <p>
- <strong>Reasons for cross-origin isolation being disabled:</strong>
- <ul>
- <li id="welcome-modal-reason-not-secure">
- This page is not served from a secure context (HTTPS <i>or</i> localhost).
- </li>
- <li>
- This page may not be served with cross-origin isolation headers
- (check with the developer tools' Network tab).
- </li>
+ <strong>The following features required by the Godot Web Editor are missing:</strong>
+ <ul id="welcome-modal-missing-list">
</ul>
</p>
<p>
If you are self-hosting the web editor,
refer to
<a
- href="https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_web.html#threads"
+ href="https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_web.html"
target="_blank"
rel="noopener"
- >Exporting for the Web - Threads</a> for more information.
+ >Exporting for the Web</a> for more information.
</p>
</div>
<div style="text-align: center">
@@ -394,16 +383,22 @@
});
}
- if (!crossOriginIsolated) {
+ const missing = Engine.getMissingFeatures();
+ if (missing.length) {
// Display error dialog as threading support is required for the editor.
setButtonEnabled('startButton', false);
document.getElementById("welcome-modal-description").style.display = "none";
- document.getElementById("welcome-modal-description-no-cross-origin-isolation").style.display = "block";
+ document.getElementById("welcome-modal-missing-description").style.display = "block";
document.getElementById("welcome-modal-dismiss").style.display = "none";
- document.getElementById("welcome-modal-reason-not-secure").style.display = window.isSecureContext ? "none" : "list-item";
+ const list = document.getElementById("welcome-modal-missing-list");
+ for (let i = 0; i < missing.length; i++) {
+ const node = document.createElement("li");
+ node.innerText = missing[i];
+ list.appendChild(node);
+ }
}
- if (!crossOriginIsolated || localStorage.getItem("welcomeModalDismissed") !== 'true') {
+ if (missing.length || localStorage.getItem("welcomeModalDismissed") !== 'true') {
document.getElementById("welcome-modal").style.display = "block";
document.getElementById("welcome-modal-dismiss").focus();
}
diff --git a/misc/dist/html/full-size.html b/misc/dist/html/full-size.html
index f385b82f1d..d5b0050cfd 100644
--- a/misc/dist/html/full-size.html
+++ b/misc/dist/html/full-size.html
@@ -215,8 +215,10 @@ $GODOT_HEAD_INCLUDE
initializing = false;
};
- if (!Engine.isWebGLAvailable()) {
- displayFailureNotice('WebGL not available');
+ const missing = Engine.getMissingFeatures();
+ if (missing.length !== 0) {
+ const missingMsg = 'Warning!\nThe following features required to run Godot projects on the Web are missing:\n';
+ displayFailureNotice(missingMsg + missing.join("\n"));
} else {
setStatusMode('indeterminate');
engine.startGame({
diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
index 467aa3ce83..b58f002f3c 100644
--- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
+++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
@@ -249,7 +249,6 @@
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
diff --git a/misc/dist/shell/_godot.zsh-completion b/misc/dist/shell/_godot.zsh-completion
index b17bb6e66b..2bc6fe9317 100644
--- a/misc/dist/shell/_godot.zsh-completion
+++ b/misc/dist/shell/_godot.zsh-completion
@@ -44,6 +44,7 @@ _arguments \
'--remote-fs-password[password for remote filesystem]:remote filesystem password' \
'--audio-driver[set the audio driver]:audio driver name' \
'--display-driver[set the display driver]:display driver name' \
+ "--rendering-method[set the renderer]:renderer name:((forward_plus\:'Desktop renderer' mobile\:'Desktop and mobile renderer' gl_compatibility\:'Desktop, mobile and web renderer'))" \
"--rendering-driver[set the rendering driver]:rendering driver name:((vulkan\:'Vulkan renderer' opengl3\:'OpenGL ES 3.0 renderer' dummy\:'Dummy renderer'))" \
"--gpu-index[use a specific GPU (run with --verbose to get available device list)]:device index" \
'--text-driver[set the text driver]:text driver name' \
diff --git a/misc/dist/shell/godot.bash-completion b/misc/dist/shell/godot.bash-completion
index 1ab687e1fc..bc5fa600f5 100644
--- a/misc/dist/shell/godot.bash-completion
+++ b/misc/dist/shell/godot.bash-completion
@@ -47,6 +47,7 @@ _complete_godot_options() {
--remote-fs-password
--audio-driver
--display-driver
+--rendering-method
--rendering-driver
--gpu-index
--text-driver
@@ -58,7 +59,6 @@ _complete_godot_options() {
--always-on-top
--resolution
--position
---headless
--single-window
--debug
--breakpoints
@@ -112,6 +112,10 @@ _complete_godot_bash() {
local IFS=$' \n\t'
# shellcheck disable=SC2207
COMPREPLY=($(compgen -W "unsafe safe separate" -- "$cur"))
+ elif [[ $prev == "--rendering-method" ]]; then
+ local IFS=$' \n\t'
+ # shellcheck disable=SC2207
+ COMPREPLY=($(compgen -W "forward_plus mobile gl_compatibility" -- "$cur"))
elif [[ $prev == "--rendering-driver" ]]; then
local IFS=$' \n\t'
# shellcheck disable=SC2207
diff --git a/misc/dist/shell/godot.fish b/misc/dist/shell/godot.fish
index d58066c135..9ac692eace 100644
--- a/misc/dist/shell/godot.fish
+++ b/misc/dist/shell/godot.fish
@@ -23,6 +23,13 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+function godot_rendering_method_args
+ # Use a function instead of a fixed string to customize the argument descriptions.
+ echo -e "forward_plus\tHigh-end desktop renderer"
+ echo -e "mobile\tHigh-end mobile/desktop renderer"
+ echo -e "gl_compatibility\tLow-end desktop, mobile and web renderer"
+end
+
function godot_rendering_driver_args
# Use a function instead of a fixed string to customize the argument descriptions.
echo -e "vulkan\tVulkan renderer"
@@ -53,6 +60,7 @@ complete -c godot -l remote-fs -d "Use a remote filesystem (<host/IP>[:<port>] a
complete -c godot -l remote-fs-password -d "Password for remote filesystem" -x
complete -c godot -l audio-driver -d "Set the audio driver" -x
complete -c godot -l display-driver -d "Set the display driver" -x
+complete -c godot -l rendering-method -d "Set the renderer" -x -a "(godot_rendering_method_args)"
complete -c godot -l rendering-driver -d "Set the rendering driver" -x -a "(godot_rendering_driver_args)"
complete -c godot -l gpu-index -d "Use a specific GPU (run with --verbose to get available device list)" -x
complete -c godot -l text-driver -d "Set the text driver" -x
diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format
index 44b6f59132..9570d5120b 100755
--- a/misc/hooks/pre-commit-clang-format
+++ b/misc/hooks/pre-commit-clang-format
@@ -76,8 +76,8 @@ fi
# To get consistent formatting, we recommend contributors to use the same
# clang-format version as CI.
-RECOMMENDED_CLANG_FORMAT_MAJOR_MIN="12"
-RECOMMENDED_CLANG_FORMAT_MAJOR_MAX="14"
+RECOMMENDED_CLANG_FORMAT_MAJOR_MIN="13"
+RECOMMENDED_CLANG_FORMAT_MAJOR_MAX="15"
if [ ! -x "$CLANG_FORMAT" ] ; then
message="Error: clang-format executable not found. Please install clang-format $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX."
diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp
index ae03abca50..cc21ed28e8 100644
--- a/modules/bmp/image_loader_bmp.cpp
+++ b/modules/bmp/image_loader_bmp.cpp
@@ -200,7 +200,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
return err;
}
-Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
bmp_header_s bmp_header;
Error err = ERR_INVALID_DATA;
diff --git a/modules/bmp/image_loader_bmp.h b/modules/bmp/image_loader_bmp.h
index cf8346ecad..0ca54de1dc 100644
--- a/modules/bmp/image_loader_bmp.h
+++ b/modules/bmp/image_loader_bmp.h
@@ -83,7 +83,7 @@ protected:
const bmp_header_s &p_header);
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderBMP();
};
diff --git a/modules/bmp/register_types.cpp b/modules/bmp/register_types.cpp
index 7c4a2085b2..67858e9d46 100644
--- a/modules/bmp/register_types.cpp
+++ b/modules/bmp/register_types.cpp
@@ -32,14 +32,14 @@
#include "image_loader_bmp.h"
-static ImageLoaderBMP *image_loader_bmp = nullptr;
+static Ref<ImageLoaderBMP> image_loader_bmp;
void initialize_bmp_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
- image_loader_bmp = memnew(ImageLoaderBMP);
+ image_loader_bmp.instantiate();
ImageLoader::add_image_format_loader(image_loader_bmp);
}
@@ -48,5 +48,6 @@ void uninitialize_bmp_module(ModuleInitializationLevel p_level) {
return;
}
- memdelete(image_loader_bmp);
+ ImageLoader::remove_image_format_loader(image_loader_bmp);
+ image_loader_bmp.unref();
}
diff --git a/modules/csg/csg.h b/modules/csg/csg.h
index 738e3d68ea..aae99c52a3 100644
--- a/modules/csg/csg.h
+++ b/modules/csg/csg.h
@@ -39,7 +39,6 @@
#include "core/object/ref_counted.h"
#include "core/templates/list.h"
#include "core/templates/oa_hash_map.h"
-#include "core/templates/rb_map.h"
#include "core/templates/vector.h"
#include "scene/resources/material.h"
diff --git a/modules/denoise/SCsub b/modules/denoise/SCsub
index 97feea2b44..779ce165d2 100644
--- a/modules/denoise/SCsub
+++ b/modules/denoise/SCsub
@@ -103,9 +103,9 @@ env_oidn.Append(
"__STDC_LIMIT_MACROS",
"DISABLE_VERBOSE",
"MKLDNN_ENABLE_CONCURRENT_EXEC",
- "NDEBUG",
]
)
+env_oidn.AppendUnique(CPPDEFINES=["NDEBUG"]) # No assert() even in debug builds.
env_thirdparty = env_oidn.Clone()
env_thirdparty.disable_warnings()
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 4f325fcf52..6cf8c1a30e 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -555,7 +555,7 @@
<annotation name="@onready">
<return type="void" />
<description>
- Mark the following property as assigned on [Node]'s ready state change. Values for these properties are no assigned immediately upon the node's creation, and instead are computed and stored right before [method Node._ready].
+ Mark the following property as assigned on [Node]'s ready state change. Values for these properties are not assigned immediately upon the node's creation, and instead are computed and stored right before [method Node._ready].
[codeblock]
@onready var character_name: Label = $Label
[/codeblock]
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 1cff2181af..54cadf7df3 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -2390,7 +2390,7 @@ Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const Str
}
Error err;
- Ref<GDScript> script = GDScriptCache::get_full_script(p_path, err);
+ Ref<GDScript> script = GDScriptCache::get_full_script(p_path, err, "", p_cache_mode == CACHE_MODE_IGNORE);
// TODO: Reintroduce binary and encrypted scripts.
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index e37ac1dc3b..32d9aec84f 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -484,12 +484,23 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
if (parser->script_path == ScriptServer::get_global_class_path(first)) {
result = parser->head->get_datatype();
} else {
- Ref<GDScriptParserRef> ref = get_parser_for(ScriptServer::get_global_class_path(first));
- if (!ref.is_valid() || ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
- push_error(vformat(R"(Could not parse global class "%s" from "%s".)", first, ScriptServer::get_global_class_path(first)), p_type);
- return GDScriptParser::DataType();
+ String path = ScriptServer::get_global_class_path(first);
+ String ext = path.get_extension();
+ if (ext == GDScriptLanguage::get_singleton()->get_extension()) {
+ Ref<GDScriptParserRef> ref = get_parser_for(path);
+ if (!ref.is_valid() || ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
+ push_error(vformat(R"(Could not parse global class "%s" from "%s".)", first, ScriptServer::get_global_class_path(first)), p_type);
+ return GDScriptParser::DataType();
+ }
+ result = ref->get_parser()->head->get_datatype();
+ } else {
+ result.kind = GDScriptParser::DataType::SCRIPT;
+ result.native_type = ScriptServer::get_global_class_native_base(first);
+ result.script_type = ResourceLoader::load(path, "Script");
+ result.script_path = path;
+ result.is_constant = true;
+ result.is_meta_type = false;
}
- result = ref->get_parser()->head->get_datatype();
}
} else if (ProjectSettings::get_singleton()->has_autoload(first) && ProjectSettings::get_singleton()->get_autoload(first).is_singleton) {
const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(first);
@@ -540,12 +551,13 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
result = ref->get_parser()->head->get_datatype();
result.is_meta_type = false;
} else {
- Ref<GDScript> script = member.constant->initializer->reduced_value;
+ Ref<Script> script = member.constant->initializer->reduced_value;
result.kind = GDScriptParser::DataType::SCRIPT;
result.builtin_type = Variant::OBJECT;
result.script_type = script;
result.script_path = script->get_path();
result.native_type = script->get_instance_base_type();
+ result.is_meta_type = false;
}
break;
}
@@ -2676,31 +2688,45 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node)
GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source) {
GDScriptParser::DataType type;
- Ref<GDScriptParserRef> ref = get_parser_for(ScriptServer::get_global_class_path(p_class_name));
- if (ref.is_null()) {
- push_error(vformat(R"(Could not find script for class "%s".)", p_class_name), p_source);
- type.type_source = GDScriptParser::DataType::UNDETECTED;
- type.kind = GDScriptParser::DataType::VARIANT;
+ String path = ScriptServer::get_global_class_path(p_class_name);
+ String ext = path.get_extension();
+ if (ext == GDScriptLanguage::get_singleton()->get_extension()) {
+ Ref<GDScriptParserRef> ref = get_parser_for(path);
+ if (ref.is_null()) {
+ push_error(vformat(R"(Could not find script for class "%s".)", p_class_name), p_source);
+ type.type_source = GDScriptParser::DataType::UNDETECTED;
+ type.kind = GDScriptParser::DataType::VARIANT;
+ return type;
+ }
+
+ Error err = ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ if (err) {
+ push_error(vformat(R"(Could not resolve class "%s", because of a parser error.)", p_class_name), p_source);
+ type.type_source = GDScriptParser::DataType::UNDETECTED;
+ type.kind = GDScriptParser::DataType::VARIANT;
+ return type;
+ }
+
+ type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
+ type.kind = GDScriptParser::DataType::CLASS;
+ type.builtin_type = Variant::OBJECT;
+ type.native_type = ScriptServer::get_global_class_native_base(p_class_name);
+ type.class_type = ref->get_parser()->head;
+ type.script_path = ref->get_parser()->script_path;
+ type.is_constant = true;
+ type.is_meta_type = true;
return type;
- }
-
- Error err = ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
- if (err) {
- push_error(vformat(R"(Could not resolve class "%s", because of a parser error.)", p_class_name), p_source);
- type.type_source = GDScriptParser::DataType::UNDETECTED;
- type.kind = GDScriptParser::DataType::VARIANT;
+ } else {
+ type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
+ type.kind = GDScriptParser::DataType::SCRIPT;
+ type.builtin_type = Variant::OBJECT;
+ type.native_type = ScriptServer::get_global_class_native_base(p_class_name);
+ type.script_type = ResourceLoader::load(path, "Script");
+ type.script_path = path;
+ type.is_constant = true;
+ type.is_meta_type = true;
return type;
}
-
- type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
- type.kind = GDScriptParser::DataType::CLASS;
- type.builtin_type = Variant::OBJECT;
- type.native_type = ScriptServer::get_global_class_native_base(p_class_name);
- type.class_type = ref->get_parser()->head;
- type.script_path = ref->get_parser()->script_path;
- type.is_constant = true;
- type.is_meta_type = true;
- return type;
}
void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNode *p_identifier, GDScriptParser::DataType *p_base) {
@@ -3189,7 +3215,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
p_preload->resolved_path = parser->script_path.get_base_dir().path_join(p_preload->resolved_path);
}
p_preload->resolved_path = p_preload->resolved_path.simplify_path();
- if (!FileAccess::exists(p_preload->resolved_path)) {
+ if (!ResourceLoader::exists(p_preload->resolved_path)) {
push_error(vformat(R"(Preload file "%s" does not exist.)", p_preload->resolved_path), p_preload->path);
} else {
// TODO: Don't load if validating: use completion cache.
@@ -3808,7 +3834,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
Ref<Script> base_script = p_base_type.script_type;
- while (base_script.is_valid() && base_script->is_valid()) {
+ while (base_script.is_valid() && base_script->has_method(function_name)) {
MethodInfo info = base_script->get_method_info(function_name);
if (!(info == MethodInfo())) {
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index c25f5b58d5..271296c2f9 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -183,20 +183,26 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const Stri
return script;
}
-Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_error, const String &p_owner) {
+Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_error, const String &p_owner, bool p_update_from_disk) {
MutexLock lock(singleton->lock);
if (!p_owner.is_empty()) {
singleton->dependencies[p_owner].insert(p_path);
}
+ Ref<GDScript> script;
r_error = OK;
if (singleton->full_gdscript_cache.has(p_path)) {
- return singleton->full_gdscript_cache[p_path];
+ script = Ref<GDScript>(singleton->full_gdscript_cache[p_path]);
+ if (!p_update_from_disk) {
+ return script;
+ }
}
- Ref<GDScript> script = get_shallow_script(p_path);
- ERR_FAIL_COND_V(script.is_null(), Ref<GDScript>());
+ if (script.is_null()) {
+ script = get_shallow_script(p_path);
+ ERR_FAIL_COND_V(script.is_null(), Ref<GDScript>());
+ }
r_error = script->load_source_code(p_path);
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index b971bdd984..3d111ea229 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -88,7 +88,7 @@ public:
static Ref<GDScriptParserRef> get_parser(const String &p_path, GDScriptParserRef::Status status, Error &r_error, const String &p_owner = String());
static String get_source_code(const String &p_path);
static Ref<GDScript> get_shallow_script(const String &p_path, const String &p_owner = String());
- static Ref<GDScript> get_full_script(const String &p_path, Error &r_error, const String &p_owner = String());
+ static Ref<GDScript> get_full_script(const String &p_path, Error &r_error, const String &p_owner = String(), bool p_update_from_disk = false);
static Error finish_compiling(const String &p_owner);
GDScriptCache();
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 888cd782fb..b4da94e448 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -3758,6 +3758,33 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
return false;
}
break;
+ case GDScriptParser::DataType::CLASS:
+ // Can assume type is a global GDScript class.
+ if (!ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) {
+ push_error(R"(Exported script type must extend Resource.)");
+ return false;
+ }
+ variable->export_info.type = Variant::OBJECT;
+ variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ variable->export_info.hint_string = export_type.class_type->identifier->name;
+ break;
+ case GDScriptParser::DataType::SCRIPT: {
+ StringName class_name;
+ if (export_type.script_type != nullptr && export_type.script_type.is_valid()) {
+ class_name = export_type.script_type->get_language()->get_global_class_name(export_type.script_type->get_path());
+ }
+ if (class_name == StringName()) {
+ Ref<Script> script = ResourceLoader::load(export_type.script_path, SNAME("Script"));
+ if (script.is_valid()) {
+ class_name = script->get_language()->get_global_class_name(export_type.script_path);
+ }
+ }
+ if (class_name != StringName() && ClassDB::is_parent_class(ScriptServer::get_global_class_native_base(class_name), SNAME("Resource"))) {
+ variable->export_info.type = Variant::OBJECT;
+ variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ variable->export_info.hint_string = class_name;
+ }
+ } break;
case GDScriptParser::DataType::ENUM: {
variable->export_info.type = Variant::INT;
variable->export_info.hint = PROPERTY_HINT_ENUM;
@@ -3974,7 +4001,7 @@ String GDScriptParser::DataType::to_string() const {
if (is_meta_type) {
return script_type->get_class_name().operator String();
}
- String name = script_type->get_name();
+ String name = script_type != nullptr ? script_type->get_name() : "";
if (!name.is_empty()) {
return name;
}
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 5ad9680ea0..ccde0521f2 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -422,6 +422,7 @@ void GDScriptTextDocument::sync_script_content(const String &p_path, const Strin
if (error == OK) {
if (script->load_source_code(path) == OK) {
script->reload(true);
+ ScriptEditor::get_singleton()->reload_scripts(true); // Refresh scripts opened in the internal editor.
}
}
}
diff --git a/modules/gltf/SCsub b/modules/gltf/SCsub
index 71f3ba58d9..5f111165fd 100644
--- a/modules/gltf/SCsub
+++ b/modules/gltf/SCsub
@@ -7,7 +7,7 @@ env_gltf = env_modules.Clone()
# Godot source files
env_gltf.add_source_files(env.modules_sources, "*.cpp")
-env_gltf.add_source_files(env.modules_sources, "extensions/*.cpp")
env_gltf.add_source_files(env.modules_sources, "structures/*.cpp")
+SConscript("extensions/SCsub")
if env["tools"]:
env_gltf.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
index d2a9022445..936794976d 100644
--- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml
+++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFDocumentExtension" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
+ [GLTFDocument] extension class.
</brief_description>
<description>
+ Extends the functionality of the [GLTFDocument] class by allowing you to run arbitrary code at various stages of GLTF import or export.
</description>
<tutorials>
</tutorials>
@@ -28,6 +30,12 @@
<description>
</description>
</method>
+ <method name="_get_supported_extensions" qualifiers="virtual">
+ <return type="PackedStringArray" />
+ <description>
+ Returns an array of the GLTF extensions supported by this GLTFDocumentExtension class. This is used to validate if a GLTF file with required extensions can be loaded.
+ </description>
+ </method>
<method name="_import_node" qualifiers="virtual">
<return type="int" />
<param index="0" name="state" type="GLTFState" />
diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index e933e6046a..4d1aa89ac9 100644
--- a/modules/gltf/doc_classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
@@ -1,10 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFNode" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
+ GLTF node class.
</brief_description>
<description>
+ Represents a GLTF node. GLTF nodes may have names, transforms, children (other GLTF nodes), and more specialized properties (represented by their own classes).
</description>
<tutorials>
+ <link title="GLTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link>
</tutorials>
<members>
<member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1">
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index 1dbd89aed8..6c2f488c1c 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -7,6 +7,14 @@
<tutorials>
</tutorials>
<methods>
+ <method name="add_used_extension">
+ <return type="void" />
+ <param index="0" name="extension_name" type="String" />
+ <param index="1" name="required" type="bool" />
+ <description>
+ Appends an extension to the list of extensions used by this GLTF file during serialization. If [param required] is true, the extension will also be added to the list of required extensions. Do not run this in [method GLTFDocumentExtension._export_post], as that stage is too late to add extensions. The final list is sorted alphabetically.
+ </description>
+ </method>
<method name="get_accessors">
<return type="GLTFAccessor[]" />
<description>
diff --git a/modules/gltf/extensions/SCsub b/modules/gltf/extensions/SCsub
new file mode 100644
index 0000000000..ad214bb79c
--- /dev/null
+++ b/modules/gltf/extensions/SCsub
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_gltf = env_modules.Clone()
+
+# Godot source files
+env_gltf.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/gltf/gltf_defines.h b/modules/gltf/gltf_defines.h
index c20c87f798..9ee2397968 100644
--- a/modules/gltf/gltf_defines.h
+++ b/modules/gltf/gltf_defines.h
@@ -66,9 +66,9 @@ using GLTFBufferIndex = int;
using GLTFBufferViewIndex = int;
using GLTFCameraIndex = int;
using GLTFImageIndex = int;
+using GLTFLightIndex = int;
using GLTFMaterialIndex = int;
using GLTFMeshIndex = int;
-using GLTFLightIndex = int;
using GLTFNodeIndex = int;
using GLTFSkeletonIndex = int;
using GLTFSkinIndex = int;
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index f5730e7137..8d2e37be3a 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -191,14 +191,14 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) {
return Error::FAILED;
}
- /* STEP SERIALIZE SCENE */
+ /* STEP SERIALIZE LIGHTS */
err = _serialize_lights(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE EXTENSIONS */
- err = _serialize_extensions(state);
+ err = _serialize_gltf_extensions(state);
if (err != OK) {
return Error::FAILED;
}
@@ -219,9 +219,9 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) {
return OK;
}
-Error GLTFDocument::_serialize_extensions(Ref<GLTFState> state) const {
- Array extensions_used;
- Array extensions_required;
+Error GLTFDocument::_serialize_gltf_extensions(Ref<GLTFState> state) const {
+ Vector<String> extensions_used = state->extensions_used;
+ Vector<String> extensions_required = state->extensions_required;
if (!state->lights.is_empty()) {
extensions_used.push_back("KHR_lights_punctual");
}
@@ -230,9 +230,11 @@ Error GLTFDocument::_serialize_extensions(Ref<GLTFState> state) const {
extensions_required.push_back("KHR_texture_transform");
}
if (!extensions_used.is_empty()) {
+ extensions_used.sort();
state->json["extensionsUsed"] = extensions_used;
}
if (!extensions_required.is_empty()) {
+ extensions_required.sort();
state->json["extensionsRequired"] = extensions_required;
}
return OK;
@@ -401,47 +403,47 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
Array nodes;
for (int i = 0; i < state->nodes.size(); i++) {
Dictionary node;
- Ref<GLTFNode> n = state->nodes[i];
+ Ref<GLTFNode> gltf_node = state->nodes[i];
Dictionary extensions;
node["extensions"] = extensions;
- if (!n->get_name().is_empty()) {
- node["name"] = n->get_name();
+ if (!gltf_node->get_name().is_empty()) {
+ node["name"] = gltf_node->get_name();
}
- if (n->camera != -1) {
- node["camera"] = n->camera;
+ if (gltf_node->camera != -1) {
+ node["camera"] = gltf_node->camera;
}
- if (n->light != -1) {
+ if (gltf_node->light != -1) {
Dictionary lights_punctual;
extensions["KHR_lights_punctual"] = lights_punctual;
- lights_punctual["light"] = n->light;
+ lights_punctual["light"] = gltf_node->light;
}
- if (n->mesh != -1) {
- node["mesh"] = n->mesh;
+ if (gltf_node->mesh != -1) {
+ node["mesh"] = gltf_node->mesh;
}
- if (n->skin != -1) {
- node["skin"] = n->skin;
+ if (gltf_node->skin != -1) {
+ node["skin"] = gltf_node->skin;
}
- if (n->skeleton != -1 && n->skin < 0) {
+ if (gltf_node->skeleton != -1 && gltf_node->skin < 0) {
}
- if (n->xform != Transform3D()) {
- node["matrix"] = _xform_to_array(n->xform);
+ if (gltf_node->xform != Transform3D()) {
+ node["matrix"] = _xform_to_array(gltf_node->xform);
}
- if (!n->rotation.is_equal_approx(Quaternion())) {
- node["rotation"] = _quaternion_to_array(n->rotation);
+ if (!gltf_node->rotation.is_equal_approx(Quaternion())) {
+ node["rotation"] = _quaternion_to_array(gltf_node->rotation);
}
- if (!n->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) {
- node["scale"] = _vec3_to_arr(n->scale);
+ if (!gltf_node->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) {
+ node["scale"] = _vec3_to_arr(gltf_node->scale);
}
- if (!n->position.is_zero_approx()) {
- node["translation"] = _vec3_to_arr(n->position);
+ if (!gltf_node->position.is_zero_approx()) {
+ node["translation"] = _vec3_to_arr(gltf_node->position);
}
- if (n->children.size()) {
+ if (gltf_node->children.size()) {
Array children;
- for (int j = 0; j < n->children.size(); j++) {
- children.push_back(n->children[j]);
+ for (int j = 0; j < gltf_node->children.size(); j++) {
+ children.push_back(gltf_node->children[j]);
}
node["children"] = children;
}
@@ -450,7 +452,7 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
ERR_CONTINUE(ext.is_null());
ERR_CONTINUE(!state->scene_nodes.find(i));
- Error err = ext->export_node(state, n, state->json, state->scene_nodes[i]);
+ Error err = ext->export_node(state, gltf_node, node, state->scene_nodes[i]);
ERR_CONTINUE(err != OK);
}
@@ -5046,7 +5048,7 @@ ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> sta
return mi;
}
-Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index) {
+Light3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index) {
Ref<GLTFNode> gltf_node = state->nodes[node_index];
ERR_FAIL_INDEX_V(gltf_node->light, state->lights.size(), nullptr);
@@ -5102,6 +5104,7 @@ Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, const GLTFNodeInde
return spatial;
}
+
void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) {
bool retflag = true;
_check_visibility(p_current, retflag);
@@ -6916,12 +6919,32 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint
Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) {
ERR_FAIL_NULL_V(state, ERR_PARSE_ERROR);
- if (state->json.has("extensionsRequired") && state->json["extensionsRequired"].get_type() == Variant::ARRAY) {
- Array extensions_required = state->json["extensionsRequired"];
- if (extensions_required.find("KHR_draco_mesh_compression") != -1) {
- ERR_PRINT("glTF2 extension KHR_draco_mesh_compression is not supported.");
- return ERR_UNAVAILABLE;
+ if (state->json.has("extensionsUsed")) {
+ Vector<String> ext_array = state->json["extensionsUsed"];
+ state->extensions_used = ext_array;
+ }
+ if (state->json.has("extensionsRequired")) {
+ Vector<String> ext_array = state->json["extensionsRequired"];
+ state->extensions_required = ext_array;
+ }
+ HashSet<String> supported_extensions;
+ supported_extensions.insert("KHR_lights_punctual");
+ supported_extensions.insert("KHR_materials_pbrSpecularGlossiness");
+ supported_extensions.insert("KHR_texture_transform");
+ for (int ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ Vector<String> ext_supported_extensions = ext->get_supported_extensions();
+ for (int i = 0; i < ext_supported_extensions.size(); ++i) {
+ supported_extensions.insert(ext_supported_extensions[i]);
}
}
- return OK;
+ Error ret = Error::OK;
+ for (int i = 0; i < state->extensions_required.size(); i++) {
+ if (!supported_extensions.has(state->extensions_required[i])) {
+ ERR_PRINT("GLTF: Can't import file '" + state->filename + "', required extension '" + String(state->extensions_required[i]) + "' is not supported. Are you missing a GLTFDocumentExtension plugin?");
+ ret = ERR_UNAVAILABLE;
+ }
+ }
+ return ret;
}
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 36a2f94a4e..750d3d403e 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -188,7 +188,7 @@ private:
const GLTFNodeIndex bone_index);
ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, const GLTFNodeIndex node_index);
Camera3D *_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index);
- Node3D *_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index);
+ Light3D *_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index);
Node3D *_generate_spatial(Ref<GLTFState> state, const GLTFNodeIndex node_index);
void _assign_scene_names(Ref<GLTFState> state);
template <class T>
@@ -265,7 +265,7 @@ private:
Dictionary _serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material);
Error _serialize_version(Ref<GLTFState> state);
Error _serialize_file(Ref<GLTFState> state, const String p_path);
- Error _serialize_extensions(Ref<GLTFState> state) const;
+ Error _serialize_gltf_extensions(Ref<GLTFState> state) const;
public:
// https://www.itu.int/rec/R-REC-BT.601
diff --git a/modules/gltf/gltf_document_extension.cpp b/modules/gltf/gltf_document_extension.cpp
index d0bd7651e0..3b952f8246 100644
--- a/modules/gltf/gltf_document_extension.cpp
+++ b/modules/gltf/gltf_document_extension.cpp
@@ -31,6 +31,7 @@
#include "gltf_document_extension.h"
void GLTFDocumentExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_supported_extensions);
GDVIRTUAL_BIND(_import_preflight, "state");
GDVIRTUAL_BIND(_import_post_parse, "state");
GDVIRTUAL_BIND(_import_node, "state", "gltf_node", "json", "node");
@@ -40,6 +41,12 @@ void GLTFDocumentExtension::_bind_methods() {
GDVIRTUAL_BIND(_export_post, "state");
}
+Vector<String> GLTFDocumentExtension::get_supported_extensions() {
+ Vector<String> ret;
+ GDVIRTUAL_CALL(_get_supported_extensions, ret);
+ return ret;
+}
+
Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) {
ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
diff --git a/modules/gltf/gltf_document_extension.h b/modules/gltf/gltf_document_extension.h
index 0ef9109584..d4bb3993dc 100644
--- a/modules/gltf/gltf_document_extension.h
+++ b/modules/gltf/gltf_document_extension.h
@@ -41,6 +41,7 @@ protected:
static void _bind_methods();
public:
+ virtual Vector<String> get_supported_extensions();
virtual Error import_preflight(Ref<GLTFState> p_state);
virtual Error import_post_parse(Ref<GLTFState> p_state);
virtual Error export_post(Ref<GLTFState> p_state);
@@ -48,6 +49,7 @@ public:
virtual Error export_preflight(Node *p_state);
virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
virtual Error export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
+ GDVIRTUAL0R(Vector<String>, _get_supported_extensions);
GDVIRTUAL1R(int, _import_preflight, Ref<GLTFState>);
GDVIRTUAL1R(int, _import_post_parse, Ref<GLTFState>);
GDVIRTUAL4R(int, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index 85bac446cc..a23fb39503 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -31,6 +31,7 @@
#include "gltf_state.h"
void GLTFState::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("add_used_extension", "extension_name", "required"), &GLTFState::add_used_extension);
ClassDB::bind_method(D_METHOD("get_json"), &GLTFState::get_json);
ClassDB::bind_method(D_METHOD("set_json", "json"), &GLTFState::set_json);
ClassDB::bind_method(D_METHOD("get_major_version"), &GLTFState::get_major_version);
@@ -112,6 +113,17 @@ void GLTFState::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>>
}
+void GLTFState::add_used_extension(const String &p_extension_name, bool p_required) {
+ if (!extensions_used.has(p_extension_name)) {
+ extensions_used.push_back(p_extension_name);
+ }
+ if (p_required) {
+ if (!extensions_required.has(p_extension_name)) {
+ extensions_required.push_back(p_extension_name);
+ }
+ }
+}
+
Dictionary GLTFState::get_json() {
return json;
}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index 6b2d1ca228..791431f376 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -78,6 +78,8 @@ class GLTFState : public Resource {
Vector<int> root_nodes;
Vector<Ref<GLTFTexture>> textures;
Vector<Ref<Texture2D>> images;
+ Vector<String> extensions_used;
+ Vector<String> extensions_required;
Vector<Ref<GLTFSkin>> skins;
Vector<Ref<GLTFCamera>> cameras;
@@ -97,6 +99,8 @@ protected:
static void _bind_methods();
public:
+ void add_used_extension(const String &p_extension, bool p_required = false);
+
Dictionary get_json();
void set_json(Dictionary p_json);
diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp
index e7c6fe592d..6f0bc16a26 100644
--- a/modules/hdr/image_loader_hdr.cpp
+++ b/modules/hdr/image_loader_hdr.cpp
@@ -33,7 +33,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
String header = f->get_token();
ERR_FAIL_COND_V_MSG(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED, "Unsupported header information in HDR: " + header + ".");
diff --git a/modules/hdr/image_loader_hdr.h b/modules/hdr/image_loader_hdr.h
index 1bff05129b..5f817f0ba8 100644
--- a/modules/hdr/image_loader_hdr.h
+++ b/modules/hdr/image_loader_hdr.h
@@ -35,7 +35,7 @@
class ImageLoaderHDR : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderHDR();
};
diff --git a/modules/hdr/register_types.cpp b/modules/hdr/register_types.cpp
index b988bf4587..18b1a73f1c 100644
--- a/modules/hdr/register_types.cpp
+++ b/modules/hdr/register_types.cpp
@@ -32,14 +32,14 @@
#include "image_loader_hdr.h"
-static ImageLoaderHDR *image_loader_hdr = nullptr;
+static Ref<ImageLoaderHDR> image_loader_hdr;
void initialize_hdr_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
- image_loader_hdr = memnew(ImageLoaderHDR);
+ image_loader_hdr.instantiate();
ImageLoader::add_image_format_loader(image_loader_hdr);
}
@@ -48,5 +48,6 @@ void uninitialize_hdr_module(ModuleInitializationLevel p_level) {
return;
}
- memdelete(image_loader_hdr);
+ ImageLoader::remove_image_format_loader(image_loader_hdr);
+ image_loader_hdr.unref();
}
diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp
index 3e138bf633..ce20ac9060 100644
--- a/modules/jpg/image_loader_jpegd.cpp
+++ b/modules/jpg/image_loader_jpegd.cpp
@@ -104,7 +104,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
return OK;
}
-Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
diff --git a/modules/jpg/image_loader_jpegd.h b/modules/jpg/image_loader_jpegd.h
index caa0461d05..f63db51521 100644
--- a/modules/jpg/image_loader_jpegd.h
+++ b/modules/jpg/image_loader_jpegd.h
@@ -35,7 +35,7 @@
class ImageLoaderJPG : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderJPG();
};
diff --git a/modules/jpg/register_types.cpp b/modules/jpg/register_types.cpp
index b8b48a550f..7da216bbe2 100644
--- a/modules/jpg/register_types.cpp
+++ b/modules/jpg/register_types.cpp
@@ -32,14 +32,14 @@
#include "image_loader_jpegd.h"
-static ImageLoaderJPG *image_loader_jpg = nullptr;
+static Ref<ImageLoaderJPG> image_loader_jpg;
void initialize_jpg_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
- image_loader_jpg = memnew(ImageLoaderJPG);
+ image_loader_jpg.instantiate();
ImageLoader::add_image_format_loader(image_loader_jpg);
}
@@ -48,5 +48,6 @@ void uninitialize_jpg_module(ModuleInitializationLevel p_level) {
return;
}
- memdelete(image_loader_jpg);
+ ImageLoader::remove_image_format_loader(image_loader_jpg);
+ image_loader_jpg.unref();
}
diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py
index 6f66ce9efa..d78a9c7db8 100755
--- a/modules/mono/build_scripts/build_assemblies.py
+++ b/modules/mono/build_scripts/build_assemblies.py
@@ -315,6 +315,8 @@ def main():
output_dir = os.path.abspath(args.godot_output_dir)
+ push_nupkgs_local = os.path.abspath(args.push_nupkgs_local) if args.push_nupkgs_local else None
+
msbuild_tool = find_any_msbuild_tool(args.mono_prefix)
if msbuild_tool is None:
@@ -327,7 +329,7 @@ def main():
output_dir,
args.godot_platform,
args.dev_debug,
- args.push_nupkgs_local,
+ push_nupkgs_local,
args.float,
)
sys.exit(exit_code)
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 8fd3626a20..97a1d5c8d8 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -1299,7 +1299,7 @@ GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token,
MonoGCHandleData &gchandle = script_binding.gchandle;
- int refcount = rc_owner->reference_get_count();
+ int refcount = rc_owner->get_reference_count();
if (!script_binding.inited) {
return refcount == 0;
@@ -1818,7 +1818,7 @@ void CSharpInstance::refcount_incremented() {
RefCounted *rc_owner = Object::cast_to<RefCounted>(owner);
- if (rc_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ if (rc_owner->get_reference_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
// The reference count was increased after the managed side was the only one referencing our owner.
// This means the owner is being referenced again by the unmanaged side,
// so the owner must hold the managed side alive again to avoid it from being GCed.
@@ -1849,7 +1849,7 @@ bool CSharpInstance::refcount_decremented() {
RefCounted *rc_owner = Object::cast_to<RefCounted>(owner);
- int refcount = rc_owner->reference_get_count();
+ int refcount = rc_owner->get_reference_count();
if (refcount == 1 && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
// If owner owner is no longer referenced by the unmanaged side,
@@ -1995,7 +1995,7 @@ CSharpInstance::~CSharpInstance() {
#ifdef DEBUG_ENABLED
// The "instance binding" holds a reference so the refcount should be at least 2 before `scope_keep_owner_alive` goes out of scope
- CRASH_COND(rc_owner->reference_get_count() <= 1);
+ CRASH_COND(rc_owner->get_reference_count() <= 1);
#endif
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
index bff9760b32..859ea52c93 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
@@ -17,7 +17,7 @@
<!-- C# source generators -->
<ItemGroup Condition=" '$(DisableImplicitGodotGeneratorReferences)' != 'true' ">
- <PackageReference Include="Godot.SourceGenerators" Version="$(PackageFloatingVersion_Godot)" />
+ <PackageReference Include="Godot.SourceGenerators" Version="$(PackageVersion_Godot_SourceGenerators)" />
</ItemGroup>
<!-- Godot API references -->
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs
new file mode 100644
index 0000000000..ddde730fa2
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs
@@ -0,0 +1,53 @@
+using System.Collections.Immutable;
+using System.Linq;
+using System.Threading;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Godot.SourceGenerators
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class EventHandlerSuffixSuppressor : DiagnosticSuppressor
+ {
+ private static readonly SuppressionDescriptor _descriptor = new(
+ id: "GDSP0001",
+ suppressedDiagnosticId: "CA1711",
+ justification: "Signal delegates are used in events so the naming follows the guidelines.");
+
+ public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions =>
+ ImmutableArray.Create(_descriptor);
+
+ public override void ReportSuppressions(SuppressionAnalysisContext context)
+ {
+ foreach (var diagnostic in context.ReportedDiagnostics)
+ {
+ AnalyzeDiagnostic(context, diagnostic, context.CancellationToken);
+ }
+ }
+
+ private static void AnalyzeDiagnostic(SuppressionAnalysisContext context, Diagnostic diagnostic, CancellationToken cancellationToken = default)
+ {
+ var location = diagnostic.Location;
+ var root = location.SourceTree?.GetRoot(cancellationToken);
+ var dds = root?
+ .FindNode(location.SourceSpan)
+ .DescendantNodesAndSelf()
+ .OfType<DelegateDeclarationSyntax>()
+ .FirstOrDefault();
+
+ if (dds == null)
+ return;
+
+ var semanticModel = context.GetSemanticModel(dds.SyntaxTree);
+ var delegateSymbol = semanticModel.GetDeclaredSymbol(dds, cancellationToken);
+ if (delegateSymbol == null)
+ return;
+
+ if (delegateSymbol.GetAttributes().Any(a => a.AttributeClass?.IsGodotSignalAttribute() ?? false))
+ {
+ context.ReportSuppression(Suppression.Create(_descriptor, diagnostic));
+ }
+ }
+ }
+}
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 de3b6c862a..8de12de23b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -29,7 +29,7 @@ namespace Godot.SourceGenerators
{
while (symbol != null)
{
- if (symbol.ContainingAssembly.Name == assemblyName &&
+ if (symbol.ContainingAssembly?.Name == assemblyName &&
symbol.ToString() == typeFullName)
{
return true;
@@ -47,7 +47,7 @@ namespace Godot.SourceGenerators
while (symbol != null)
{
- if (symbol.ContainingAssembly.Name == "GodotSharp")
+ if (symbol.ContainingAssembly?.Name == "GodotSharp")
return symbol;
symbol = symbol.BaseType;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
index efdd50098e..bd40675fd3 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
@@ -124,8 +124,8 @@ namespace Godot.SourceGenerators
if (typeKind == TypeKind.Struct)
{
- if (type.ContainingAssembly.Name == "GodotSharp" &&
- type.ContainingNamespace.Name == "Godot")
+ if (type.ContainingAssembly?.Name == "GodotSharp" &&
+ type.ContainingNamespace?.Name == "Godot")
{
return type switch
{
@@ -156,6 +156,10 @@ namespace Godot.SourceGenerators
else if (typeKind == TypeKind.Array)
{
var arrayType = (IArrayTypeSymbol)type;
+
+ if (arrayType.Rank != 1)
+ return null;
+
var elementType = arrayType.ElementType;
switch (elementType.SpecialType)
@@ -177,8 +181,8 @@ namespace Godot.SourceGenerators
if (elementType.SimpleDerivesFrom(typeCache.GodotObjectType))
return MarshalType.GodotObjectOrDerivedArray;
- if (elementType.ContainingAssembly.Name == "GodotSharp" &&
- elementType.ContainingNamespace.Name == "Godot")
+ if (elementType.ContainingAssembly?.Name == "GodotSharp" &&
+ elementType.ContainingNamespace?.Name == "Godot")
{
switch (elementType)
{
@@ -204,9 +208,9 @@ namespace Godot.SourceGenerators
if (type.SimpleDerivesFrom(typeCache.GodotObjectType))
return MarshalType.GodotObjectOrDerived;
- if (type.ContainingAssembly.Name == "GodotSharp")
+ if (type.ContainingAssembly?.Name == "GodotSharp")
{
- switch (type.ContainingNamespace.Name)
+ switch (type.ContainingNamespace?.Name)
{
case "Godot":
return type switch
@@ -216,7 +220,7 @@ namespace Godot.SourceGenerators
_ => null
};
case "Collections"
- when type.ContainingNamespace.FullQualifiedName() == "Godot.Collections":
+ when type.ContainingNamespace?.FullQualifiedName() == "Godot.Collections":
return type switch
{
{ Name: "Dictionary" } =>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
index 1df41a905b..eeda1042ca 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -235,6 +235,8 @@ namespace Godot.SourceGenerators
.Append(signalName)
.Append(";\n");
+ source.Append($" /// <inheritdoc cref=\"{signalDelegate.DelegateSymbol.FullQualifiedName()}\"/>\n");
+
source.Append(" public event ")
.Append(signalDelegate.DelegateSymbol.FullQualifiedName())
.Append(" ")
diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
index 4baae77b34..37bd4a0be0 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
+++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
@@ -21,10 +21,13 @@
Outputs="$(GeneratedGodotNupkgsVersionsFile)">
<PropertyGroup>
<GenerateGodotNupkgsVersionsCode><![CDATA[
-namespace $(RootNamespace) {
- public class GeneratedGodotNupkgsVersions {
+namespace $(RootNamespace)
+{
+ public class GeneratedGodotNupkgsVersions
+ {
public const string GodotNETSdk = "$(PackageVersion_Godot_NET_Sdk)"%3b
public const string GodotSourceGenerators = "$(PackageVersion_Godot_SourceGenerators)"%3b
+ public const string GodotSharp = "$(PackageVersion_GodotSharp)"%3b
}
}
]]></GenerateGodotNupkgsVersionsCode>
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index ad4fce8daa..4d40724a83 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -69,51 +69,41 @@ namespace GodotTools.Build
private void LoadIssuesFromFile(string csvFile)
{
- using (var file = new Godot.File())
+ using var file = FileAccess.Open(csvFile, FileAccess.ModeFlags.Read);
+
+ if (file == null)
+ return;
+
+ while (!file.EofReached())
{
- try
- {
- Error openError = file.Open(csvFile, Godot.File.ModeFlags.Read);
+ string[] csvColumns = file.GetCsvLine();
- if (openError != Error.Ok)
- return;
+ if (csvColumns.Length == 1 && string.IsNullOrEmpty(csvColumns[0]))
+ return;
- while (!file.EofReached())
- {
- string[] csvColumns = file.GetCsvLine();
-
- if (csvColumns.Length == 1 && string.IsNullOrEmpty(csvColumns[0]))
- return;
-
- if (csvColumns.Length != 7)
- {
- GD.PushError($"Expected 7 columns, got {csvColumns.Length}");
- continue;
- }
-
- var issue = new BuildIssue
- {
- Warning = csvColumns[0] == "warning",
- File = csvColumns[1],
- Line = int.Parse(csvColumns[2]),
- Column = int.Parse(csvColumns[3]),
- Code = csvColumns[4],
- Message = csvColumns[5],
- ProjectFile = csvColumns[6]
- };
-
- if (issue.Warning)
- WarningCount += 1;
- else
- ErrorCount += 1;
-
- _issues.Add(issue);
- }
- }
- finally
+ if (csvColumns.Length != 7)
{
- file.Close(); // Disposing it is not enough. We need to call Close()
+ GD.PushError($"Expected 7 columns, got {csvColumns.Length}");
+ continue;
}
+
+ var issue = new BuildIssue
+ {
+ Warning = csvColumns[0] == "warning",
+ File = csvColumns[1],
+ Line = int.Parse(csvColumns[2]),
+ Column = int.Parse(csvColumns[3]),
+ Code = csvColumns[4],
+ Message = csvColumns[5],
+ ProjectFile = csvColumns[6]
+ };
+
+ if (issue.Warning)
+ WarningCount += 1;
+ else
+ ErrorCount += 1;
+
+ _issues.Add(issue);
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs
index 7bce53308c..b437c7e742 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
+using System.Runtime.InteropServices;
using JetBrains.Annotations;
using OS = GodotTools.Utils.OS;
@@ -16,6 +17,23 @@ namespace GodotTools.Build
// In the future, this method may do more than just search in PATH. We could look in
// known locations or use Godot's linked nethost to search from the hostfxr location.
+ if (OS.IsMacOS)
+ {
+ if (RuntimeInformation.OSArchitecture == Architecture.X64)
+ {
+ string dotnet_x64 = "/usr/local/share/dotnet/x64/dotnet"; // Look for x64 version, when running under Rosetta 2.
+ if (File.Exists(dotnet_x64))
+ {
+ return dotnet_x64;
+ }
+ }
+ string dotnet = "/usr/local/share/dotnet/dotnet"; // Look for native version.
+ if (File.Exists(dotnet))
+ {
+ return dotnet;
+ }
+ }
+
return OS.PathWhich("dotnet");
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
index d2e0e128b5..fe309b8102 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
@@ -22,71 +22,13 @@ namespace GodotTools.Build
public static string GodotFallbackFolderPath
=> Path.Combine(GodotSharpDirs.MonoUserDir, "GodotNuGetFallbackFolder");
- private static void AddFallbackFolderToNuGetConfig(string nuGetConfigPath, string name, string path)
- {
- var xmlDoc = new XmlDocument();
- xmlDoc.Load(nuGetConfigPath);
-
- const string nuGetConfigRootName = "configuration";
-
- var rootNode = xmlDoc.DocumentElement;
-
- if (rootNode == null)
- {
- // No root node, create it
- rootNode = xmlDoc.CreateElement(nuGetConfigRootName);
- xmlDoc.AppendChild(rootNode);
-
- // Since this can be considered pretty much a new NuGet.Config, add the default nuget.org source as well
- XmlElement nugetOrgSourceEntry = xmlDoc.CreateElement("add");
- nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("key")).Value = "nuget.org";
- nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("value")).Value =
- "https://api.nuget.org/v3/index.json";
- nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("protocolVersion")).Value = "3";
- rootNode.AppendChild(xmlDoc.CreateElement("packageSources")).AppendChild(nugetOrgSourceEntry);
- }
- else
- {
- // Check that the root node is the expected one
- if (rootNode.Name != nuGetConfigRootName)
- throw new FormatException("Invalid root Xml node for NuGet.Config. " +
- $"Expected '{nuGetConfigRootName}' got '{rootNode.Name}'.");
- }
-
- var fallbackFoldersNode = rootNode["fallbackPackageFolders"] ??
- rootNode.AppendChild(xmlDoc.CreateElement("fallbackPackageFolders"));
-
- // Check if it already has our fallback package folder
- for (var xmlNode = fallbackFoldersNode.FirstChild; xmlNode != null; xmlNode = xmlNode.NextSibling)
- {
- if (xmlNode.NodeType != XmlNodeType.Element)
- continue;
-
- var xmlElement = (XmlElement)xmlNode;
- if (xmlElement.Name == "add" &&
- xmlElement.Attributes["key"]?.Value == name &&
- xmlElement.Attributes["value"]?.Value == path)
- {
- return;
- }
- }
-
- XmlElement newEntry = xmlDoc.CreateElement("add");
- newEntry.Attributes.Append(xmlDoc.CreateAttribute("key")).Value = name;
- newEntry.Attributes.Append(xmlDoc.CreateAttribute("value")).Value = path;
-
- fallbackFoldersNode.AppendChild(newEntry);
-
- xmlDoc.Save(nuGetConfigPath);
- }
-
/// <summary>
- /// Returns all the paths where the user NuGet.Config files can be found.
+ /// Returns all the paths where the Godot.Offline.Config files can be found.
/// Does not determine whether the returned files exist or not.
/// </summary>
- private static string[] GetAllUserNuGetConfigFilePaths()
+ private static string[] GetAllGodotNuGetConfigFilePaths()
{
- // Where to find 'NuGet/NuGet.Config':
+ // Where to find 'NuGet/config/Godot.Offline.Config':
//
// - Mono/.NETFramework (standalone NuGet):
// Uses Environment.SpecialFolder.ApplicationData
@@ -98,10 +40,12 @@ namespace GodotTools.Build
string applicationData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
+ const string configFileName = "Godot.Offline.Config";
+
if (Utils.OS.IsWindows)
{
// %APPDATA% for both
- return new[] { Path.Combine(applicationData, "NuGet", "NuGet.Config") };
+ return new[] { Path.Combine(applicationData, "NuGet", "config", configFileName) };
}
var paths = new string[2];
@@ -111,20 +55,20 @@ namespace GodotTools.Build
string dotnetCliHome = Environment.GetEnvironmentVariable("DOTNET_CLI_HOME");
if (!string.IsNullOrEmpty(dotnetCliHome))
{
- paths[0] = Path.Combine(dotnetCliHome, ".nuget", "NuGet", "NuGet.Config");
+ paths[0] = Path.Combine(dotnetCliHome, ".nuget", "NuGet", "config", configFileName);
}
else
{
string home = Environment.GetEnvironmentVariable("HOME");
if (string.IsNullOrEmpty(home))
throw new InvalidOperationException("Required environment variable 'HOME' is not set.");
- paths[0] = Path.Combine(home, ".nuget", "NuGet", "NuGet.Config");
+ paths[0] = Path.Combine(home, ".nuget", "NuGet", "config", configFileName);
}
// Mono/.NETFramework (standalone NuGet)
// ApplicationData is $HOME/.config on Linux/macOS
- paths[1] = Path.Combine(applicationData, "NuGet", "NuGet.Config");
+ paths[1] = Path.Combine(applicationData, "NuGet", "config", configFileName);
return paths;
}
@@ -141,28 +85,26 @@ namespace GodotTools.Build
// The nuspec is not lower case inside the nupkg but must be made lower case when extracted.
/// <summary>
- /// Adds the specified fallback folder to the user NuGet.Config files,
+ /// Adds the specified fallback folder to the Godot.Offline.Config files,
/// for both standalone NuGet (Mono/.NETFramework) and dotnet CLI NuGet.
/// </summary>
- public static void AddFallbackFolderToUserNuGetConfigs(string name, string path)
+ public static void AddFallbackFolderToGodotNuGetConfigs(string name, string path)
{
- foreach (string nuGetConfigPath in GetAllUserNuGetConfigFilePaths())
+ // Make sure the fallback folder exists to avoid error:
+ // MSB4018: The "ResolvePackageAssets" task failed unexpectedly.
+ System.IO.Directory.CreateDirectory(path);
+
+ foreach (string nuGetConfigPath in GetAllGodotNuGetConfigFilePaths())
{
- if (!System.IO.File.Exists(nuGetConfigPath))
- {
- // It doesn't exist, so we create a default one
- const string defaultConfig = @"<?xml version=""1.0"" encoding=""utf-8""?>
+ string defaultConfig = @$"<?xml version=""1.0"" encoding=""utf-8""?>
<configuration>
- <packageSources>
- <add key=""nuget.org"" value=""https://api.nuget.org/v3/index.json"" protocolVersion=""3"" />
- </packageSources>
+ <fallbackPackageFolders>
+ <add key=""{name}"" value=""{path}"" />
+ </fallbackPackageFolders>
</configuration>
";
- System.IO.Directory.CreateDirectory(Path.GetDirectoryName(nuGetConfigPath));
- System.IO.File.WriteAllText(nuGetConfigPath, defaultConfig, Encoding.UTF8); // UTF-8 with BOM
- }
-
- AddFallbackFolderToNuGetConfig(nuGetConfigPath, name, path);
+ System.IO.Directory.CreateDirectory(Path.GetDirectoryName(nuGetConfigPath));
+ System.IO.File.WriteAllText(nuGetConfigPath, defaultConfig, Encoding.UTF8); // UTF-8 with BOM
}
}
@@ -189,6 +131,7 @@ namespace GodotTools.Build
string destDir = Path.Combine(fallbackFolder, packageIdLower, packageVersionLower);
string nupkgDestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg");
string nupkgSha512DestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg.sha512");
+ string nupkgMetadataDestPath = Path.Combine(destDir, ".nupkg.metadata");
if (File.Exists(nupkgDestPath) && File.Exists(nupkgSha512DestPath))
return; // Already added (for speed we don't check if every file is properly extracted)
@@ -197,12 +140,18 @@ namespace GodotTools.Build
// Generate .nupkg.sha512 file
- using (var alg = SHA512.Create())
- {
- alg.ComputeHash(File.ReadAllBytes(nupkgPath));
- string base64Hash = Convert.ToBase64String(alg.Hash);
- File.WriteAllText(nupkgSha512DestPath, base64Hash);
- }
+ byte[] hash = SHA512.HashData(File.ReadAllBytes(nupkgPath));
+ string base64Hash = Convert.ToBase64String(hash);
+ File.WriteAllText(nupkgSha512DestPath, base64Hash);
+
+ // Generate .nupkg.metadata file
+ // Spec: https://github.com/NuGet/Home/wiki/Nupkg-Metadata-File
+
+ File.WriteAllText(nupkgMetadataDestPath, @$"{{
+ ""version"": 2,
+ ""contentHash"": ""{base64Hash}"",
+ ""source"": null
+}}");
// Extract nupkg
ExtractNupkg(destDir, nupkgPath, packageId, packageVersion);
@@ -251,7 +200,7 @@ namespace GodotTools.Build
entryFullName.EndsWith(".nupkg.sha512", StringComparison.OrdinalIgnoreCase) ||
entryFullName.EndsWith(".nupkg.metadata", StringComparison.OrdinalIgnoreCase) ||
// Nuspec at root level. We already extracted it previously but in lower case.
- entryFullName.IndexOf('/') == -1 && entryFullName.EndsWith(".nuspec"))
+ !entryFullName.Contains('/') && entryFullName.EndsWith(".nuspec"))
{
continue;
}
@@ -297,6 +246,8 @@ namespace GodotTools.Build
{
("Godot.NET.Sdk", GeneratedGodotNupkgsVersions.GodotNETSdk),
("Godot.SourceGenerators", GeneratedGodotNupkgsVersions.GodotSourceGenerators),
+ ("GodotSharp", GeneratedGodotNupkgsVersions.GodotSharp),
+ ("GodotSharpEditor", GeneratedGodotNupkgsVersions.GodotSharp),
};
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 1cfaea3ec9..89364d1c02 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -123,7 +123,7 @@ namespace GodotTools
try
{
string fallbackFolder = NuGetUtils.GodotFallbackFolderPath;
- NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
+ NuGetUtils.AddFallbackFolderToGodotNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
fallbackFolder);
NuGetUtils.AddBundledPackagesToFallbackFolder(fallbackFolder);
}
@@ -497,7 +497,7 @@ namespace GodotTools
try
{
// At startup we make sure NuGet.Config files have our Godot NuGet fallback folder included
- NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
+ NuGetUtils.AddFallbackFolderToGodotNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
NuGetUtils.GodotFallbackFolderPath);
}
catch (Exception e)
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index c27bb959fe..95a44d3b7e 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -2229,6 +2229,35 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
// Generate signal
{
+ p_output.append(MEMBER_BEGIN "/// <summary>\n");
+ p_output.append(INDENT1 "/// ");
+ p_output.append("Represents the method that handles the ");
+ p_output.append("<see cref=\"" BINDINGS_NAMESPACE "." + p_itype.proxy_name + "." + p_isignal.proxy_name + "\"/>");
+ p_output.append(" event of a ");
+ p_output.append("<see cref=\"" BINDINGS_NAMESPACE "." + p_itype.proxy_name + "\"/>");
+ p_output.append(" class.\n");
+ p_output.append(INDENT1 "/// </summary>");
+
+ if (p_isignal.is_deprecated) {
+ if (p_isignal.deprecation_message.is_empty()) {
+ WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + p_isignal.proxy_name + "'.");
+ }
+
+ p_output.append(MEMBER_BEGIN "[Obsolete(\"");
+ p_output.append(p_isignal.deprecation_message);
+ p_output.append("\")]");
+ }
+
+ String delegate_name = p_isignal.proxy_name;
+ delegate_name += "EventHandler"; // Delegate name is [SignalName]EventHandler
+
+ // Generate delegate
+ p_output.append(MEMBER_BEGIN "public delegate void ");
+ p_output.append(delegate_name);
+ p_output.append("(");
+ p_output.append(arguments_sig);
+ p_output.append(");\n");
+
if (p_isignal.method_doc && p_isignal.method_doc->description.size()) {
String xml_summary = bbcode_to_xml(fix_doc_description(p_isignal.method_doc->description), &p_itype);
Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
@@ -2247,25 +2276,11 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
}
if (p_isignal.is_deprecated) {
- if (p_isignal.deprecation_message.is_empty()) {
- WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + p_isignal.proxy_name + "'.");
- }
-
p_output.append(MEMBER_BEGIN "[Obsolete(\"");
p_output.append(p_isignal.deprecation_message);
p_output.append("\")]");
}
- String delegate_name = p_isignal.proxy_name;
- delegate_name += "EventHandler"; // Delegate name is [SignalName]EventHandler
-
- // Generate delegate
- p_output.append(MEMBER_BEGIN "public delegate void ");
- p_output.append(delegate_name);
- p_output.append("(");
- p_output.append(arguments_sig);
- p_output.append(");\n");
-
// TODO:
// Could we assume the StringName instance of signal name will never be freed (it's stored in ClassDB) before the managed world is unloaded?
// If so, we could store the pointer we get from `data_unique_pointer()` instead of allocating StringName here.
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 6f42ad6916..91392c8f79 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -152,7 +152,7 @@ bool godot_icall_Internal_ScriptEditorEdit(Resource *p_resource, int32_t p_line,
}
void godot_icall_Internal_EditorNodeShowScriptScreen() {
- EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
+ EditorNode::get_singleton()->editor_select(EditorNode::EDITOR_SCRIPT);
}
void godot_icall_Internal_EditorRunPlay() {
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
index 44f951e314..d77baab24b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -1245,12 +1245,12 @@ namespace Godot
/// <summary>
/// If the string is a path, this concatenates <paramref name="file"/>
/// at the end of the string as a subpath.
- /// E.g. <c>"this/is".PlusFile("path") == "this/is/path"</c>.
+ /// E.g. <c>"this/is".PathJoin("path") == "this/is/path"</c>.
/// </summary>
/// <param name="instance">The path that will be concatenated.</param>
/// <param name="file">File name to concatenate with the path.</param>
/// <returns>The concatenated path with the given file name.</returns>
- public static string PlusFile(this string instance, string file)
+ public static string PathJoin(this string instance, string file)
{
if (instance.Length > 0 && instance[instance.Length - 1] == '/')
return instance + file;
diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp
index 9d0864e4d5..9d28feef09 100644
--- a/modules/multiplayer/multiplayer_spawner.cpp
+++ b/modules/multiplayer/multiplayer_spawner.cpp
@@ -86,24 +86,41 @@ void MultiplayerSpawner::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
#endif
+
+PackedStringArray MultiplayerSpawner::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
+
+ if (spawn_path.is_empty() || !has_node(spawn_path)) {
+ warnings.push_back(RTR("A valid NodePath must be set in the \"Spawn Path\" property in order for MultiplayerSpawner to be able to spawn Nodes."));
+ }
+ bool has_scenes = get_spawnable_scene_count() > 0;
+ // Can't check if method is overriden in placeholder scripts.
+ bool has_placeholder_script = get_script_instance() && get_script_instance()->is_placeholder();
+ if (!has_scenes && !GDVIRTUAL_IS_OVERRIDDEN(_spawn_custom) && !has_placeholder_script) {
+ warnings.push_back(RTR("A list of PackedScenes must be set in the \"Auto Spawn List\" property in order for MultiplayerSpawner to automatically spawn them remotely when added as child of \"spawn_path\"."));
+ warnings.push_back(RTR("Alternatively, a Script implementing the function \"_spawn_custom\" must be set for this MultiplayerSpawner, and \"spawn\" must be called explicitly in code."));
+ }
+ return warnings;
+}
+
void MultiplayerSpawner::add_spawnable_scene(const String &p_path) {
SpawnableScene sc;
sc.path = p_path;
if (Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_COND(!FileAccess::exists(p_path));
- } else {
- sc.cache = ResourceLoader::load(p_path);
- ERR_FAIL_COND_MSG(sc.cache.is_null(), "Invalid spawnable scene: " + p_path);
}
spawnable_scenes.push_back(sc);
}
+
int MultiplayerSpawner::get_spawnable_scene_count() const {
return spawnable_scenes.size();
}
+
String MultiplayerSpawner::get_spawnable_scene(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, (int)spawnable_scenes.size(), "");
return spawnable_scenes[p_idx].path;
}
+
void MultiplayerSpawner::clear_spawnable_scenes() {
spawnable_scenes.clear();
}
@@ -271,9 +288,12 @@ const Variant MultiplayerSpawner::get_spawn_argument(const ObjectID &p_id) const
Node *MultiplayerSpawner::instantiate_scene(int p_id) {
ERR_FAIL_COND_V_MSG(spawn_limit && spawn_limit <= tracked_nodes.size(), nullptr, "Spawn limit reached!");
ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_id, spawnable_scenes.size(), nullptr);
- Ref<PackedScene> scene = spawnable_scenes[p_id].cache;
- ERR_FAIL_COND_V(scene.is_null(), nullptr);
- return scene->instantiate();
+ SpawnableScene &sc = spawnable_scenes[p_id];
+ if (sc.cache.is_null()) {
+ sc.cache = ResourceLoader::load(sc.path);
+ }
+ ERR_FAIL_COND_V_MSG(sc.cache.is_null(), nullptr, "Invalid spawnable scene: " + sc.path);
+ return sc.cache->instantiate();
}
Node *MultiplayerSpawner::instantiate_custom(const Variant &p_data) {
diff --git a/modules/multiplayer/multiplayer_spawner.h b/modules/multiplayer/multiplayer_spawner.h
index fc3befc2d4..587c99efd1 100644
--- a/modules/multiplayer/multiplayer_spawner.h
+++ b/modules/multiplayer/multiplayer_spawner.h
@@ -91,6 +91,8 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const;
#endif
public:
+ PackedStringArray get_configuration_warnings() const override;
+
Node *get_spawn_node() const {
return spawn_node.is_valid() ? Object::cast_to<Node>(ObjectDB::get_instance(spawn_node)) : nullptr;
}
diff --git a/modules/multiplayer/multiplayer_synchronizer.cpp b/modules/multiplayer/multiplayer_synchronizer.cpp
index eee1495c14..2c3ebccaeb 100644
--- a/modules/multiplayer/multiplayer_synchronizer.cpp
+++ b/modules/multiplayer/multiplayer_synchronizer.cpp
@@ -94,6 +94,16 @@ void MultiplayerSynchronizer::_update_process() {
}
}
+PackedStringArray MultiplayerSynchronizer::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
+
+ if (root_path.is_empty() || !has_node(root_path)) {
+ warnings.push_back(RTR("A valid NodePath must be set in the \"Root Path\" property in order for MultiplayerSynchronizer to be able to synchronize properties."));
+ }
+
+ return warnings;
+}
+
Error MultiplayerSynchronizer::get_state(const List<NodePath> &p_properties, Object *p_obj, Vector<Variant> &r_variant, Vector<const Variant *> &r_variant_ptrs) {
ERR_FAIL_COND_V(!p_obj, ERR_INVALID_PARAMETER);
r_variant.resize(p_properties.size());
diff --git a/modules/multiplayer/multiplayer_synchronizer.h b/modules/multiplayer/multiplayer_synchronizer.h
index e84d41db86..f10a95a1d4 100644
--- a/modules/multiplayer/multiplayer_synchronizer.h
+++ b/modules/multiplayer/multiplayer_synchronizer.h
@@ -66,6 +66,8 @@ public:
static Error get_state(const List<NodePath> &p_properties, Object *p_obj, Vector<Variant> &r_variant, Vector<const Variant *> &r_variant_ptrs);
static Error set_state(const List<NodePath> &p_properties, Object *p_obj, const Vector<Variant> &p_state);
+ PackedStringArray get_configuration_warnings() const override;
+
void set_replication_interval(double p_interval);
double get_replication_interval() const;
uint64_t get_replication_interval_msec() const;
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index 9e5d666a51..8ca73a3adb 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -810,6 +810,32 @@ void GodotNavigationServer::process(real_t p_delta_time) {
}
}
+NavigationUtilities::PathQueryResult GodotNavigationServer::_query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const {
+ NavigationUtilities::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) {
+ // 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);
+ }
+ } else {
+ return r_query_result;
+ }
+
+ // add path postprocessing
+
+ // add path stats
+
+ return r_query_result;
+}
+
#undef COMMAND_1
#undef COMMAND_2
#undef COMMAND_4
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index e6ef7e3bb1..ab5e722d35 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -175,6 +175,8 @@ public:
void flush_queries();
virtual void process(real_t p_delta_time) override;
+
+ virtual NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const override;
};
#undef COMMAND_1
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index cfb8e0cd42..f989fc45a5 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -209,6 +209,9 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
for (uint32_t shape_owner : shape_owners) {
const int shape_count = static_body->shape_owner_get_shape_count(shape_owner);
for (int i = 0; i < shape_count; i++) {
+ if (static_body->is_shape_owner_disabled(i)) {
+ continue;
+ }
Ref<Shape3D> s = static_body->shape_owner_get_shape(shape_owner, i);
if (s.is_null()) {
continue;
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index f2b1c3da14..76f7b2a60a 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -1655,7 +1655,7 @@ void OpenXRAPI::end_frame() {
XrCompositionLayerProjection projection_layer = {
XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type
nullptr, // next
- layers_list.size() > 1 ? XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT : XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, // layerFlags
+ layers_list.size() > 0 ? XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT : XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, // layerFlags
play_space, // space
view_count, // viewCount
projection_views, // views
diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub
index 074795759a..0670c7f468 100644
--- a/modules/raycast/SCsub
+++ b/modules/raycast/SCsub
@@ -63,7 +63,8 @@ if env["builtin_embree"]:
thirdparty_sources = [thirdparty_dir + file for file in embree_src]
env_raycast.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "include"])
- env_raycast.Append(CPPDEFINES=["EMBREE_TARGET_SSE2", "EMBREE_LOWEST_ISA", "TASKING_INTERNAL", "NDEBUG"])
+ env_raycast.Append(CPPDEFINES=["EMBREE_TARGET_SSE2", "EMBREE_LOWEST_ISA", "TASKING_INTERNAL"])
+ env_raycast.AppendUnique(CPPDEFINES=["NDEBUG"]) # No assert() even in debug builds.
if not env.msvc:
if env["arch"] == "x86_64":
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index cd6081f91b..f43f2784c7 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -142,7 +142,7 @@ void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const
p_extensions->push_back("svg");
}
-Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags, float p_scale) {
+Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
String svg = p_fileaccess->get_as_utf8_string();
if (p_flags & FLAG_CONVERT_COLORS) {
diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h
index e6f73ab18f..b0b0963c15 100644
--- a/modules/svg/image_loader_svg.h
+++ b/modules/svg/image_loader_svg.h
@@ -43,7 +43,7 @@ public:
void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map);
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags, float p_scale) override;
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) override;
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
};
diff --git a/modules/svg/register_types.cpp b/modules/svg/register_types.cpp
index 5b4d1d31ca..323b1d652a 100644
--- a/modules/svg/register_types.cpp
+++ b/modules/svg/register_types.cpp
@@ -34,7 +34,7 @@
#include <thorvg.h>
-static ImageLoaderSVG *image_loader_svg = nullptr;
+static Ref<ImageLoaderSVG> image_loader_svg;
void initialize_svg_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
@@ -45,7 +45,8 @@ void initialize_svg_module(ModuleInitializationLevel p_level) {
if (tvg::Initializer::init(tvgEngine, 1) != tvg::Result::Success) {
return;
}
- image_loader_svg = memnew(ImageLoaderSVG);
+
+ image_loader_svg.instantiate();
ImageLoader::add_image_format_loader(image_loader_svg);
}
@@ -54,9 +55,12 @@ void uninitialize_svg_module(ModuleInitializationLevel p_level) {
return;
}
- if (!image_loader_svg) {
+ if (image_loader_svg.is_null()) {
+ // It failed to initialize so it was not added.
return;
}
- memdelete(image_loader_svg);
+
+ ImageLoader::remove_image_format_loader(image_loader_svg);
+ image_loader_svg.unref();
tvg::Initializer::term(tvg::CanvasEngine::Sw);
}
diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct
index 0170c007ae..488d1f641b 100644
--- a/modules/text_server_adv/gdextension_build/SConstruct
+++ b/modules/text_server_adv/gdextension_build/SConstruct
@@ -19,6 +19,7 @@ env = SConscript("./godot-cpp/SConstruct")
env.__class__.disable_warnings = methods.disable_warnings
opts = Variables([], ARGUMENTS)
+opts.Add(BoolVariable("brotli_enabled", "Use Brotli library", True))
opts.Add(BoolVariable("freetype_enabled", "Use FreeType library", True))
opts.Add(BoolVariable("msdfgen_enabled", "Use MSDFgen library (require FreeType)", True))
opts.Add(BoolVariable("graphite_enabled", "Use Graphite library (require FreeType)", True))
@@ -162,6 +163,25 @@ if env["freetype_enabled"]:
]
thirdparty_freetype_sources += [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
+ if env["brotli_enabled"]:
+ thirdparty_brotli_dir = "../../../thirdparty/brotli/"
+ thirdparty_brotli_sources = [
+ "common/constants.c",
+ "common/context.c",
+ "common/dictionary.c",
+ "common/platform.c",
+ "common/shared_dictionary.c",
+ "common/transform.c",
+ "dec/bit_reader.c",
+ "dec/decode.c",
+ "dec/huffman.c",
+ "dec/state.c",
+ ]
+ thirdparty_freetype_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources]
+ env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
+ env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
+ env.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
+
env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir])
env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"])
@@ -265,6 +285,7 @@ env_harfbuzz.Append(
CPPPATH=[
"../../../thirdparty/harfbuzz/src",
"../../../thirdparty/icu4c/common/",
+ "../../../thirdparty/icu4c/i18n/",
]
)
@@ -569,6 +590,10 @@ thirdparty_icu_sources = [
"common/uvectr32.cpp",
"common/uvectr64.cpp",
"common/wintz.cpp",
+ "i18n/scriptset.cpp",
+ "i18n/ucln_in.cpp",
+ "i18n/uspoof.cpp",
+ "i18n/uspoof_impl.cpp",
]
thirdparty_icu_sources = [thirdparty_icu_dir + file for file in thirdparty_icu_sources]
@@ -584,7 +609,7 @@ if env["static_icu_data"]:
else:
thirdparty_sources += ["../icu_data/icudata_stub.cpp"]
-env_icu.Append(CPPPATH=["../../../thirdparty/icu4c/common/"])
+env_icu.Append(CPPPATH=["../../../thirdparty/icu4c/common/", "../../../thirdparty/icu4c/i18n/"])
env_icu.Append(
CXXFLAGS=[
"-DU_STATIC_IMPLEMENTATION",
@@ -610,7 +635,7 @@ env.Append(
"-DICU_DATA_NAME=" + icu_data_name,
]
)
-env.Append(CPPPATH=["../../../thirdparty/icu4c/common/"])
+env.Append(CPPPATH=["../../../thirdparty/icu4c/common/", "../../../thirdparty/icu4c/i18n/"])
if env["platform"] == "windows":
env.Append(LIBS=["advapi32"])
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 7aebeafe70..1a4831857f 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -45,7 +45,6 @@ using namespace godot;
// Headers for building as built-in module.
#include "core/config/project_settings.h"
-#include "core/core_bind.h"
#include "core/error/error_macros.h"
#include "core/object/worker_thread_pool.h"
#include "core/string/print_string.h"
@@ -53,8 +52,6 @@ using namespace godot;
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen.
-using namespace core_bind;
-
#endif
// Built-in ICU data.
@@ -408,13 +405,12 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
if (!icu_data_loaded) {
String filename = (p_filename.is_empty()) ? String("res://") + _MKSTR(ICU_DATA_NAME) : p_filename;
- Ref<File> f;
- f.instantiate();
- if (f->open(filename, File::READ) != OK) {
+ Ref<FileAccess> f = FileAccess::open(filename, FileAccess::READ);
+ if (f.is_null()) {
return false;
}
uint64_t len = f->get_length();
- PackedByteArray icu_data = f->get_buffer(len);
+ PackedByteArray icu_data = f->_get_buffer(len);
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(icu_data.ptr(), &err);
@@ -455,16 +451,15 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const {
// Store data to the res file if it's available.
- Ref<File> f;
- f.instantiate();
- if (f->open(p_filename, File::WRITE) != OK) {
+ Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::WRITE);
+ if (f.is_null()) {
return false;
}
PackedByteArray icu_data;
icu_data.resize(U_ICUDATA_SIZE);
memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
- f->store_buffer(icu_data);
+ f->_store_buffer(icu_data);
return true;
#else
@@ -1940,12 +1935,12 @@ int64_t TextServerAdvanced::font_get_face_count(const RID &p_font_rid) const {
fargs.flags = FT_OPEN_MEMORY;
fargs.stream = &stream;
- FT_Face tmp_face;
+ FT_Face tmp_face = nullptr;
error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
if (error == 0) {
face_count = tmp_face->num_faces;
+ FT_Done_Face(tmp_face);
}
- FT_Done_Face(tmp_face);
#endif
}
@@ -3070,8 +3065,10 @@ int64_t TextServerAdvanced::font_get_glyph_index(const RID &p_font_rid, int64_t
bool TextServerAdvanced::font_has_char(const RID &p_font_rid, int64_t p_char) const {
FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, false);
ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
+ if (!fd) {
+ return false;
+ }
MutexLock lock(fd->mutex);
if (fd->cache.is_empty()) {
@@ -4500,35 +4497,40 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(const RID &p_shaped_l
int glyphs_to = (is_rtl) ? sd_size - 1 : -1;
int glyphs_delta = (is_rtl) ? +1 : -1;
- for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {
- if (!is_rtl) {
- width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
- }
- if (sd_glyphs[i].count > 0) {
- bool above_min_char_threshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;
+ if (enforce_ellipsis && (width + ellipsis_width <= p_width)) {
+ trim_pos = -1;
+ ellipsis_pos = (is_rtl) ? 0 : sd_size;
+ } else {
+ for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {
+ if (!is_rtl) {
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
+ }
+ if (sd_glyphs[i].count > 0) {
+ bool above_min_char_threshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;
- if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
- if (cut_per_word && above_min_char_threshold) {
- if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
+ if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
+ if (cut_per_word && above_min_char_threshold) {
+ if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
+ last_valid_cut = i;
+ found = true;
+ }
+ } else {
last_valid_cut = i;
found = true;
}
- } else {
- last_valid_cut = i;
- found = true;
- }
- if (found) {
- trim_pos = last_valid_cut;
+ if (found) {
+ trim_pos = last_valid_cut;
- if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
- ellipsis_pos = trim_pos;
+ if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
+ ellipsis_pos = trim_pos;
+ }
+ break;
}
- break;
}
}
- }
- if (is_rtl) {
- width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
+ if (is_rtl) {
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
+ }
}
}
@@ -5428,7 +5430,10 @@ bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) {
Array fonts_scr_only;
Array fonts_no_match;
int font_count = span.fonts.size();
- for (int l = 0; l < font_count; l++) {
+ if (font_count > 0) {
+ fonts.push_back(sd->spans[k].fonts[0]);
+ }
+ for (int l = 1; l < font_count; l++) {
if (font_is_script_supported(span.fonts[l], script)) {
if (font_is_language_supported(span.fonts[l], span.language)) {
fonts.push_back(sd->spans[k].fonts[l]);
@@ -5849,9 +5854,9 @@ String TextServerAdvanced::percent_sign(const String &p_language) const {
return "%";
}
-int TextServerAdvanced::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
+int64_t TextServerAdvanced::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
UErrorCode status = U_ZERO_ERROR;
- int match_index = -1;
+ int64_t match_index = -1;
Char16String utf16 = p_string.utf16();
Vector<UChar *> skeletons;
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 1db95d153b..b9633a9b71 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -52,6 +52,7 @@
#include <godot_cpp/variant/rect2.hpp>
#include <godot_cpp/variant/rid.hpp>
#include <godot_cpp/variant/string.hpp>
+#include <godot_cpp/variant/typed_array.hpp>
#include <godot_cpp/variant/vector2.hpp>
#include <godot_cpp/variant/vector2i.hpp>
@@ -705,7 +706,7 @@ public:
virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override;
- virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
+ virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
virtual bool spoof_check(const String &p_string) const override;
virtual String strip_diacritics(const String &p_string) const override;
diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct
index de0a549900..488f9ca24e 100644
--- a/modules/text_server_fb/gdextension_build/SConstruct
+++ b/modules/text_server_fb/gdextension_build/SConstruct
@@ -19,6 +19,7 @@ env = SConscript("./godot-cpp/SConstruct")
env.__class__.disable_warnings = methods.disable_warnings
opts = Variables([], ARGUMENTS)
+opts.Add(BoolVariable("brotli_enabled", "Use Brotli library", True))
opts.Add(BoolVariable("freetype_enabled", "Use FreeType library", True))
opts.Add(BoolVariable("msdfgen_enabled", "Use MSDFgen library (require FreeType)", True))
opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False))
@@ -157,6 +158,25 @@ if env["freetype_enabled"]:
]
thirdparty_freetype_sources += [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
+ if env["brotli_enabled"]:
+ thirdparty_brotli_dir = "../../../thirdparty/brotli/"
+ thirdparty_brotli_sources = [
+ "common/constants.c",
+ "common/context.c",
+ "common/dictionary.c",
+ "common/platform.c",
+ "common/shared_dictionary.c",
+ "common/transform.c",
+ "dec/bit_reader.c",
+ "dec/decode.c",
+ "dec/huffman.c",
+ "dec/state.c",
+ ]
+ thirdparty_freetype_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources]
+ env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
+ env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
+ env.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
+
env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir])
env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"])
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 4d599dbcb5..9ef0f0ad82 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -1039,12 +1039,12 @@ int64_t TextServerFallback::font_get_face_count(const RID &p_font_rid) const {
fargs.flags = FT_OPEN_MEMORY;
fargs.stream = &stream;
- FT_Face tmp_face;
+ FT_Face tmp_face = nullptr;
error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
if (error == 0) {
face_count = tmp_face->num_faces;
+ FT_Done_Face(tmp_face);
}
- FT_Done_Face(tmp_face);
#endif
}
@@ -2127,8 +2127,10 @@ int64_t TextServerFallback::font_get_glyph_index(const RID &p_font_rid, int64_t
bool TextServerFallback::font_has_char(const RID &p_font_rid, int64_t p_char) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, false);
ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
+ if (!fd) {
+ return false;
+ }
MutexLock lock(fd->mutex);
if (fd->cache.is_empty()) {
@@ -2842,7 +2844,10 @@ bool TextServerFallback::shaped_text_add_string(const RID &p_shaped, const Strin
// Pre-sort fonts, push fonts with the language support first.
Array fonts_no_match;
int font_count = p_fonts.size();
- for (int i = 0; i < font_count; i++) {
+ if (font_count > 0) {
+ span.fonts.push_back(p_fonts[0]);
+ }
+ for (int i = 1; i < font_count; i++) {
if (font_is_language_supported(p_fonts[i], p_language)) {
span.fonts.push_back(p_fonts[i]);
} else {
@@ -3453,29 +3458,34 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(const RID &p_shaped_l
int last_valid_cut = 0;
bool found = false;
- for (int i = sd_size - 1; i != -1; i--) {
- width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
+ if (enforce_ellipsis && (width + ellipsis_width <= p_width)) {
+ trim_pos = -1;
+ ellipsis_pos = sd_size;
+ } else {
+ for (int i = sd_size - 1; i != -1; i--) {
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
- if (sd_glyphs[i].count > 0) {
- bool above_min_char_threshold = (i >= ell_min_characters);
+ if (sd_glyphs[i].count > 0) {
+ bool above_min_char_threshold = (i >= ell_min_characters);
- if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
- if (cut_per_word && above_min_char_threshold) {
- if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
+ if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
+ if (cut_per_word && above_min_char_threshold) {
+ if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
+ last_valid_cut = i;
+ found = true;
+ }
+ } else {
last_valid_cut = i;
found = true;
}
- } else {
- last_valid_cut = i;
- found = true;
- }
- if (found) {
- trim_pos = last_valid_cut;
+ if (found) {
+ trim_pos = last_valid_cut;
- if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
- ellipsis_pos = trim_pos;
+ if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
+ ellipsis_pos = trim_pos;
+ }
+ break;
}
- break;
}
}
}
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index cbb2fb03f2..42f311f5ad 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -52,6 +52,7 @@
#include <godot_cpp/variant/rect2.hpp>
#include <godot_cpp/variant/rid.hpp>
#include <godot_cpp/variant/string.hpp>
+#include <godot_cpp/variant/typed_array.hpp>
#include <godot_cpp/variant/vector2.hpp>
#include <godot_cpp/variant/vector2i.hpp>
diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp
index 16d9bf7b93..aed95294e7 100644
--- a/modules/tga/image_loader_tga.cpp
+++ b/modules/tga/image_loader_tga.cpp
@@ -100,7 +100,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
uint32_t width = p_header.image_width;
uint32_t height = p_header.image_height;
tga_origin_e origin = static_cast<tga_origin_e>((p_header.image_descriptor & TGA_ORIGIN_MASK) >> TGA_ORIGIN_SHIFT);
-
+ uint8_t alpha_bits = p_header.image_descriptor & TGA_IMAGE_DESCRIPTOR_ALPHA_MASK;
uint32_t x_start;
int32_t x_step;
uint32_t x_end;
@@ -184,6 +184,27 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
y += y_step;
}
}
+ } else if (p_header.pixel_depth == 16) {
+ while (y != y_end) {
+ while (x != x_end) {
+ if (i + 1 >= p_input_size) {
+ return ERR_PARSE_ERROR;
+ }
+
+ // Always stored as RGBA5551
+ uint8_t r = (p_buffer[i + 1] & 0x7c) << 1;
+ uint8_t g = ((p_buffer[i + 1] & 0x03) << 6) | ((p_buffer[i + 0] & 0xe0) >> 2);
+ uint8_t b = (p_buffer[i + 0] & 0x1f) << 3;
+ uint8_t a = (p_buffer[i + 1] & 0x80) ? 0xff : 0;
+
+ TGA_PUT_PIXEL(r, g, b, alpha_bits ? a : 0xff);
+
+ x += x_step;
+ i += 2;
+ }
+ x = x_start;
+ y += y_step;
+ }
} else if (p_header.pixel_depth == 24) {
while (y != y_end) {
while (x != x_end) {
@@ -230,7 +251,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
return OK;
}
-Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
@@ -277,7 +298,7 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t
err = FAILED;
}
- if (!(tga_header.pixel_depth == 8 || tga_header.pixel_depth == 24 || tga_header.pixel_depth == 32)) {
+ if (!(tga_header.pixel_depth == 8 || tga_header.pixel_depth == 16 || tga_header.pixel_depth == 24 || tga_header.pixel_depth == 32)) {
err = FAILED;
}
diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h
index d95c5ff30b..de964373ed 100644
--- a/modules/tga/image_loader_tga.h
+++ b/modules/tga/image_loader_tga.h
@@ -33,6 +33,8 @@
#include "core/io/image_loader.h"
+#define TGA_IMAGE_DESCRIPTOR_ALPHA_MASK 0xf
+
class ImageLoaderTGA : public ImageFormatLoader {
enum tga_type_e {
TGA_TYPE_NO_DATA = 0,
@@ -73,7 +75,7 @@ class ImageLoaderTGA : public ImageFormatLoader {
static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size);
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderTGA();
};
diff --git a/modules/tga/register_types.cpp b/modules/tga/register_types.cpp
index 520ed5f799..3a9d2324e7 100644
--- a/modules/tga/register_types.cpp
+++ b/modules/tga/register_types.cpp
@@ -32,14 +32,14 @@
#include "image_loader_tga.h"
-static ImageLoaderTGA *image_loader_tga = nullptr;
+static Ref<ImageLoaderTGA> image_loader_tga;
void initialize_tga_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
- image_loader_tga = memnew(ImageLoaderTGA);
+ image_loader_tga.instantiate();
ImageLoader::add_image_format_loader(image_loader_tga);
}
@@ -48,5 +48,6 @@ void uninitialize_tga_module(ModuleInitializationLevel p_level) {
return;
}
- memdelete(image_loader_tga);
+ ImageLoader::remove_image_format_loader(image_loader_tga);
+ image_loader_tga.unref();
}
diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp
index 6f61251f9b..5c43bfc8b7 100644
--- a/modules/tinyexr/image_loader_tinyexr.cpp
+++ b/modules/tinyexr/image_loader_tinyexr.cpp
@@ -37,7 +37,7 @@
#include "thirdparty/tinyexr/tinyexr.h"
-Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
diff --git a/modules/tinyexr/image_loader_tinyexr.h b/modules/tinyexr/image_loader_tinyexr.h
index 8da2a0d4af..ab34a59da5 100644
--- a/modules/tinyexr/image_loader_tinyexr.h
+++ b/modules/tinyexr/image_loader_tinyexr.h
@@ -35,7 +35,7 @@
class ImageLoaderTinyEXR : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderTinyEXR();
};
diff --git a/modules/tinyexr/register_types.cpp b/modules/tinyexr/register_types.cpp
index c5897f37c3..b1a9f18e3b 100644
--- a/modules/tinyexr/register_types.cpp
+++ b/modules/tinyexr/register_types.cpp
@@ -33,14 +33,14 @@
#include "image_loader_tinyexr.h"
#include "image_saver_tinyexr.h"
-static ImageLoaderTinyEXR *image_loader_tinyexr = nullptr;
+static Ref<ImageLoaderTinyEXR> image_loader_tinyexr;
void initialize_tinyexr_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
- image_loader_tinyexr = memnew(ImageLoaderTinyEXR);
+ image_loader_tinyexr.instantiate();
ImageLoader::add_image_format_loader(image_loader_tinyexr);
Image::save_exr_func = save_exr;
@@ -52,7 +52,8 @@ void uninitialize_tinyexr_module(ModuleInitializationLevel p_level) {
return;
}
- memdelete(image_loader_tinyexr);
+ ImageLoader::remove_image_format_loader(image_loader_tinyexr);
+ image_loader_tinyexr.unref();
Image::save_exr_func = nullptr;
}
diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp
index 705ab508ab..dd387db554 100644
--- a/modules/webp/image_loader_webp.cpp
+++ b/modules/webp/image_loader_webp.cpp
@@ -48,7 +48,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) {
return img;
}
-Error ImageLoaderWebP::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderWebP::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
diff --git a/modules/webp/image_loader_webp.h b/modules/webp/image_loader_webp.h
index d868ae3f7f..0522e4ef91 100644
--- a/modules/webp/image_loader_webp.h
+++ b/modules/webp/image_loader_webp.h
@@ -35,7 +35,7 @@
class ImageLoaderWebP : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderWebP();
};
diff --git a/modules/webp/register_types.cpp b/modules/webp/register_types.cpp
index 29f633743e..e523f43cfe 100644
--- a/modules/webp/register_types.cpp
+++ b/modules/webp/register_types.cpp
@@ -33,7 +33,7 @@
#include "image_loader_webp.h"
#include "resource_saver_webp.h"
-static ImageLoaderWebP *image_loader_webp = nullptr;
+static Ref<ImageLoaderWebP> image_loader_webp;
static Ref<ResourceSaverWebP> resource_saver_webp;
void initialize_webp_module(ModuleInitializationLevel p_level) {
@@ -41,9 +41,10 @@ void initialize_webp_module(ModuleInitializationLevel p_level) {
return;
}
- image_loader_webp = memnew(ImageLoaderWebP);
- resource_saver_webp.instantiate();
+ image_loader_webp.instantiate();
ImageLoader::add_image_format_loader(image_loader_webp);
+
+ resource_saver_webp.instantiate();
ResourceSaver::add_resource_format_saver(resource_saver_webp);
}
@@ -52,7 +53,9 @@ void uninitialize_webp_module(ModuleInitializationLevel p_level) {
return;
}
- memdelete(image_loader_webp);
+ ImageLoader::remove_image_format_loader(image_loader_webp);
+ image_loader_webp.unref();
+
ResourceSaver::remove_resource_format_saver(resource_saver_webp);
resource_saver_webp.unref();
}
diff --git a/modules/websocket/websocket_macros.h b/modules/websocket/websocket_macros.h
index a01ae65c56..b03bd8f45c 100644
--- a/modules/websocket/websocket_macros.h
+++ b/modules/websocket/websocket_macros.h
@@ -35,34 +35,32 @@
#define DEF_PKT_SHIFT 10
#define DEF_BUF_SHIFT 16
-/* clang-format off */
-#define GDCICLASS(CNAME) \
-public:\
- static CNAME *(*_create)();\
-\
- static Ref<CNAME > create_ref() {\
-\
- if (!_create)\
- return Ref<CNAME >();\
- return Ref<CNAME >(_create());\
- }\
-\
- static CNAME *create() {\
-\
- if (!_create)\
- return nullptr;\
- return _create();\
- }\
-protected:\
+#define GDCICLASS(CNAME) \
+public: \
+ static CNAME *(*_create)(); \
+ \
+ static Ref<CNAME> create_ref() { \
+ if (!_create) \
+ return Ref<CNAME>(); \
+ return Ref<CNAME>(_create()); \
+ } \
+ \
+ static CNAME *create() { \
+ if (!_create) \
+ return nullptr; \
+ return _create(); \
+ } \
+ \
+protected:
#define GDCINULL(CNAME) \
-CNAME *(*CNAME::_create)() = nullptr;
+ CNAME *(*CNAME::_create)() = nullptr;
-#define GDCIIMPL(IMPNAME, CNAME) \
-public:\
- static CNAME *_create() { return memnew(IMPNAME); }\
- static void make_default() { CNAME::_create = IMPNAME::_create; }\
-protected:\
-/* clang-format on */
+#define GDCIIMPL(IMPNAME, CNAME) \
+public: \
+ static CNAME *_create() { return memnew(IMPNAME); } \
+ static void make_default() { CNAME::_create = IMPNAME::_create; } \
+ \
+protected:
#endif // WEBSOCKET_MACROS_H
diff --git a/modules/webxr/config.py b/modules/webxr/config.py
index f676ef3483..8d75e7f531 100644
--- a/modules/webxr/config.py
+++ b/modules/webxr/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return not env["disable_3d"]
+ return env["opengl3"] and not env["disable_3d"]
def configure(env):
diff --git a/modules/webxr/godot_webxr.h b/modules/webxr/godot_webxr.h
index 52104895d4..34d068be3e 100644
--- a/modules/webxr/godot_webxr.h
+++ b/modules/webxr/godot_webxr.h
@@ -65,8 +65,7 @@ extern int godot_webxr_get_view_count();
extern int *godot_webxr_get_render_target_size();
extern float *godot_webxr_get_transform_for_eye(int p_eye);
extern float *godot_webxr_get_projection_for_eye(int p_eye);
-extern int godot_webxr_get_external_texture_for_eye(int p_eye);
-extern void godot_webxr_commit_for_eye(int p_eye);
+extern void godot_webxr_commit_for_eye(int p_eye, unsigned int p_destination_fbo);
extern void godot_webxr_sample_controller_data();
extern int godot_webxr_get_controller_count();
diff --git a/modules/webxr/native/library_godot_webxr.js b/modules/webxr/native/library_godot_webxr.js
index c4b21defce..9b75796ee5 100644
--- a/modules/webxr/native/library_godot_webxr.js
+++ b/modules/webxr/native/library_godot_webxr.js
@@ -32,9 +32,6 @@ const GodotWebXR = {
$GodotWebXR: {
gl: null,
- texture_ids: [null, null],
- textures: [null, null],
-
session: null,
space: null,
frame: null,
@@ -77,110 +74,6 @@ const GodotWebXR = {
}, 0);
},
- // Some custom WebGL code for blitting our eye textures to the
- // framebuffer we get from WebXR.
- shaderProgram: null,
- programInfo: null,
- buffer: null,
- // Vertex shader source.
- vsSource: `
- const vec2 scale = vec2(0.5, 0.5);
- attribute vec4 aVertexPosition;
-
- varying highp vec2 vTextureCoord;
-
- void main () {
- gl_Position = aVertexPosition;
- vTextureCoord = aVertexPosition.xy * scale + scale;
- }
- `,
- // Fragment shader source.
- fsSource: `
- varying highp vec2 vTextureCoord;
-
- uniform sampler2D uSampler;
-
- void main() {
- gl_FragColor = texture2D(uSampler, vTextureCoord);
- }
- `,
-
- initShaderProgram: (gl, vsSource, fsSource) => {
- const vertexShader = GodotWebXR.loadShader(gl, gl.VERTEX_SHADER, vsSource);
- const fragmentShader = GodotWebXR.loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
-
- const shaderProgram = gl.createProgram();
- gl.attachShader(shaderProgram, vertexShader);
- gl.attachShader(shaderProgram, fragmentShader);
- gl.linkProgram(shaderProgram);
-
- if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
- GodotRuntime.error(`Unable to initialize the shader program: ${gl.getProgramInfoLog(shaderProgram)}`);
- return null;
- }
-
- return shaderProgram;
- },
- loadShader: (gl, type, source) => {
- const shader = gl.createShader(type);
- gl.shaderSource(shader, source);
- gl.compileShader(shader);
-
- if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
- GodotRuntime.error(`An error occurred compiling the shader: ${gl.getShaderInfoLog(shader)}`);
- gl.deleteShader(shader);
- return null;
- }
-
- return shader;
- },
- initBuffer: (gl) => {
- const positionBuffer = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
- const positions = [
- -1.0, -1.0,
- 1.0, -1.0,
- -1.0, 1.0,
- 1.0, 1.0,
- ];
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
- return positionBuffer;
- },
- blitTexture: (gl, texture) => {
- if (GodotWebXR.shaderProgram === null) {
- GodotWebXR.shaderProgram = GodotWebXR.initShaderProgram(gl, GodotWebXR.vsSource, GodotWebXR.fsSource);
- GodotWebXR.programInfo = {
- program: GodotWebXR.shaderProgram,
- attribLocations: {
- vertexPosition: gl.getAttribLocation(GodotWebXR.shaderProgram, 'aVertexPosition'),
- },
- uniformLocations: {
- uSampler: gl.getUniformLocation(GodotWebXR.shaderProgram, 'uSampler'),
- },
- };
- GodotWebXR.buffer = GodotWebXR.initBuffer(gl);
- }
-
- const orig_program = gl.getParameter(gl.CURRENT_PROGRAM);
- gl.useProgram(GodotWebXR.shaderProgram);
-
- gl.bindBuffer(gl.ARRAY_BUFFER, GodotWebXR.buffer);
- gl.vertexAttribPointer(GodotWebXR.programInfo.attribLocations.vertexPosition, 2, gl.FLOAT, false, 0, 0);
- gl.enableVertexAttribArray(GodotWebXR.programInfo.attribLocations.vertexPosition);
-
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.uniform1i(GodotWebXR.programInfo.uniformLocations.uSampler, 0);
-
- gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
-
- // Restore state.
- gl.bindTexture(gl.TEXTURE_2D, null);
- gl.disableVertexAttribArray(GodotWebXR.programInfo.attribLocations.vertexPosition);
- gl.bindBuffer(gl.ARRAY_BUFFER, null);
- gl.useProgram(orig_program);
- },
-
// Holds the controllers list between function calls.
controllers: [],
@@ -370,22 +263,6 @@ const GodotWebXR = {
.catch((e) => { });
}
- // Clean-up the textures we allocated for each view.
- const gl = GodotWebXR.gl;
- for (let i = 0; i < GodotWebXR.textures.length; i++) {
- const texture = GodotWebXR.textures[i];
- if (texture !== null) {
- gl.deleteTexture(texture);
- }
- GodotWebXR.textures[i] = null;
-
- const texture_id = GodotWebXR.texture_ids[i];
- if (texture_id !== null) {
- GL.textures[texture_id] = null;
- }
- GodotWebXR.texture_ids[i] = null;
- }
-
GodotWebXR.session = null;
GodotWebXR.space = null;
GodotWebXR.frame = null;
@@ -460,50 +337,9 @@ const GodotWebXR = {
return buf;
},
- godot_webxr_get_external_texture_for_eye__proxy: 'sync',
- godot_webxr_get_external_texture_for_eye__sig: 'ii',
- godot_webxr_get_external_texture_for_eye: function (p_eye) {
- if (!GodotWebXR.session) {
- return 0;
- }
-
- const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0;
- if (GodotWebXR.texture_ids[view_index]) {
- return GodotWebXR.texture_ids[view_index];
- }
-
- // Check pose separately and after returning the cached texture id,
- // because we won't get a pose in some cases if we lose tracking, and
- // we don't want to return 0 just because tracking was lost.
- if (!GodotWebXR.pose) {
- return 0;
- }
-
- const glLayer = GodotWebXR.session.renderState.baseLayer;
- const view = GodotWebXR.pose.views[view_index];
- const viewport = glLayer.getViewport(view);
- const gl = GodotWebXR.gl;
-
- const texture = gl.createTexture();
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, viewport.width, viewport.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
-
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
- gl.bindTexture(gl.TEXTURE_2D, null);
-
- const texture_id = GL.getNewId(GL.textures);
- GL.textures[texture_id] = texture;
- GodotWebXR.textures[view_index] = texture;
- GodotWebXR.texture_ids[view_index] = texture_id;
- return texture_id;
- },
-
godot_webxr_commit_for_eye__proxy: 'sync',
- godot_webxr_commit_for_eye__sig: 'vi',
- godot_webxr_commit_for_eye: function (p_eye) {
+ godot_webxr_commit_for_eye__sig: 'vii',
+ godot_webxr_commit_for_eye: function (p_eye, p_destination_fbo) {
if (!GodotWebXR.session || !GodotWebXR.pose) {
return;
}
@@ -514,18 +350,29 @@ const GodotWebXR = {
const viewport = glLayer.getViewport(view);
const gl = GodotWebXR.gl;
+ const framebuffer = GL.framebuffers[p_destination_fbo];
+
const orig_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
- const orig_viewport = gl.getParameter(gl.VIEWPORT);
+ const orig_read_framebuffer = gl.getParameter(gl.READ_FRAMEBUFFER_BINDING);
+ const orig_read_buffer = gl.getParameter(gl.READ_BUFFER);
+ const orig_draw_framebuffer = gl.getParameter(gl.DRAW_FRAMEBUFFER_BINDING);
- // Bind to WebXR's framebuffer.
- gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
- gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+ // Copy from Godot render target into framebuffer from WebXR.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, framebuffer);
+ gl.readBuffer(gl.COLOR_ATTACHMENT0);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, glLayer.framebuffer);
- GodotWebXR.blitTexture(gl, GodotWebXR.textures[view_index]);
+ // Flip Y upside down on destination.
+ gl.blitFramebuffer(0, 0, viewport.width, viewport.height,
+ viewport.x, viewport.height, viewport.width, viewport.y,
+ gl.COLOR_BUFFER_BIT, gl.NEAREST);
// Restore state.
gl.bindFramebuffer(gl.FRAMEBUFFER, orig_framebuffer);
- gl.viewport(orig_viewport[0], orig_viewport[1], orig_viewport[2], orig_viewport[3]);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, orig_read_framebuffer);
+ gl.readBuffer(orig_read_buffer);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, orig_draw_framebuffer);
},
godot_webxr_sample_controller_data__proxy: 'sync',
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 7d97dbfa0b..d0c7484aa1 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -34,9 +34,11 @@
#include "core/input/input.h"
#include "core/os/os.h"
+#include "drivers/gles3/storage/texture_storage.h"
#include "emscripten.h"
#include "godot_webxr.h"
#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/rendering_server_globals.h"
#include <stdlib.h>
@@ -232,6 +234,8 @@ bool WebXRInterfaceJS::initialize() {
}
// we must create a tracker for our head
+ head_transform.basis = Basis();
+ head_transform.origin = Vector3();
head_tracker.instantiate();
head_tracker->set_tracker_type(XRServer::TRACKER_HEAD);
head_tracker->set_tracker_name("head");
@@ -334,15 +338,17 @@ Transform3D WebXRInterfaceJS::get_camera_transform() {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, transform_for_eye);
- float *js_matrix = godot_webxr_get_transform_for_eye(0);
- if (!initialized || js_matrix == nullptr) {
- return transform_for_eye;
- }
+ if (initialized) {
+ float world_scale = xr_server->get_world_scale();
- transform_for_eye = _js_matrix_to_transform(js_matrix);
- free(js_matrix);
+ // just scale our origin point of our transform
+ Transform3D _head_transform = head_transform;
+ _head_transform.origin *= world_scale;
+
+ transform_for_eye = (xr_server->get_reference_frame()) * _head_transform;
+ }
- return xr_server->get_reference_frame() * transform_for_eye;
+ return transform_for_eye;
};
Transform3D WebXRInterfaceJS::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
@@ -360,6 +366,14 @@ Transform3D WebXRInterfaceJS::get_transform_for_view(uint32_t p_view, const Tran
transform_for_eye = _js_matrix_to_transform(js_matrix);
free(js_matrix);
+ float world_scale = xr_server->get_world_scale();
+ // Scale only the center point of our eye transform, so we don't scale the
+ // distance between the eyes.
+ Transform3D _head_transform = head_transform;
+ transform_for_eye.origin -= _head_transform.origin;
+ _head_transform.origin *= world_scale;
+ transform_for_eye.origin += _head_transform.origin;
+
return p_cam_transform * xr_server->get_reference_frame() * transform_for_eye;
};
@@ -394,29 +408,33 @@ Vector<BlitToScreen> WebXRInterfaceJS::post_draw_viewport(RID p_render_target, c
return blit_to_screen;
}
- // @todo Refactor this to be based on "views" rather than "eyes".
- godot_webxr_commit_for_eye(1);
- if (godot_webxr_get_view_count() > 1) {
- godot_webxr_commit_for_eye(2);
+ GLES3::TextureStorage *texture_storage = dynamic_cast<GLES3::TextureStorage *>(RSG::texture_storage);
+ if (!texture_storage) {
+ return blit_to_screen;
}
+ GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
+
+ // @todo Support multiple eyes!
+ godot_webxr_commit_for_eye(1, rt->fbo);
+
return blit_to_screen;
};
void WebXRInterfaceJS::process() {
if (initialized) {
- godot_webxr_sample_controller_data();
-
+ // Get the "head" position.
+ float *js_matrix = godot_webxr_get_transform_for_eye(0);
+ if (js_matrix != nullptr) {
+ head_transform = _js_matrix_to_transform(js_matrix);
+ free(js_matrix);
+ }
if (head_tracker.is_valid()) {
- // TODO set default pose to our head location (i.e. get_camera_transform without world scale and reference frame applied)
- // head_tracker->set_pose("default", head_transform, Vector3(), Vector3());
+ head_tracker->set_pose("default", head_transform, Vector3(), Vector3());
}
+ godot_webxr_sample_controller_data();
int controller_count = godot_webxr_get_controller_count();
- if (controller_count == 0) {
- return;
- }
-
for (int i = 0; i < controller_count; i++) {
_update_tracker(i);
}
diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h
index dbe89dad83..319adc2ac9 100644
--- a/modules/webxr/webxr_interface_js.h
+++ b/modules/webxr/webxr_interface_js.h
@@ -45,6 +45,7 @@ class WebXRInterfaceJS : public WebXRInterface {
private:
bool initialized;
Ref<XRPositionalTracker> head_tracker;
+ Transform3D head_transform;
String session_mode;
String required_features;
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 1d9bcdd932..2ff9cd3dc5 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -47,9 +47,6 @@ def get_flags():
return [
("arch", "arm64"), # Default for convenience.
("tools", False),
- # Benefits of LTO for Android (size, performance) haven't been clearly established yet.
- # So for now we override the default value which may be set when using `production=yes`.
- ("lto", "none"),
]
@@ -124,18 +121,18 @@ def configure(env):
# `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces
# when using `target=release_debug`.
opt = "-O3" if env["target"] == "release" else "-O2"
- env.Append(CCFLAGS=[opt, "-fomit-frame-pointer"])
+ env.Append(CCFLAGS=[opt])
elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["-Oz"])
- env.Append(CPPDEFINES=["NDEBUG"])
- env.Append(CCFLAGS=["-ftree-vectorize"])
elif env["target"] == "debug":
env.Append(LINKFLAGS=["-O0"])
- env.Append(CCFLAGS=["-O0", "-g", "-fno-limit-debug-info"])
- env.Append(CPPDEFINES=["_DEBUG"])
- env.Append(CPPFLAGS=["-UNDEBUG"])
+ env.Append(CCFLAGS=["-O0", "-g"])
# LTO
+
+ if env["lto"] == "auto": # LTO benefits for Android (size, performance) haven't been clearly established yet.
+ env["lto"] = "none"
+
if env["lto"] != "none":
if env["lto"] == "thin":
env.Append(CCFLAGS=["-flto=thin"])
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index e5656bd00b..366bd1c48c 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -1669,14 +1669,7 @@ Vector<String> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExp
}
void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const {
- String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
- if (driver == "opengl3") {
- r_features->push_back("etc");
- }
- // FIXME: Review what texture formats are used for Vulkan.
- if (driver == "vulkan") {
- r_features->push_back("etc2");
- }
+ r_features->push_back("etc2");
Vector<String> abis = get_enabled_abis(p_preset);
for (int i = 0; i < abis.size(); ++i) {
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
index 8d370a31a4..2f53942f76 100644
--- a/platform/android/export/gradle_export_util.cpp
+++ b/platform/android/export/gradle_export_util.cpp
@@ -189,9 +189,7 @@ String bool_to_string(bool v) {
}
String _get_gles_tag() {
- bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "GLES3" &&
- !ProjectSettings::get_singleton()->get("rendering/driver/fallback_to_gles2");
- return min_gles3 ? " <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n" : "";
+ return " <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n";
}
String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) {
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
index ace7636e6c..d6cd62e9f5 100644
--- a/platform/android/file_access_android.cpp
+++ b/platform/android/file_access_android.cpp
@@ -42,7 +42,7 @@ String FileAccessAndroid::get_path_absolute() const {
return absolute_path;
}
-Error FileAccessAndroid::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessAndroid::open_internal(const String &p_path, int p_mode_flags) {
_close();
path_src = p_path;
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
index 8d7ade8ead..55f8fbe0f4 100644
--- a/platform/android/file_access_android.h
+++ b/platform/android/file_access_android.h
@@ -49,7 +49,7 @@ class FileAccessAndroid : public FileAccess {
public:
static AAssetManager *asset_manager;
- virtual Error _open(const String &p_path, int p_mode_flags) override; // open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; // open a file
virtual bool is_open() const override; // true when file is open
/// returns the path for the current open file
diff --git a/platform/android/file_access_filesystem_jandroid.cpp b/platform/android/file_access_filesystem_jandroid.cpp
index 56561cb616..c2ee3389ae 100644
--- a/platform/android/file_access_filesystem_jandroid.cpp
+++ b/platform/android/file_access_filesystem_jandroid.cpp
@@ -61,7 +61,7 @@ String FileAccessFilesystemJAndroid::get_path_absolute() const {
return absolute_path;
}
-Error FileAccessFilesystemJAndroid::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessFilesystemJAndroid::open_internal(const String &p_path, int p_mode_flags) {
if (is_open()) {
_close();
}
diff --git a/platform/android/file_access_filesystem_jandroid.h b/platform/android/file_access_filesystem_jandroid.h
index 76d7db6e3a..815ab36516 100644
--- a/platform/android/file_access_filesystem_jandroid.h
+++ b/platform/android/file_access_filesystem_jandroid.h
@@ -60,7 +60,7 @@ class FileAccessFilesystemJAndroid : public FileAccess {
void _set_eof(bool eof);
public:
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
/// returns the path for the current open file
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index a75c69484c..92e5e59496 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -274,11 +274,11 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
return false;
}
- final String videoDriver = GodotLib.getGlobal("rendering/driver/driver_name");
- if (videoDriver.equals("vulkan")) {
- mRenderView = new GodotVulkanRenderView(activity, this);
- } else {
+ final String renderer = GodotLib.getGlobal("rendering/renderer/rendering_method");
+ if (renderer.equals("gl_compatibility")) {
mRenderView = new GodotGLRenderView(activity, this, xrMode, use_debug_opengl);
+ } else {
+ mRenderView = new GodotVulkanRenderView(activity, this);
}
View view = mRenderView.getView();
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 142dc54c45..4469c7a0f7 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -44,6 +44,7 @@
#include "net_socket_android.h"
#include <dlfcn.h>
+#include <sys/system_properties.h>
#include "java_godot_io_wrapper.h"
#include "java_godot_wrapper.h"
@@ -175,6 +176,79 @@ String OS_Android::get_name() const {
return "Android";
}
+String OS_Android::get_system_property(const char *key) const {
+ static String value;
+ char value_str[PROP_VALUE_MAX];
+ if (__system_property_get(key, value_str)) {
+ value = String(value_str);
+ }
+ return value;
+}
+
+String OS_Android::get_distribution_name() const {
+ if (!get_system_property("ro.havoc.version").is_empty()) {
+ return "Havoc OS";
+ } else if (!get_system_property("org.pex.version").is_empty()) { // Putting before "Pixel Experience", because it's derivating from it.
+ return "Pixel Extended";
+ } else if (!get_system_property("org.pixelexperience.version").is_empty()) {
+ return "Pixel Experience";
+ } else if (!get_system_property("ro.potato.version").is_empty()) {
+ return "POSP";
+ } else if (!get_system_property("ro.xtended.version").is_empty()) {
+ return "Project-Xtended";
+ } else if (!get_system_property("org.evolution.version").is_empty()) {
+ return "Evolution X";
+ } else if (!get_system_property("ro.corvus.version").is_empty()) {
+ return "Corvus-Q";
+ } else if (!get_system_property("ro.pa.version").is_empty()) {
+ return "Paranoid Android";
+ } else if (!get_system_property("ro.crdroid.version").is_empty()) {
+ return "crDroid Android";
+ } else if (!get_system_property("ro.syberia.version").is_empty()) {
+ return "Syberia Project";
+ } else if (!get_system_property("ro.arrow.version").is_empty()) {
+ return "ArrowOS";
+ } else if (!get_system_property("ro.lineage.version").is_empty()) { // Putting LineageOS last, just in case any derivative writes to "ro.lineage.version".
+ return "LineageOS";
+ }
+
+ if (!get_system_property("ro.modversion").is_empty()) { // Handles other Android custom ROMs.
+ return vformat("%s %s", get_name(), "Custom ROM");
+ }
+
+ // Handles stock Android.
+ return get_name();
+}
+
+String OS_Android::get_version() const {
+ const Vector<const char *> roms = { "ro.havoc.version", "org.pex.version", "org.pixelexperience.version",
+ "ro.potato.version", "ro.xtended.version", "org.evolution.version", "ro.corvus.version", "ro.pa.version",
+ "ro.crdroid.version", "ro.syberia.version", "ro.arrow.version", "ro.lineage.version" };
+ for (int i = 0; i < roms.size(); i++) {
+ static String rom_version = get_system_property(roms[i]);
+ if (!rom_version.is_empty()) {
+ return rom_version;
+ }
+ }
+
+ static String mod_version = get_system_property("ro.modversion"); // Handles other Android custom ROMs.
+ if (!mod_version.is_empty()) {
+ return mod_version;
+ }
+
+ // Handles stock Android.
+ static String sdk_version = get_system_property("ro.build.version.sdk_int");
+ static String build = get_system_property("ro.build.version.incremental");
+ if (!sdk_version.is_empty()) {
+ if (!build.is_empty()) {
+ return vformat("%s.%s", sdk_version, build);
+ }
+ return sdk_version;
+ }
+
+ return "";
+}
+
MainLoop *OS_Android::get_main_loop() const {
return main_loop;
}
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 96c06d715c..d6546a3507 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -65,6 +65,8 @@ private:
GodotJavaWrapper *godot_java = nullptr;
GodotIOJavaWrapper *godot_io_java = nullptr;
+ String get_system_property(const char *key) const;
+
public:
static const char *ANDROID_EXEC_PATH;
@@ -93,6 +95,8 @@ public:
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override;
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual MainLoop *get_main_loop() const override;
void main_loop_begin();
diff --git a/platform/ios/detect.py b/platform/ios/detect.py
index ed7e714c4e..0f277d6b3a 100644
--- a/platform/ios/detect.py
+++ b/platform/ios/detect.py
@@ -39,9 +39,6 @@ def get_flags():
("arch", "arm64"), # Default for convenience.
("tools", False),
("use_volk", False),
- # Disable by default even if production is set, as it makes linking in Xcode
- # on exports very slow and that's not what most users expect.
- ("lto", "none"),
]
@@ -58,22 +55,25 @@ def configure(env):
## Build type
if env["target"].startswith("release"):
- env.Append(CPPDEFINES=["NDEBUG", ("NS_BLOCK_ASSERTIONS", 1)])
+ env.Append(CPPDEFINES=[("NS_BLOCK_ASSERTIONS", 1)])
if env["optimize"] == "speed": # optimize for speed (default)
# `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces
# when using `target=release_debug`.
opt = "-O3" if env["target"] == "release" else "-O2"
- env.Append(CCFLAGS=[opt, "-ftree-vectorize", "-fomit-frame-pointer"])
+ env.Append(CCFLAGS=[opt])
env.Append(LINKFLAGS=[opt])
elif env["optimize"] == "size": # optimize for size
- env.Append(CCFLAGS=["-Os", "-ftree-vectorize"])
+ env.Append(CCFLAGS=["-Os"])
env.Append(LINKFLAGS=["-Os"])
elif env["target"] == "debug":
- env.Append(CCFLAGS=["-gdwarf-2", "-O0"])
- env.Append(CPPDEFINES=["_DEBUG", ("DEBUG", 1)])
+ env.Append(CCFLAGS=["-g", "-O0"])
+
+ ## LTO
+
+ if env["lto"] == "auto": # Disable by default as it makes linking in Xcode very slow.
+ env["lto"] = "none"
- # LTO
if env["lto"] != "none":
if env["lto"] == "thin":
env.Append(CCFLAGS=["-flto=thin"])
diff --git a/platform/ios/display_layer.mm b/platform/ios/display_layer.mm
index 7c83494768..74c760ae9a 100644
--- a/platform/ios/display_layer.mm
+++ b/platform/ios/display_layer.mm
@@ -89,12 +89,12 @@
// FIXME: Add Vulkan support via MoltenVK. Add fallback code back?
- // Create GL ES 2 context
- if (GLOBAL_GET("rendering/driver/driver_name") == "opengl3") {
- context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
- NSLog(@"Setting up an OpenGL ES 2.0 context.");
+ // Create GL ES 3 context
+ if (GLOBAL_GET("rendering/renderer/rendering_method") == "gl_compatibility") {
+ context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
+ NSLog(@"Setting up an OpenGL ES 3.0 context.");
if (!context) {
- NSLog(@"Failed to create OpenGL ES 2.0 context!");
+ NSLog(@"Failed to create OpenGL ES 3.0 context!");
return;
}
}
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index 74d6bc2e97..d3a0f38463 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -62,7 +62,7 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
// Note that we should be checking "opengl3" as the driver, might never enable this seeing OpenGL is deprecated on iOS
// We are hardcoding the rendering_driver to "vulkan" down below
- if (rendering_driver == "opengl_es") {
+ if (rendering_driver == "opengl3") {
bool gl_initialization_error = false;
// FIXME: Add Vulkan support via MoltenVK. Add fallback code back?
@@ -163,7 +163,7 @@ Vector<String> DisplayServerIOS::get_rendering_drivers_func() {
drivers.push_back("vulkan");
#endif
#if defined(GLES3_ENABLED)
- drivers.push_back("opengl_es");
+ drivers.push_back("opengl3");
#endif
return drivers;
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index 7aacb2de85..74a57dc614 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -34,7 +34,6 @@
#include "editor/editor_node.h"
void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const {
- String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
// Vulkan and OpenGL ES 3.0 both mandate ETC2 support.
r_features->push_back("etc2");
diff --git a/platform/ios/godot_view.mm b/platform/ios/godot_view.mm
index 9ed219508c..ff90c05b1d 100644
--- a/platform/ios/godot_view.mm
+++ b/platform/ios/godot_view.mm
@@ -74,7 +74,7 @@ static const float earth_gravity = 9.80665;
if ([driverName isEqualToString:@"vulkan"]) {
layer = [GodotMetalLayer layer];
- } else if ([driverName isEqualToString:@"opengl_es"]) {
+ } else if ([driverName isEqualToString:@"opengl3"]) {
if (@available(iOS 13, *)) {
NSLog(@"OpenGL ES is deprecated on iOS 13");
}
diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h
index 3b88f53b6a..00d91da771 100644
--- a/platform/ios/os_ios.h
+++ b/platform/ios/os_ios.h
@@ -100,6 +100,8 @@ public:
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override;
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual String get_model_name() const override;
virtual Error shell_open(String p_uri) override;
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index b9d186f355..a674498620 100644
--- a/platform/ios/os_ios.mm
+++ b/platform/ios/os_ios.mm
@@ -240,6 +240,15 @@ String OS_IOS::get_name() const {
return "iOS";
}
+String OS_IOS::get_distribution_name() const {
+ return get_name();
+}
+
+String OS_IOS::get_version() const {
+ NSOperatingSystemVersion ver = [NSProcessInfo processInfo].operatingSystemVersion;
+ return vformat("%d.%d.%d", (int64_t)ver.majorVersion, (int64_t)ver.minorVersion, (int64_t)ver.patchVersion);
+}
+
String OS_IOS::get_model_name() const {
String model = ios->get_model();
if (model != "") {
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 36644d5f29..12d2432eea 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -171,6 +171,10 @@ def configure(env):
env.Append(LINKFLAGS=["-fsanitize=memory"])
# LTO
+
+ if env["lto"] == "auto": # Full LTO for production.
+ env["lto"] = "full"
+
if env["lto"] != "none":
if env["lto"] == "thin":
if not env["use_llvm"]:
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 0236e134fb..66dea6cf1b 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -397,7 +397,10 @@ void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
//flush pending motion events
_flush_mouse_motion();
- WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
WindowData &window = windows[window_id];
if (XGrabPointer(
@@ -433,7 +436,11 @@ void DisplayServerX11::warp_mouse(const Point2i &p_position) {
if (mouse_mode == MOUSE_MODE_CAPTURED) {
last_mouse_pos = p_position;
} else {
- WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
+
XWarpPointer(x11_display, None, windows[window_id].x11_window,
0, 0, 0, 0, (int)p_position.x, (int)p_position.y);
}
@@ -3181,6 +3188,15 @@ void DisplayServerX11::_window_changed(XEvent *event) {
}
}
+DisplayServer::WindowID DisplayServerX11::_get_focused_window_or_popup() const {
+ const List<WindowID>::Element *E = popup_list.back();
+ if (E) {
+ return E->get();
+ }
+
+ return last_focused_window;
+}
+
void DisplayServerX11::_dispatch_input_events(const Ref<InputEvent> &p_event) {
static_cast<DisplayServerX11 *>(get_singleton())->_dispatch_input_event(p_event);
}
@@ -3936,7 +3952,11 @@ void DisplayServerX11::process_events() {
// The X11 API requires filtering one-by-one through the motion
// notify events, in order to figure out which event is the one
// generated by warping the mouse pointer.
- WindowID focused_window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID focused_window_id = _get_focused_window_or_popup();
+ if (!windows.has(focused_window_id)) {
+ focused_window_id = MAIN_WINDOW_ID;
+ }
+
while (true) {
if (mouse_mode == MOUSE_MODE_CAPTURED && event.xmotion.x == windows[focused_window_id].size.width / 2 && event.xmotion.y == windows[focused_window_id].size.height / 2) {
//this is likely the warp event since it was warped here
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index ea03b2328c..a5fa7613bc 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -284,6 +284,8 @@ class DisplayServerX11 : public DisplayServer {
Context context = CONTEXT_ENGINE;
+ WindowID _get_focused_window_or_popup() const;
+
void _send_window_event(const WindowData &wd, WindowEvent p_event);
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
void _dispatch_input_event(const Ref<InputEvent> &p_event);
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index f0d7b6ede5..f4e94f1a91 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -50,6 +50,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/utsname.h>
#include <unistd.h>
#ifdef FONTCONFIG_ENABLED
@@ -205,6 +206,42 @@ String OS_LinuxBSD::get_name() const {
#endif
}
+String OS_LinuxBSD::get_systemd_os_release_info_value(const String &key) const {
+ static String info;
+ if (info.is_empty()) {
+ Ref<FileAccess> f = FileAccess::open("/etc/os-release", FileAccess::READ);
+ if (f.is_valid()) {
+ while (!f->eof_reached()) {
+ const String line = f->get_line();
+ if (line.find(key) != -1) {
+ return line.split("=")[1].strip_edges();
+ }
+ }
+ }
+ }
+ return info;
+}
+
+String OS_LinuxBSD::get_distribution_name() const {
+ static String systemd_name = get_systemd_os_release_info_value("NAME"); // returns a value for systemd users, otherwise an empty string.
+ if (!systemd_name.is_empty()) {
+ return systemd_name;
+ }
+ struct utsname uts; // returns a decent value for BSD family.
+ uname(&uts);
+ return uts.sysname;
+}
+
+String OS_LinuxBSD::get_version() const {
+ static String systemd_version = get_systemd_os_release_info_value("VERSION"); // returns a value for systemd users, otherwise an empty string.
+ if (!systemd_version.is_empty()) {
+ return systemd_version;
+ }
+ struct utsname uts; // returns a decent value for BSD family.
+ uname(&uts);
+ return uts.version;
+}
+
Error OS_LinuxBSD::shell_open(String p_uri) {
Error ok;
int err_code;
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index d5b2321316..722d83ba19 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -67,6 +67,8 @@ class OS_LinuxBSD : public OS_Unix {
MainLoop *main_loop = nullptr;
+ String get_systemd_os_release_info_value(const String &key) const;
+
protected:
virtual void initialize() override;
virtual void finalize() override;
@@ -77,6 +79,8 @@ protected:
public:
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual MainLoop *get_main_loop() const override;
diff --git a/platform/macos/SCsub b/platform/macos/SCsub
index bbd461fba9..7ffb80f70b 100644
--- a/platform/macos/SCsub
+++ b/platform/macos/SCsub
@@ -12,6 +12,7 @@ files = [
"crash_handler_macos.mm",
"macos_terminal_logger.mm",
"display_server_macos.mm",
+ "godot_button_view.mm",
"godot_content_view.mm",
"godot_window_delegate.mm",
"godot_window.mm",
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index bcf4776609..58d9c0e99f 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -40,9 +40,6 @@ def get_flags():
return [
("arch", detect_arch()),
("use_volk", False),
- # Benefits of LTO for macOS (size, performance) haven't been clearly established yet.
- # So for now we override the default value which may be set when using `production=yes`.
- ("lto", "none"),
]
@@ -91,9 +88,9 @@ def configure(env):
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
- env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize"])
+ env.Prepend(CCFLAGS=["-O3"])
elif env["optimize"] == "size": # optimize for size
- env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize"])
+ env.Prepend(CCFLAGS=["-Os"])
if env["arch"] != "arm64":
env.Prepend(CCFLAGS=["-msse2"])
@@ -170,6 +167,10 @@ def configure(env):
env["AS"] = basecmd + "as"
# LTO
+
+ if env["lto"] == "auto": # LTO benefits for macOS (size, performance) haven't been clearly established yet.
+ env["lto"] = "none"
+
if env["lto"] != "none":
if env["lto"] == "thin":
env.Append(CCFLAGS=["-flto=thin"])
@@ -178,6 +179,8 @@ def configure(env):
env.Append(CCFLAGS=["-flto"])
env.Append(LINKFLAGS=["-flto"])
+ # Sanitizers
+
if env["use_ubsan"] or env["use_asan"] or env["use_tsan"]:
env.extra_suffix += ".san"
env.Append(CCFLAGS=["-DSANITIZERS_ENABLED"])
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index 769cba2de5..e72273a681 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -76,6 +76,7 @@ public:
id window_delegate;
id window_object;
id window_view;
+ id window_button_view;
Vector<Vector2> mpath;
@@ -84,6 +85,9 @@ public:
Size2i min_size;
Size2i max_size;
Size2i size;
+ Vector2i wb_offset = Vector2i(14, 14);
+
+ NSRect last_frame_rect;
bool im_active = false;
Size2i im_position;
@@ -175,6 +179,12 @@ private:
IOPMAssertionID screen_keep_on_assertion = kIOPMNullAssertionID;
+ struct MenuCall {
+ Variant tag;
+ Callable callback;
+ };
+ Vector<MenuCall> deferred_menu_calls;
+
const NSMenu *_get_menu_root(const String &p_menu_root) const;
NSMenu *_get_menu_root(const String &p_menu_root);
@@ -187,6 +197,8 @@ private:
Point2i _get_native_screen_position(int p_screen) const;
static void _displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info);
+ WindowID _get_focused_window_or_popup() const;
+
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
void _dispatch_input_event(const Ref<InputEvent> &p_event);
void _push_input(const Ref<InputEvent> &p_event);
@@ -224,6 +236,7 @@ public:
void window_update(WindowID p_window);
void window_destroy(WindowID p_window);
void window_resize(WindowID p_window, int p_width, int p_height);
+ void window_set_custom_window_buttons(WindowData &p_wd, bool p_enabled);
virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const override;
@@ -387,6 +400,7 @@ public:
virtual bool window_maximize_on_title_dbl_click() const override;
virtual bool window_minimize_on_title_dbl_click() const override;
+ virtual void window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window = MAIN_WINDOW_ID) override;
virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual Point2i ime_get_selection() const override;
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 91c6da5d13..1914c5f35d 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -30,6 +30,7 @@
#include "display_server_macos.h"
+#include "godot_button_view.h"
#include "godot_content_view.h"
#include "godot_menu_delegate.h"
#include "godot_menu_item.h"
@@ -317,6 +318,15 @@ void DisplayServerMacOS::_displays_arrangement_changed(CGDirectDisplayID display
}
}
+DisplayServer::WindowID DisplayServerMacOS::_get_focused_window_or_popup() const {
+ const List<WindowID>::Element *E = popup_list.back();
+ if (E) {
+ return E->get();
+ }
+
+ return last_focused_window;
+}
+
void DisplayServerMacOS::_dispatch_input_events(const Ref<InputEvent> &p_event) {
((DisplayServerMacOS *)(get_singleton()))->_dispatch_input_event(p_event);
}
@@ -555,11 +565,11 @@ void DisplayServerMacOS::menu_callback(id p_sender) {
}
if (value->callback != Callable()) {
- Variant tag = value->meta;
- Variant *tagp = &tag;
- Variant ret;
- Callable::CallError ce;
- value->callback.callp((const Variant **)&tagp, 1, ret, ce);
+ MenuCall mc;
+ mc.tag = value->meta;
+ mc.callback = value->callback;
+ deferred_menu_calls.push_back(mc);
+ // Do not run callback from here! If it is opening a new window or calling process_events, it will corrupt OS event queue and crash.
}
}
}
@@ -1828,7 +1838,10 @@ void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) {
return;
}
- WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
WindowData &wd = windows[window_id];
if (p_mode == MOUSE_MODE_CAPTURED) {
// Apple Docs state that the display parameter is not used.
@@ -1943,7 +1956,10 @@ void DisplayServerMacOS::warp_mouse(const Point2i &p_position) {
_THREAD_SAFE_METHOD_
if (mouse_mode != MOUSE_MODE_CAPTURED) {
- WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
WindowData &wd = windows[window_id];
// Local point in window coords.
@@ -2197,7 +2213,9 @@ void DisplayServerMacOS::show_window(WindowID p_id) {
WindowData &wd = windows[p_id];
popup_open(p_id);
- if (wd.no_focus || wd.is_popup) {
+ if ([wd.window_object isMiniaturized]) {
+ return;
+ } else if (wd.no_focus || wd.is_popup) {
[wd.window_object orderFront:nil];
} else {
[wd.window_object makeKeyAndOrderFront:nil];
@@ -2354,6 +2372,10 @@ void DisplayServerMacOS::window_set_position(const Point2i &p_position, WindowID
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
+ if ([wd.window_object isZoomed]) {
+ return;
+ }
+
Point2i position = p_position;
// OS X native y-coordinate relative to _get_screens_origin() is negative,
// Godot passes a positive value.
@@ -2478,6 +2500,10 @@ void DisplayServerMacOS::window_set_size(const Size2i p_size, WindowID p_window)
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
+ if ([wd.window_object isZoomed]) {
+ return;
+ }
+
Size2i size = p_size / screen_get_max_scale();
NSPoint top_left;
@@ -2624,27 +2650,59 @@ bool DisplayServerMacOS::window_minimize_on_title_dbl_click() const {
return false;
}
+void DisplayServerMacOS::window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.wb_offset = p_offset;
+}
+
Vector2i DisplayServerMacOS::window_get_safe_title_margins(WindowID p_window) const {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V(!windows.has(p_window), Vector2i());
const WindowData &wd = windows[p_window];
- float max_x = 0.f;
- NSButton *cb = [wd.window_object standardWindowButton:NSWindowCloseButton];
- if (cb) {
- max_x = MAX(max_x, [cb frame].origin.x + [cb frame].size.width);
+ if (!wd.window_button_view) {
+ return Vector2i();
}
- NSButton *mb = [wd.window_object standardWindowButton:NSWindowMiniaturizeButton];
- if (mb) {
- max_x = MAX(max_x, [mb frame].origin.x + [mb frame].size.width);
+
+ float max_x = wd.wb_offset.x + [wd.window_button_view frame].size.width;
+
+ if ([wd.window_object windowTitlebarLayoutDirection] == NSUserInterfaceLayoutDirectionRightToLeft) {
+ return Vector2i(0, max_x * screen_get_max_scale());
+ } else {
+ return Vector2i(max_x * screen_get_max_scale(), 0);
}
- NSButton *zb = [wd.window_object standardWindowButton:NSWindowZoomButton];
- if (zb) {
- max_x = MAX(max_x, [zb frame].origin.x + [zb frame].size.width);
+}
+
+void DisplayServerMacOS::window_set_custom_window_buttons(WindowData &p_wd, bool p_enabled) {
+ if (p_wd.window_button_view) {
+ [p_wd.window_button_view removeFromSuperview];
+ p_wd.window_button_view = nil;
}
+ if (p_enabled) {
+ float cb_frame = NSMinX([[p_wd.window_object standardWindowButton:NSWindowCloseButton] frame]);
+ float mb_frame = NSMinX([[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] frame]);
+ bool is_rtl = ([p_wd.window_object windowTitlebarLayoutDirection] == NSUserInterfaceLayoutDirectionRightToLeft);
+
+ float window_buttons_spacing = (is_rtl) ? (cb_frame - mb_frame) : (mb_frame - cb_frame);
+
+ [p_wd.window_object setTitleVisibility:NSWindowTitleHidden];
+ [[p_wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:YES];
+ [[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
+ [[p_wd.window_object standardWindowButton:NSWindowCloseButton] setHidden:YES];
- return Vector2i(max_x * screen_get_max_scale(), 0);
+ p_wd.window_button_view = [[GodotButtonView alloc] initWithFrame:NSZeroRect];
+ [p_wd.window_button_view initButtons:window_buttons_spacing offset:NSMakePoint(p_wd.wb_offset.x, p_wd.wb_offset.y) rtl:is_rtl];
+ [p_wd.window_view addSubview:p_wd.window_button_view];
+ } else {
+ [p_wd.window_object setTitleVisibility:NSWindowTitleVisible];
+ [[p_wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:NO];
+ [[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:NO];
+ [[p_wd.window_object standardWindowButton:NSWindowCloseButton] setHidden:NO];
+ }
}
void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
@@ -2669,14 +2727,21 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
NSRect rect = [wd.window_object frame];
if (p_enabled) {
[wd.window_object setTitlebarAppearsTransparent:YES];
- [wd.window_object setTitleVisibility:NSWindowTitleHidden];
[wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskFullSizeContentView];
+
+ if (!wd.fullscreen) {
+ window_set_custom_window_buttons(wd, true);
+ }
} else {
[wd.window_object setTitlebarAppearsTransparent:NO];
- [wd.window_object setTitleVisibility:NSWindowTitleVisible];
[wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskFullSizeContentView];
+
+ if (!wd.fullscreen) {
+ window_set_custom_window_buttons(wd, false);
+ }
}
[wd.window_object setFrame:rect display:YES];
+ send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE);
} break;
case WINDOW_FLAG_BORDERLESS: {
// OrderOut prevents a lose focus bug with the window.
@@ -2696,7 +2761,9 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
}
_update_window_style(wd);
if ([wd.window_object isVisible]) {
- if (wd.no_focus || wd.is_popup) {
+ if ([wd.window_object isMiniaturized]) {
+ return;
+ } else if (wd.no_focus || wd.is_popup) {
[wd.window_object orderFront:nil];
} else {
[wd.window_object makeKeyAndOrderFront:nil];
@@ -3213,6 +3280,16 @@ void DisplayServerMacOS::process_events() {
[NSApp sendEvent:event];
}
+ // Process "menu_callback"s.
+ for (MenuCall &E : deferred_menu_calls) {
+ Variant tag = E.tag;
+ Variant *tagp = &tag;
+ Variant ret;
+ Callable::CallError ce;
+ E.callback.callp((const Variant **)&tagp, 1, ret, ce);
+ }
+ deferred_menu_calls.clear();
+
if (!drop_events) {
_process_key_events();
Input::get_singleton()->flush_buffered_events();
@@ -3537,7 +3614,7 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
[apple_menu addItem:[NSMenuItem separatorItem]];
- title = [NSString stringWithFormat:NSLocalizedString(@"\t\tQuit %@", nil), nsappname];
+ title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname];
[apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
// Add items to the menu bar.
diff --git a/platform/macos/godot_button_view.h b/platform/macos/godot_button_view.h
new file mode 100644
index 0000000000..e7627a9e9b
--- /dev/null
+++ b/platform/macos/godot_button_view.h
@@ -0,0 +1,52 @@
+/*************************************************************************/
+/* godot_button_view.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GODOT_BUTTON_VIEW_H
+#define GODOT_BUTTON_VIEW_H
+
+#include "servers/display_server.h"
+
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+
+@interface GodotButtonView : NSView {
+ NSTrackingArea *tracking_area;
+ NSPoint offset;
+ CGFloat spacing;
+ bool mouse_in_group;
+ bool rtl;
+}
+
+- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset rtl:(bool)is_rtl;
+- (void)displayButtons;
+
+@end
+
+#endif // GODOT_BUTTON_VIEW_H
diff --git a/platform/macos/godot_button_view.mm b/platform/macos/godot_button_view.mm
new file mode 100644
index 0000000000..9106f0b0db
--- /dev/null
+++ b/platform/macos/godot_button_view.mm
@@ -0,0 +1,123 @@
+/*************************************************************************/
+/* godot_button_view.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "godot_button_view.h"
+
+@implementation GodotButtonView
+
+- (id)initWithFrame:(NSRect)frame {
+ self = [super initWithFrame:frame];
+
+ tracking_area = nil;
+ offset = NSMakePoint(8, 8);
+ spacing = 20;
+ mouse_in_group = false;
+ rtl = false;
+
+ return self;
+}
+
+- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset rtl:(bool)is_rtl {
+ spacing = button_spacing;
+ rtl = is_rtl;
+
+ NSButton *close_button = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:NSWindowStyleMaskTitled];
+ [close_button setFrameOrigin:NSMakePoint(rtl ? spacing * 2 : 0, 0)];
+ [self addSubview:close_button];
+
+ NSButton *miniaturize_button = [NSWindow standardWindowButton:NSWindowMiniaturizeButton forStyleMask:NSWindowStyleMaskTitled];
+ [miniaturize_button setFrameOrigin:NSMakePoint(spacing, 0)];
+ [self addSubview:miniaturize_button];
+
+ NSButton *zoom_button = [NSWindow standardWindowButton:NSWindowZoomButton forStyleMask:NSWindowStyleMaskTitled];
+ [zoom_button setFrameOrigin:NSMakePoint(rtl ? 0 : spacing * 2, 0)];
+ [self addSubview:zoom_button];
+
+ offset.y = button_offset.y - zoom_button.frame.size.height / 2;
+ offset.x = button_offset.x - zoom_button.frame.size.width / 2;
+
+ if (rtl) {
+ [self setFrameSize:NSMakeSize(close_button.frame.origin.x + close_button.frame.size.width, close_button.frame.size.height)];
+ } else {
+ [self setFrameSize:NSMakeSize(zoom_button.frame.origin.x + zoom_button.frame.size.width, zoom_button.frame.size.height)];
+ }
+ [self displayButtons];
+}
+
+- (void)viewDidMoveToWindow {
+ if (!self.window) {
+ return;
+ }
+
+ if (rtl) {
+ [self setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
+ [self setFrameOrigin:NSMakePoint(self.window.frame.size.width - self.frame.size.width - offset.x, self.window.frame.size.height - self.frame.size.height - offset.y)];
+ } else {
+ [self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
+ [self setFrameOrigin:NSMakePoint(offset.x, self.window.frame.size.height - self.frame.size.height - offset.y)];
+ }
+}
+
+- (BOOL)_mouseInGroup:(NSButton *)button {
+ return mouse_in_group;
+}
+
+- (void)updateTrackingAreas {
+ if (tracking_area != nil) {
+ [self removeTrackingArea:tracking_area];
+ }
+
+ NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect;
+ tracking_area = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:options owner:self userInfo:nil];
+
+ [self addTrackingArea:tracking_area];
+}
+
+- (void)mouseEntered:(NSEvent *)event {
+ [super mouseEntered:event];
+
+ mouse_in_group = true;
+ [self displayButtons];
+}
+
+- (void)mouseExited:(NSEvent *)event {
+ [super mouseExited:event];
+
+ mouse_in_group = false;
+ [self displayButtons];
+}
+
+- (void)displayButtons {
+ for (NSView *subview in self.subviews) {
+ [subview setNeedsDisplay:YES];
+ }
+}
+
+@end
diff --git a/platform/macos/godot_content_view.mm b/platform/macos/godot_content_view.mm
index f93ef48f6c..cb70a5db86 100644
--- a/platform/macos/godot_content_view.mm
+++ b/platform/macos/godot_content_view.mm
@@ -61,6 +61,24 @@
@implementation GodotContentView
- (void)setFrameSize:(NSSize)newSize {
+ DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
+ if (ds && ds->has_window(window_id)) {
+ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ NSRect frameRect = [wd.window_object frame];
+ bool left = (wd.last_frame_rect.origin.x != frameRect.origin.x);
+ bool top = (wd.last_frame_rect.origin.y == frameRect.origin.y);
+ if (left && top) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementBottomRight;
+ } else if (left && !top) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementTopRight;
+ } else if (!left && top) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementBottomLeft;
+ } else {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
+ }
+ wd.last_frame_rect = frameRect;
+ }
+
[super setFrameSize:newSize];
[self.layer setNeedsDisplay]; // Force "drawRect" call.
}
diff --git a/platform/macos/godot_window.h b/platform/macos/godot_window.h
index 9fc5599e86..d3653fda82 100644
--- a/platform/macos/godot_window.h
+++ b/platform/macos/godot_window.h
@@ -38,9 +38,11 @@
@interface GodotWindow : NSWindow {
DisplayServer::WindowID window_id;
+ NSTimeInterval anim_duration;
}
- (void)setWindowID:(DisplayServer::WindowID)wid;
+- (void)setAnimDuration:(NSTimeInterval)duration;
@end
diff --git a/platform/macos/godot_window.mm b/platform/macos/godot_window.mm
index e205e7546d..bc51da4f72 100644
--- a/platform/macos/godot_window.mm
+++ b/platform/macos/godot_window.mm
@@ -37,9 +37,22 @@
- (id)init {
self = [super init];
window_id = DisplayServer::INVALID_WINDOW_ID;
+ anim_duration = -1.0f;
return self;
}
+- (void)setAnimDuration:(NSTimeInterval)duration {
+ anim_duration = duration;
+}
+
+- (NSTimeInterval)animationResizeTime:(NSRect)newFrame {
+ if (anim_duration > 0) {
+ return anim_duration;
+ } else {
+ return [super animationResizeTime:newFrame];
+ }
+}
+
- (void)setWindowID:(DisplayServerMacOS::WindowID)wid {
window_id = wid;
}
diff --git a/platform/macos/godot_window_delegate.h b/platform/macos/godot_window_delegate.h
index 98c226aa2f..01cc13a016 100644
--- a/platform/macos/godot_window_delegate.h
+++ b/platform/macos/godot_window_delegate.h
@@ -38,6 +38,8 @@
@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 2d9329ab3c..279fd2a359 100644
--- a/platform/macos/godot_window_delegate.mm
+++ b/platform/macos/godot_window_delegate.mm
@@ -31,6 +31,8 @@
#include "godot_window_delegate.h"
#include "display_server_macos.h"
+#include "godot_button_view.h"
+#include "godot_window.h"
@implementation GodotWindowDelegate
@@ -68,6 +70,26 @@
ds->window_destroy(window_id);
}
+- (NSArray<NSWindow *> *)customWindowsToEnterFullScreenForWindow:(NSWindow *)window {
+ DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
+ if (!ds || !ds->has_window(window_id)) {
+ return nullptr;
+ }
+
+ old_frame = [window frame];
+ old_style_mask = [window styleMask];
+
+ NSMutableArray<NSWindow *> *windows = [[NSMutableArray alloc] init];
+ [windows addObject:window];
+
+ return windows;
+}
+
+- (void)window:(NSWindow *)window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration {
+ [(GodotWindow *)window setAnimDuration:duration];
+ [window setFrame:[[window screen] frame] display:YES animate:YES];
+}
+
- (void)windowDidEnterFullScreen:(NSNotification *)notification {
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
if (!ds || !ds->has_window(window_id)) {
@@ -76,12 +98,46 @@
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
wd.fullscreen = true;
+
// 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);
+}
+
+- (NSArray<NSWindow *> *)customWindowsToExitFullScreenForWindow:(NSWindow *)window {
+ DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
+ if (!ds || !ds->has_window(window_id)) {
+ return nullptr;
+ }
+
+ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+
+ // Restore custom window buttons.
+ if ([wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView) {
+ ds->window_set_custom_window_buttons(wd, true);
+ }
+
+ 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)windowDidExitFullScreen:(NSNotification *)notification {
@@ -93,6 +149,8 @@
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
wd.fullscreen = false;
+ [(GodotWindow *)wd.window_object setAnimDuration:-1.0f];
+
// Set window size limits.
const float scale = ds->screen_get_max_scale();
if (wd.min_size != Size2i()) {
@@ -151,7 +209,9 @@
- (void)windowWillStartLiveResize:(NSNotification *)notification {
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
- if (ds) {
+ if (ds && ds->has_window(window_id)) {
+ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ wd.last_frame_rect = [wd.window_object frame];
ds->set_is_resizing(true);
}
}
@@ -217,6 +277,10 @@
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ if (wd.window_button_view) {
+ [(GodotButtonView *)wd.window_button_view displayButtons];
+ }
+
if (ds->mouse_get_mode() == DisplayServer::MOUSE_MODE_CAPTURED) {
const NSRect content_rect = [wd.window_view frame];
NSRect point_in_window_rect = NSMakeRect(content_rect.size.width / 2, content_rect.size.height / 2, 0, 0);
@@ -239,6 +303,10 @@
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ if (wd.window_button_view) {
+ [(GodotButtonView *)wd.window_button_view displayButtons];
+ }
+
ds->release_pressed_events();
ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT);
}
diff --git a/platform/macos/os_macos.h b/platform/macos/os_macos.h
index 61db99689c..46e7c17ebe 100644
--- a/platform/macos/os_macos.h
+++ b/platform/macos/os_macos.h
@@ -75,6 +75,8 @@ public:
virtual List<String> get_cmdline_platform_args() const override;
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index c250a9d71a..ae8534f6ab 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -134,6 +134,15 @@ String OS_MacOS::get_name() const {
return "macOS";
}
+String OS_MacOS::get_distribution_name() const {
+ return get_name();
+}
+
+String OS_MacOS::get_version() const {
+ NSOperatingSystemVersion ver = [NSProcessInfo processInfo].operatingSystemVersion;
+ return vformat("%d.%d.%d", (int64_t)ver.majorVersion, (int64_t)ver.minorVersion, (int64_t)ver.patchVersion);
+}
+
void OS_MacOS::alert(const String &p_alert, const String &p_title) {
NSAlert *window = [[NSAlert alloc] init];
NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 791328964b..8050d299f0 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -444,6 +444,16 @@ String OS_UWP::get_name() const {
return "UWP";
}
+String OS_UWP::get_distribution_name() const {
+ return get_name();
+}
+
+String OS_UWP::get_version() const {
+ winrt::hstring df_version = VersionInfo().DeviceFamilyVersion();
+ static String version = String(winrt::to_string(df_version).c_str());
+ return version;
+}
+
OS::DateTime OS_UWP::get_datetime(bool p_utc) const {
SYSTEMTIME systemtime;
if (p_utc) {
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index 7d4224cf74..0c1c4a793a 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -183,6 +183,8 @@ public:
virtual MainLoop *get_main_loop() const;
virtual String get_name() const;
+ virtual String get_distribution_name() const;
+ virtual String get_version() const;
virtual DateTime get_datetime(bool p_utc) const;
virtual TimeZoneInfo get_time_zone_info() const;
diff --git a/platform/web/.eslintrc.engine.js b/platform/web/.eslintrc.engine.js
index 78df6d41d9..a76bd46b9e 100644
--- a/platform/web/.eslintrc.engine.js
+++ b/platform/web/.eslintrc.engine.js
@@ -5,6 +5,7 @@ module.exports = {
"globals": {
"InternalConfig": true,
"Godot": true,
+ "Features": true,
"Preloader": true,
},
};
diff --git a/platform/web/SCsub b/platform/web/SCsub
index e8d0181ede..013b734be2 100644
--- a/platform/web/SCsub
+++ b/platform/web/SCsub
@@ -66,6 +66,7 @@ sys_env.Depends(build[0], sys_env["JS_PRE"])
sys_env.Depends(build[0], sys_env["JS_EXTERNS"])
engine = [
+ "js/engine/features.js",
"js/engine/preloader.js",
"js/engine/config.js",
"js/engine/engine.js",
diff --git a/platform/web/detect.py b/platform/web/detect.py
index 08f964db92..9cce73efc4 100644
--- a/platform/web/detect.py
+++ b/platform/web/detect.py
@@ -109,6 +109,10 @@ def configure(env):
env["ENV"] = os.environ
# LTO
+
+ if env["lto"] == "auto": # Full LTO for production.
+ env["lto"] = "full"
+
if env["lto"] != "none":
if env["lto"] == "thin":
env.Append(CCFLAGS=["-flto=thin"])
diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index 306453c1eb..1c327fe4b2 100644
--- a/platform/web/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -307,13 +307,7 @@ void EditorExportPlatformWeb::get_preset_features(const Ref<EditorExportPreset>
}
if (p_preset->get("vram_texture_compression/for_mobile")) {
- String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
- if (driver == "opengl3") {
- r_features->push_back("etc");
- } else if (driver == "vulkan") {
- // FIXME: Review if this is correct.
- r_features->push_back("etc2");
- }
+ r_features->push_back("etc2");
}
r_features->push_back("wasm32");
}
diff --git a/platform/web/js/engine/engine.js b/platform/web/js/engine/engine.js
index 6f0d51b2be..9227aa1f05 100644
--- a/platform/web/js/engine/engine.js
+++ b/platform/web/js/engine/engine.js
@@ -61,20 +61,6 @@ const Engine = (function () {
};
/**
- * Check whether WebGL is available. Optionally, specify a particular version of WebGL to check for.
- *
- * @param {number=} [majorVersion=1] The major WebGL version to check for.
- * @returns {boolean} If the given major version of WebGL is available.
- * @function Engine.isWebGLAvailable
- */
- Engine.isWebGLAvailable = function (majorVersion = 1) {
- try {
- return !!document.createElement('canvas').getContext(['webgl', 'webgl2'][majorVersion - 1]);
- } catch (e) { /* Not available */ }
- return false;
- };
-
- /**
* Safe Engine constructor, creates a new prototype for every new instance to avoid prototype pollution.
* @ignore
* @constructor
@@ -265,14 +251,21 @@ const Engine = (function () {
// Also expose static methods as instance methods
Engine.prototype['load'] = Engine.load;
Engine.prototype['unload'] = Engine.unload;
- Engine.prototype['isWebGLAvailable'] = Engine.isWebGLAvailable;
return new Engine(initConfig);
}
// Closure compiler exported static methods.
SafeEngine['load'] = Engine.load;
SafeEngine['unload'] = Engine.unload;
- SafeEngine['isWebGLAvailable'] = Engine.isWebGLAvailable;
+
+ // Feature-detection utilities.
+ SafeEngine['isWebGLAvailable'] = Features.isWebGLAvailable;
+ SafeEngine['isFetchAvailable'] = Features.isFetchAvailable;
+ SafeEngine['isSecureContext'] = Features.isSecureContext;
+ SafeEngine['isCrossOriginIsolated'] = Features.isCrossOriginIsolated;
+ SafeEngine['isSharedArrayBufferAvailable'] = Features.isSharedArrayBufferAvailable;
+ SafeEngine['isAudioWorkletAvailable'] = Features.isAudioWorkletAvailable;
+ SafeEngine['getMissingFeatures'] = Features.getMissingFeatures;
return SafeEngine;
}());
diff --git a/platform/web/js/engine/features.js b/platform/web/js/engine/features.js
new file mode 100644
index 0000000000..f91a4eff81
--- /dev/null
+++ b/platform/web/js/engine/features.js
@@ -0,0 +1,96 @@
+const Features = { // eslint-disable-line no-unused-vars
+ /**
+ * Check whether WebGL is available. Optionally, specify a particular version of WebGL to check for.
+ *
+ * @param {number=} [majorVersion=1] The major WebGL version to check for.
+ * @returns {boolean} If the given major version of WebGL is available.
+ * @function Engine.isWebGLAvailable
+ */
+ isWebGLAvailable: function (majorVersion = 1) {
+ try {
+ return !!document.createElement('canvas').getContext(['webgl', 'webgl2'][majorVersion - 1]);
+ } catch (e) { /* Not available */ }
+ return false;
+ },
+
+ /**
+ * Check whether the Fetch API available and supports streaming responses.
+ *
+ * @returns {boolean} If the Fetch API is available and supports streaming responses.
+ * @function Engine.isFetchAvailable
+ */
+ isFetchAvailable: function () {
+ return 'fetch' in window && 'Response' in window && 'body' in window.Response.prototype;
+ },
+
+ /**
+ * Check whether the engine is running in a Secure Context.
+ *
+ * @returns {boolean} If the engine is running in a Secure Context.
+ * @function Engine.isSecureContext
+ */
+ isSecureContext: function () {
+ return window['isSecureContext'] === true;
+ },
+
+ /**
+ * Check whether the engine is cross origin isolated.
+ * This value is dependent on Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers sent by the server.
+ *
+ * @returns {boolean} If the engine is running in a Secure Context.
+ * @function Engine.isSecureContext
+ */
+ isCrossOriginIsolated: function () {
+ return window['crossOriginIsolated'] === true;
+ },
+
+ /**
+ * Check whether SharedBufferArray is available.
+ *
+ * Most browsers require the page to be running in a secure context, and the
+ * the server to provide specific CORS headers for SharedArrayBuffer to be available.
+ *
+ * @returns {boolean} If SharedArrayBuffer is available.
+ * @function Engine.isSharedArrayBufferAvailable
+ */
+ isSharedArrayBufferAvailable: function () {
+ return 'SharedArrayBuffer' in window;
+ },
+
+ /**
+ * Check whether the AudioContext supports AudioWorkletNodes.
+ *
+ * @returns {boolean} If AudioWorkletNode is available.
+ * @function Engine.isAudioWorkletAvailable
+ */
+ isAudioWorkletAvailable: function () {
+ return 'AudioContext' in window && 'audioWorklet' in AudioContext.prototype;
+ },
+
+ /**
+ * Return an array of missing required features (as string).
+ *
+ * @returns {Array<string>} A list of human-readable missing features.
+ * @function Engine.getMissingFeatures
+ */
+ getMissingFeatures: function () {
+ const missing = [];
+ if (!Features.isWebGLAvailable(2)) {
+ missing.push('WebGL2');
+ }
+ if (!Features.isFetchAvailable()) {
+ missing.push('Fetch');
+ }
+ if (!Features.isSecureContext()) {
+ missing.push('Secure Context');
+ }
+ if (!Features.isCrossOriginIsolated()) {
+ missing.push('Cross Origin Isolation');
+ }
+ if (!Features.isSharedArrayBufferAvailable()) {
+ missing.push('SharedArrayBuffer');
+ }
+ // Audio is normally optional since we have a dummy fallback.
+ return missing;
+ },
+};
diff --git a/platform/web/package.json b/platform/web/package.json
index a57205415a..0a8d9e4334 100644
--- a/platform/web/package.json
+++ b/platform/web/package.json
@@ -4,7 +4,7 @@
"version": "1.0.0",
"description": "Development and linting setup for Godot's Web platform code",
"scripts": {
- "docs": "jsdoc --template js/jsdoc2rst/ js/engine/engine.js js/engine/config.js --destination ''",
+ "docs": "jsdoc --template js/jsdoc2rst/ js/engine/engine.js js/engine/config.js js/engine/features.js --destination ''",
"lint": "npm run lint:engine && npm run lint:libs && npm run lint:modules && npm run lint:tools",
"lint:engine": "eslint \"js/engine/*.js\" --no-eslintrc -c .eslintrc.engine.js",
"lint:libs": "eslint \"js/libs/*.js\" --no-eslintrc -c .eslintrc.libs.js",
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index e6e1874fc0..095d688213 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -350,7 +350,6 @@ def configure_msvc(env, vcvars_msvc_config):
elif env["target"] == "debug":
env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"])
- # Allow big objects. Only needed for debug, see MinGW branch for rationale.
env.Append(LINKFLAGS=["/DEBUG"])
if env["debug_symbols"]:
@@ -448,6 +447,9 @@ def configure_msvc(env, vcvars_msvc_config):
## LTO
+ if env["lto"] == "auto": # No LTO by default for MSVC, doesn't help.
+ env["lto"] = "none"
+
if env["lto"] != "none":
if env["lto"] == "thin":
print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
@@ -564,6 +566,11 @@ def configure_mingw(env):
if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]):
env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib"
+ ## LTO
+
+ if env["lto"] == "auto": # Full LTO for production with MinGW.
+ env["lto"] = "full"
+
if env["lto"] != "none":
if env["lto"] == "thin":
if not env["use_llvm"]:
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index a14170525d..b9e6f7b843 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -104,7 +104,10 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
if (windows.has(MAIN_WINDOW_ID) && (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN)) {
// Mouse is grabbed (captured or confined).
- WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
WindowData &wd = windows[window_id];
@@ -119,11 +122,15 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
ClientToScreen(wd.hWnd, &pos);
SetCursorPos(pos.x, pos.y);
SetCapture(wd.hWnd);
+
+ _register_raw_input_devices(window_id);
}
} else {
// Mouse is free to move around (not captured or confined).
ReleaseCapture();
ClipCursor(nullptr);
+
+ _register_raw_input_devices(INVALID_WINDOW_ID);
}
if (p_mode == MOUSE_MODE_HIDDEN || p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED_HIDDEN) {
@@ -139,6 +146,37 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
}
}
+DisplayServer::WindowID DisplayServerWindows::_get_focused_window_or_popup() const {
+ const List<WindowID>::Element *E = popup_list.back();
+ if (E) {
+ return E->get();
+ }
+
+ return last_focused_window;
+}
+
+void DisplayServerWindows::_register_raw_input_devices(WindowID p_target_window) {
+ use_raw_input = true;
+
+ RAWINPUTDEVICE rid[1] = {};
+ rid[0].usUsagePage = 0x01;
+ rid[0].usUsage = 0x02;
+ rid[0].dwFlags = 0;
+
+ if (p_target_window != INVALID_WINDOW_ID && windows.has(p_target_window)) {
+ // Follow the defined window
+ rid[0].hwndTarget = windows[p_target_window].hWnd;
+ } else {
+ // Follow the keyboard focus
+ rid[0].hwndTarget = 0;
+ }
+
+ if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == FALSE) {
+ // Registration failed.
+ use_raw_input = false;
+ }
+}
+
bool DisplayServerWindows::tts_is_speaking() const {
ERR_FAIL_COND_V(!tts, false);
return tts->is_speaking();
@@ -194,7 +232,9 @@ DisplayServer::MouseMode DisplayServerWindows::mouse_get_mode() const {
void DisplayServerWindows::warp_mouse(const Point2i &p_position) {
_THREAD_SAFE_METHOD_
- if (!windows.has(last_focused_window)) {
+ WindowID window_id = _get_focused_window_or_popup();
+
+ if (!windows.has(window_id)) {
return; // No focused window?
}
@@ -205,7 +245,7 @@ void DisplayServerWindows::warp_mouse(const Point2i &p_position) {
POINT p;
p.x = p_position.x;
p.y = p_position.y;
- ClientToScreen(windows[last_focused_window].hWnd, &p);
+ ClientToScreen(windows[window_id].hWnd, &p);
SetCursorPos(p.x, p.y);
}
@@ -645,7 +685,13 @@ void DisplayServerWindows::show_window(WindowID p_id) {
_update_window_style(p_id);
}
- if (wd.no_focus || wd.is_popup) {
+ if (wd.maximized) {
+ ShowWindow(wd.hWnd, SW_SHOWMAXIMIZED);
+ SetForegroundWindow(wd.hWnd); // Slightly higher priority.
+ SetFocus(wd.hWnd); // Set keyboard focus.
+ } else if (wd.minimized) {
+ ShowWindow(wd.hWnd, SW_SHOWMINIMIZED);
+ } else if (wd.no_focus || wd.is_popup) {
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
ShowWindow(wd.hWnd, SW_SHOWNA);
} else {
@@ -886,7 +932,7 @@ void DisplayServerWindows::window_set_position(const Point2i &p_position, Window
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
- if (wd.fullscreen) {
+ if (wd.fullscreen || wd.maximized) {
return;
}
@@ -1019,6 +1065,10 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
+ if (wd.fullscreen || wd.maximized) {
+ return;
+ }
+
int w = p_size.width;
int h = p_size.height;
@@ -1036,10 +1086,6 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
}
#endif
- if (wd.fullscreen) {
- return;
- }
-
RECT rect;
GetWindowRect(wd.hWnd, &rect);
@@ -1496,7 +1542,7 @@ void DisplayServerWindows::cursor_set_shape(CursorShape p_shape) {
IDC_HELP
};
- if (cursors[p_shape] != nullptr) {
+ if (cursors_cache.has(p_shape)) {
SetCursor(cursors[p_shape]);
} else {
SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
@@ -1509,55 +1555,6 @@ DisplayServer::CursorShape DisplayServerWindows::cursor_get_shape() const {
return cursor_shape;
}
-void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap) {
- // Get the system display DC.
- HDC hDC = GetDC(nullptr);
-
- // Create helper DC.
- HDC hMainDC = CreateCompatibleDC(hDC);
- HDC hAndMaskDC = CreateCompatibleDC(hDC);
- HDC hXorMaskDC = CreateCompatibleDC(hDC);
-
- // Get the dimensions of the source bitmap.
- BITMAP bm;
- GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
-
- // Create the mask bitmaps.
- hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // Color.
- hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // Color.
-
- // Release the system display DC.
- ReleaseDC(nullptr, hDC);
-
- // Select the bitmaps to helper DC.
- HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap);
- HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap);
- HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap);
-
- // Assign the monochrome AND mask bitmap pixels so that the pixels of the source bitmap
- // with 'clrTransparent' will be white pixels of the monochrome bitmap.
- SetBkColor(hMainDC, clrTransparent);
- BitBlt(hAndMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCCOPY);
-
- // Assign the color XOR mask bitmap pixels so that the pixels of the source bitmap
- // with 'clrTransparent' will be black and rest the pixels same as corresponding
- // pixels of the source bitmap.
- SetBkColor(hXorMaskDC, RGB(0, 0, 0));
- SetTextColor(hXorMaskDC, RGB(255, 255, 255));
- BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hAndMaskDC, 0, 0, SRCCOPY);
- BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCAND);
-
- // Deselect bitmaps from the helper DC.
- SelectObject(hMainDC, hOldMainBitmap);
- SelectObject(hAndMaskDC, hOldAndMaskBitmap);
- SelectObject(hXorMaskDC, hOldXorMaskBitmap);
-
- // Delete the helper DC.
- DeleteDC(hXorMaskDC);
- DeleteDC(hAndMaskDC);
- DeleteDC(hMainDC);
-}
-
void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
_THREAD_SAFE_METHOD_
@@ -1610,8 +1607,26 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
UINT image_size = texture_size.width * texture_size.height;
// Create the BITMAP with alpha channel.
- COLORREF *buffer = (COLORREF *)memalloc(sizeof(COLORREF) * image_size);
-
+ COLORREF *buffer = nullptr;
+
+ BITMAPV5HEADER bi;
+ ZeroMemory(&bi, sizeof(bi));
+ bi.bV5Size = sizeof(bi);
+ bi.bV5Width = texture_size.width;
+ bi.bV5Height = -texture_size.height;
+ bi.bV5Planes = 1;
+ bi.bV5BitCount = 32;
+ bi.bV5Compression = BI_BITFIELDS;
+ bi.bV5RedMask = 0x00ff0000;
+ bi.bV5GreenMask = 0x0000ff00;
+ bi.bV5BlueMask = 0x000000ff;
+ bi.bV5AlphaMask = 0xff000000;
+
+ HDC dc = GetDC(nullptr);
+ HBITMAP bitmap = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO *>(&bi), DIB_RGB_COLORS, reinterpret_cast<void **>(&buffer), nullptr, 0);
+ HBITMAP mask = CreateBitmap(texture_size.width, texture_size.height, 1, 1, nullptr);
+
+ bool fully_transparent = true;
for (UINT index = 0; index < image_size; index++) {
int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
@@ -1620,39 +1635,28 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
column_index = MIN(column_index, atlas_rect.size.width - 1);
row_index = MIN(row_index, atlas_rect.size.height - 1);
}
+ const Color &c = image->get_pixel(column_index, row_index);
+ fully_transparent = fully_transparent && (c.a == 0.f);
- *(buffer + index) = image->get_pixel(column_index, row_index).to_argb32();
- }
-
- // Using 4 channels, so 4 * 8 bits.
- HBITMAP bitmap = CreateBitmap(texture_size.width, texture_size.height, 1, 4 * 8, buffer);
- COLORREF clrTransparent = -1;
-
- // Create the AND and XOR masks for the bitmap.
- HBITMAP hAndMask = nullptr;
- HBITMAP hXorMask = nullptr;
-
- GetMaskBitmaps(bitmap, clrTransparent, hAndMask, hXorMask);
-
- if (nullptr == hAndMask || nullptr == hXorMask) {
- memfree(buffer);
- DeleteObject(bitmap);
- return;
+ *(buffer + index) = c.to_argb32();
}
// Finally, create the icon.
- ICONINFO iconinfo;
- iconinfo.fIcon = FALSE;
- iconinfo.xHotspot = p_hotspot.x;
- iconinfo.yHotspot = p_hotspot.y;
- iconinfo.hbmMask = hAndMask;
- iconinfo.hbmColor = hXorMask;
-
if (cursors[p_shape]) {
DestroyIcon(cursors[p_shape]);
}
- cursors[p_shape] = CreateIconIndirect(&iconinfo);
+ if (fully_transparent) {
+ cursors[p_shape] = nullptr;
+ } else {
+ ICONINFO iconinfo;
+ iconinfo.fIcon = FALSE;
+ iconinfo.xHotspot = p_hotspot.x;
+ iconinfo.yHotspot = p_hotspot.y;
+ iconinfo.hbmMask = mask;
+ iconinfo.hbmColor = bitmap;
+ cursors[p_shape] = CreateIconIndirect(&iconinfo);
+ }
Vector<Variant> params;
params.push_back(p_cursor);
@@ -1665,17 +1669,15 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
}
}
- DeleteObject(hAndMask);
- DeleteObject(hXorMask);
-
- memfree(buffer);
+ DeleteObject(mask);
DeleteObject(bitmap);
+ ReleaseDC(nullptr, dc);
} else {
// Reset to default system cursor.
if (cursors[p_shape]) {
DestroyIcon(cursors[p_shape]);
- cursors[p_shape] = nullptr;
}
+ cursors[p_shape] = nullptr;
CursorShape c = cursor_shape;
cursor_shape = CURSOR_MAX;
@@ -2527,7 +2529,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
old_y = coords.y;
}
- if (windows[window_id].window_has_focus && mm->get_relative() != Vector2()) {
+ if ((windows[window_id].window_has_focus || windows[window_id].is_popup) && mm->get_relative() != Vector2()) {
Input::get_singleton()->parse_input_event(mm);
}
}
@@ -3350,7 +3352,7 @@ void DisplayServerWindows::_process_key_events() {
k->set_ctrl_pressed(ke.control);
k->set_meta_pressed(ke.meta);
k->set_pressed(true);
- k->set_keycode((Key)KeyMappingWindows::get_keysym(ke.wParam));
+ k->set_keycode((Key)KeyMappingWindows::get_keysym(MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK)));
k->set_physical_keycode((Key)(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24))));
k->set_unicode(unicode);
if (k->get_unicode() && gr_mem) {
@@ -3603,6 +3605,16 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
wd.wtctx = 0;
}
+ if (p_mode == WINDOW_MODE_MAXIMIZED) {
+ wd.maximized = true;
+ wd.minimized = false;
+ }
+
+ if (p_mode == WINDOW_MODE_MINIMIZED) {
+ wd.maximized = false;
+ wd.minimized = true;
+ }
+
wd.last_pressure = 0;
wd.last_pressure_update = 0;
wd.last_tilt = Vector2();
@@ -3817,19 +3829,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
return;
}
- use_raw_input = true;
-
- RAWINPUTDEVICE Rid[1];
-
- Rid[0].usUsagePage = 0x01;
- Rid[0].usUsage = 0x02;
- Rid[0].dwFlags = 0;
- Rid[0].hwndTarget = 0;
-
- if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
- // Registration failed.
- use_raw_input = false;
- }
+ _register_raw_input_devices(INVALID_WINDOW_ID);
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index b0ad7e36c0..d85d6364bd 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -311,8 +311,6 @@ class DisplayServerWindows : public DisplayServer {
String tablet_driver;
Vector<String> tablet_drivers;
- void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap);
-
enum {
KEY_EVENT_BUFFER_SIZE = 512
};
@@ -468,6 +466,8 @@ class DisplayServerWindows : public DisplayServer {
void _update_real_mouse_position(WindowID p_window);
void _set_mouse_mode_impl(MouseMode p_mode);
+ WindowID _get_focused_window_or_popup() const;
+ void _register_raw_input_devices(WindowID p_target_window);
void _process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam);
void _process_key_events();
diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis
index cdd1c14978..36b0919185 100644
--- a/platform/windows/godot.natvis
+++ b/platform/windows/godot.natvis
@@ -32,6 +32,38 @@
</Expand>
</Type>
+ <Type Name="HashMap&lt;*,*&gt;">
+ <Expand>
+ <Item Name="[size]">num_elements</Item>
+ <LinkedListItems>
+ <Size>num_elements</Size>
+ <HeadPointer>head_element</HeadPointer>
+ <NextPointer>next</NextPointer>
+ <ValueNode>data</ValueNode>
+ </LinkedListItems>
+ </Expand>
+ </Type>
+
+ <Type Name="VMap&lt;*,*&gt;">
+ <Expand>
+ <Item Condition="_cowdata._ptr" Name="[size]">*(reinterpret_cast&lt;int*&gt;(_cowdata._ptr) - 1)</Item>
+ <ArrayItems Condition="_cowdata._ptr">
+ <Size>*(reinterpret_cast&lt;int*&gt;(_cowdata._ptr) - 1)</Size>
+ <ValuePointer>reinterpret_cast&lt;VMap&lt;$T1,$T2&gt;::Pair*&gt;(_cowdata._ptr)</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="VMap&lt;Callable,*&gt;::Pair">
+ <DisplayString Condition="dynamic_cast&lt;CallableCustomMethodPointerBase*&gt;(key.custom)">{dynamic_cast&lt;CallableCustomMethodPointerBase*&gt;(key.custom)->text}</DisplayString>
+ </Type>
+
+ <!-- requires PR 64364
+ <Type Name="GDScriptThreadContext">
+ <DisplayString Condition="_is_main == true">main thread {_debug_thread_id}</DisplayString>
+ </Type>
+ -->
+
<Type Name="Variant">
<DisplayString Condition="type == Variant::NIL">nil</DisplayString>
<DisplayString Condition="type == Variant::BOOL">{_data._bool}</DisplayString>
@@ -55,15 +87,17 @@
<DisplayString Condition="type == Variant::OBJECT">{*(Object *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::DICTIONARY">{*(Dictionary *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::ARRAY">{*(Array *)_data._mem}</DisplayString>
- <DisplayString Condition="type == Variant::PACKED_BYTE_ARRAY">{*(PackedByteArray *)_data._mem}</DisplayString>
- <DisplayString Condition="type == Variant::PACKED_INT32_ARRAY">{*(PackedInt32Array *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::PACKED_BYTE_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;unsigned char&gt;*&gt;(_data.packed_array)->array}</DisplayString>
+ <DisplayString Condition="type == Variant::PACKED_INT32_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;int&gt;*&gt;(_data.packed_array)->array}</DisplayString>
+ <!-- broken, will show incorrect data
<DisplayString Condition="type == Variant::PACKED_INT64_ARRAY">{*(PackedInt64Array *)_data._mem}</DisplayString>
- <DisplayString Condition="type == Variant::PACKED_FLOAT32_ARRAY">{*(PackedFloat32Array *)_data._mem}</DisplayString>
- <DisplayString Condition="type == Variant::PACKED_FLOAT64_ARRAY">{*(PackedFloat64Array *)_data._mem}</DisplayString>
- <DisplayString Condition="type == Variant::PACKED_STRING_ARRAY">{*(PackedStringArray *)_data._mem}</DisplayString>
- <DisplayString Condition="type == Variant::PACKED_VECTOR2_ARRAY">{*(PackedVector2Array *)_data._mem}</DisplayString>
- <DisplayString Condition="type == Variant::PACKED_VECTOR3_ARRAY">{*(PackedVector3Array *)_data._mem}</DisplayString>
- <DisplayString Condition="type == Variant::PACKED_COLOR_ARRAY">{*(PackedColorArray *)_data._mem}</DisplayString>
+ -->
+ <DisplayString Condition="type == Variant::PACKED_FLOAT32_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;float&gt;*&gt;(_data.packed_array)->array}</DisplayString>
+ <DisplayString Condition="type == Variant::PACKED_FLOAT64_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;double&gt;*&gt;(_data.packed_array)->array}</DisplayString>
+ <DisplayString Condition="type == Variant::PACKED_STRING_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;String&gt;*&gt;(_data.packed_array)->array}</DisplayString>
+ <DisplayString Condition="type == Variant::PACKED_VECTOR2_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;Vector2&gt;*&gt;(_data.packed_array)->array}</DisplayString>
+ <DisplayString Condition="type == Variant::PACKED_VECTOR3_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;Vector3&gt;*&gt;(_data.packed_array)->array}</DisplayString>
+ <DisplayString Condition="type == Variant::PACKED_COLOR_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;Color&gt;*&gt;(_data.packed_array)->array}</DisplayString>
<StringView Condition="type == Variant::STRING &amp;&amp; ((String *)(_data._mem))->_cowdata._ptr">((String *)(_data._mem))->_cowdata._ptr,s32</StringView>
@@ -87,7 +121,7 @@
<Item Name="[value]" Condition="type == Variant::OBJECT">*(Object *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::DICTIONARY">*(Dictionary *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::ARRAY">*(Array *)_data._mem</Item>
- <Item Name="[value]" Condition="type == Variant::PACKED_BYTE_ARRAY">*(PackedByteArray *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::PACKED_BYTE_ARRAY">reinterpret_cast&lt;const Variant::PackedArrayRef&lt;unsigned char&gt;*&gt;(_data.packed_array)->array</Item>
<Item Name="[value]" Condition="type == Variant::PACKED_INT32_ARRAY">*(PackedInt32Array *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::PACKED_INT64_ARRAY">*(PackedInt64Array *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::PACKED_FLOAT32_ARRAY">*(PackedFloat32Array *)_data._mem</Item>
@@ -105,6 +139,14 @@
<StringView Condition="_cowdata._ptr != 0">_cowdata._ptr,s32</StringView>
</Type>
+ <Type Name="godot::String">
+ <DisplayString>{*reinterpret_cast&lt;void**&gt;(opaque),s32}</DisplayString>
+ <Expand>
+ <Item Name="opaque_ptr">*reinterpret_cast&lt;void**&gt;(opaque)</Item>
+ <Item Name="string">*reinterpret_cast&lt;void**&gt;(opaque),s32</Item>
+ </Expand>
+ </Type>
+
<Type Name="StringName">
<DisplayString Condition="_data &amp;&amp; _data->cname">{_data->cname}</DisplayString>
<DisplayString Condition="_data &amp;&amp; !_data->cname">{_data->name,s32}</DisplayString>
@@ -113,6 +155,22 @@
<StringView Condition="_data &amp;&amp; !_data->cname">_data->name,s32</StringView>
</Type>
+ <!-- can't cast the opaque to ::StringName because Natvis does not support global namespace specifier? -->
+ <Type Name="godot::StringName">
+ <DisplayString Condition="(*reinterpret_cast&lt;const char***&gt;(opaque))[1]">{(*reinterpret_cast&lt;const char***&gt;(opaque))[1],s8}</DisplayString>
+ <DisplayString Condition="!(*reinterpret_cast&lt;const char***&gt;(opaque))[1]">{(*reinterpret_cast&lt;const char***&gt;(opaque))[2],s32}</DisplayString>
+ <Expand>
+ <Item Name="opaque_ptr">*reinterpret_cast&lt;void**&gt;(opaque)</Item>
+ <Item Name="&amp;cname">(*reinterpret_cast&lt;const char***&gt;(opaque))+1</Item>
+ <Item Name="cname">(*reinterpret_cast&lt;const char***&gt;(opaque))[1],s8</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Object::SignalData">
+ <DisplayString Condition="user.name._cowdata._ptr">"{user.name}" {slot_map}</DisplayString>
+ <DisplayString Condition="!user.name._cowdata._ptr">"{slot_map}</DisplayString>
+ </Type>
+
<Type Name="Vector2">
<DisplayString>{{{x},{y}}}</DisplayString>
<Expand>
@@ -149,12 +207,4 @@
<Item Name="alpha">a</Item>
</Expand>
</Type>
-
- <Type Name="Node" Inheritable="false">
- <Expand>
- <Item Name="Object">(Object*)this</Item>
- <Item Name="class_name">(StringName*)(((char*)this) + sizeof(Object))</Item>
- <Item Name="data">(Node::Data*)(((char*)this) + sizeof(Object) + sizeof(StringName))</Item>
- </Expand>
- </Type>
</AutoVisualizer>
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 2c268ff3d5..1978ec5ab6 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -290,6 +290,24 @@ String OS_Windows::get_name() const {
return "Windows";
}
+String OS_Windows::get_distribution_name() const {
+ return get_name();
+}
+
+String OS_Windows::get_version() const {
+ typedef LONG NTSTATUS, *PNTSTATUS;
+ typedef NTSTATUS(WINAPI * RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
+ RtlGetVersionPtr version_ptr = (RtlGetVersionPtr)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion");
+ if (version_ptr != nullptr) {
+ RTL_OSVERSIONINFOW fow = { 0 };
+ fow.dwOSVersionInfoSize = sizeof(fow);
+ if (version_ptr(&fow) == 0x00000000) {
+ return vformat("%d.%d.%d", (int64_t)fow.dwMajorVersion, (int64_t)fow.dwMinorVersion, (int64_t)fow.dwBuildNumber);
+ }
+ }
+ return "";
+}
+
OS::DateTime OS_Windows::get_datetime(bool p_utc) const {
SYSTEMTIME systemtime;
if (p_utc) {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 53451b780e..491de2266f 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -143,6 +143,8 @@ public:
virtual MainLoop *get_main_loop() const override;
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual void initialize_joypads() override {}
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index 7fe464d2f4..7ee9861d3f 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -63,9 +63,13 @@ Rect2 AnimatedSprite2D::_edit_get_rect() const {
}
bool AnimatedSprite2D::_edit_use_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return false;
}
+ if (frame < 0 || frame >= frames->get_frame_count(animation)) {
+ return false;
+ }
+
Ref<Texture2D> t;
if (animation) {
t = frames->get_frame(animation, frame);
@@ -79,7 +83,10 @@ Rect2 AnimatedSprite2D::get_anchorable_rect() const {
}
Rect2 AnimatedSprite2D::_get_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
+ return Rect2();
+ }
+ if (frame < 0 || frame >= frames->get_frame_count(animation)) {
return Rect2();
}
@@ -161,29 +168,22 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const {
void AnimatedSprite2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
- if (frames.is_null()) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
- if (!frames->has_animation(animation)) {
- return;
- }
- if (frame < 0) {
- return;
+
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
+ if (speed == 0) {
+ return; // Do nothing.
}
+ int last_frame = frames->get_frame_count(animation) - 1;
double remaining = get_process_delta_time();
-
while (remaining) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
- if (speed == 0) {
- return; // Do nothing.
- }
-
if (timeout <= 0) {
timeout = _get_frame_duration();
- int last_frame = frames->get_frame_count(animation) - 1;
- if (!backwards) {
+ if (!playing_backwards) {
// Forward.
if (frame >= last_frame) {
if (frames->get_animation_loop(animation)) {
@@ -229,13 +229,7 @@ void AnimatedSprite2D::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
- if (frames.is_null()) {
- return;
- }
- if (frame < 0) {
- return;
- }
- if (!frames->has_animation(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
@@ -327,9 +321,14 @@ int AnimatedSprite2D::get_frame() const {
}
void AnimatedSprite2D::set_speed_scale(double p_speed_scale) {
+ if (speed_scale == p_speed_scale) {
+ return;
+ }
+
double elapsed = _get_frame_duration() - timeout;
- speed_scale = MAX(p_speed_scale, 0.0f);
+ speed_scale = p_speed_scale;
+ playing_backwards = signbit(speed_scale) != backwards;
// We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed.
_reset_timeout();
@@ -398,12 +397,13 @@ bool AnimatedSprite2D::is_playing() const {
return playing;
}
-void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backwards) {
+void AnimatedSprite2D::play(const StringName &p_animation, bool p_backwards) {
backwards = p_backwards;
+ playing_backwards = signbit(speed_scale) != backwards;
if (p_animation) {
set_animation(p_animation);
- if (frames.is_valid() && backwards && get_frame() == 0) {
+ if (frames.is_valid() && playing_backwards && get_frame() == 0) {
set_frame(frames->get_frame_count(p_animation) - 1);
}
}
@@ -418,7 +418,7 @@ void AnimatedSprite2D::stop() {
double AnimatedSprite2D::_get_frame_duration() {
if (frames.is_valid() && frames->has_animation(animation)) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
if (speed > 0) {
return 1.0 / speed;
}
@@ -454,11 +454,11 @@ StringName AnimatedSprite2D::get_animation() const {
return animation;
}
-TypedArray<String> AnimatedSprite2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray AnimatedSprite2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (frames.is_null()) {
- warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames."));
+ warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite2D to display frames."));
}
return warnings;
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
index 0a19e250d8..11c4adb816 100644
--- a/scene/2d/animated_sprite_2d.h
+++ b/scene/2d/animated_sprite_2d.h
@@ -39,6 +39,7 @@ class AnimatedSprite2D : public Node2D {
Ref<SpriteFrames> frames;
bool playing = false;
+ bool playing_backwards = false;
bool backwards = false;
StringName animation = "default";
int frame = 0;
@@ -81,7 +82,7 @@ public:
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
Ref<SpriteFrames> get_sprite_frames() const;
- void play(const StringName &p_animation = StringName(), const bool p_backwards = false);
+ void play(const StringName &p_animation = StringName(), bool p_backwards = false);
void stop();
void set_playing(bool p_playing);
@@ -108,7 +109,7 @@ public:
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
AnimatedSprite2D();
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index a11b2b66bf..e120aa871b 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -172,7 +172,7 @@ Transform2D Camera2D::get_camera_transform() {
Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom_scale) : Point2());
real_t angle = get_global_rotation();
- if (rotating) {
+ if (!ignore_rotation) {
screen_offset = screen_offset.rotated(angle);
}
@@ -204,7 +204,7 @@ Transform2D Camera2D::get_camera_transform() {
Transform2D xform;
xform.scale_basis(zoom_scale);
- if (rotating) {
+ if (!ignore_rotation) {
xform.set_rotation(angle);
}
xform.set_origin(screen_rect.position);
@@ -363,15 +363,15 @@ Camera2D::AnchorMode Camera2D::get_anchor_mode() const {
return anchor_mode;
}
-void Camera2D::set_rotating(bool p_rotating) {
- rotating = p_rotating;
+void Camera2D::set_ignore_rotation(bool p_ignore) {
+ ignore_rotation = p_ignore;
Point2 old_smoothed_camera_pos = smoothed_camera_pos;
_update_scroll();
smoothed_camera_pos = old_smoothed_camera_pos;
}
-bool Camera2D::is_rotating() const {
- return rotating;
+bool Camera2D::is_ignoring_rotation() const {
+ return ignore_rotation;
}
void Camera2D::set_process_callback(Camera2DProcessCallback p_mode) {
@@ -668,8 +668,8 @@ void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_anchor_mode", "anchor_mode"), &Camera2D::set_anchor_mode);
ClassDB::bind_method(D_METHOD("get_anchor_mode"), &Camera2D::get_anchor_mode);
- ClassDB::bind_method(D_METHOD("set_rotating", "rotating"), &Camera2D::set_rotating);
- ClassDB::bind_method(D_METHOD("is_rotating"), &Camera2D::is_rotating);
+ ClassDB::bind_method(D_METHOD("set_ignore_rotation", "ignore"), &Camera2D::set_ignore_rotation);
+ ClassDB::bind_method(D_METHOD("is_ignoring_rotation"), &Camera2D::is_ignoring_rotation);
ClassDB::bind_method(D_METHOD("_update_scroll"), &Camera2D::_update_scroll);
@@ -733,7 +733,7 @@ void Camera2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_mode", PROPERTY_HINT_ENUM, "Fixed TopLeft,Drag Center"), "set_anchor_mode", "get_anchor_mode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotating"), "set_rotating", "is_rotating");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_rotation"), "set_ignore_rotation", "is_ignoring_rotation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom", PROPERTY_HINT_LINK), "set_zoom", "get_zoom");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", PROPERTY_USAGE_NONE), "set_custom_viewport", "get_custom_viewport");
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 78654ee606..1ce622388c 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -63,7 +63,7 @@ protected:
Vector2 zoom = Vector2(1, 1);
Vector2 zoom_scale = Vector2(1, 1);
AnchorMode anchor_mode = ANCHOR_MODE_DRAG_CENTER;
- bool rotating = false;
+ bool ignore_rotation = true;
bool current = false;
real_t smoothing = 5.0;
bool smoothing_enabled = false;
@@ -109,8 +109,8 @@ public:
void set_anchor_mode(AnchorMode p_anchor_mode);
AnchorMode get_anchor_mode() const;
- void set_rotating(bool p_rotating);
- bool is_rotating() const;
+ void set_ignore_rotation(bool p_ignore);
+ bool is_ignoring_rotation() const;
void set_limit(Side p_side, int p_limit);
int get_limit(Side p_side) const;
diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp
index 61a17a4845..330afe4a1b 100644
--- a/scene/2d/canvas_modulate.cpp
+++ b/scene/2d/canvas_modulate.cpp
@@ -78,8 +78,8 @@ Color CanvasModulate::get_color() const {
return color;
}
-TypedArray<String> CanvasModulate::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray CanvasModulate::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (is_visible_in_tree() && is_inside_tree()) {
List<Node *> nodes;
diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h
index 1fd54898f8..4f522ca1c7 100644
--- a/scene/2d/canvas_modulate.h
+++ b/scene/2d/canvas_modulate.h
@@ -46,7 +46,7 @@ public:
void set_color(const Color &p_color);
Color get_color() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
CanvasModulate();
~CanvasModulate();
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index a79c81e8bd..23948c2fd3 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -565,8 +565,8 @@ void CollisionObject2D::_update_pickable() {
}
}
-TypedArray<String> CollisionObject2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray CollisionObject2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (shapes.is_empty()) {
warnings.push_back(RTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape."));
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index 48ea59e040..6b778d1b60 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -157,7 +157,7 @@ public:
void set_pickable(bool p_enabled);
bool is_pickable() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
_FORCE_INLINE_ RID get_rid() const { return rid; }
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index b69b19d30d..d06461b566 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -235,8 +235,8 @@ bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, doubl
}
#endif
-TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray CollisionPolygon2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
warnings.push_back(RTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape."));
diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h
index e18022ab7e..066f7271c6 100644
--- a/scene/2d/collision_polygon_2d.h
+++ b/scene/2d/collision_polygon_2d.h
@@ -77,7 +77,7 @@ public:
void set_polygon(const Vector<Point2> &p_polygon);
Vector<Point2> get_polygon() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
void set_disabled(bool p_disabled);
bool is_disabled() const;
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 039bfee451..7e167a3807 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -168,8 +168,8 @@ bool CollisionShape2D::_edit_is_selected_on_click(const Point2 &p_point, double
return shape->_edit_is_selected_on_click(p_point, p_tolerance);
}
-TypedArray<String> CollisionShape2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray CollisionShape2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
warnings.push_back(RTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape."));
diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h
index dbc81e8424..5e50420e00 100644
--- a/scene/2d/collision_shape_2d.h
+++ b/scene/2d/collision_shape_2d.h
@@ -72,7 +72,7 @@ public:
void set_one_way_collision_margin(real_t p_margin);
real_t get_one_way_collision_margin() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
CollisionShape2D();
};
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 4523e5dfe9..eece90190b 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -242,8 +242,8 @@ bool CPUParticles2D::get_fractional_delta() const {
return fractional_delta;
}
-TypedArray<String> CPUParticles2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node2D::get_configuration_warnings();
+PackedStringArray CPUParticles2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 3fd1c7fd0f..ea735411a8 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -282,7 +282,7 @@ public:
void set_gravity(const Vector2 &p_gravity);
Vector2 get_gravity() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
void restart();
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index bed68b4ee0..18f709f241 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -296,8 +296,8 @@ bool GPUParticles2D::get_interpolate() const {
return interpolate;
}
-TypedArray<String> GPUParticles2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node2D::get_configuration_warnings();
+PackedStringArray GPUParticles2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (RenderingServer::get_singleton()->is_low_end()) {
warnings.push_back(RTR("GPU-based particles are not supported by the OpenGL video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" option for this purpose."));
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index 10ae91775f..d613b4ef51 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -145,7 +145,7 @@ public:
void set_texture(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
void set_sub_emitter(const NodePath &p_path);
NodePath get_sub_emitter() const;
diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp
index 89b6f3f9da..6000508f36 100644
--- a/scene/2d/joint_2d.cpp
+++ b/scene/2d/joint_2d.cpp
@@ -202,8 +202,8 @@ bool Joint2D::get_exclude_nodes_from_collision() const {
return exclude_from_collision;
}
-TypedArray<String> Joint2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node2D::get_configuration_warnings();
+PackedStringArray Joint2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (!warning.is_empty()) {
warnings.push_back(warning);
diff --git a/scene/2d/joint_2d.h b/scene/2d/joint_2d.h
index e3cd600cbd..8b145be6ae 100644
--- a/scene/2d/joint_2d.h
+++ b/scene/2d/joint_2d.h
@@ -62,7 +62,7 @@ protected:
_FORCE_INLINE_ bool is_configured() const { return configured; }
public:
- virtual TypedArray<String> get_configuration_warnings() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
void set_node_a(const NodePath &p_node_a);
NodePath get_node_a() const;
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 7eb6b43af7..90402260ed 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -395,8 +395,8 @@ Vector2 PointLight2D::get_texture_offset() const {
return texture_offset;
}
-TypedArray<String> PointLight2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray PointLight2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!texture.is_valid()) {
warnings.push_back(RTR("A texture with the shape of the light must be supplied to the \"Texture\" property."));
diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h
index 373cfe59fd..29870923aa 100644
--- a/scene/2d/light_2d.h
+++ b/scene/2d/light_2d.h
@@ -171,7 +171,7 @@ public:
void set_texture_scale(real_t p_scale);
real_t get_texture_scale() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
PointLight2D();
};
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 6c171383ca..67e82140e4 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -246,8 +246,8 @@ int LightOccluder2D::get_occluder_light_mask() const {
return mask;
}
-TypedArray<String> LightOccluder2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray LightOccluder2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!occluder_polygon.is_valid()) {
warnings.push_back(RTR("An occluder polygon must be set (or drawn) for this occluder to take effect."));
diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h
index b61e23464a..ee4d87e54b 100644
--- a/scene/2d/light_occluder_2d.h
+++ b/scene/2d/light_occluder_2d.h
@@ -105,7 +105,7 @@ public:
void set_as_sdf_collision(bool p_enable);
bool is_set_as_sdf_collision() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
LightOccluder2D();
~LightOccluder2D();
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index d7f75c63a4..55cebdaadc 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -368,8 +368,8 @@ void NavigationAgent2D::_avoidance_done(Vector3 p_new_velocity) {
emit_signal(SNAME("velocity_computed"), velocity);
}
-TypedArray<String> NavigationAgent2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray NavigationAgent2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node2D>(get_parent())) {
warnings.push_back(RTR("The NavigationAgent2D can be used only under a Node2D inheriting parent node."));
diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h
index 11b845665d..2fbacc4c76 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -155,7 +155,7 @@ public:
void set_velocity(Vector2 p_velocity);
void _avoidance_done(Vector3 p_new_velocity);
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
private:
void update_navigation();
diff --git a/scene/2d/navigation_link_2d.cpp b/scene/2d/navigation_link_2d.cpp
index 8ba51482ee..3f7e10eaea 100644
--- a/scene/2d/navigation_link_2d.cpp
+++ b/scene/2d/navigation_link_2d.cpp
@@ -267,8 +267,8 @@ void NavigationLink2D::set_travel_cost(real_t p_travel_cost) {
NavigationServer2D::get_singleton()->link_set_travel_cost(link, travel_cost);
}
-TypedArray<String> NavigationLink2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray NavigationLink2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (start_location.is_equal_approx(end_location)) {
warnings.push_back(RTR("NavigationLink2D start location should be different than the end location to be useful."));
diff --git a/scene/2d/navigation_link_2d.h b/scene/2d/navigation_link_2d.h
index 5990ea082c..2a5092216d 100644
--- a/scene/2d/navigation_link_2d.h
+++ b/scene/2d/navigation_link_2d.h
@@ -79,7 +79,7 @@ public:
void set_travel_cost(real_t p_travel_cost);
real_t get_travel_cost() const { return travel_cost; }
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
NavigationLink2D();
~NavigationLink2D();
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index 1850e00ecd..e46bb79551 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -120,8 +120,8 @@ NavigationObstacle2D::~NavigationObstacle2D() {
agent = RID(); // Pointless
}
-TypedArray<String> NavigationObstacle2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray NavigationObstacle2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node2D>(get_parent())) {
warnings.push_back(RTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object."));
diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h
index 6eff95adec..d4c1df343f 100644
--- a/scene/2d/navigation_obstacle_2d.h
+++ b/scene/2d/navigation_obstacle_2d.h
@@ -73,7 +73,7 @@ public:
return radius;
}
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
private:
void initialize_agent();
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index ffccb95a22..6e8ecb13b1 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -354,10 +354,13 @@ void NavigationPolygon::_bind_methods() {
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;
}
+
enabled = p_enabled;
if (!is_inside_tree()) {
@@ -384,35 +387,50 @@ bool NavigationRegion2D::is_enabled() const {
}
void NavigationRegion2D::set_navigation_layers(uint32_t p_navigation_layers) {
- NavigationServer2D::get_singleton()->region_set_navigation_layers(region, p_navigation_layers);
+ if (navigation_layers == p_navigation_layers) {
+ return;
+ }
+
+ navigation_layers = p_navigation_layers;
+
+ NavigationServer2D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
}
uint32_t NavigationRegion2D::get_navigation_layers() const {
- return NavigationServer2D::get_singleton()->region_get_navigation_layers(region);
+ return navigation_layers;
}
void NavigationRegion2D::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 NavigationRegion2D::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 NavigationRegion2D::set_enter_cost(real_t p_enter_cost) {
ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
- enter_cost = MAX(p_enter_cost, 0.0);
- NavigationServer2D::get_singleton()->region_set_enter_cost(region, p_enter_cost);
+ if (Math::is_equal_approx(enter_cost, p_enter_cost)) {
+ return;
+ }
+
+ enter_cost = p_enter_cost;
+
+ NavigationServer2D::get_singleton()->region_set_enter_cost(region, enter_cost);
}
real_t NavigationRegion2D::get_enter_cost() const {
@@ -421,7 +439,12 @@ real_t NavigationRegion2D::get_enter_cost() const {
void NavigationRegion2D::set_travel_cost(real_t p_travel_cost) {
ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
- travel_cost = MAX(p_travel_cost, 0.0);
+ if (Math::is_equal_approx(travel_cost, p_travel_cost)) {
+ return;
+ }
+
+ travel_cost = p_travel_cost;
+
NavigationServer2D::get_singleton()->region_set_travel_cost(region, travel_cost);
}
@@ -433,7 +456,6 @@ RID NavigationRegion2D::get_region_rid() const {
return region;
}
-/////////////////////////////
#ifdef TOOLS_ENABLED
Rect2 NavigationRegion2D::_edit_get_rect() const {
return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2();
@@ -566,8 +588,8 @@ void NavigationRegion2D::_map_changed(RID p_map) {
#endif // DEBUG_ENABLED
}
-TypedArray<String> NavigationRegion2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node2D::get_configuration_warnings();
+PackedStringArray NavigationRegion2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (is_visible_in_tree() && is_inside_tree()) {
if (!navpoly.is_valid()) {
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 3c9df91fe3..c630e20780 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -96,10 +96,10 @@ class NavigationRegion2D : public Node2D {
bool enabled = true;
RID region;
- Ref<NavigationPolygon> navpoly;
-
+ uint32_t navigation_layers = 1;
real_t enter_cost = 0.0;
real_t travel_cost = 1.0;
+ Ref<NavigationPolygon> navpoly;
void _navpoly_changed();
void _map_changed(RID p_RID);
@@ -134,7 +134,7 @@ public:
void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly);
Ref<NavigationPolygon> get_navigation_polygon() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
NavigationRegion2D();
~NavigationRegion2D();
diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp
index bd5a01f5a4..f1a28b7852 100644
--- a/scene/2d/parallax_background.cpp
+++ b/scene/2d/parallax_background.cpp
@@ -102,9 +102,9 @@ void ParallaxBackground::_update_scroll() {
}
if (ignore_camera_zoom) {
- l->set_base_offset_and_scale((ofs + screen_offset * (scale - 1)) / scale, 1.0, screen_offset);
+ l->set_base_offset_and_scale((ofs + screen_offset * (scale - 1)) / scale, 1.0);
} else {
- l->set_base_offset_and_scale(ofs, scale, screen_offset);
+ l->set_base_offset_and_scale(ofs, scale);
}
}
}
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp
index f0aad1b8a4..01e4bf19f3 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -39,7 +39,7 @@ void ParallaxLayer::set_motion_scale(const Size2 &p_scale) {
if (pb && is_inside_tree()) {
Vector2 ofs = pb->get_final_offset();
real_t scale = pb->get_scroll_scale();
- set_base_offset_and_scale(ofs, scale, screen_offset);
+ set_base_offset_and_scale(ofs, scale);
}
}
@@ -54,7 +54,7 @@ void ParallaxLayer::set_motion_offset(const Size2 &p_offset) {
if (pb && is_inside_tree()) {
Vector2 ofs = pb->get_final_offset();
real_t scale = pb->get_scroll_scale();
- set_base_offset_and_scale(ofs, scale, screen_offset);
+ set_base_offset_and_scale(ofs, scale);
}
}
@@ -111,9 +111,7 @@ void ParallaxLayer::_notification(int p_what) {
}
}
-void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale, const Point2 &p_screen_offset) {
- screen_offset = p_screen_offset;
-
+void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale) {
if (!is_inside_tree()) {
return;
}
@@ -121,7 +119,7 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_s
return;
}
- Point2 new_ofs = (screen_offset + (p_offset - screen_offset) * motion_scale) + motion_offset * p_scale + orig_offset * p_scale;
+ Point2 new_ofs = p_offset * motion_scale + motion_offset * p_scale + orig_offset * p_scale;
if (mirroring.x) {
real_t den = mirroring.x * p_scale;
@@ -139,8 +137,8 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_s
_update_mirroring();
}
-TypedArray<String> ParallaxLayer::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray ParallaxLayer::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!Object::cast_to<ParallaxBackground>(get_parent())) {
warnings.push_back(RTR("ParallaxLayer node only works when set as child of a ParallaxBackground node."));
diff --git a/scene/2d/parallax_layer.h b/scene/2d/parallax_layer.h
index b4dcf0ea61..6471f56c5c 100644
--- a/scene/2d/parallax_layer.h
+++ b/scene/2d/parallax_layer.h
@@ -43,8 +43,6 @@ class ParallaxLayer : public Node2D {
Vector2 mirroring;
void _update_mirroring();
- Point2 screen_offset;
-
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -59,9 +57,9 @@ public:
void set_mirroring(const Size2 &p_mirroring);
Size2 get_mirroring() const;
- void set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale, const Point2 &p_screen_offset);
+ void set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale);
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
ParallaxLayer();
};
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 90b2e3d460..c1044fdf5b 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -256,8 +256,8 @@ void PathFollow2D::_validate_property(PropertyInfo &p_property) const {
}
}
-TypedArray<String> PathFollow2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray PathFollow2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (is_visible_in_tree() && is_inside_tree()) {
if (!Object::cast_to<Path2D>(get_parent())) {
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index 3d66ca1fab..5e436fb9f6 100644
--- a/scene/2d/path_2d.h
+++ b/scene/2d/path_2d.h
@@ -106,7 +106,7 @@ public:
void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
PathFollow2D() {}
};
diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp
index e6933b8a40..5ff706ebb7 100644
--- a/scene/2d/physical_bone_2d.cpp
+++ b/scene/2d/physical_bone_2d.cpp
@@ -106,8 +106,8 @@ void PhysicalBone2D::_find_joint_child() {
}
}
-TypedArray<String> PhysicalBone2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray PhysicalBone2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!parent_skeleton) {
warnings.push_back(RTR("A PhysicalBone2D only works with a Skeleton2D or another PhysicalBone2D as a parent node!"));
diff --git a/scene/2d/physical_bone_2d.h b/scene/2d/physical_bone_2d.h
index 9fbfa04100..33ac0d9935 100644
--- a/scene/2d/physical_bone_2d.h
+++ b/scene/2d/physical_bone_2d.h
@@ -79,7 +79,7 @@ public:
void set_follow_bone_when_simulating(bool p_follow);
bool get_follow_bone_when_simulating() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
PhysicalBone2D();
~PhysicalBone2D();
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 714d196779..4e6b37a860 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -34,8 +34,8 @@
#include "scene/scene_string_names.h"
void PhysicsBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08));
- ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
@@ -54,15 +54,15 @@ PhysicsBody2D::~PhysicsBody2D() {
}
}
-Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_distance, bool p_test_only, real_t p_margin) {
+Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_distance, bool p_test_only, real_t p_margin, bool p_recovery_as_collision) {
PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_distance, p_margin);
- parameters.recovery_as_collision = false; // Don't report collisions generated only from recovery.
+ parameters.recovery_as_collision = p_recovery_as_collision;
PhysicsServer2D::MotionResult result;
if (move_and_collide(parameters, result, p_test_only)) {
// Create a new instance when the cached reference is invalid or still in use in script.
- if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) {
+ if (motion_cache.is_null() || motion_cache->get_reference_count() > 1) {
motion_cache.instantiate();
motion_cache->owner = this;
}
@@ -128,7 +128,7 @@ bool PhysicsBody2D::move_and_collide(const PhysicsServer2D::MotionParameters &p_
return colliding;
}
-bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) {
+bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision, real_t p_margin, bool p_recovery_as_collision) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer2D::MotionResult *r = nullptr;
@@ -141,7 +141,7 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distan
}
PhysicsServer2D::MotionParameters parameters(p_from, p_distance, p_margin);
- parameters.recovery_as_collision = false; // Don't report collisions generated only from recovery.
+ parameters.recovery_as_collision = p_recovery_as_collision;
return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r);
}
@@ -262,21 +262,16 @@ void AnimatableBody2D::_update_kinematic_motion() {
#endif
if (sync_to_physics) {
- PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
+ PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &AnimatableBody2D::_body_state_changed));
set_only_update_transform_changes(true);
set_notify_local_transform(true);
} else {
- PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr);
+ PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), Callable());
set_only_update_transform_changes(false);
set_notify_local_transform(false);
}
}
-void AnimatableBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) {
- AnimatableBody2D *body = static_cast<AnimatableBody2D *>(p_instance);
- body->_body_state_changed(p_state);
-}
-
void AnimatableBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
if (!sync_to_physics) {
return;
@@ -438,11 +433,6 @@ struct _RigidBody2DInOut {
int local_shape = 0;
};
-void RigidBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) {
- RigidBody2D *body = static_cast<RigidBody2D *>(p_instance);
- body->_body_state_changed(p_state);
-}
-
void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
set_block_transform_notify(true); // don't want notify (would feedback loop)
if (!freeze || freeze_mode != FREEZE_MODE_KINEMATIC) {
@@ -921,10 +911,10 @@ void RigidBody2D::_notification(int p_what) {
#endif
}
-TypedArray<String> RigidBody2D::get_configuration_warnings() const {
+PackedStringArray RigidBody2D::get_configuration_warnings() const {
Transform2D t = get_transform();
- TypedArray<String> warnings = CollisionObject2D::get_configuration_warnings();
+ PackedStringArray warnings = CollisionObject2D::get_configuration_warnings();
if (ABS(t.columns[0].length() - 1.0) > 0.05 || ABS(t.columns[1].length() - 1.0) > 0.05) {
warnings.push_back(RTR("Size changes to RigidBody2D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
@@ -1079,7 +1069,7 @@ void RigidBody2D::_validate_property(PropertyInfo &p_property) const {
RigidBody2D::RigidBody2D() :
PhysicsBody2D(PhysicsServer2D::BODY_MODE_RIGID) {
- PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
+ PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &RigidBody2D::_body_state_changed));
}
RigidBody2D::~RigidBody2D() {
@@ -1144,7 +1134,6 @@ bool CharacterBody2D::move_and_slide() {
if (!current_platform_velocity.is_zero_approx()) {
PhysicsServer2D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin);
- parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
parameters.exclude_bodies.insert(platform_rid);
if (platform_object_id.is_valid()) {
parameters.exclude_objects.insert(platform_object_id);
@@ -1203,7 +1192,6 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin);
- parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
Vector2 prev_position = parameters.from.columns[2];
@@ -1360,7 +1348,6 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) {
bool first_slide = true;
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin);
- parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
PhysicsServer2D::MotionResult result;
bool collided = move_and_collide(parameters, result, false, false);
@@ -1407,7 +1394,7 @@ void CharacterBody2D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_
real_t length = MAX(floor_snap_length, margin);
PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
- parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
+ parameters.recovery_as_collision = true; // Report margin recovery as collision to improve floor detection.
parameters.collide_separation_ray = true;
PhysicsServer2D::MotionResult result;
@@ -1443,7 +1430,7 @@ bool CharacterBody2D::_on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_f
real_t length = MAX(floor_snap_length, margin);
PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
- parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
+ parameters.recovery_as_collision = true; // Report margin recovery as collision to improve floor detection.
parameters.collide_separation_ray = true;
PhysicsServer2D::MotionResult result;
@@ -1557,7 +1544,7 @@ Ref<KinematicCollision2D> CharacterBody2D::_get_slide_collision(int p_bounce) {
}
// Create a new instance when the cached reference is invalid or still in use in script.
- if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->reference_get_count() > 1) {
+ if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->get_reference_count() > 1) {
slide_colliders.write[p_bounce].instantiate();
slide_colliders.write[p_bounce]->owner = this;
}
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index eaba9aadad..932ec1de16 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -47,11 +47,11 @@ protected:
Ref<KinematicCollision2D> motion_cache;
- Ref<KinematicCollision2D> _move(const Vector2 &p_distance, bool p_test_only = false, real_t p_margin = 0.08);
+ Ref<KinematicCollision2D> _move(const Vector2 &p_distance, bool p_test_only = false, real_t p_margin = 0.08, bool p_recovery_as_collision = false);
public:
bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true);
- bool test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08);
+ bool test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08, bool p_recovery_as_collision = false);
TypedArray<PhysicsBody2D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
@@ -309,7 +309,7 @@ public:
TypedArray<Node2D> get_colliding_bodies() const; //function for script
- virtual TypedArray<String> get_configuration_warnings() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
RigidBody2D();
~RigidBody2D();
diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp
index 6c4bfd58ce..f4343e4c03 100644
--- a/scene/2d/remote_transform_2d.cpp
+++ b/scene/2d/remote_transform_2d.cpp
@@ -183,8 +183,8 @@ void RemoteTransform2D::force_update_cache() {
_update_cache();
}
-TypedArray<String> RemoteTransform2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray RemoteTransform2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) {
warnings.push_back(RTR("Path property must point to a valid Node2D node to work."));
diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h
index bd352e1054..f98eec75c6 100644
--- a/scene/2d/remote_transform_2d.h
+++ b/scene/2d/remote_transform_2d.h
@@ -70,7 +70,7 @@ public:
void force_update_cache();
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
RemoteTransform2D();
};
diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp
index a25d5934ee..6222b0db14 100644
--- a/scene/2d/shape_cast_2d.cpp
+++ b/scene/2d/shape_cast_2d.cpp
@@ -391,8 +391,8 @@ Array ShapeCast2D::_get_collision_result() const {
return ret;
}
-TypedArray<String> ShapeCast2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node2D::get_configuration_warnings();
+PackedStringArray ShapeCast2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (shape.is_null()) {
warnings.push_back(RTR("This node cannot interact with other objects unless a Shape2D is assigned."));
diff --git a/scene/2d/shape_cast_2d.h b/scene/2d/shape_cast_2d.h
index 660e52f189..7b55566b01 100644
--- a/scene/2d/shape_cast_2d.h
+++ b/scene/2d/shape_cast_2d.h
@@ -117,7 +117,7 @@ public:
void remove_exception(const CollisionObject2D *p_node);
void clear_exceptions();
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
};
#endif // SHAPE_CAST_2D_H
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 8f0bf22617..b5759c54f7 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -434,8 +434,8 @@ int Bone2D::get_index_in_skeleton() const {
return skeleton_index;
}
-TypedArray<String> Bone2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray Bone2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!skeleton) {
if (parent_bone) {
warnings.push_back(RTR("This Bone2D chain should end at a Skeleton2D node."));
diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h
index 98fb867d99..580aed97ce 100644
--- a/scene/2d/skeleton_2d.h
+++ b/scene/2d/skeleton_2d.h
@@ -78,7 +78,7 @@ public:
void apply_rest();
Transform2D get_skeleton_rest() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
void set_default_length(real_t p_length);
real_t get_default_length() const;
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 5de6d547d7..577284a752 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1861,7 +1861,6 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
Ref<PackedScene> packed_scene = scenes_collection_source->get_scene_tile_scene(c.alternative_tile);
if (packed_scene.is_valid()) {
Node *scene = packed_scene->instantiate();
- add_child(scene);
Control *scene_as_control = Object::cast_to<Control>(scene);
Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene);
if (scene_as_control) {
@@ -1871,6 +1870,7 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
xform.set_origin(map_to_local(E_cell));
scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform());
}
+ add_child(scene);
q.scenes[E_cell] = scene->get_name();
}
}
@@ -3819,8 +3819,8 @@ void TileMap::draw_cells_outline(Control *p_control, RBSet<Vector2i> p_cells, Co
#undef DRAW_SIDE_IF_NEEDED
}
-TypedArray<String> TileMap::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray TileMap::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
// Retrieve the set of Z index values with a Y-sorted layer.
RBSet<int> y_sorted_z_index;
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index a819eeab71..b1a2118c6b 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -406,7 +406,7 @@ public:
GDVIRTUAL3(_tile_data_runtime_update, int, Vector2i, TileData *);
// Configuration warnings.
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
TileMap();
~TileMap();
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index b3ff6497a7..7b0a6c7e3e 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -100,8 +100,8 @@ void BoneAttachment3D::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-TypedArray<String> BoneAttachment3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node3D::get_configuration_warnings();
+PackedStringArray BoneAttachment3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
if (use_external_skeleton) {
if (external_skeleton_node_cache.is_null()) {
diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h
index f85053e614..2db6ba6268 100644
--- a/scene/3d/bone_attachment_3d.h
+++ b/scene/3d/bone_attachment_3d.h
@@ -76,7 +76,7 @@ protected:
#endif // TOOLS_ENABLED
public:
- virtual TypedArray<String> get_configuration_warnings() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
void set_bone_name(const String &p_name);
String get_bone_name() const;
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index f5e3e8b015..c3c1c8ba36 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -703,8 +703,8 @@ bool CollisionObject3D::get_capture_input_on_drag() const {
return capture_input_on_drag;
}
-TypedArray<String> CollisionObject3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray CollisionObject3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (shapes.is_empty()) {
warnings.push_back(RTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape."));
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index c638be9d90..1406e6c698 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -164,7 +164,7 @@ public:
_FORCE_INLINE_ RID get_rid() const { return rid; }
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
CollisionObject3D();
~CollisionObject3D();
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index 90099d787b..81b2c85de4 100644
--- a/scene/3d/collision_polygon_3d.cpp
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -167,8 +167,8 @@ void CollisionPolygon3D::set_margin(real_t p_margin) {
}
}
-TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray CollisionPolygon3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
warnings.push_back(RTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
diff --git a/scene/3d/collision_polygon_3d.h b/scene/3d/collision_polygon_3d.h
index 74e5867a2f..bbcea539b2 100644
--- a/scene/3d/collision_polygon_3d.h
+++ b/scene/3d/collision_polygon_3d.h
@@ -74,7 +74,7 @@ public:
real_t get_margin() const;
void set_margin(real_t p_margin);
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
CollisionPolygon3D();
};
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index a9bc28b464..7a0001bc6f 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -114,8 +114,8 @@ void CollisionShape3D::resource_changed(Ref<Resource> res) {
update_gizmos();
}
-TypedArray<String> CollisionShape3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray CollisionShape3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
warnings.push_back(RTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h
index 124c0d166d..70653daa19 100644
--- a/scene/3d/collision_shape_3d.h
+++ b/scene/3d/collision_shape_3d.h
@@ -62,7 +62,7 @@ public:
void set_disabled(bool p_disabled);
bool is_disabled() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
CollisionShape3D();
~CollisionShape3D();
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index d7bf76a6f6..ef373cf9ca 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -188,8 +188,8 @@ bool CPUParticles3D::get_fractional_delta() const {
return fractional_delta;
}
-TypedArray<String> CPUParticles3D::get_configuration_warnings() const {
- TypedArray<String> warnings = GeometryInstance3D::get_configuration_warnings();
+PackedStringArray CPUParticles3D::get_configuration_warnings() const {
+ PackedStringArray warnings = GeometryInstance3D::get_configuration_warnings();
bool mesh_found = false;
bool anim_material_found = false;
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index d84b0aedd2..26c702172b 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -302,7 +302,7 @@ public:
void set_gravity(const Vector3 &p_gravity);
Vector3 get_gravity() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
void restart();
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index 460402ad1d..fc442986a8 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -158,8 +158,8 @@ void Decal::_validate_property(PropertyInfo &p_property) const {
}
}
-TypedArray<String> Decal::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray Decal::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (textures[TEXTURE_ALBEDO].is_null() && textures[TEXTURE_NORMAL].is_null() && textures[TEXTURE_ORM].is_null() && textures[TEXTURE_EMISSION].is_null()) {
warnings.push_back(RTR("The decal has no textures loaded into any of its texture properties, and will therefore not be visible."));
diff --git a/scene/3d/decal.h b/scene/3d/decal.h
index 1a7d55b108..ab39350b75 100644
--- a/scene/3d/decal.h
+++ b/scene/3d/decal.h
@@ -65,7 +65,7 @@ protected:
void _validate_property(PropertyInfo &p_property) const;
public:
- virtual TypedArray<String> get_configuration_warnings() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp
index cfee7028d4..4606e70310 100644
--- a/scene/3d/fog_volume.cpp
+++ b/scene/3d/fog_volume.cpp
@@ -99,8 +99,8 @@ AABB FogVolume::get_aabb() const {
return AABB();
}
-TypedArray<String> FogVolume::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray FogVolume::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
Ref<Environment> environment = get_viewport()->find_world_3d()->get_environment();
diff --git a/scene/3d/fog_volume.h b/scene/3d/fog_volume.h
index fcdc1e2807..d79836be0e 100644
--- a/scene/3d/fog_volume.h
+++ b/scene/3d/fog_volume.h
@@ -62,7 +62,7 @@ public:
Ref<Material> get_material() const;
virtual AABB get_aabb() const override;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
FogVolume();
~FogVolume();
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index bd63939d74..dbbf196f7a 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -269,8 +269,8 @@ bool GPUParticles3D::get_interpolate() const {
return interpolate;
}
-TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
- TypedArray<String> warnings = GeometryInstance3D::get_configuration_warnings();
+PackedStringArray GPUParticles3D::get_configuration_warnings() const {
+ PackedStringArray warnings = GeometryInstance3D::get_configuration_warnings();
if (RenderingServer::get_singleton()->is_low_end()) {
warnings.push_back(RTR("GPU-based particles are not supported by the OpenGL video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose."));
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index 2ad9672474..ef92218e4d 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -147,7 +147,7 @@ public:
void set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh);
Ref<Mesh> get_draw_pass_mesh(int p_pass) const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
void set_sub_emitter(const NodePath &p_path);
NodePath get_sub_emitter() const;
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index 24bfa7b6de..d3f53d9c0d 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -503,8 +503,8 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() {
return ret;
}
-TypedArray<String> GPUParticlesCollisionSDF3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray GPUParticlesCollisionSDF3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (bake_mask == 0) {
warnings.push_back(RTR("The Bake Mask has no bits enabled, which means baking will not produce any collision for this GPUParticlesCollisionSDF3D.\nTo resolve this, enable at least one bit in the Bake Mask property."));
diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h
index 712bd015ff..548552bb70 100644
--- a/scene/3d/gpu_particles_collision_3d.h
+++ b/scene/3d/gpu_particles_collision_3d.h
@@ -162,7 +162,7 @@ protected:
static void _bind_methods();
public:
- virtual TypedArray<String> get_configuration_warnings() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
void set_thickness(float p_thickness);
float get_thickness() const;
diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp
index 7dc094062b..1a18f43e7b 100644
--- a/scene/3d/joint_3d.cpp
+++ b/scene/3d/joint_3d.cpp
@@ -198,8 +198,8 @@ bool Joint3D::get_exclude_nodes_from_collision() const {
return exclude_from_collision;
}
-TypedArray<String> Joint3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node3D::get_configuration_warnings();
+PackedStringArray Joint3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
if (!warning.is_empty()) {
warnings.push_back(warning);
diff --git a/scene/3d/joint_3d.h b/scene/3d/joint_3d.h
index cb967023e8..5af427446f 100644
--- a/scene/3d/joint_3d.h
+++ b/scene/3d/joint_3d.h
@@ -63,7 +63,7 @@ protected:
_FORCE_INLINE_ bool is_configured() const { return configured; }
public:
- virtual TypedArray<String> get_configuration_warnings() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
void set_node_a(const NodePath &p_node_a);
NodePath get_node_a() const;
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index e51f06e083..23fd091be6 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -578,8 +578,8 @@ OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const {
return shadow_mode;
}
-TypedArray<String> OmniLight3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray OmniLight3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!has_shadow() && get_projector().is_valid()) {
warnings.push_back(RTR("Projector texture only works with shadows active."));
@@ -608,8 +608,8 @@ OmniLight3D::OmniLight3D() :
set_param(PARAM_SHADOW_BIAS, 0.2);
}
-TypedArray<String> SpotLight3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray SpotLight3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) {
warnings.push_back(RTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows."));
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index e43d6f0419..8da45bee79 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -216,7 +216,7 @@ public:
void set_shadow_mode(ShadowMode p_mode);
ShadowMode get_shadow_mode() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
OmniLight3D();
};
@@ -230,7 +230,7 @@ protected:
static void _bind_methods();
public:
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
SpotLight3D() :
Light3D(RenderingServer::LIGHT_SPOT) {}
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index b0bccc4571..555884f445 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -1418,7 +1418,8 @@ float LightmapGI::get_bias() const {
}
void LightmapGI::set_max_texture_size(int p_size) {
- ERR_FAIL_COND(p_size < 2048);
+ ERR_FAIL_COND_MSG(p_size < 2048, vformat("The LightmapGI maximum texture size supplied (%d) is too small. The minimum allowed value is 2048.", p_size));
+ ERR_FAIL_COND_MSG(p_size > 16384, vformat("The LightmapGI maximum texture size supplied (%d) is too large. The maximum allowed value is 16384.", p_size));
max_texture_size = p_size;
}
@@ -1506,7 +1507,7 @@ void LightmapGI::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_denoiser"), "set_use_denoiser", "is_using_denoiser");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0.00001,0.1,0.00001,or_greater"), "set_bias", "get_bias");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "max_texture_size"), "set_max_texture_size", "get_max_texture_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_texture_size", PROPERTY_HINT_RANGE, "2048,16384,1"), "set_max_texture_size", "get_max_texture_size");
ADD_GROUP("Environment", "environment_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "environment_mode", PROPERTY_HINT_ENUM, "Disabled,Scene,Custom Sky,Custom Color"), "set_environment_mode", "get_environment_mode");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment_custom_sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_environment_custom_sky", "get_environment_custom_sky");
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index 0062a4a093..1d282e92c8 100644
--- a/scene/3d/lightmap_gi.h
+++ b/scene/3d/lightmap_gi.h
@@ -142,16 +142,16 @@ public:
private:
BakeQuality bake_quality = BAKE_QUALITY_MEDIUM;
bool use_denoiser = true;
- int bounces = 1;
+ int bounces = 3;
float bias = 0.0005;
int max_texture_size = 16384;
bool interior = false;
- EnvironmentMode environment_mode = ENVIRONMENT_MODE_DISABLED;
+ EnvironmentMode environment_mode = ENVIRONMENT_MODE_SCENE;
Ref<Sky> environment_custom_sky;
- Color environment_custom_color = Color(0.2, 0.7, 1.0);
+ Color environment_custom_color = Color(1, 1, 1);
float environment_custom_energy = 1.0;
bool directional = false;
- GenerateProbes gen_probes = GENERATE_PROBES_DISABLED;
+ GenerateProbes gen_probes = GENERATE_PROBES_SUBDIV_8;
Ref<CameraAttributes> camera_attributes;
Ref<LightmapGIData> light_data;
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 34e84861a2..3476ced6ee 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -383,8 +383,8 @@ void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) {
emit_signal(SNAME("velocity_computed"), p_new_velocity);
}
-TypedArray<String> NavigationAgent3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray NavigationAgent3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node3D>(get_parent())) {
warnings.push_back(RTR("The NavigationAgent3D can be used only under a Node3D inheriting parent node."));
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index 35c1b1175a..eed6457f4a 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -167,7 +167,7 @@ public:
void set_velocity(Vector3 p_velocity);
void _avoidance_done(Vector3 p_new_velocity);
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
private:
void update_navigation();
diff --git a/scene/3d/navigation_link_3d.cpp b/scene/3d/navigation_link_3d.cpp
index 47b602c966..78fe4754ea 100644
--- a/scene/3d/navigation_link_3d.cpp
+++ b/scene/3d/navigation_link_3d.cpp
@@ -378,8 +378,8 @@ void NavigationLink3D::set_travel_cost(real_t p_travel_cost) {
NavigationServer3D::get_singleton()->link_set_travel_cost(link, travel_cost);
}
-TypedArray<String> NavigationLink3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray NavigationLink3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (start_location.is_equal_approx(end_location)) {
warnings.push_back(RTR("NavigationLink3D start location should be different than the end location to be useful."));
diff --git a/scene/3d/navigation_link_3d.h b/scene/3d/navigation_link_3d.h
index 1f88075527..1fc03546fa 100644
--- a/scene/3d/navigation_link_3d.h
+++ b/scene/3d/navigation_link_3d.h
@@ -84,7 +84,7 @@ public:
void set_travel_cost(real_t p_travel_cost);
real_t get_travel_cost() const { return travel_cost; }
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
};
#endif // NAVIGATION_LINK_3D_H
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index 9b49238333..07d8cd9289 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -126,8 +126,8 @@ NavigationObstacle3D::~NavigationObstacle3D() {
agent = RID(); // Pointless
}
-TypedArray<String> NavigationObstacle3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray NavigationObstacle3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node3D>(get_parent())) {
warnings.push_back(RTR("The NavigationObstacle3D only serves to provide collision avoidance to a Node3D inheriting parent object."));
diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h
index 24caf50680..f242d2f99e 100644
--- a/scene/3d/navigation_obstacle_3d.h
+++ b/scene/3d/navigation_obstacle_3d.h
@@ -72,7 +72,7 @@ public:
return radius;
}
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
private:
void initialize_agent();
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 049ca4c8a0..b060d314ba 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -37,6 +37,7 @@ void NavigationRegion3D::set_enabled(bool p_enabled) {
if (enabled == p_enabled) {
return;
}
+
enabled = p_enabled;
if (!is_inside_tree()) {
@@ -81,35 +82,50 @@ bool NavigationRegion3D::is_enabled() const {
}
void NavigationRegion3D::set_navigation_layers(uint32_t p_navigation_layers) {
- NavigationServer3D::get_singleton()->region_set_navigation_layers(region, p_navigation_layers);
+ if (navigation_layers == p_navigation_layers) {
+ return;
+ }
+
+ navigation_layers = p_navigation_layers;
+
+ NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
}
uint32_t NavigationRegion3D::get_navigation_layers() const {
- return NavigationServer3D::get_singleton()->region_get_navigation_layers(region);
+ return navigation_layers;
}
void NavigationRegion3D::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 NavigationRegion3D::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 NavigationRegion3D::set_enter_cost(real_t p_enter_cost) {
ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
- enter_cost = MAX(p_enter_cost, 0.0);
- NavigationServer3D::get_singleton()->region_set_enter_cost(region, p_enter_cost);
+ if (Math::is_equal_approx(enter_cost, p_enter_cost)) {
+ return;
+ }
+
+ enter_cost = p_enter_cost;
+
+ NavigationServer3D::get_singleton()->region_set_enter_cost(region, enter_cost);
}
real_t NavigationRegion3D::get_enter_cost() const {
@@ -118,7 +134,12 @@ real_t NavigationRegion3D::get_enter_cost() const {
void NavigationRegion3D::set_travel_cost(real_t p_travel_cost) {
ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
- travel_cost = MAX(p_travel_cost, 0.0);
+ if (Math::is_equal_approx(travel_cost, p_travel_cost)) {
+ return;
+ }
+
+ travel_cost = p_travel_cost;
+
NavigationServer3D::get_singleton()->region_set_travel_cost(region, travel_cost);
}
@@ -130,8 +151,6 @@ RID NavigationRegion3D::get_region_rid() const {
return region;
}
-/////////////////////////////
-
void NavigationRegion3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -260,8 +279,8 @@ void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {
emit_signal(SNAME("bake_finished"));
}
-TypedArray<String> NavigationRegion3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray NavigationRegion3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (is_visible_in_tree() && is_inside_tree()) {
if (!navmesh.is_valid()) {
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index ba326abb46..660538d314 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -39,10 +39,10 @@ class NavigationRegion3D : public Node3D {
bool enabled = true;
RID region;
- Ref<NavigationMesh> navmesh;
-
+ uint32_t navigation_layers = 1;
real_t enter_cost = 0.0;
real_t travel_cost = 1.0;
+ Ref<NavigationMesh> navmesh;
Thread bake_thread;
@@ -90,7 +90,7 @@ public:
void bake_navigation_mesh(bool p_on_thread);
void _bake_finished(Ref<NavigationMesh> p_nav_mesh);
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
NavigationRegion3D();
~NavigationRegion3D();
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 59ec036558..ebf26996dd 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -1037,6 +1037,7 @@ void Node3D::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_ENTER_WORLD);
BIND_CONSTANT(NOTIFICATION_EXIT_WORLD);
BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
+ BIND_CONSTANT(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
BIND_ENUM_CONSTANT(ROTATION_EDIT_MODE_EULER);
BIND_ENUM_CONSTANT(ROTATION_EDIT_MODE_QUATERNION);
diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
index 015cb9a21d..4e1ed5654a 100644
--- a/scene/3d/occluder_instance_3d.cpp
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -682,8 +682,8 @@ OccluderInstance3D::BakeError OccluderInstance3D::bake_scene(Node *p_from_node,
return BAKE_ERROR_OK;
}
-TypedArray<String> OccluderInstance3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray OccluderInstance3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!bool(GLOBAL_GET("rendering/occlusion_culling/use_occlusion_culling"))) {
warnings.push_back(RTR("Occlusion culling is disabled in the Project Settings, which means occlusion culling won't be performed in the root viewport.\nTo resolve this, open the Project Settings and enable Rendering > Occlusion Culling > Use Occlusion Culling."));
diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h
index 69a80e63fc..f507fee024 100644
--- a/scene/3d/occluder_instance_3d.h
+++ b/scene/3d/occluder_instance_3d.h
@@ -181,7 +181,7 @@ protected:
static void _bind_methods();
public:
- virtual TypedArray<String> get_configuration_warnings() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
enum BakeError {
BAKE_ERROR_OK,
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 2d1f4a579b..123a044b84 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -341,8 +341,8 @@ void PathFollow3D::_validate_property(PropertyInfo &p_property) const {
}
}
-TypedArray<String> PathFollow3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray PathFollow3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (is_visible_in_tree() && is_inside_tree()) {
if (!Object::cast_to<Path3D>(get_parent())) {
diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h
index 45fa2c8917..b161b12185 100644
--- a/scene/3d/path_3d.h
+++ b/scene/3d/path_3d.h
@@ -112,7 +112,7 @@ public:
void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
PathFollow3D() {}
};
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 8888aa183a..594e94644c 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -34,8 +34,8 @@
#include "scene/scene_string_names.h"
void PhysicsBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(1));
- ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(false), DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(false), DEFVAL(1));
ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock);
ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock);
@@ -91,16 +91,16 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
}
-Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_distance, bool p_test_only, real_t p_margin, int p_max_collisions) {
+Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_distance, bool p_test_only, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) {
PhysicsServer3D::MotionParameters parameters(get_global_transform(), p_distance, p_margin);
parameters.max_collisions = p_max_collisions;
- parameters.recovery_as_collision = false; // Don't report collisions generated only from recovery.
+ parameters.recovery_as_collision = p_recovery_as_collision;
PhysicsServer3D::MotionResult result;
if (move_and_collide(parameters, result, p_test_only)) {
// Create a new instance when the cached reference is invalid or still in use in script.
- if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) {
+ if (motion_cache.is_null() || motion_cache->get_reference_count() > 1) {
motion_cache.instantiate();
motion_cache->owner = this;
}
@@ -169,7 +169,7 @@ bool PhysicsBody3D::move_and_collide(const PhysicsServer3D::MotionParameters &p_
return colliding;
}
-bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, int p_max_collisions) {
+bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer3D::MotionResult *r = nullptr;
@@ -182,7 +182,7 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_distan
}
PhysicsServer3D::MotionParameters parameters(p_from, p_distance, p_margin);
- parameters.recovery_as_collision = false; // Don't report collisions generated only from recovery.
+ parameters.recovery_as_collision = p_recovery_as_collision;
return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), parameters, r);
}
@@ -317,11 +317,6 @@ void AnimatableBody3D::_update_kinematic_motion() {
}
}
-void AnimatableBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
- AnimatableBody3D *body = (AnimatableBody3D *)p_instance;
- body->_body_state_changed(p_state);
-}
-
void AnimatableBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
linear_velocity = p_state->get_linear_velocity();
angular_velocity = p_state->get_angular_velocity();
@@ -373,7 +368,7 @@ void AnimatableBody3D::_bind_methods() {
AnimatableBody3D::AnimatableBody3D() :
StaticBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) {
- PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &AnimatableBody3D::_body_state_changed));
}
void RigidBody3D::_body_enter_tree(ObjectID p_id) {
@@ -488,11 +483,6 @@ struct _RigidBodyInOut {
int local_shape = 0;
};
-void RigidBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
- RigidBody3D *body = (RigidBody3D *)p_instance;
- body->_body_state_changed(p_state);
-}
-
void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
set_ignore_transform_notification(true);
set_global_transform(p_state->get_transform());
@@ -982,10 +972,10 @@ TypedArray<Node3D> RigidBody3D::get_colliding_bodies() const {
return ret;
}
-TypedArray<String> RigidBody3D::get_configuration_warnings() const {
+PackedStringArray RigidBody3D::get_configuration_warnings() const {
Transform3D t = get_transform();
- TypedArray<String> warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (ABS(t.basis.get_column(0).length() - 1.0) > 0.05 || ABS(t.basis.get_column(1).length() - 1.0) > 0.05 || ABS(t.basis.get_column(2).length() - 1.0) > 0.05) {
warnings.push_back(RTR("Size changes to RigidBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
@@ -1139,7 +1129,7 @@ void RigidBody3D::_validate_property(PropertyInfo &p_property) const {
RigidBody3D::RigidBody3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) {
- PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &RigidBody3D::_body_state_changed));
}
RigidBody3D::~RigidBody3D() {
@@ -1210,7 +1200,6 @@ bool CharacterBody3D::move_and_slide() {
if (!current_platform_velocity.is_zero_approx()) {
PhysicsServer3D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin);
- parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
parameters.exclude_bodies.insert(platform_rid);
if (platform_object_id.is_valid()) {
@@ -1274,8 +1263,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer3D::MotionParameters parameters(get_global_transform(), motion, margin);
- parameters.max_collisions = 4;
- parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
+ parameters.max_collisions = 6; // There can be 4 collisions between 2 walls + 2 more for the floor.
PhysicsServer3D::MotionResult result;
bool collided = move_and_collide(parameters, result, false, !sliding_enabled);
@@ -1520,7 +1508,6 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) {
bool first_slide = true;
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer3D::MotionParameters parameters(get_global_transform(), motion, margin);
- parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
PhysicsServer3D::MotionResult result;
bool collided = move_and_collide(parameters, result, false, false);
@@ -1575,7 +1562,7 @@ void CharacterBody3D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_
PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
parameters.max_collisions = 4;
- parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
+ parameters.recovery_as_collision = true; // Report margin recovery as collision to improve floor detection.
parameters.collide_separation_ray = true;
PhysicsServer3D::MotionResult result;
@@ -1611,7 +1598,7 @@ bool CharacterBody3D::_on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_f
PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
parameters.max_collisions = 4;
- parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
+ parameters.recovery_as_collision = true; // Report margin recovery as collision to improve floor detection.
parameters.collide_separation_ray = true;
PhysicsServer3D::MotionResult result;
@@ -1810,7 +1797,7 @@ Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) {
}
// Create a new instance when the cached reference is invalid or still in use in script.
- if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->reference_get_count() > 1) {
+ if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->get_reference_count() > 1) {
slide_colliders.write[p_bounce].instantiate();
slide_colliders.write[p_bounce]->owner = this;
}
@@ -2903,11 +2890,6 @@ void PhysicalBone3D::_notification(int p_what) {
}
}
-void PhysicalBone3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
- PhysicalBone3D *bone = (PhysicalBone3D *)p_instance;
- bone->_body_state_changed(p_state);
-}
-
void PhysicalBone3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
if (!simulate_physics || !_internal_simulate_physics) {
return;
@@ -3425,7 +3407,7 @@ void PhysicalBone3D::_start_physics_simulation() {
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority());
- PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &PhysicalBone3D::_body_state_changed));
set_as_top_level(true);
_internal_simulate_physics = true;
}
@@ -3446,7 +3428,7 @@ void PhysicalBone3D::_stop_physics_simulation() {
PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), 1.0);
}
if (_internal_simulate_physics) {
- PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr);
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), Callable());
parent_skeleton->set_bone_global_pose_override(bone_id, Transform3D(), 0.0, false);
set_as_top_level(false);
_internal_simulate_physics = false;
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 184d8b00d0..4b874b91d9 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -50,11 +50,11 @@ protected:
uint16_t locked_axis = 0;
- Ref<KinematicCollision3D> _move(const Vector3 &p_distance, bool p_test_only = false, real_t p_margin = 0.001, int p_max_collisions = 1);
+ Ref<KinematicCollision3D> _move(const Vector3 &p_distance, bool p_test_only = false, real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1);
public:
bool move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true);
- bool test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, int p_max_collisions = 1);
+ bool test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1);
void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
@@ -325,7 +325,7 @@ public:
void set_constant_torque(const Vector3 &p_torque);
Vector3 get_constant_torque() const;
- virtual TypedArray<String> get_configuration_warnings() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
RigidBody3D();
~RigidBody3D();
diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp
index 9979052385..ff05e88241 100644
--- a/scene/3d/remote_transform_3d.cpp
+++ b/scene/3d/remote_transform_3d.cpp
@@ -178,8 +178,8 @@ void RemoteTransform3D::force_update_cache() {
_update_cache();
}
-TypedArray<String> RemoteTransform3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray RemoteTransform3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) {
warnings.push_back(RTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work."));
diff --git a/scene/3d/remote_transform_3d.h b/scene/3d/remote_transform_3d.h
index ab134c1261..cc83661f26 100644
--- a/scene/3d/remote_transform_3d.h
+++ b/scene/3d/remote_transform_3d.h
@@ -70,7 +70,7 @@ public:
void force_update_cache();
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
RemoteTransform3D();
};
diff --git a/scene/3d/shape_cast_3d.cpp b/scene/3d/shape_cast_3d.cpp
index a2fecf9c31..e7d1a8ec7d 100644
--- a/scene/3d/shape_cast_3d.cpp
+++ b/scene/3d/shape_cast_3d.cpp
@@ -167,8 +167,8 @@ void ShapeCast3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_shape_custom_color"), "set_debug_shape_custom_color", "get_debug_shape_custom_color");
}
-TypedArray<String> ShapeCast3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node3D::get_configuration_warnings();
+PackedStringArray ShapeCast3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node3D::get_configuration_warnings();
if (shape.is_null()) {
warnings.push_back(RTR("This node cannot interact with other objects unless a Shape3D is assigned."));
diff --git a/scene/3d/shape_cast_3d.h b/scene/3d/shape_cast_3d.h
index 5bda15e4b0..2526d8d32c 100644
--- a/scene/3d/shape_cast_3d.h
+++ b/scene/3d/shape_cast_3d.h
@@ -136,7 +136,7 @@ public:
void remove_exception(const Object *p_object);
void clear_exceptions();
- virtual TypedArray<String> get_configuration_warnings() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
};
#endif // SHAPE_CAST_3D_H
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index e04e1866db..85b2c5154b 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -45,7 +45,6 @@ void SkinReference::_skin_changed() {
}
void SkinReference::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_skin_changed"), &SkinReference::_skin_changed);
ClassDB::bind_method(D_METHOD("get_skeleton"), &SkinReference::get_skeleton);
ClassDB::bind_method(D_METHOD("get_skin"), &SkinReference::get_skin);
}
@@ -1007,7 +1006,7 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
skin_bindings.insert(skin_ref.operator->());
- skin_ref->skin->connect("changed", Callable(skin_ref.operator->(), "_skin_changed"));
+ skin_ref->skin->connect("changed", callable_mp(skin_ref.operator->(), &SkinReference::_skin_changed));
_make_dirty(); // Skin needs to be updated, so update skeleton.
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 5e49dfa1f4..c2e9cfcced 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -51,12 +51,14 @@ class SkinReference : public RefCounted {
uint64_t skeleton_version = 0;
Vector<uint32_t> skin_bone_indices;
uint32_t *skin_bone_indices_ptrs = nullptr;
- void _skin_changed();
protected:
static void _bind_methods();
public:
+ // Public for use with callable_mp.
+ void _skin_changed();
+
RID get_skeleton() const;
Ref<Skin> get_skin() const;
~SkinReference();
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 47858b372c..2466b71aea 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -384,8 +384,8 @@ void SoftBody3D::_bind_methods() {
BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE);
}
-TypedArray<String> SoftBody3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray SoftBody3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (mesh.is_null()) {
warnings.push_back(RTR("This body will be ignored until you set a mesh."));
diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h
index 40f3d6f1f4..9ec1f18396 100644
--- a/scene/3d/soft_body_3d.h
+++ b/scene/3d/soft_body_3d.h
@@ -125,7 +125,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
public:
RID get_physics_rid() const { return physics_rid; }
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 7a89bf81bb..4b83bcdfc4 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -87,6 +87,182 @@ void SpriteBase3D::_notification(int p_what) {
}
}
+void SpriteBase3D::draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect, Rect2 p_src_rect) {
+ ERR_FAIL_COND(p_texture.is_null());
+
+ Rect2 final_rect;
+ Rect2 final_src_rect;
+ if (!p_texture->get_rect_region(p_dst_rect, p_src_rect, final_rect, final_src_rect)) {
+ return;
+ }
+
+ if (final_rect.size.x == 0 || final_rect.size.y == 0) {
+ return;
+ }
+
+ // 2D: 3D plane (axes match exactly when `axis == Vector3::AXIS_Z`):
+ // -X+ -X+
+ // - +
+ // Y +--------+ +--------+ +--------+ Y +--------+
+ // + | +--+ | | | (2) | | - | 0--1 |
+ // | |ab| | (1) | +--+ | (3) | 3--2 | | |ab| |
+ // | |cd| | --> | |ab| | --> | |cd| | <==> | |cd| |
+ // | +--+ | | |cd| | | |ab| | | 3--2 |
+ // | | | +--+ | | 0--1 | | |
+ // +--------+ +--------+ +--------+ +--------+
+
+ // (1) Y-wise shift `final_rect` within `p_dst_rect` so after inverting Y
+ // axis distances between top/bottom borders will be preserved (so for
+ // example AtlasTextures with vertical margins will look the same in 2D/3D).
+ final_rect.position.y = (p_dst_rect.position.y + p_dst_rect.size.y) - ((final_rect.position.y + final_rect.size.y) - p_dst_rect.position.y);
+
+ Color color = _get_color_accum();
+
+ real_t pixel_size = get_pixel_size();
+
+ // (2) Order vertices (0123) bottom-top in 2D / top-bottom in 3D.
+ Vector2 vertices[4] = {
+ (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
+ (final_rect.position + final_rect.size) * pixel_size,
+ (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
+ final_rect.position * pixel_size,
+ };
+
+ Vector2 src_tsize = p_texture->get_size();
+
+ // Properly setup UVs for impostor textures (AtlasTexture).
+ Ref<AtlasTexture> atlas_tex = p_texture;
+ if (atlas_tex != nullptr) {
+ src_tsize[0] = atlas_tex->get_atlas()->get_width();
+ src_tsize[1] = atlas_tex->get_atlas()->get_height();
+ }
+
+ // (3) Assign UVs (abcd) according to the vertices order (bottom-top in 2D / top-bottom in 3D).
+ Vector2 uvs[4] = {
+ final_src_rect.position / src_tsize,
+ (final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / src_tsize,
+ (final_src_rect.position + final_src_rect.size) / src_tsize,
+ (final_src_rect.position + Vector2(0, final_src_rect.size.y)) / src_tsize,
+ };
+
+ if (is_flipped_h()) {
+ SWAP(uvs[0], uvs[1]);
+ SWAP(uvs[2], uvs[3]);
+ }
+
+ if (is_flipped_v()) {
+ SWAP(uvs[0], uvs[3]);
+ SWAP(uvs[1], uvs[2]);
+ }
+
+ Vector3 normal;
+ int axis = get_axis();
+ normal[axis] = 1.0;
+
+ Plane tangent;
+ if (axis == Vector3::AXIS_X) {
+ tangent = Plane(0, 0, -1, 1);
+ } else {
+ tangent = Plane(1, 0, 0, 1);
+ }
+
+ int x_axis = ((axis + 1) % 3);
+ int y_axis = ((axis + 2) % 3);
+
+ if (axis != Vector3::AXIS_Z) {
+ SWAP(x_axis, y_axis);
+
+ for (int i = 0; i < 4; i++) {
+ //uvs[i] = Vector2(1.0,1.0)-uvs[i];
+ //SWAP(vertices[i].x,vertices[i].y);
+ if (axis == Vector3::AXIS_Y) {
+ vertices[i].y = -vertices[i].y;
+ } else if (axis == Vector3::AXIS_X) {
+ vertices[i].x = -vertices[i].x;
+ }
+ }
+ }
+
+ AABB aabb;
+
+ // Everything except position and UV is compressed.
+ uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
+ uint8_t *attribute_write_buffer = attribute_buffer.ptrw();
+
+ uint32_t v_normal;
+ {
+ Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
+
+ Vector2 res = n.octahedron_encode();
+ uint32_t value = 0;
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
+
+ v_normal = value;
+ }
+ uint32_t v_tangent;
+ {
+ Plane t = tangent;
+ Vector2 res = t.normal.octahedron_tangent_encode(t.d);
+ uint32_t value = 0;
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
+
+ v_tangent = value;
+ }
+
+ uint8_t v_color[4] = {
+ uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)),
+ uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)),
+ uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)),
+ uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0))
+ };
+
+ for (int i = 0; i < 4; i++) {
+ Vector3 vtx;
+ vtx[x_axis] = vertices[i][0];
+ vtx[y_axis] = vertices[i][1];
+ if (i == 0) {
+ aabb.position = vtx;
+ aabb.size = Vector3();
+ } else {
+ aabb.expand_to(vtx);
+ }
+
+ float v_uv[2] = { (float)uvs[i].x, (float)uvs[i].y };
+ memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8);
+
+ float v_vertex[3] = { (float)vtx.x, (float)vtx.y, (float)vtx.z };
+
+ memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3);
+ memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4);
+ memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4);
+ memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4);
+ }
+
+ RID mesh = get_mesh();
+ RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer);
+ RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer);
+
+ RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb);
+ set_aabb(aabb);
+
+ RID shader_rid;
+ StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), &shader_rid);
+ if (last_shader != shader_rid) {
+ RS::get_singleton()->material_set_shader(get_material(), shader_rid);
+ last_shader = shader_rid;
+ }
+ if (last_texture != p_texture->get_rid()) {
+ RS::get_singleton()->material_set_param(get_material(), "texture_albedo", p_texture->get_rid());
+ last_texture = p_texture->get_rid();
+ }
+ if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) {
+ RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority());
+ RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material());
+ }
+}
+
void SpriteBase3D::set_centered(bool p_center) {
centered = p_center;
_queue_redraw();
@@ -447,7 +623,7 @@ void Sprite3D::_draw() {
if (get_base() != get_mesh()) {
set_base(get_mesh());
}
- if (!texture.is_valid()) {
+ if (texture.is_null()) {
set_base(RID());
return;
}
@@ -464,171 +640,17 @@ void Sprite3D::_draw() {
}
Size2 frame_size = base_rect.size / Size2(hframes, vframes);
- Point2 frame_offset = Point2(frame % hframes, frame / hframes);
- frame_offset *= frame_size;
+ Point2 frame_offset = Point2(frame % hframes, frame / hframes) * frame_size;
- Point2 dest_offset = get_offset();
+ Point2 dst_offset = get_offset();
if (is_centered()) {
- dest_offset -= frame_size / 2;
+ dst_offset -= frame_size / 2.0f;
}
Rect2 src_rect(base_rect.position + frame_offset, frame_size);
- Rect2 final_dst_rect(dest_offset, frame_size);
- Rect2 final_rect;
- Rect2 final_src_rect;
- if (!texture->get_rect_region(final_dst_rect, src_rect, final_rect, final_src_rect)) {
- return;
- }
-
- if (final_rect.size.x == 0 || final_rect.size.y == 0) {
- return;
- }
-
- Color color = _get_color_accum();
-
- real_t pixel_size = get_pixel_size();
-
- Vector2 vertices[4] = {
-
- (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
- (final_rect.position + final_rect.size) * pixel_size,
- (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
- final_rect.position * pixel_size,
-
- };
-
- Vector2 src_tsize = tsize;
-
- // Properly setup UVs for impostor textures (AtlasTexture).
- Ref<AtlasTexture> atlas_tex = texture;
- if (atlas_tex != nullptr) {
- src_tsize[0] = atlas_tex->get_atlas()->get_width();
- src_tsize[1] = atlas_tex->get_atlas()->get_height();
- }
-
- Vector2 uvs[4] = {
- final_src_rect.position / src_tsize,
- (final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / src_tsize,
- (final_src_rect.position + final_src_rect.size) / src_tsize,
- (final_src_rect.position + Vector2(0, final_src_rect.size.y)) / src_tsize,
- };
-
- if (is_flipped_h()) {
- SWAP(uvs[0], uvs[1]);
- SWAP(uvs[2], uvs[3]);
- }
-
- if (is_flipped_v()) {
- SWAP(uvs[0], uvs[3]);
- SWAP(uvs[1], uvs[2]);
- }
-
- Vector3 normal;
- int axis = get_axis();
- normal[axis] = 1.0;
-
- Plane tangent;
- if (axis == Vector3::AXIS_X) {
- tangent = Plane(0, 0, -1, 1);
- } else {
- tangent = Plane(1, 0, 0, 1);
- }
-
- int x_axis = ((axis + 1) % 3);
- int y_axis = ((axis + 2) % 3);
-
- if (axis != Vector3::AXIS_Z) {
- SWAP(x_axis, y_axis);
-
- for (int i = 0; i < 4; i++) {
- //uvs[i] = Vector2(1.0,1.0)-uvs[i];
- //SWAP(vertices[i].x,vertices[i].y);
- if (axis == Vector3::AXIS_Y) {
- vertices[i].y = -vertices[i].y;
- } else if (axis == Vector3::AXIS_X) {
- vertices[i].x = -vertices[i].x;
- }
- }
- }
-
- AABB aabb;
-
- // Everything except position and UV is compressed.
- uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
- uint8_t *attribute_write_buffer = attribute_buffer.ptrw();
+ Rect2 dst_rect(dst_offset, frame_size);
- uint32_t v_normal;
- {
- Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
- Vector2 res = n.octahedron_encode();
- uint32_t value = 0;
- value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
- value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
-
- v_normal = value;
- }
- uint32_t v_tangent;
- {
- Plane t = tangent;
- Vector2 res = t.normal.octahedron_tangent_encode(t.d);
- uint32_t value = 0;
- value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
- value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
-
- v_tangent = value;
- }
-
- uint8_t v_color[4] = {
- uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)),
- uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)),
- uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)),
- uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0))
- };
-
- for (int i = 0; i < 4; i++) {
- Vector3 vtx;
- vtx[x_axis] = vertices[i][0];
- vtx[y_axis] = vertices[i][1];
- if (i == 0) {
- aabb.position = vtx;
- aabb.size = Vector3();
- } else {
- aabb.expand_to(vtx);
- }
-
- float v_uv[2] = { (float)uvs[i].x, (float)uvs[i].y };
- memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8);
-
- float v_vertex[3] = { (float)vtx.x, (float)vtx.y, (float)vtx.z };
-
- memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3);
- memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4);
- memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4);
- memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4);
- }
-
- RID mesh = get_mesh();
- RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer);
- RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer);
-
- RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb);
- set_aabb(aabb);
-
- RID shader_rid;
- StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), &shader_rid);
- if (last_shader != shader_rid) {
- RS::get_singleton()->material_set_shader(get_material(), shader_rid);
- last_shader = shader_rid;
- }
- if (last_texture != texture->get_rid()) {
- RS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid());
- last_texture = texture->get_rid();
- }
- if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) {
- RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority());
- RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material());
- }
+ draw_texture_rect(texture, dst_rect, src_rect);
}
void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) {
@@ -807,15 +829,7 @@ void AnimatedSprite3D::_draw() {
set_base(get_mesh());
}
- if (frames.is_null()) {
- return;
- }
-
- if (frame < 0) {
- return;
- }
-
- if (!frames->has_animation(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
@@ -839,158 +853,7 @@ void AnimatedSprite3D::_draw() {
Rect2 dst_rect(ofs, tsize);
- Rect2 final_rect;
- Rect2 final_src_rect;
- if (!texture->get_rect_region(dst_rect, src_rect, final_rect, final_src_rect)) {
- return;
- }
-
- if (final_rect.size.x == 0 || final_rect.size.y == 0) {
- return;
- }
-
- Color color = _get_color_accum();
-
- real_t pixel_size = get_pixel_size();
-
- Vector2 vertices[4] = {
-
- (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
- (final_rect.position + final_rect.size) * pixel_size,
- (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
- final_rect.position * pixel_size,
-
- };
-
- Vector2 src_tsize = tsize;
-
- // Properly setup UVs for impostor textures (AtlasTexture).
- Ref<AtlasTexture> atlas_tex = texture;
- if (atlas_tex != nullptr) {
- src_tsize[0] = atlas_tex->get_atlas()->get_width();
- src_tsize[1] = atlas_tex->get_atlas()->get_height();
- }
-
- Vector2 uvs[4] = {
- final_src_rect.position / src_tsize,
- (final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / src_tsize,
- (final_src_rect.position + final_src_rect.size) / src_tsize,
- (final_src_rect.position + Vector2(0, final_src_rect.size.y)) / src_tsize,
- };
-
- if (is_flipped_h()) {
- SWAP(uvs[0], uvs[1]);
- SWAP(uvs[2], uvs[3]);
- }
- if (is_flipped_v()) {
- SWAP(uvs[0], uvs[3]);
- SWAP(uvs[1], uvs[2]);
- }
-
- Vector3 normal;
- int axis = get_axis();
- normal[axis] = 1.0;
-
- Plane tangent;
- if (axis == Vector3::AXIS_X) {
- tangent = Plane(0, 0, -1, -1);
- } else {
- tangent = Plane(1, 0, 0, -1);
- }
-
- int x_axis = ((axis + 1) % 3);
- int y_axis = ((axis + 2) % 3);
-
- if (axis != Vector3::AXIS_Z) {
- SWAP(x_axis, y_axis);
-
- for (int i = 0; i < 4; i++) {
- //uvs[i] = Vector2(1.0,1.0)-uvs[i];
- //SWAP(vertices[i].x,vertices[i].y);
- if (axis == Vector3::AXIS_Y) {
- vertices[i].y = -vertices[i].y;
- } else if (axis == Vector3::AXIS_X) {
- vertices[i].x = -vertices[i].x;
- }
- }
- }
-
- AABB aabb;
-
- // Everything except position and UV is compressed.
- uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
- uint8_t *attribute_write_buffer = attribute_buffer.ptrw();
-
- uint32_t v_normal;
- {
- Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
- Vector2 res = n.octahedron_encode();
- uint32_t value = 0;
- value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
- value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
-
- v_normal = value;
- }
- uint32_t v_tangent;
- {
- Plane t = tangent;
- Vector2 res = t.normal.octahedron_tangent_encode(t.d);
- uint32_t value = 0;
- value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
- value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
- v_tangent = value;
- }
-
- uint8_t v_color[4] = {
- uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)),
- uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)),
- uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)),
- uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0))
- };
-
- for (int i = 0; i < 4; i++) {
- Vector3 vtx;
- vtx[x_axis] = vertices[i][0];
- vtx[y_axis] = vertices[i][1];
- if (i == 0) {
- aabb.position = vtx;
- aabb.size = Vector3();
- } else {
- aabb.expand_to(vtx);
- }
-
- float v_uv[2] = { (float)uvs[i].x, (float)uvs[i].y };
- memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8);
-
- float v_vertex[3] = { (float)vtx.x, (float)vtx.y, (float)vtx.z };
- memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3);
- memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4);
- memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4);
- memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4);
- }
-
- RID mesh = get_mesh();
- RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer);
- RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer);
-
- RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb);
- set_aabb(aabb);
-
- RID shader_rid;
- StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), &shader_rid);
- if (last_shader != shader_rid) {
- RS::get_singleton()->material_set_shader(get_material(), shader_rid);
- last_shader = shader_rid;
- }
- if (last_texture != texture->get_rid()) {
- RS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid());
- last_texture = texture->get_rid();
- }
- if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) {
- RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority());
- RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material());
- }
+ draw_texture_rect(texture, dst_rect, src_rect);
}
void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const {
@@ -1050,29 +913,22 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const {
void AnimatedSprite3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
- if (frames.is_null()) {
- return;
- }
- if (!frames->has_animation(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
- if (frame < 0) {
- return;
+
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
+ if (speed == 0) {
+ return; // Do nothing.
}
+ int last_frame = frames->get_frame_count(animation) - 1;
double remaining = get_process_delta_time();
-
while (remaining) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
- if (speed == 0) {
- return; // Do nothing.
- }
-
if (timeout <= 0) {
timeout = _get_frame_duration();
- int last_frame = frames->get_frame_count(animation) - 1;
- if (!backwards) {
+ if (!playing_backwards) {
// Forward.
if (frame >= last_frame) {
if (frames->get_animation_loop(animation)) {
@@ -1177,9 +1033,14 @@ int AnimatedSprite3D::get_frame() const {
}
void AnimatedSprite3D::set_speed_scale(double p_speed_scale) {
+ if (speed_scale == p_speed_scale) {
+ return;
+ }
+
double elapsed = _get_frame_duration() - timeout;
- speed_scale = MAX(p_speed_scale, 0.0f);
+ speed_scale = p_speed_scale;
+ playing_backwards = signbit(speed_scale) != backwards;
// We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed.
_reset_timeout();
@@ -1191,7 +1052,10 @@ double AnimatedSprite3D::get_speed_scale() const {
}
Rect2 AnimatedSprite3D::get_item_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
+ return Rect2(0, 0, 1, 1);
+ }
+ if (frame < 0 || frame >= frames->get_frame_count(animation)) {
return Rect2(0, 0, 1, 1);
}
@@ -1236,12 +1100,13 @@ bool AnimatedSprite3D::is_playing() const {
return playing;
}
-void AnimatedSprite3D::play(const StringName &p_animation, const bool p_backwards) {
+void AnimatedSprite3D::play(const StringName &p_animation, bool p_backwards) {
backwards = p_backwards;
+ playing_backwards = signbit(speed_scale) != backwards;
if (p_animation) {
set_animation(p_animation);
- if (frames.is_valid() && backwards && get_frame() == 0) {
+ if (frames.is_valid() && playing_backwards && get_frame() == 0) {
set_frame(frames->get_frame_count(p_animation) - 1);
}
}
@@ -1256,7 +1121,7 @@ void AnimatedSprite3D::stop() {
double AnimatedSprite3D::_get_frame_duration() {
if (frames.is_valid() && frames->has_animation(animation)) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
if (speed > 0) {
return 1.0 / speed;
}
@@ -1291,8 +1156,8 @@ StringName AnimatedSprite3D::get_animation() const {
return animation;
}
-TypedArray<String> AnimatedSprite3D::get_configuration_warnings() const {
- TypedArray<String> warnings = SpriteBase3D::get_configuration_warnings();
+PackedStringArray AnimatedSprite3D::get_configuration_warnings() const {
+ PackedStringArray warnings = SpriteBase3D::get_configuration_warnings();
if (frames.is_null()) {
warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames."));
}
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index e6a546a76d..edc48c7b71 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -80,6 +80,9 @@ private:
RID mesh;
RID material;
+ RID last_shader;
+ RID last_texture;
+
bool flags[FLAG_MAX] = {};
AlphaCutMode alpha_cut = ALPHA_CUT_DISABLED;
StandardMaterial3D::BillboardMode billboard_mode = StandardMaterial3D::BILLBOARD_DISABLED;
@@ -94,6 +97,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
virtual void _draw() = 0;
+ void draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect, Rect2 p_src_rect);
_FORCE_INLINE_ void set_aabb(const AABB &p_aabb) { aabb = p_aabb; }
_FORCE_INLINE_ RID &get_mesh() { return mesh; }
_FORCE_INLINE_ RID &get_material() { return material; }
@@ -167,9 +171,6 @@ class Sprite3D : public SpriteBase3D {
int vframes = 1;
int hframes = 1;
- RID last_shader;
- RID last_texture;
-
protected:
virtual void _draw() override;
static void _bind_methods();
@@ -209,6 +210,7 @@ class AnimatedSprite3D : public SpriteBase3D {
Ref<SpriteFrames> frames;
bool playing = false;
+ bool playing_backwards = false;
bool backwards = false;
StringName animation = "default";
int frame = 0;
@@ -224,9 +226,6 @@ class AnimatedSprite3D : public SpriteBase3D {
double _get_frame_duration();
void _reset_timeout();
- RID last_shader;
- RID last_texture;
-
protected:
virtual void _draw() override;
static void _bind_methods();
@@ -237,7 +236,7 @@ public:
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
Ref<SpriteFrames> get_sprite_frames() const;
- void play(const StringName &p_animation = StringName(), const bool p_backwards = false);
+ void play(const StringName &p_animation = StringName(), bool p_backwards = false);
void stop();
void set_playing(bool p_playing);
@@ -254,7 +253,7 @@ public:
virtual Rect2 get_item_rect() const override;
- virtual TypedArray<String> get_configuration_warnings() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
AnimatedSprite3D();
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index d61b49eaa7..36b5e61f45 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -105,8 +105,8 @@ void VehicleWheel3D::_notification(int p_what) {
}
}
-TypedArray<String> VehicleWheel3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray VehicleWheel3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!Object::cast_to<VehicleBody3D>(get_parent())) {
warnings.push_back(RTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D."));
diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h
index 5c4f4beaea..a6a49ee88a 100644
--- a/scene/3d/vehicle_body_3d.h
+++ b/scene/3d/vehicle_body_3d.h
@@ -147,7 +147,7 @@ public:
void set_steering(real_t p_steering);
real_t get_steering() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
VehicleWheel3D();
};
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index db9f68544b..e93ad5ecbf 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -385,8 +385,8 @@ bool GeometryInstance3D::is_ignoring_occlusion_culling() {
return ignore_occlusion_culling;
}
-TypedArray<String> GeometryInstance3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray GeometryInstance3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!Math::is_zero_approx(visibility_range_end) && visibility_range_end <= visibility_range_begin) {
warnings.push_back(RTR("The GeometryInstance3D visibility range's End distance is set to a non-zero value, but is lower than the Begin distance.\nThis means the GeometryInstance3D will never be visible.\nTo resolve this, set the End distance to 0 or to a value greater than the Begin distance."));
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 100d8d8836..4755545516 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -186,7 +186,7 @@ public:
void set_ignore_occlusion_culling(bool p_enabled);
bool is_ignoring_occlusion_culling();
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
GeometryInstance3D();
virtual ~GeometryInstance3D();
};
diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp
index c97af087bf..1b1ac32207 100644
--- a/scene/3d/voxel_gi.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -468,8 +468,8 @@ AABB VoxelGI::get_aabb() const {
return AABB(-extents, extents * 2);
}
-TypedArray<String> VoxelGI::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray VoxelGI::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (RenderingServer::get_singleton()->is_low_end()) {
warnings.push_back(RTR("VoxelGIs are not supported by the OpenGL video driver.\nUse a LightmapGI instead."));
diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h
index b31ae4cd95..fc10091d4f 100644
--- a/scene/3d/voxel_gi.h
+++ b/scene/3d/voxel_gi.h
@@ -157,7 +157,7 @@ public:
virtual AABB get_aabb() const override;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
VoxelGI();
~VoxelGI();
diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp
index ae7d79e8b0..6cc5e9ef20 100644
--- a/scene/3d/world_environment.cpp
+++ b/scene/3d/world_environment.cpp
@@ -135,8 +135,8 @@ Ref<CameraAttributes> WorldEnvironment::get_camera_attributes() const {
return camera_attributes;
}
-TypedArray<String> WorldEnvironment::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray WorldEnvironment::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!environment.is_valid() && !camera_attributes.is_valid()) {
warnings.push_back(RTR("To have any visible effect, WorldEnvironment requires its \"Environment\" property to contain an Environment, its \"Camera Attributes\" property to contain a CameraAttributes resource, or both."));
diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h
index 07f243c750..cc46a06b4c 100644
--- a/scene/3d/world_environment.h
+++ b/scene/3d/world_environment.h
@@ -55,7 +55,7 @@ public:
void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes);
Ref<CameraAttributes> get_camera_attributes() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
WorldEnvironment();
};
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index de765d7ccb..4401d22f30 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -88,8 +88,8 @@ void XRCamera3D::_pose_changed(const Ref<XRPose> &p_pose) {
}
}
-TypedArray<String> XRCamera3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray XRCamera3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (is_visible() && is_inside_tree()) {
// must be child node of XROrigin3D!
@@ -414,8 +414,8 @@ XRNode3D::~XRNode3D() {
xr_server->disconnect("tracker_removed", callable_mp(this, &XRNode3D::_removed_tracker));
}
-TypedArray<String> XRNode3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray XRNode3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (is_visible() && is_inside_tree()) {
// must be child node of XROrigin!
@@ -582,8 +582,8 @@ Plane XRAnchor3D::get_plane() const {
////////////////////////////////////////////////////////////////////////////////////////////////////
-TypedArray<String> XROrigin3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray XROrigin3D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (is_visible() && is_inside_tree()) {
if (tracked_camera == nullptr) {
diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h
index 312bef7856..ef846cc3a3 100644
--- a/scene/3d/xr_nodes.h
+++ b/scene/3d/xr_nodes.h
@@ -55,7 +55,7 @@ protected:
void _pose_changed(const Ref<XRPose> &p_pose);
public:
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const override;
virtual Point2 unproject_position(const Vector3 &p_pos) const override;
@@ -107,7 +107,7 @@ public:
Ref<XRPose> get_pose();
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
XRNode3D();
~XRNode3D();
@@ -187,7 +187,7 @@ protected:
static void _bind_methods();
public:
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
void set_tracked_camera(XRCamera3D *p_tracked_camera);
XRCamera3D *get_tracked_camera() const;
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 99f17a1eef..1efbaacb3b 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -1175,6 +1175,7 @@ void AnimationNodeBlendTree::_tree_changed() {
void AnimationNodeBlendTree::_node_changed(const StringName &p_node) {
ERR_FAIL_COND(!nodes.has(p_node));
nodes[p_node].connections.resize(nodes[p_node].node->get_input_count());
+ emit_signal(SNAME("node_changed"), p_node);
}
void AnimationNodeBlendTree::_bind_methods() {
@@ -1200,6 +1201,8 @@ void AnimationNodeBlendTree::_bind_methods() {
BIND_CONSTANT(CONNECTION_ERROR_NO_OUTPUT);
BIND_CONSTANT(CONNECTION_ERROR_SAME_NODE);
BIND_CONSTANT(CONNECTION_ERROR_CONNECTION_EXISTS);
+
+ ADD_SIGNAL(MethodInfo("node_changed", PropertyInfo(Variant::STRING_NAME, "node_name")));
}
void AnimationNodeBlendTree::_initialize_node_tree() {
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 096f4edee2..ce9406883d 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -650,15 +650,14 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
double c = Math::ease(p_time / first_key_time, transition);
Variant first_value = a->track_get_key_value(i, first_key);
first_value = _post_process_key_value(a, i, first_value, nc->node);
- Variant interp_value;
- Variant::interpolate(pa->capture, first_value, c, interp_value);
+ Variant interp_value = Animation::interpolate_variant(pa->capture, first_value, c);
if (pa->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_prop_size >= NODE_CACHE_UPDATE_MAX);
cache_update_prop[cache_update_prop_size++] = pa;
pa->value_accum = interp_value;
pa->accum_pass = accum_pass;
} else {
- Variant::interpolate(pa->value_accum, interp_value, p_interp, pa->value_accum);
+ pa->value_accum = Animation::interpolate_variant(pa->value_accum, interp_value, p_interp);
}
continue; //handled
@@ -679,7 +678,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
pa->value_accum = value;
pa->accum_pass = accum_pass;
} else {
- Variant::interpolate(pa->value_accum, value, p_interp, pa->value_accum);
+ pa->value_accum = Animation::interpolate_variant(pa->value_accum, value, p_interp);
}
} else if (p_is_current && p_delta != 0) {
@@ -1270,6 +1269,8 @@ void AnimationPlayer::_animation_set_cache_update() {
// If something was modified or removed, caches need to be cleared
clear_caches();
}
+
+ emit_signal(SNAME("animation_list_changed"));
}
void AnimationPlayer::_animation_added(const StringName &p_name, const StringName &p_library) {
@@ -2150,6 +2151,7 @@ void AnimationPlayer::_bind_methods() {
ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING_NAME, "anim_name")));
ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING_NAME, "old_name"), PropertyInfo(Variant::STRING_NAME, "new_name")));
ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING_NAME, "anim_name")));
+ ADD_SIGNAL(MethodInfo("animation_list_changed"));
ADD_SIGNAL(MethodInfo("caches_cleared"));
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index d06324f0aa..bcd52082af 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -847,6 +847,11 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
return true;
}
+void AnimationTree::_animation_player_changed() {
+ emit_signal(SNAME("animation_player_changed"));
+ _clear_caches();
+}
+
void AnimationTree::_clear_caches() {
for (KeyValue<NodePath, TrackCache *> &K : track_cache) {
memdelete(K.value);
@@ -1378,8 +1383,13 @@ void AnimationTree::_process_graph(double p_delta) {
}
t->value = Math::fposmod(rot_a + (rot_b - rot_init) * (float)blend, (float)Math_TAU);
} else {
- Variant::sub(value, t->init_value, value);
- Variant::blend(t->value, value, blend, t->value);
+ if (t->init_value.get_type() == Variant::BOOL) {
+ value = Animation::subtract_variant(value.operator real_t(), t->init_value.operator real_t());
+ t->value = Animation::blend_variant(t->value.operator real_t(), value.operator real_t(), blend);
+ } else {
+ value = Animation::subtract_variant(value, t->init_value);
+ t->value = Animation::blend_variant(t->value, value, blend);
+ }
}
} else {
if (blend < CMP_EPSILON) {
@@ -1698,7 +1708,11 @@ void AnimationTree::_process_graph(double p_delta) {
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
- t->object->set_indexed(t->subpath, t->value);
+ if (t->init_value.get_type() == Variant::BOOL) {
+ t->object->set_indexed(t->subpath, t->value.operator real_t() >= 0.5);
+ } else {
+ t->object->set_indexed(t->subpath, t->value);
+ }
} break;
case Animation::TYPE_BEZIER: {
@@ -1738,6 +1752,7 @@ void AnimationTree::advance(real_t p_time) {
void AnimationTree::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
+ _setup_animation_player();
if (last_animation_player.is_valid()) {
Object *player = ObjectDB::get_instance(last_animation_player);
if (player) {
@@ -1770,8 +1785,43 @@ void AnimationTree::_notification(int p_what) {
}
}
+void AnimationTree::_setup_animation_player() {
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ AnimationPlayer *new_player = nullptr;
+ if (!animation_player.is_empty()) {
+ new_player = Object::cast_to<AnimationPlayer>(get_node(animation_player));
+ if (new_player && !new_player->is_connected("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed))) {
+ new_player->connect("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed));
+ }
+ }
+
+ if (new_player) {
+ if (!last_animation_player.is_valid()) {
+ // Animation player set newly.
+ emit_signal(SNAME("animation_player_changed"));
+ return;
+ } else if (last_animation_player == new_player->get_instance_id()) {
+ // Animation player isn't changed.
+ return;
+ }
+ } else if (!last_animation_player.is_valid()) {
+ // Animation player is being empty.
+ return;
+ }
+
+ AnimationPlayer *old_player = Object::cast_to<AnimationPlayer>(ObjectDB::get_instance(last_animation_player));
+ if (old_player && old_player->is_connected("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed))) {
+ old_player->disconnect("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed));
+ }
+ emit_signal(SNAME("animation_player_changed"));
+}
+
void AnimationTree::set_animation_player(const NodePath &p_player) {
animation_player = p_player;
+ _setup_animation_player();
update_configuration_warnings();
}
@@ -1799,8 +1849,8 @@ uint64_t AnimationTree::get_last_process_pass() const {
return process_pass;
}
-TypedArray<String> AnimationTree::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray AnimationTree::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!root.is_valid()) {
warnings.push_back(RTR("No root AnimationNode for the graph is set."));
@@ -2008,6 +2058,8 @@ void AnimationTree::_bind_methods() {
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS);
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE);
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL);
+
+ ADD_SIGNAL(MethodInfo("animation_player_changed"));
}
AnimationTree::AnimationTree() {
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index ee0c0303dc..fc31c52bc6 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -282,6 +282,8 @@ private:
bool cache_valid = false;
void _node_removed(Node *p_node);
+ void _setup_animation_player();
+ void _animation_player_changed();
void _clear_caches();
bool _update_caches(AnimationPlayer *player);
void _process_graph(double p_delta);
@@ -340,7 +342,7 @@ public:
void set_advance_expression_base_node(const NodePath &p_advance_expression_base_node);
NodePath get_advance_expression_base_node() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
bool is_state_invalid() const;
String get_invalid_state_reason() const;
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 5b18d4e457..b02f1959b7 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -32,6 +32,7 @@
#include "scene/animation/easing_equations.h"
#include "scene/main/node.h"
+#include "scene/resources/animation.h"
Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = {
{ &linear::in, &linear::in, &linear::in, &linear::in }, // Linear is the same for each easing.
@@ -314,6 +315,7 @@ bool Tween::step(float p_delta) {
running = false;
dead = true;
emit_signal(SNAME("finished"));
+ break;
} else {
emit_signal(SNAME("loop_finished"), loops_done);
current_step = 0;
@@ -375,264 +377,14 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, f
ERR_FAIL_INDEX_V(p_trans, TransitionType::TRANS_MAX, Variant());
ERR_FAIL_INDEX_V(p_ease, EaseType::EASE_MAX, Variant());
-// Helper macro to run equation on sub-elements of the value (e.g. x and y of Vector2).
-#define APPLY_EQUATION(element) \
- r.element = run_equation(p_trans, p_ease, p_time, i.element, d.element, p_duration);
-
- switch (p_initial_val.get_type()) {
- case Variant::BOOL: {
- return (run_equation(p_trans, p_ease, p_time, p_initial_val, p_delta_val, p_duration)) >= 0.5;
- }
-
- case Variant::INT: {
- return (int)run_equation(p_trans, p_ease, p_time, (int)p_initial_val, (int)p_delta_val, p_duration);
- }
-
- case Variant::FLOAT: {
- return run_equation(p_trans, p_ease, p_time, (real_t)p_initial_val, (real_t)p_delta_val, p_duration);
- }
-
- case Variant::VECTOR2: {
- Vector2 i = p_initial_val;
- Vector2 d = p_delta_val;
- Vector2 r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- return r;
- }
-
- case Variant::VECTOR2I: {
- Vector2i i = p_initial_val;
- Vector2i d = p_delta_val;
- Vector2i r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- return r;
- }
-
- case Variant::RECT2: {
- Rect2 i = p_initial_val;
- Rect2 d = p_delta_val;
- Rect2 r;
-
- APPLY_EQUATION(position.x);
- APPLY_EQUATION(position.y);
- APPLY_EQUATION(size.x);
- APPLY_EQUATION(size.y);
- return r;
- }
-
- case Variant::RECT2I: {
- Rect2i i = p_initial_val;
- Rect2i d = p_delta_val;
- Rect2i r;
-
- APPLY_EQUATION(position.x);
- APPLY_EQUATION(position.y);
- APPLY_EQUATION(size.x);
- APPLY_EQUATION(size.y);
- return r;
- }
-
- case Variant::VECTOR3: {
- Vector3 i = p_initial_val;
- Vector3 d = p_delta_val;
- Vector3 r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- APPLY_EQUATION(z);
- return r;
- }
-
- case Variant::VECTOR3I: {
- Vector3i i = p_initial_val;
- Vector3i d = p_delta_val;
- Vector3i r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- APPLY_EQUATION(z);
- return r;
- }
-
- case Variant::TRANSFORM2D: {
- Transform2D i = p_initial_val;
- Transform2D d = p_delta_val;
- Transform2D r;
-
- APPLY_EQUATION(columns[0][0]);
- APPLY_EQUATION(columns[0][1]);
- APPLY_EQUATION(columns[1][0]);
- APPLY_EQUATION(columns[1][1]);
- APPLY_EQUATION(columns[2][0]);
- APPLY_EQUATION(columns[2][1]);
- return r;
- }
- case Variant::VECTOR4: {
- Vector4 i = p_initial_val;
- Vector4 d = p_delta_val;
- Vector4 r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- APPLY_EQUATION(z);
- APPLY_EQUATION(w);
- return r;
- }
-
- case Variant::QUATERNION: {
- Quaternion i = p_initial_val;
- Quaternion d = p_delta_val;
- Quaternion r = i * d;
- r = i.slerp(r, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration));
- return r;
- }
-
- case Variant::AABB: {
- AABB i = p_initial_val;
- AABB d = p_delta_val;
- AABB r;
-
- APPLY_EQUATION(position.x);
- APPLY_EQUATION(position.y);
- APPLY_EQUATION(position.z);
- APPLY_EQUATION(size.x);
- APPLY_EQUATION(size.y);
- APPLY_EQUATION(size.z);
- return r;
- }
-
- case Variant::BASIS: {
- Basis i = p_initial_val;
- Basis d = p_delta_val;
- Basis r;
-
- APPLY_EQUATION(rows[0][0]);
- APPLY_EQUATION(rows[0][1]);
- APPLY_EQUATION(rows[0][2]);
- APPLY_EQUATION(rows[1][0]);
- APPLY_EQUATION(rows[1][1]);
- APPLY_EQUATION(rows[1][2]);
- APPLY_EQUATION(rows[2][0]);
- APPLY_EQUATION(rows[2][1]);
- APPLY_EQUATION(rows[2][2]);
- return r;
- }
-
- case Variant::TRANSFORM3D: {
- Transform3D i = p_initial_val;
- Transform3D d = p_delta_val;
- Transform3D r;
-
- APPLY_EQUATION(basis.rows[0][0]);
- APPLY_EQUATION(basis.rows[0][1]);
- APPLY_EQUATION(basis.rows[0][2]);
- APPLY_EQUATION(basis.rows[1][0]);
- APPLY_EQUATION(basis.rows[1][1]);
- APPLY_EQUATION(basis.rows[1][2]);
- APPLY_EQUATION(basis.rows[2][0]);
- APPLY_EQUATION(basis.rows[2][1]);
- APPLY_EQUATION(basis.rows[2][2]);
- APPLY_EQUATION(origin.x);
- APPLY_EQUATION(origin.y);
- APPLY_EQUATION(origin.z);
- return r;
- }
-
- case Variant::COLOR: {
- Color i = p_initial_val;
- Color d = p_delta_val;
- Color r;
-
- APPLY_EQUATION(r);
- APPLY_EQUATION(g);
- APPLY_EQUATION(b);
- APPLY_EQUATION(a);
- return r;
- }
-
- default: {
- return p_initial_val;
- }
- };
-#undef APPLY_EQUATION
-}
-
-Variant Tween::calculate_delta_value(Variant p_intial_val, Variant p_final_val) {
- ERR_FAIL_COND_V_MSG(p_intial_val.get_type() != p_final_val.get_type(), p_intial_val, "Type mismatch between initial and final value: " + Variant::get_type_name(p_intial_val.get_type()) + " and " + Variant::get_type_name(p_final_val.get_type()));
-
- switch (p_intial_val.get_type()) {
- case Variant::BOOL: {
- return (int)p_final_val - (int)p_intial_val;
- }
-
- case Variant::RECT2: {
- Rect2 i = p_intial_val;
- Rect2 f = p_final_val;
- return Rect2(f.position - i.position, f.size - i.size);
- }
-
- case Variant::RECT2I: {
- Rect2i i = p_intial_val;
- Rect2i f = p_final_val;
- return Rect2i(f.position - i.position, f.size - i.size);
- }
-
- case Variant::TRANSFORM2D: {
- Transform2D i = p_intial_val;
- Transform2D f = p_final_val;
- return Transform2D(f.columns[0][0] - i.columns[0][0],
- f.columns[0][1] - i.columns[0][1],
- f.columns[1][0] - i.columns[1][0],
- f.columns[1][1] - i.columns[1][1],
- f.columns[2][0] - i.columns[2][0],
- f.columns[2][1] - i.columns[2][1]);
- }
-
- case Variant::AABB: {
- AABB i = p_intial_val;
- AABB f = p_final_val;
- return AABB(f.position - i.position, f.size - i.size);
- }
-
- case Variant::BASIS: {
- Basis i = p_intial_val;
- Basis f = p_final_val;
- return Basis(f.rows[0][0] - i.rows[0][0],
- f.rows[0][1] - i.rows[0][1],
- f.rows[0][2] - i.rows[0][2],
- f.rows[1][0] - i.rows[1][0],
- f.rows[1][1] - i.rows[1][1],
- f.rows[1][2] - i.rows[1][2],
- f.rows[2][0] - i.rows[2][0],
- f.rows[2][1] - i.rows[2][1],
- f.rows[2][2] - i.rows[2][2]);
- }
-
- case Variant::TRANSFORM3D: {
- Transform3D i = p_intial_val;
- Transform3D f = p_final_val;
- return Transform3D(f.basis.rows[0][0] - i.basis.rows[0][0],
- f.basis.rows[0][1] - i.basis.rows[0][1],
- f.basis.rows[0][2] - i.basis.rows[0][2],
- f.basis.rows[1][0] - i.basis.rows[1][0],
- f.basis.rows[1][1] - i.basis.rows[1][1],
- f.basis.rows[1][2] - i.basis.rows[1][2],
- f.basis.rows[2][0] - i.basis.rows[2][0],
- f.basis.rows[2][1] - i.basis.rows[2][1],
- f.basis.rows[2][2] - i.basis.rows[2][2],
- f.origin.x - i.origin.x,
- f.origin.y - i.origin.y,
- f.origin.z - i.origin.z);
- }
+ // Special case for bool.
+ if (p_initial_val.get_type() == Variant::BOOL) {
+ return run_equation(p_trans, p_ease, p_time, p_initial_val, p_delta_val, p_duration) >= 0.5;
+ }
- default: {
- return Variant::evaluate(Variant::OP_SUBTRACT, p_final_val, p_intial_val);
- }
- };
+ Variant ret = Animation::add_variant(p_initial_val, p_delta_val);
+ ret = Animation::interpolate_variant(p_initial_val, ret, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration));
+ return ret;
}
void Tween::_bind_methods() {
@@ -748,10 +500,10 @@ void PropertyTweener::start() {
}
if (relative) {
- final_val = Variant::evaluate(Variant::Operator::OP_ADD, initial_val, base_final_val);
+ final_val = Animation::add_variant(initial_val, base_final_val);
}
- delta_val = tween->calculate_delta_value(initial_val, final_val);
+ delta_val = Animation::subtract_variant(final_val, initial_val);
}
bool PropertyTweener::step(float &r_delta) {
@@ -973,7 +725,7 @@ void MethodTweener::_bind_methods() {
MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration) {
callback = p_callback;
initial_val = p_from;
- delta_val = tween->calculate_delta_value(p_from, p_to);
+ delta_val = Animation::subtract_variant(p_to, p_from);
final_val = p_to;
duration = p_duration;
}
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index b57ec2e5e7..da7a8b5d71 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -164,7 +164,6 @@ public:
static real_t run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d);
static Variant interpolate_variant(Variant p_initial_val, Variant p_delta_val, float p_time, float p_duration, Tween::TransitionType p_trans, Tween::EaseType p_ease);
- Variant calculate_delta_value(Variant p_intial_val, Variant p_final_val);
bool step(float p_delta);
bool can_process(bool p_tree_paused) const;
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index cf467ceafb..3d95677dcf 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -469,7 +469,7 @@ void BaseButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "Shortcut"), "set_shortcut", "get_shortcut");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "button_group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_RESOURCE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
BIND_ENUM_CONSTANT(DRAW_NORMAL);
BIND_ENUM_CONSTANT(DRAW_PRESSED);
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index f6e0e4216d..8069ab465b 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -1216,30 +1216,39 @@ bool CodeEdit::is_drawing_executing_lines_gutter() const {
}
void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) {
+ bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
+
if (draw_breakpoints && breakpoint_icon.is_valid()) {
bool hovering = p_region.has_point(get_local_mouse_pos());
bool breakpointed = is_line_breakpointed(p_line);
- if (breakpointed || (hovering && !is_dragging_cursor())) {
+ if (breakpointed || (hovering && !is_dragging_cursor() && !shift_pressed)) {
int padding = p_region.size.x / 6;
Rect2 icon_region = p_region;
icon_region.position += Point2(padding, padding);
icon_region.size -= Point2(padding, padding) * 2;
- // Darken icon when hovering & not yet breakpointed.
- Color use_color = hovering && !breakpointed ? breakpoint_color.darkened(0.4) : breakpoint_color;
+ // Darken icon when hovering, shift not pressed & not yet breakpointed.
+ Color use_color = hovering && !breakpointed && !shift_pressed ? breakpoint_color.darkened(0.4) : breakpoint_color;
breakpoint_icon->draw_rect(get_canvas_item(), icon_region, false, use_color);
}
}
- if (draw_bookmarks && is_line_bookmarked(p_line) && bookmark_icon.is_valid()) {
- int horizontal_padding = p_region.size.x / 2;
- int vertical_padding = p_region.size.y / 4;
+ if (draw_bookmarks && bookmark_icon.is_valid()) {
+ bool hovering = p_region.has_point(get_local_mouse_pos());
+ bool bookmarked = is_line_bookmarked(p_line);
- Rect2 bookmark_region = p_region;
- bookmark_region.position += Point2(horizontal_padding, 0);
- bookmark_region.size -= Point2(horizontal_padding * 1.1, vertical_padding);
- bookmark_icon->draw_rect(get_canvas_item(), bookmark_region, false, bookmark_color);
+ if (bookmarked || (hovering && !is_dragging_cursor() && shift_pressed)) {
+ int horizontal_padding = p_region.size.x / 2;
+ int vertical_padding = p_region.size.y / 4;
+ Rect2 icon_region = p_region;
+ icon_region.position += Point2(horizontal_padding, 0);
+ icon_region.size -= Point2(horizontal_padding * 1.1, vertical_padding);
+
+ // Darken icon when hovering, shift pressed & not yet bookmarked.
+ Color use_color = hovering && !bookmarked && shift_pressed ? bookmark_color.darkened(0.4) : bookmark_color;
+ bookmark_icon->draw_rect(get_canvas_item(), icon_region, false, use_color);
+ }
}
if (draw_executing_lines && is_line_executing(p_line) && executing_line_icon.is_valid()) {
@@ -2378,9 +2387,13 @@ int CodeEdit::_get_auto_brace_pair_close_at_pos(int p_line, int p_col) {
/* Gutters */
void CodeEdit::_gutter_clicked(int p_line, int p_gutter) {
+ bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
+
if (p_gutter == main_gutter) {
- if (draw_breakpoints) {
+ if (draw_breakpoints && !shift_pressed) {
set_line_as_breakpoint(p_line, !is_line_breakpointed(p_line));
+ } else if (draw_bookmarks && shift_pressed) {
+ set_line_as_bookmarked(p_line, !is_line_bookmarked(p_line));
}
return;
}
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 4a1f2ab7c6..5751c54877 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -427,12 +427,15 @@ void ColorPicker::_html_submitted(const String &p_html) {
return;
}
- float last_alpha = color.a;
+ Color previous_color = color;
color = Color::html(p_html);
if (!is_editing_alpha()) {
- color.a = last_alpha;
+ color.a = previous_color.a;
}
+ if (color == previous_color) {
+ return;
+ }
if (!is_inside_tree()) {
return;
}
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index 5512c0f1fd..3c29c37479 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -192,8 +192,8 @@ void Container::_notification(int p_what) {
}
}
-TypedArray<String> Container::get_configuration_warnings() const {
- TypedArray<String> warnings = Control::get_configuration_warnings();
+PackedStringArray Container::get_configuration_warnings() const {
+ PackedStringArray warnings = Control::get_configuration_warnings();
if (get_class() == "Container" && get_script().is_null()) {
warnings.push_back(RTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, use a plain Control node instead."));
diff --git a/scene/gui/container.h b/scene/gui/container.h
index 9ec4ad3200..21bdb95186 100644
--- a/scene/gui/container.h
+++ b/scene/gui/container.h
@@ -63,7 +63,7 @@ public:
virtual Vector<int> get_allowed_size_flags_horizontal() const;
virtual Vector<int> get_allowed_size_flags_vertical() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
Container();
};
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 347fe9aa11..ae94be8437 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -213,8 +213,8 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
}
}
-TypedArray<String> Control::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray Control::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (data.mouse_filter == MOUSE_FILTER_IGNORE && !data.tooltip.is_empty()) {
warnings.push_back(RTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."));
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 38cafd835a..ee6443c81c 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -387,7 +387,7 @@ public:
// Editor integration.
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
virtual bool is_text_field() const;
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 69512903b4..7295ab9e9d 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -190,6 +190,14 @@ void GraphEditMinimap::_adjust_graph_scroll(const Vector2 &p_offset) {
ge->set_scroll_ofs(p_offset + graph_offset - camera_size / 2);
}
+PackedStringArray GraphEdit::get_configuration_warnings() const {
+ PackedStringArray warnings = Control::get_configuration_warnings();
+
+ warnings.push_back(RTR("Please be aware that GraphEdit and GraphNode will undergo extensive refactoring in a future beta version involving compatibility-breaking API changes."));
+
+ return warnings;
+}
+
Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port) {
if (is_node_connected(p_from, p_from_port, p_to, p_to_port)) {
return OK;
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 9371ed3df4..101087bdbd 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -287,6 +287,8 @@ protected:
GDVIRTUAL4R(bool, _is_node_hover_valid, StringName, int, StringName, int);
public:
+ PackedStringArray get_configuration_warnings() const override;
+
Error connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
bool is_node_connected(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
void disconnect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 008109da65..357f2480bd 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -662,19 +662,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
pos.x = get_size().width - pos.x;
}
- int closest = -1;
-
- for (int i = 0; i < items.size(); i++) {
- Rect2 rc = items[i].rect_cache;
- if (i % current_columns == current_columns - 1) {
- rc.size.width = get_size().width; //not right but works
- }
-
- if (rc.has_point(pos)) {
- closest = i;
- break;
- }
- }
+ int closest = get_item_at_position(mb->get_position(), true);
if (closest != -1 && (mb->get_button_index() == MouseButton::LEFT || (allow_rmb_select && mb->get_button_index() == MouseButton::RIGHT))) {
int i = closest;
@@ -1467,7 +1455,7 @@ int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const {
for (int i = 0; i < items.size(); i++) {
Rect2 rc = items[i].rect_cache;
if (i % current_columns == current_columns - 1) {
- rc.size.width = get_size().width - rc.position.x; //make sure you can still select the last item when clicking past the column
+ rc.size.width = get_size().width - rc.position.x; // Make sure you can still select the last item when clicking past the column.
}
if (rc.has_point(pos)) {
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index d6bf84ea5a..75592a1b99 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -703,7 +703,7 @@ void MenuBar::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "start_index"), "set_start_index", "get_start_index");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "switch_on_hover"), "set_switch_on_hover", "is_switch_on_hover");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefer_global_menu"), "set_prefer_global_menu", "is_prefer_global_menu");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_RESOURCE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index 1eb412abaf..2d2b3e413d 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -30,8 +30,8 @@
#include "range.h"
-TypedArray<String> Range::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray Range::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (shared->exp_ratio && shared->min <= 0) {
warnings.push_back(RTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."));
diff --git a/scene/gui/range.h b/scene/gui/range.h
index 87bd0d88af..19452243cf 100644
--- a/scene/gui/range.h
+++ b/scene/gui/range.h
@@ -100,7 +100,7 @@ public:
void share(Range *p_range);
void unshare();
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
Range();
~Range();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 64a0402149..3c45b90612 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -965,17 +965,18 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
uint32_t gl = glyphs[i].index;
uint16_t gl_fl = glyphs[i].flags;
uint8_t gl_cn = glyphs[i].count;
- bool cprev = false;
+ bool cprev_cluster = false;
+ bool cprev_conn = false;
if (gl_cn == 0) { // Parts of the same cluster, always connected.
- cprev = true;
+ cprev_cluster = true;
}
if (gl_fl & TextServer::GRAPHEME_IS_RTL) { // Check if previous grapheme cluster is connected.
if (i > 0 && (glyphs[i - 1].flags & TextServer::GRAPHEME_IS_CONNECTED)) {
- cprev = true;
+ cprev_conn = true;
}
} else {
if (glyphs[i].flags & TextServer::GRAPHEME_IS_CONNECTED) {
- cprev = true;
+ cprev_conn = true;
}
}
@@ -994,6 +995,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
for (int j = 0; j < fx_stack.size(); j++) {
ItemFX *item_fx = fx_stack[j];
+ bool cn = cprev_cluster || (cprev_conn && item_fx->connected);
+
if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) {
ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx);
@@ -1024,7 +1027,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_SHAKE) {
ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
- if (!cprev) {
+ if (!cn) {
uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
uint64_t max_rand = 2147483647;
@@ -1038,7 +1041,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_WAVE) {
ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
- if (!cprev) {
+ if (!cn) {
double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_wave->amplitude / 10.0f);
item_wave->prev_off = Point2(0, 1) * value;
}
@@ -1046,7 +1049,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_TORNADO) {
ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
- if (!cprev) {
+ if (!cn) {
double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
item_tornado->prev_off = Point2(torn_x, torn_y);
@@ -1181,17 +1184,18 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
uint32_t gl = glyphs[i].index;
uint16_t gl_fl = glyphs[i].flags;
uint8_t gl_cn = glyphs[i].count;
- bool cprev = false;
+ bool cprev_cluster = false;
+ bool cprev_conn = false;
if (gl_cn == 0) { // Parts of the same grapheme cluster, always connected.
- cprev = true;
+ cprev_cluster = true;
}
if (gl_fl & TextServer::GRAPHEME_IS_RTL) { // Check if previous grapheme cluster is connected.
if (i > 0 && (glyphs[i - 1].flags & TextServer::GRAPHEME_IS_CONNECTED)) {
- cprev = true;
+ cprev_conn = true;
}
} else {
if (glyphs[i].flags & TextServer::GRAPHEME_IS_CONNECTED) {
- cprev = true;
+ cprev_conn = true;
}
}
@@ -1209,6 +1213,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
for (int j = 0; j < fx_stack.size(); j++) {
ItemFX *item_fx = fx_stack[j];
+ bool cn = cprev_cluster || (cprev_conn && item_fx->connected);
+
if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) {
ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx);
@@ -1239,7 +1245,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_SHAKE) {
ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
- if (!cprev) {
+ if (!cn) {
uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
uint64_t max_rand = 2147483647;
@@ -1253,7 +1259,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_WAVE) {
ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
- if (!cprev) {
+ if (!cn) {
double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f);
item_wave->prev_off = Point2(0, 1) * value;
}
@@ -1261,7 +1267,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_TORNADO) {
ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
- if (!cprev) {
+ if (!cn) {
double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
item_tornado->prev_off = Point2(torn_x, torn_y);
@@ -2188,6 +2194,30 @@ RichTextLabel::ItemFont *RichTextLabel::_find_font(Item *p_item) {
while (fontitem) {
if (fontitem->type == ITEM_FONT) {
ItemFont *fi = static_cast<ItemFont *>(fontitem);
+ switch (fi->def_font) {
+ case NORMAL_FONT: {
+ fi->font = theme_cache.normal_font;
+ fi->font_size = theme_cache.normal_font_size;
+ } break;
+ case BOLD_FONT: {
+ fi->font = theme_cache.bold_font;
+ fi->font_size = theme_cache.bold_font_size;
+ } break;
+ case ITALICS_FONT: {
+ fi->font = theme_cache.italics_font;
+ fi->font_size = theme_cache.italics_font_size;
+ } break;
+ case BOLD_ITALICS_FONT: {
+ fi->font = theme_cache.bold_italics_font;
+ fi->font_size = theme_cache.bold_italics_font_size;
+ } break;
+ case MONO_FONT: {
+ fi->font = theme_cache.mono_font;
+ fi->font_size = theme_cache.mono_font_size;
+ } break;
+ default: {
+ } break;
+ }
return fi;
}
@@ -3004,6 +3034,17 @@ void RichTextLabel::push_dropcap(const String &p_string, const Ref<Font> &p_font
_add_item(item, false);
}
+void RichTextLabel::_push_def_font(DefaultFont p_font) {
+ _stop_thread();
+ MutexLock data_lock(data_mutex);
+
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
+ ItemFont *item = memnew(ItemFont);
+
+ item->def_font = p_font;
+ _add_item(item, true);
+}
+
void RichTextLabel::push_font(const Ref<Font> &p_font, int p_size) {
_stop_thread();
MutexLock data_lock(data_mutex);
@@ -3020,31 +3061,31 @@ void RichTextLabel::push_font(const Ref<Font> &p_font, int p_size) {
void RichTextLabel::push_normal() {
ERR_FAIL_COND(theme_cache.normal_font.is_null());
- push_font(theme_cache.normal_font, theme_cache.normal_font_size);
+ _push_def_font(NORMAL_FONT);
}
void RichTextLabel::push_bold() {
ERR_FAIL_COND(theme_cache.bold_font.is_null());
- push_font(theme_cache.bold_font, theme_cache.bold_font_size);
+ _push_def_font(BOLD_FONT);
}
void RichTextLabel::push_bold_italics() {
ERR_FAIL_COND(theme_cache.bold_italics_font.is_null());
- push_font(theme_cache.bold_italics_font, theme_cache.bold_italics_font_size);
+ _push_def_font(BOLD_ITALICS_FONT);
}
void RichTextLabel::push_italics() {
ERR_FAIL_COND(theme_cache.italics_font.is_null());
- push_font(theme_cache.italics_font, theme_cache.italics_font_size);
+ _push_def_font(ITALICS_FONT);
}
void RichTextLabel::push_mono() {
ERR_FAIL_COND(theme_cache.mono_font.is_null());
- push_font(theme_cache.mono_font, theme_cache.mono_font_size);
+ _push_def_font(MONO_FONT);
}
void RichTextLabel::push_font_size(int p_font_size) {
@@ -3201,33 +3242,36 @@ void RichTextLabel::push_fade(int p_start_index, int p_length) {
_add_item(item, true);
}
-void RichTextLabel::push_shake(int p_strength = 10, float p_rate = 24.0f) {
+void RichTextLabel::push_shake(int p_strength = 10, float p_rate = 24.0f, bool p_connected = true) {
_stop_thread();
MutexLock data_lock(data_mutex);
ItemShake *item = memnew(ItemShake);
item->strength = p_strength;
item->rate = p_rate;
+ item->connected = p_connected;
_add_item(item, true);
}
-void RichTextLabel::push_wave(float p_frequency = 1.0f, float p_amplitude = 10.0f) {
+void RichTextLabel::push_wave(float p_frequency = 1.0f, float p_amplitude = 10.0f, bool p_connected = true) {
_stop_thread();
MutexLock data_lock(data_mutex);
ItemWave *item = memnew(ItemWave);
item->frequency = p_frequency;
item->amplitude = p_amplitude;
+ item->connected = p_connected;
_add_item(item, true);
}
-void RichTextLabel::push_tornado(float p_frequency = 1.0f, float p_radius = 10.0f) {
+void RichTextLabel::push_tornado(float p_frequency = 1.0f, float p_radius = 10.0f, bool p_connected = true) {
_stop_thread();
MutexLock data_lock(data_mutex);
ItemTornado *item = memnew(ItemTornado);
item->frequency = p_frequency;
item->radius = p_radius;
+ item->connected = p_connected;
_add_item(item, true);
}
@@ -3635,9 +3679,9 @@ void RichTextLabel::append_text(const String &p_bbcode) {
//use bold font
in_bold = true;
if (in_italics) {
- push_font(theme_cache.bold_italics_font, theme_cache.bold_italics_font_size);
+ _push_def_font(BOLD_ITALICS_FONT);
} else {
- push_font(theme_cache.bold_font, theme_cache.bold_font_size);
+ _push_def_font(BOLD_FONT);
}
pos = brk_end + 1;
tag_stack.push_front(tag);
@@ -3645,15 +3689,15 @@ void RichTextLabel::append_text(const String &p_bbcode) {
//use italics font
in_italics = true;
if (in_bold) {
- push_font(theme_cache.bold_italics_font, theme_cache.bold_italics_font_size);
+ _push_def_font(BOLD_ITALICS_FONT);
} else {
- push_font(theme_cache.italics_font, theme_cache.italics_font_size);
+ _push_def_font(ITALICS_FONT);
}
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "code") {
//use monospace font
- push_font(theme_cache.mono_font, theme_cache.mono_font_size);
+ _push_def_font(MONO_FONT);
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag.begins_with("table=")) {
@@ -4230,7 +4274,13 @@ void RichTextLabel::append_text(const String &p_bbcode) {
rate = rate_option->value.to_float();
}
- push_shake(strength, rate);
+ bool connected = true;
+ OptionMap::Iterator connected_option = bbcode_options.find("connected");
+ if (connected_option) {
+ connected = connected_option->value.to_int();
+ }
+
+ push_shake(strength, rate, connected);
pos = brk_end + 1;
tag_stack.push_front("shake");
set_process_internal(true);
@@ -4247,7 +4297,13 @@ void RichTextLabel::append_text(const String &p_bbcode) {
period = period_option->value.to_float();
}
- push_wave(period, amplitude);
+ bool connected = true;
+ OptionMap::Iterator connected_option = bbcode_options.find("connected");
+ if (connected_option) {
+ connected = connected_option->value.to_int();
+ }
+
+ push_wave(period, amplitude, connected);
pos = brk_end + 1;
tag_stack.push_front("wave");
set_process_internal(true);
@@ -4264,7 +4320,13 @@ void RichTextLabel::append_text(const String &p_bbcode) {
frequency = frequency_option->value.to_float();
}
- push_tornado(frequency, radius);
+ bool connected = true;
+ OptionMap::Iterator connected_option = bbcode_options.find("connected");
+ if (connected_option) {
+ connected = connected_option->value.to_int();
+ }
+
+ push_tornado(frequency, radius, connected);
pos = brk_end + 1;
tag_stack.push_front("tornado");
set_process_internal(true);
@@ -4641,7 +4703,10 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
queue_redraw();
return true;
}
- p_search_previous ? current_line-- : current_line++;
+
+ if (current_line != ending_line) {
+ p_search_previous ? current_line-- : current_line++;
+ }
}
if (p_from_selection && selection.active) {
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 8bc28a9ecf..e714cb4ced 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -82,6 +82,15 @@ public:
MENU_SELECT_ALL,
};
+ enum DefaultFont {
+ NORMAL_FONT,
+ BOLD_FONT,
+ ITALICS_FONT,
+ BOLD_ITALICS_FONT,
+ MONO_FONT,
+ CUSTOM_FONT,
+ };
+
protected:
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
@@ -178,6 +187,7 @@ private:
};
struct ItemFont : public Item {
+ DefaultFont def_font = CUSTOM_FONT;
Ref<Font> font;
int font_size = 0;
ItemFont() { type = ITEM_FONT; }
@@ -272,6 +282,7 @@ private:
struct ItemFX : public Item {
double elapsed_time = 0.f;
+ bool connected = true;
};
struct ItemShake : public ItemFX {
@@ -560,6 +571,7 @@ public:
void add_newline();
bool remove_line(const int p_line);
void push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0));
+ void _push_def_font(DefaultFont p_font);
void push_font(const Ref<Font> &p_font, int p_size = 0);
void push_font_size(int p_font_size);
void push_outline_size(int p_font_size);
@@ -579,9 +591,9 @@ public:
void push_hint(const String &p_string);
void push_table(int p_columns, InlineAlignment p_alignment = INLINE_ALIGNMENT_TOP);
void push_fade(int p_start_index, int p_length);
- void push_shake(int p_strength, float p_rate);
- void push_wave(float p_frequency, float p_amplitude);
- void push_tornado(float p_frequency, float p_radius);
+ void push_shake(int p_strength, float p_rate, bool p_connected);
+ void push_wave(float p_frequency, float p_amplitude, bool p_connected);
+ void push_tornado(float p_frequency, float p_radius, bool p_connected);
void push_rainbow(float p_saturation, float p_value, float p_frequency);
void push_bgcolor(const Color &p_color);
void push_fgcolor(const Color &p_color);
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index c12ac115b7..761072c5bc 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -501,8 +501,8 @@ void ScrollContainer::set_follow_focus(bool p_follow) {
follow_focus = p_follow;
}
-TypedArray<String> ScrollContainer::get_configuration_warnings() const {
- TypedArray<String> warnings = Container::get_configuration_warnings();
+PackedStringArray ScrollContainer::get_configuration_warnings() const {
+ PackedStringArray warnings = Container::get_configuration_warnings();
int found = 0;
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index f4899846f4..0079358ef7 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -114,7 +114,7 @@ public:
VScrollBar *get_v_scroll_bar();
void ensure_control_visible(Control *p_control);
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
ScrollContainer();
};
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index 88e68ec763..3ad84cbc6d 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -227,8 +227,8 @@ void SubViewportContainer::unhandled_input(const Ref<InputEvent> &p_event) {
}
}
-TypedArray<String> SubViewportContainer::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray SubViewportContainer::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
bool has_viewport = false;
for (int i = 0; i < get_child_count(); i++) {
diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h
index 5b488fb79e..63a58b5f07 100644
--- a/scene/gui/subviewport_container.h
+++ b/scene/gui/subviewport_container.h
@@ -58,7 +58,7 @@ public:
virtual Vector<int> get_allowed_size_flags_horizontal() const override;
virtual Vector<int> get_allowed_size_flags_vertical() const override;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
SubViewportContainer();
};
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index f45d132a66..ab4808d312 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -519,12 +519,12 @@ void TabContainer::_refresh_tab_names() {
}
void TabContainer::add_child_notify(Node *p_child) {
+ Container::add_child_notify(p_child);
+
if (p_child == tab_bar) {
return;
}
- Container::add_child_notify(p_child);
-
Control *c = Object::cast_to<Control>(p_child);
if (!c || c->is_set_as_top_level()) {
return;
@@ -838,7 +838,7 @@ Size2 TabContainer::get_minimum_size() const {
}
Vector<Control *> controls = _get_tab_controls();
- int max_control_height = 0;
+ Size2 largest_child_min_size;
for (int i = 0; i < controls.size(); i++) {
Control *c = controls[i];
@@ -847,13 +847,14 @@ Size2 TabContainer::get_minimum_size() const {
}
Size2 cms = c->get_combined_minimum_size();
- ms.x = MAX(ms.x, cms.x);
- max_control_height = MAX(max_control_height, cms.y);
+ largest_child_min_size.x = MAX(largest_child_min_size.x, cms.x);
+ largest_child_min_size.y = MAX(largest_child_min_size.y, cms.y);
}
- ms.y += max_control_height;
+ ms.y += largest_child_min_size.y;
Size2 panel_ms = theme_cache.panel_style->get_minimum_size();
- ms.x = MAX(ms.x, panel_ms.x);
+
+ ms.x = MAX(ms.x, largest_child_min_size.x + panel_ms.x);
ms.y += panel_ms.y;
return ms;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 318447ecd8..38302136d6 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1201,13 +1201,14 @@ void TextEdit::_notification(int p_what) {
current_color.a = font_readonly_color.a;
}
}
+ Color gl_color = current_color;
if (selection.active && line >= selection.from_line && line <= selection.to_line) { // Selection
int sel_from = (line > selection.from_line) ? TS->shaped_text_get_range(rid).x : selection.from_column;
int sel_to = (line < selection.to_line) ? TS->shaped_text_get_range(rid).y : selection.to_column;
if (glyphs[j].start >= sel_from && glyphs[j].end <= sel_to && override_selected_font_color) {
- current_color = font_selected_color;
+ gl_color = font_selected_color;
}
}
@@ -1217,29 +1218,29 @@ void TextEdit::_notification(int p_what) {
if ((brace_open_match_line == line && brace_open_match_column == glyphs[j].start) ||
(caret.column == glyphs[j].start && caret.line == line && caret_wrap_index == line_wrap_index && (brace_open_matching || brace_open_mismatch))) {
if (brace_open_mismatch) {
- current_color = brace_mismatch_color;
+ gl_color = brace_mismatch_color;
}
Rect2 rect = Rect2(char_pos, ofs_y + font->get_underline_position(font_size), glyphs[j].advance * glyphs[j].repeat, MAX(font->get_underline_thickness(font_size) * get_theme_default_base_scale(), 1));
- draw_rect(rect, current_color);
+ draw_rect(rect, gl_color);
}
if ((brace_close_match_line == line && brace_close_match_column == glyphs[j].start) ||
(caret.column == glyphs[j].start + 1 && caret.line == line && caret_wrap_index == line_wrap_index && (brace_close_matching || brace_close_mismatch))) {
if (brace_close_mismatch) {
- current_color = brace_mismatch_color;
+ gl_color = brace_mismatch_color;
}
Rect2 rect = Rect2(char_pos, ofs_y + font->get_underline_position(font_size), glyphs[j].advance * glyphs[j].repeat, MAX(font->get_underline_thickness(font_size) * get_theme_default_base_scale(), 1));
- draw_rect(rect, current_color);
+ draw_rect(rect, gl_color);
}
}
if (draw_tabs && ((glyphs[j].flags & TextServer::GRAPHEME_IS_TAB) == TextServer::GRAPHEME_IS_TAB)) {
int yofs = (text_height - tab_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
- tab_icon->draw(ci, Point2(char_pos, ofs_y + yofs), current_color);
+ tab_icon->draw(ci, Point2(char_pos, ofs_y + yofs), gl_color);
} else if (draw_spaces && ((glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE)) {
int yofs = (text_height - space_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
int xofs = (glyphs[j].advance * glyphs[j].repeat - space_icon->get_width()) / 2;
- space_icon->draw(ci, Point2(char_pos + xofs, ofs_y + yofs), current_color);
+ space_icon->draw(ci, Point2(char_pos + xofs, ofs_y + yofs), gl_color);
}
}
@@ -1247,10 +1248,10 @@ void TextEdit::_notification(int p_what) {
for (int k = 0; k < glyphs[j].repeat; k++) {
if (!clipped && (char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) {
if (glyphs[j].font_rid != RID()) {
- TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color);
+ TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color);
had_glyphs_drawn = true;
} else if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
- TS->draw_hex_code_box(ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color);
+ TS->draw_hex_code_box(ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color);
had_glyphs_drawn = true;
}
}
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 237c78407b..f82a853e56 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -563,6 +563,57 @@ bool TreeItem::is_collapsed() {
return collapsed;
}
+void TreeItem::set_collapsed_recursive(bool p_collapsed) {
+ if (!tree) {
+ return;
+ }
+
+ set_collapsed(p_collapsed);
+
+ TreeItem *child = get_first_child();
+ while (child) {
+ child->set_collapsed_recursive(p_collapsed);
+ child = child->get_next();
+ }
+}
+
+bool TreeItem::_is_any_collapsed(bool p_only_visible) {
+ TreeItem *child = get_first_child();
+
+ // Check on children directly first (avoid recursing if possible).
+ while (child) {
+ if (child->get_first_child() && child->is_collapsed() && (!p_only_visible || (child->is_visible() && child->get_visible_child_count()))) {
+ return true;
+ }
+ child = child->get_next();
+ }
+
+ child = get_first_child();
+
+ // Otherwise recurse on children.
+ while (child) {
+ if (child->get_first_child() && (!p_only_visible || (child->is_visible() && child->get_visible_child_count())) && child->_is_any_collapsed(p_only_visible)) {
+ return true;
+ }
+ child = child->get_next();
+ }
+
+ return false;
+}
+
+bool TreeItem::is_any_collapsed(bool p_only_visible) {
+ if (p_only_visible && !is_visible()) {
+ return false;
+ }
+
+ // Collapsed if this is collapsed and it has children (only considers visible if only visible is set).
+ if (is_collapsed() && get_first_child() && (!p_only_visible || get_visible_child_count())) {
+ return true;
+ }
+
+ return _is_any_collapsed(p_only_visible);
+}
+
void TreeItem::set_visible(bool p_visible) {
if (visible == p_visible) {
return;
@@ -1406,6 +1457,9 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collapsed", "enable"), &TreeItem::set_collapsed);
ClassDB::bind_method(D_METHOD("is_collapsed"), &TreeItem::is_collapsed);
+ ClassDB::bind_method(D_METHOD("set_collapsed_recursive", "enable"), &TreeItem::set_collapsed_recursive);
+ ClassDB::bind_method(D_METHOD("is_any_collapsed", "only_visible"), &TreeItem::is_any_collapsed, DEFVAL(false));
+
ClassDB::bind_method(D_METHOD("set_visible", "enable"), &TreeItem::set_visible);
ClassDB::bind_method(D_METHOD("is_visible"), &TreeItem::is_visible);
@@ -2572,7 +2626,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
}
if (!p_item->disable_folding && !hide_folding && p_item->first_child && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + theme_cache.item_margin))) {
- p_item->set_collapsed(!p_item->is_collapsed());
+ if (enable_recursive_folding && p_mod->is_shift_pressed()) {
+ p_item->set_collapsed_recursive(!p_item->is_collapsed());
+ } else {
+ p_item->set_collapsed(!p_item->is_collapsed());
+ }
return -1;
}
@@ -2623,7 +2681,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
}
if (!p_item->disable_folding && !hide_folding && !p_item->cells[col].editable && !p_item->cells[col].selectable && p_item->get_first_child()) {
- p_item->set_collapsed(!p_item->is_collapsed());
+ if (enable_recursive_folding && p_mod->is_shift_pressed()) {
+ p_item->set_collapsed_recursive(!p_item->is_collapsed());
+ } else {
+ p_item->set_collapsed(!p_item->is_collapsed());
+ }
return -1; //collapse/uncollapse because nothing can be done with item
}
@@ -5026,6 +5088,14 @@ bool Tree::is_folding_hidden() const {
return hide_folding;
}
+void Tree::set_enable_recursive_folding(bool p_enable) {
+ enable_recursive_folding = p_enable;
+}
+
+bool Tree::is_recursive_folding_enabled() const {
+ return enable_recursive_folding;
+}
+
void Tree::set_drop_mode_flags(int p_flags) {
if (drop_mode_flags == p_flags) {
return;
@@ -5129,6 +5199,9 @@ void Tree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hide_folding", "hide"), &Tree::set_hide_folding);
ClassDB::bind_method(D_METHOD("is_folding_hidden"), &Tree::is_folding_hidden);
+ ClassDB::bind_method(D_METHOD("set_enable_recursive_folding", "enable"), &Tree::set_enable_recursive_folding);
+ ClassDB::bind_method(D_METHOD("is_recursive_folding_enabled"), &Tree::is_recursive_folding_enabled);
+
ClassDB::bind_method(D_METHOD("set_drop_mode_flags", "flags"), &Tree::set_drop_mode_flags);
ClassDB::bind_method(D_METHOD("get_drop_mode_flags"), &Tree::get_drop_mode_flags);
@@ -5143,6 +5216,7 @@ void Tree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_reselect"), "set_allow_reselect", "get_allow_reselect");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_folding"), "set_hide_folding", "is_folding_hidden");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_recursive_folding"), "set_enable_recursive_folding", "is_recursive_folding_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_root"), "set_hide_root", "is_root_hidden");
ADD_PROPERTY(PropertyInfo(Variant::INT, "drop_mode_flags", PROPERTY_HINT_FLAGS, "On Item,In Between"), "set_drop_mode_flags", "get_drop_mode_flags");
ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Row,Multi"), "set_select_mode", "get_select_mode");
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 450943c048..f994a5cec1 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -173,6 +173,8 @@ private:
}
}
+ bool _is_any_collapsed(bool p_only_visible);
+
protected:
static void _bind_methods();
@@ -272,6 +274,9 @@ public:
void set_collapsed(bool p_collapsed);
bool is_collapsed();
+ void set_collapsed_recursive(bool p_collapsed);
+ bool is_any_collapsed(bool p_only_visible = false);
+
void set_visible(bool p_visible);
bool is_visible();
@@ -613,6 +618,8 @@ private:
bool hide_folding = false;
+ bool enable_recursive_folding = true;
+
int _count_selected_items(TreeItem *p_from) const;
bool _is_branch_selected(TreeItem *p_from) const;
bool _is_sibling_branch_selected(TreeItem *p_from) const;
@@ -712,6 +719,9 @@ public:
void set_hide_folding(bool p_hide);
bool is_folding_hidden() const;
+ void set_enable_recursive_folding(bool p_enable);
+ bool is_recursive_folding_enabled() const;
+
void set_drop_mode_flags(int p_flags);
int get_drop_mode_flags() const;
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index bec378dd91..2c395ec07d 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -32,9 +32,6 @@
#include "core/io/compression.h"
#include "scene/main/timer.h"
-void HTTPRequest::_redirect_request(const String &p_new_url) {
-}
-
Error HTTPRequest::_request() {
return client->connect_to_host(url, port, use_tls, validate_tls);
}
@@ -48,6 +45,7 @@ Error HTTPRequest::_parse_url(const String &p_url) {
body_len = -1;
body.clear();
downloaded.set(0);
+ final_body_size.set(0);
redirections = 0;
String scheme;
@@ -153,7 +151,7 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust
client->set_blocking_mode(false);
err = _request();
if (err != OK) {
- call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
return ERR_CANT_CONNECT;
}
@@ -169,7 +167,7 @@ void HTTPRequest::_thread_func(void *p_userdata) {
Error err = hr->_request();
if (err != OK) {
- hr->call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
+ hr->_defer_done(RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
} else {
while (!hr->thread_request_quit.is_set()) {
bool exit = hr->_update_connection();
@@ -198,6 +196,7 @@ void HTTPRequest::cancel_request() {
}
file.unref();
+ decompressor.unref();
client->close();
body.clear();
got_response = false;
@@ -208,7 +207,7 @@ void HTTPRequest::cancel_request() {
bool HTTPRequest::_handle_response(bool *ret_value) {
if (!client->has_response()) {
- call_deferred(SNAME("_request_done"), RESULT_NO_RESPONSE, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_NO_RESPONSE, 0, PackedStringArray(), PackedByteArray());
*ret_value = true;
return true;
}
@@ -219,6 +218,9 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
client->get_response_headers(&rheaders);
response_headers.clear();
downloaded.set(0);
+ final_body_size.set(0);
+ decompressor.unref();
+
for (const String &E : rheaders) {
response_headers.push_back(E);
}
@@ -227,7 +229,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
// Handle redirect.
if (max_redirects >= 0 && redirections >= max_redirects) {
- call_deferred(SNAME("_request_done"), RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray());
*ret_value = true;
return true;
}
@@ -259,6 +261,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
body_len = -1;
body.clear();
downloaded.set(0);
+ final_body_size.set(0);
redirections = new_redirs;
*ret_value = false;
return true;
@@ -266,13 +269,26 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
}
}
+ // Check if we need to start streaming decompression.
+ String content_encoding;
+ if (accept_gzip) {
+ content_encoding = get_header_value(response_headers, "Content-Encoding").to_lower();
+ }
+ if (content_encoding == "gzip") {
+ decompressor.instantiate();
+ decompressor->start_decompression(false, get_download_chunk_size() * 2);
+ } else if (content_encoding == "deflate") {
+ decompressor.instantiate();
+ decompressor->start_decompression(true, get_download_chunk_size() * 2);
+ }
+
return false;
}
bool HTTPRequest::_update_connection() {
switch (client->get_status()) {
case HTTPClient::STATUS_DISCONNECTED: {
- call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
return true; // End it, since it's disconnected.
} break;
case HTTPClient::STATUS_RESOLVING: {
@@ -281,7 +297,7 @@ bool HTTPRequest::_update_connection() {
return false;
} break;
case HTTPClient::STATUS_CANT_RESOLVE: {
- call_deferred(SNAME("_request_done"), RESULT_CANT_RESOLVE, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_CANT_RESOLVE, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
@@ -291,7 +307,7 @@ bool HTTPRequest::_update_connection() {
return false;
} break; // Connecting to IP.
case HTTPClient::STATUS_CANT_CONNECT: {
- call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
@@ -306,16 +322,16 @@ bool HTTPRequest::_update_connection() {
return ret_value;
}
- call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_SUCCESS, response_code, response_headers, PackedByteArray());
return true;
}
if (body_len < 0) {
// Chunked transfer is done.
- call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body);
+ _defer_done(RESULT_SUCCESS, response_code, response_headers, body);
return true;
}
- call_deferred(SNAME("_request_done"), RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray());
return true;
// Request might have been done.
} else {
@@ -324,7 +340,7 @@ bool HTTPRequest::_update_connection() {
int size = request_data.size();
Error err = client->request(method, request_string, headers, size > 0 ? request_data.ptr() : nullptr, size);
if (err != OK) {
- call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
return true;
}
@@ -347,7 +363,7 @@ bool HTTPRequest::_update_connection() {
}
if (!client->is_response_chunked() && client->get_response_body_length() == 0) {
- call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_SUCCESS, response_code, response_headers, PackedByteArray());
return true;
}
@@ -356,14 +372,14 @@ bool HTTPRequest::_update_connection() {
body_len = client->get_response_body_length();
if (body_size_limit >= 0 && body_len > body_size_limit) {
- call_deferred(SNAME("_request_done"), RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
return true;
}
if (!download_to_file.is_empty()) {
file = FileAccess::open(download_to_file, FileAccess::WRITE);
if (file.is_null()) {
- call_deferred(SNAME("_request_done"), RESULT_DOWNLOAD_FILE_CANT_OPEN, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_DOWNLOAD_FILE_CANT_OPEN, response_code, response_headers, PackedByteArray());
return true;
}
}
@@ -375,14 +391,33 @@ bool HTTPRequest::_update_connection() {
}
PackedByteArray chunk = client->read_response_body_chunk();
+ downloaded.add(chunk.size());
+
+ // Decompress chunk if needed.
+ if (decompressor.is_valid()) {
+ Error err = decompressor->put_data(chunk.ptr(), chunk.size());
+ if (err == OK) {
+ chunk.resize(decompressor->get_available_bytes());
+ err = decompressor->get_data(chunk.ptrw(), chunk.size());
+ }
+ if (err != OK) {
+ _defer_done(RESULT_BODY_DECOMPRESS_FAILED, response_code, response_headers, PackedByteArray());
+ return true;
+ }
+ }
+ final_body_size.add(chunk.size());
+
+ if (body_size_limit >= 0 && final_body_size.get() > body_size_limit) {
+ _defer_done(RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
+ return true;
+ }
if (chunk.size()) {
- downloaded.add(chunk.size());
if (file.is_valid()) {
const uint8_t *r = chunk.ptr();
file->store_buffer(r, chunk.size());
if (file->get_error() != OK) {
- call_deferred(SNAME("_request_done"), RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray());
return true;
}
} else {
@@ -390,19 +425,14 @@ bool HTTPRequest::_update_connection() {
}
}
- if (body_size_limit >= 0 && downloaded.get() > body_size_limit) {
- call_deferred(SNAME("_request_done"), RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
- return true;
- }
-
if (body_len >= 0) {
if (downloaded.get() == body_len) {
- call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body);
+ _defer_done(RESULT_SUCCESS, response_code, response_headers, body);
return true;
}
} else if (client->get_status() == HTTPClient::STATUS_DISCONNECTED) {
// We read till EOF, with no errors. Request is done.
- call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body);
+ _defer_done(RESULT_SUCCESS, response_code, response_headers, body);
return true;
}
@@ -410,11 +440,11 @@ bool HTTPRequest::_update_connection() {
} break; // Request resulted in body: break which must be read.
case HTTPClient::STATUS_CONNECTION_ERROR: {
- call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
case HTTPClient::STATUS_TLS_HANDSHAKE_ERROR: {
- call_deferred(SNAME("_request_done"), RESULT_TLS_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_TLS_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
}
@@ -422,41 +452,13 @@ bool HTTPRequest::_update_connection() {
ERR_FAIL_V(false);
}
+void HTTPRequest::_defer_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) {
+ call_deferred(SNAME("_request_done"), p_status, p_code, p_headers, p_data);
+}
+
void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) {
cancel_request();
- // Determine if the request body is compressed.
- bool is_compressed;
- String content_encoding = get_header_value(p_headers, "Content-Encoding").to_lower();
- Compression::Mode mode;
- if (content_encoding == "gzip") {
- mode = Compression::Mode::MODE_GZIP;
- is_compressed = true;
- } else if (content_encoding == "deflate") {
- mode = Compression::Mode::MODE_DEFLATE;
- is_compressed = true;
- } else {
- is_compressed = false;
- }
-
- if (accept_gzip && is_compressed && p_data.size() > 0) {
- // Decompress request body
- PackedByteArray decompressed;
- int result = Compression::decompress_dynamic(&decompressed, body_size_limit, p_data.ptr(), p_data.size(), mode);
- if (result == OK) {
- emit_signal(SNAME("request_completed"), p_status, p_code, p_headers, decompressed);
- return;
- } else if (result == -5) {
- WARN_PRINT("Decompressed size of HTTP response body exceeded body_size_limit");
- p_status = RESULT_BODY_SIZE_LIMIT_EXCEEDED;
- // Just return the raw data if we failed to decompress it.
- } else {
- WARN_PRINT("Failed to decompress HTTP response body");
- p_status = RESULT_BODY_DECOMPRESS_FAILED;
- // Just return the raw data if we failed to decompress it.
- }
- }
-
emit_signal(SNAME("request_completed"), p_status, p_code, p_headers, p_data);
}
@@ -566,7 +568,7 @@ double HTTPRequest::get_timeout() {
void HTTPRequest::_timeout() {
cancel_request();
- call_deferred(SNAME("_request_done"), RESULT_TIMEOUT, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_TIMEOUT, 0, PackedStringArray(), PackedByteArray());
}
void HTTPRequest::_bind_methods() {
@@ -594,7 +596,6 @@ void HTTPRequest::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_downloaded_bytes"), &HTTPRequest::get_downloaded_bytes);
ClassDB::bind_method(D_METHOD("get_body_size"), &HTTPRequest::get_body_size);
- ClassDB::bind_method(D_METHOD("_redirect_request"), &HTTPRequest::_redirect_request);
ClassDB::bind_method(D_METHOD("_request_done"), &HTTPRequest::_request_done);
ClassDB::bind_method(D_METHOD("set_timeout", "timeout"), &HTTPRequest::set_timeout);
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index 290bacd9d2..80445684b0 100644
--- a/scene/main/http_request.h
+++ b/scene/main/http_request.h
@@ -32,6 +32,7 @@
#define HTTP_REQUEST_H
#include "core/io/http_client.h"
+#include "core/io/stream_peer_gzip.h"
#include "core/os/thread.h"
#include "core/templates/safe_refcount.h"
#include "scene/main/node.h"
@@ -84,10 +85,12 @@ private:
String download_to_file;
+ Ref<StreamPeerGZIP> decompressor;
Ref<FileAccess> file;
int body_len = -1;
SafeNumeric<int> downloaded;
+ SafeNumeric<int> final_body_size;
int body_size_limit = -1;
int redirections = 0;
@@ -113,6 +116,7 @@ private:
Thread thread;
+ void _defer_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data);
void _request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data);
static void _thread_func(void *p_userdata);
diff --git a/scene/main/missing_node.cpp b/scene/main/missing_node.cpp
index 395fdad9e4..7ce527fd9c 100644
--- a/scene/main/missing_node.cpp
+++ b/scene/main/missing_node.cpp
@@ -74,9 +74,9 @@ bool MissingNode::is_recording_properties() const {
return recording_properties;
}
-TypedArray<String> MissingNode::get_configuration_warnings() const {
+PackedStringArray MissingNode::get_configuration_warnings() const {
// The mere existence of this node is warning.
- TypedArray<String> ret;
+ PackedStringArray ret;
ret.push_back(vformat(RTR("This node was saved as class type '%s', which was no longer available when this scene was loaded."), original_class));
ret.push_back(RTR("Data from the original node is kept as a placeholder until this type of node is available again. It can hence be safely re-saved without risk of data loss."));
return ret;
diff --git a/scene/main/missing_node.h b/scene/main/missing_node.h
index d200fbb47f..0003f71f29 100644
--- a/scene/main/missing_node.h
+++ b/scene/main/missing_node.h
@@ -55,7 +55,7 @@ public:
void set_recording_properties(bool p_enable);
bool is_recording_properties() const;
- virtual TypedArray<String> get_configuration_warnings() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
MissingNode();
};
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 29f4d4fb1c..a2b0f1a825 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2640,21 +2640,19 @@ void Node::clear_internal_tree_resource_paths() {
}
}
-TypedArray<String> Node::get_configuration_warnings() const {
- TypedArray<String> ret;
+PackedStringArray Node::get_configuration_warnings() const {
+ PackedStringArray ret;
Vector<String> warnings;
if (GDVIRTUAL_CALL(_get_configuration_warnings, warnings)) {
- for (int i = 0; i < warnings.size(); i++) {
- ret.push_back(warnings[i]);
- }
+ ret.append_array(warnings);
}
return ret;
}
String Node::get_configuration_warnings_as_string() const {
- TypedArray<String> warnings = get_configuration_warnings();
+ PackedStringArray warnings = get_configuration_warnings();
String all_warnings = String();
for (int i = 0; i < warnings.size(); i++) {
if (i > 0) {
@@ -2662,7 +2660,7 @@ String Node::get_configuration_warnings_as_string() const {
}
// Format as a bullet point list to make multiple warnings easier to distinguish
// from each other.
- all_warnings += String::utf8("• ") + String(warnings[i]);
+ all_warnings += String::utf8("• ") + warnings[i];
}
return all_warnings;
}
diff --git a/scene/main/node.h b/scene/main/node.h
index 13a938ef97..4e6530cccd 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -477,7 +477,7 @@ public:
_FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; }
- virtual TypedArray<String> get_configuration_warnings() const;
+ virtual PackedStringArray get_configuration_warnings() const;
String get_configuration_warnings_as_string() const;
void update_configuration_warnings();
diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp
index 13034c5447..455b8c6866 100644
--- a/scene/main/shader_globals_override.cpp
+++ b/scene/main/shader_globals_override.cpp
@@ -271,8 +271,8 @@ void ShaderGlobalsOverride::_notification(int p_what) {
}
}
-TypedArray<String> ShaderGlobalsOverride::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray ShaderGlobalsOverride::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!active) {
warnings.push_back(RTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene."));
diff --git a/scene/main/shader_globals_override.h b/scene/main/shader_globals_override.h
index af99bf9aa7..f3d0074f28 100644
--- a/scene/main/shader_globals_override.h
+++ b/scene/main/shader_globals_override.h
@@ -58,7 +58,7 @@ protected:
static void _bind_methods();
public:
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
ShaderGlobalsOverride();
};
diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp
index bb9359ef59..210b60171a 100644
--- a/scene/main/timer.cpp
+++ b/scene/main/timer.cpp
@@ -180,8 +180,8 @@ void Timer::_set_process(bool p_process, bool p_force) {
processing = p_process;
}
-TypedArray<String> Timer::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray Timer::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (wait_time < 0.05 - CMP_EPSILON) {
warnings.push_back(RTR("Very low timer wait times (< 0.05 seconds) may behave in significantly different ways depending on the rendered or physics frame rate.\nConsider using a script's process loop instead of relying on a Timer for very low wait times."));
diff --git a/scene/main/timer.h b/scene/main/timer.h
index 8785d31a8a..53503e31b2 100644
--- a/scene/main/timer.h
+++ b/scene/main/timer.h
@@ -73,7 +73,7 @@ public:
double get_time_left() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
void set_timer_process_callback(TimerProcessCallback p_callback);
TimerProcessCallback get_timer_process_callback() const;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 5295de5c09..a1c7139b25 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -795,11 +795,20 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override,
stretch_transform = p_stretch_transform;
to_screen_rect = p_to_screen_rect;
- if (p_allocated) {
- RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
- } else {
- RS::get_singleton()->viewport_set_size(viewport, 0, 0);
- }
+#ifndef _3D_DISABLED
+ if (!use_xr) {
+#endif
+
+ if (p_allocated) {
+ RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
+ } else {
+ RS::get_singleton()->viewport_set_size(viewport, 0, 0);
+ }
+
+#ifndef _3D_DISABLED
+ } // if (!use_xr)
+#endif
+
_update_global_transform();
update_configuration_warnings();
@@ -813,6 +822,19 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override,
}
Size2i Viewport::_get_size() const {
+#ifndef _3D_DISABLED
+ if (use_xr) {
+ if (XRServer::get_singleton() != nullptr) {
+ Ref<XRInterface> xr_interface = XRServer::get_singleton()->get_primary_interface();
+ if (xr_interface.is_valid() && xr_interface->is_initialized()) {
+ Size2 xr_size = xr_interface->get_render_target_size();
+ return (Size2i)xr_size;
+ }
+ }
+ return Size2i();
+ }
+#endif // _3D_DISABLED
+
return size;
}
@@ -2850,8 +2872,8 @@ Variant Viewport::gui_get_drag_data() const {
return gui.drag_data;
}
-TypedArray<String> Viewport::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray Viewport::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (size.x <= 1 || size.y <= 1) {
warnings.push_back(RTR("The Viewport size must be greater than or equal to 2 pixels on both dimensions to render anything."));
@@ -3612,9 +3634,20 @@ void Viewport::_propagate_exit_world_3d(Node *p_node) {
}
void Viewport::set_use_xr(bool p_use_xr) {
- use_xr = p_use_xr;
+ if (use_xr != p_use_xr) {
+ use_xr = p_use_xr;
- RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
+ RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
+
+ if (!use_xr) {
+ // Set viewport to previous size when exiting XR.
+ if (size_allocated) {
+ RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
+ } else {
+ RS::get_singleton()->viewport_set_size(viewport, 0, 0);
+ }
+ }
+ }
}
bool Viewport::is_using_xr() {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index afea3ea56c..471dc41246 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -568,7 +568,7 @@ public:
bool is_input_disabled() const;
Vector2 get_mouse_position() const;
- virtual void warp_mouse(const Vector2 &p_position);
+ void warp_mouse(const Vector2 &p_position);
void set_physics_object_picking(bool p_enable);
bool get_physics_object_picking();
@@ -581,7 +581,7 @@ public:
void gui_release_focus();
Control *gui_get_focus_owner();
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
void set_debug_draw(DebugDraw p_debug_draw);
DebugDraw get_debug_draw() const;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 04f56bb874..cf30ca259d 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -389,6 +389,9 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
_propagate_window_notification(this, NOTIFICATION_WM_DPI_CHANGE);
emit_signal(SNAME("dpi_changed"));
} break;
+ case DisplayServer::WINDOW_EVENT_TITLEBAR_CHANGE: {
+ emit_signal(SNAME("titlebar_changed"));
+ } break;
}
}
@@ -986,18 +989,6 @@ DisplayServer::WindowID Window::get_window_id() const {
return window_id;
}
-void Window::warp_mouse(const Vector2 &p_position) {
- Transform2D xform = get_screen_transform();
- Vector2 gpos = xform.xform(p_position);
-
- if (transient_parent && !transient_parent->is_embedding_subwindows()) {
- Transform2D window_trans = Transform2D().translated(get_position() + (transient_parent->get_visible_rect().size - transient_parent->get_real_size()));
- gpos = window_trans.xform(gpos);
- }
-
- Input::get_singleton()->warp_mouse(gpos);
-}
-
void Window::set_wrap_controls(bool p_enable) {
wrap_controls = p_enable;
if (wrap_controls) {
@@ -1153,7 +1144,7 @@ void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio
Rect2 parent_rect;
if (is_embedded()) {
- parent_rect = get_parent_viewport()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
@@ -1179,7 +1170,7 @@ void Window::popup_centered(const Size2i &p_minsize) {
Rect2 parent_rect;
if (is_embedded()) {
- parent_rect = get_parent_viewport()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
@@ -1207,7 +1198,7 @@ void Window::popup_centered_ratio(float p_ratio) {
Rect2 parent_rect;
if (is_embedded()) {
- parent_rect = get_parent_viewport()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
@@ -1794,6 +1785,7 @@ void Window::_bind_methods() {
ADD_SIGNAL(MethodInfo("visibility_changed"));
ADD_SIGNAL(MethodInfo("about_to_popup"));
ADD_SIGNAL(MethodInfo("theme_changed"));
+ ADD_SIGNAL(MethodInfo("titlebar_changed"));
BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
BIND_CONSTANT(NOTIFICATION_THEME_CHANGED);
diff --git a/scene/main/window.h b/scene/main/window.h
index 8113117103..8c6ca65436 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -254,8 +254,6 @@ public:
void set_use_font_oversampling(bool p_oversampling);
bool is_using_font_oversampling() const;
- void warp_mouse(const Vector2 &p_position) override;
-
void set_wrap_controls(bool p_enable);
bool is_wrapping_controls() const;
void child_controls_changed();
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 72c57f1bfc..e536aeee51 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -794,6 +794,7 @@ void register_scene_types() {
GDREGISTER_CLASS(CylinderMesh);
GDREGISTER_CLASS(PlaneMesh);
GDREGISTER_CLASS(PrismMesh);
+ GDREGISTER_CLASS(QuadMesh);
GDREGISTER_CLASS(SphereMesh);
GDREGISTER_CLASS(TextMesh);
GDREGISTER_CLASS(TorusMesh);
@@ -959,7 +960,6 @@ void register_scene_types() {
ClassDB::add_compatibility_class("Navigation3D", "Node3D");
ClassDB::add_compatibility_class("Navigation2D", "Node2D");
ClassDB::add_compatibility_class("OpenSimplexNoise", "FastNoiseLite");
- ClassDB::add_compatibility_class("QuadMesh", "PlaneMesh");
ClassDB::add_compatibility_class("ToolButton", "Button");
ClassDB::add_compatibility_class("YSort", "Node2D");
// Portal and room occlusion was replaced by raster occlusion (OccluderInstance3D node).
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 9d5bc18c96..a52bfe97e7 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -2317,9 +2317,7 @@ Quaternion Animation::_interpolate(const Quaternion &p_a, const Quaternion &p_b,
}
Variant Animation::_interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const {
- Variant dst;
- Variant::interpolate(p_a, p_b, p_c, dst);
- return dst;
+ return interpolate_variant(p_a, p_b, p_c);
}
real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const {
@@ -5563,6 +5561,466 @@ bool Animation::_fetch_compressed_by_index(uint32_t p_compressed_track, int p_in
return false;
}
+// Helper math functions for Variant.
+Variant Animation::add_variant(const Variant &a, const Variant &b) {
+ if (a.get_type() != b.get_type()) {
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::BOOL: {
+ return (a.operator real_t()) + (b.operator real_t()); // It is cast for interpolation.
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position + rb.position, ra.size + rb.size);
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(ra.position + rb.position, ra.size + rb.size);
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal + pb.normal, pa.d + pb.d);
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position + ab.position, aa.size + ab.size);
+ }
+ case Variant::QUATERNION: {
+ return (a.operator Quaternion()) * (b.operator Quaternion());
+ }
+ case Variant::TRANSFORM2D: {
+ return (a.operator Transform2D()) * (b.operator Transform2D());
+ }
+ case Variant::TRANSFORM3D: {
+ return (a.operator Transform3D()) * (b.operator Transform3D());
+ }
+ default: {
+ return Variant::evaluate(Variant::OP_ADD, a, b);
+ }
+ }
+}
+
+Variant Animation::subtract_variant(const Variant &a, const Variant &b) {
+ if (a.get_type() != b.get_type()) {
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::BOOL: {
+ return (a.operator real_t()) - (b.operator real_t()); // It is cast for interpolation.
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position - rb.position, ra.size - rb.size);
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(ra.position - rb.position, ra.size - rb.size);
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal - pb.normal, pa.d - pb.d);
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position - ab.position, aa.size - ab.size);
+ }
+ case Variant::QUATERNION: {
+ return (b.operator Quaternion()).inverse() * (a.operator Quaternion());
+ }
+ case Variant::TRANSFORM2D: {
+ return (b.operator Transform2D()).inverse() * (a.operator Transform2D());
+ }
+ case Variant::TRANSFORM3D: {
+ return (b.operator Transform3D()).inverse() * (a.operator Transform3D());
+ }
+ default: {
+ return Variant::evaluate(Variant::OP_SUBTRACT, a, b);
+ }
+ }
+}
+
+Variant Animation::blend_variant(const Variant &a, const Variant &b, float c) {
+ if (a.get_type() != b.get_type()) {
+ if (a.is_num() && b.is_num()) {
+ real_t va = a;
+ real_t vb = b;
+ return va + vb * c;
+ }
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::INT: {
+ return int((a.operator int64_t()) + (b.operator int64_t()) * c + 0.5);
+ }
+ case Variant::FLOAT: {
+ return (a.operator double()) + (b.operator double()) * c;
+ }
+ case Variant::VECTOR2: {
+ return (a.operator Vector2()) + (b.operator Vector2()) * c;
+ }
+ case Variant::VECTOR2I: {
+ const Vector2i va = a.operator Vector2i();
+ const Vector2i vb = b.operator Vector2i();
+ return Vector2i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5));
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position + rb.position * c, ra.size + rb.size * c);
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(int32_t(ra.position.x + rb.position.x * c + 0.5), int32_t(ra.position.y + rb.position.y * c + 0.5), int32_t(ra.size.x + rb.size.x * c + 0.5), int32_t(ra.size.y + rb.size.y * c + 0.5));
+ }
+ case Variant::VECTOR3: {
+ return (a.operator Vector3()) + (b.operator Vector3()) * c;
+ }
+ case Variant::VECTOR3I: {
+ const Vector3i va = a.operator Vector3i();
+ const Vector3i vb = b.operator Vector3i();
+ return Vector3i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5), int32_t(va.z + vb.z * c + 0.5));
+ }
+ case Variant::VECTOR4: {
+ return (a.operator Vector4()) + (b.operator Vector4()) * c;
+ }
+ case Variant::VECTOR4I: {
+ const Vector4i va = a.operator Vector4i();
+ const Vector4i vb = b.operator Vector4i();
+ return Vector4i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5), int32_t(va.z + vb.z * c + 0.5), int32_t(va.w + vb.w * c + 0.5));
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal + pb.normal * c, pa.d + pb.d * c);
+ }
+ case Variant::COLOR: {
+ return (a.operator Color()) + (b.operator Color()) * c;
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position + ab.position * c, aa.size + ab.size * c);
+ }
+ case Variant::BASIS: {
+ return (a.operator Basis()) + (b.operator Basis()) * c;
+ }
+ case Variant::QUATERNION: {
+ return (a.operator Quaternion()) * Quaternion().slerp((b.operator Quaternion()), c);
+ }
+ case Variant::TRANSFORM2D: {
+ return (a.operator Transform2D()) * Transform2D().interpolate_with((b.operator Transform2D()), c);
+ }
+ case Variant::TRANSFORM3D: {
+ return (a.operator Transform3D()) * Transform3D().interpolate_with((b.operator Transform3D()), c);
+ }
+ default: {
+ return c < 0.5 ? a : b;
+ }
+ }
+}
+
+Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float c) {
+ if (a.get_type() != b.get_type()) {
+ if (a.is_num() && b.is_num()) {
+ real_t va = a;
+ real_t vb = b;
+ return va + (vb - va) * c;
+ }
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::INT: {
+ const int64_t va = a.operator int64_t();
+ return int(va + ((b.operator int64_t()) - va) * c);
+ }
+ case Variant::FLOAT: {
+ const real_t va = a.operator real_t();
+ return va + ((b.operator real_t()) - va) * c;
+ }
+ case Variant::VECTOR2: {
+ return (a.operator Vector2()).lerp(b.operator Vector2(), c);
+ }
+ case Variant::VECTOR2I: {
+ const Vector2i va = a.operator Vector2i();
+ const Vector2i vb = b.operator Vector2i();
+ return Vector2i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c));
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position.lerp(rb.position, c), ra.size.lerp(rb.size, c));
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(int32_t(ra.position.x + (rb.position.x - ra.position.x) * c), int32_t(ra.position.y + (rb.position.y - ra.position.y) * c), int32_t(ra.size.x + (rb.size.x - ra.size.x) * c), int32_t(ra.size.y + (rb.size.y - ra.size.y) * c));
+ }
+ case Variant::VECTOR3: {
+ return (a.operator Vector3()).lerp(b.operator Vector3(), c);
+ }
+ case Variant::VECTOR3I: {
+ const Vector3i va = a.operator Vector3i();
+ const Vector3i vb = b.operator Vector3i();
+ return Vector3i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c), int32_t(va.z + (vb.z - va.z) * c));
+ }
+ case Variant::VECTOR4: {
+ return (a.operator Vector4()).lerp(b.operator Vector4(), c);
+ }
+ case Variant::VECTOR4I: {
+ const Vector4i va = a.operator Vector4i();
+ const Vector4i vb = b.operator Vector4i();
+ return Vector4i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c), int32_t(va.z + (vb.z - va.z) * c), int32_t(va.w + (vb.w - va.w) * c));
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal.lerp(pb.normal, c), pa.d + (pb.d - pa.d) * c);
+ }
+ case Variant::COLOR: {
+ return (a.operator Color()).lerp(b.operator Color(), c);
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position.lerp(ab.position, c), aa.size.lerp(ab.size, c));
+ }
+ case Variant::BASIS: {
+ return (a.operator Basis()).lerp(b.operator Basis(), c);
+ }
+ case Variant::QUATERNION: {
+ return (a.operator Quaternion()).slerp(b.operator Quaternion(), c);
+ }
+ case Variant::TRANSFORM2D: {
+ return (a.operator Transform2D()).interpolate_with(b.operator Transform2D(), c);
+ }
+ case Variant::TRANSFORM3D: {
+ return (a.operator Transform3D()).interpolate_with(b.operator Transform3D(), c);
+ }
+ case Variant::STRING: {
+ // This is pretty funny and bizarre, but artists like to use it for typewriter effects.
+ const String sa = a.operator String();
+ const String sb = b.operator String();
+ String dst;
+ int sa_len = sa.length();
+ int sb_len = sb.length();
+ int csize = sa_len + (sb_len - sa_len) * c;
+ if (csize == 0) {
+ return "";
+ }
+ dst.resize(csize + 1);
+ dst[csize] = 0;
+ int split = csize / 2;
+
+ for (int i = 0; i < csize; i++) {
+ char32_t chr = ' ';
+
+ if (i < split) {
+ if (i < sa.length()) {
+ chr = sa[i];
+ } else if (i < sb.length()) {
+ chr = sb[i];
+ }
+
+ } else {
+ if (i < sb.length()) {
+ chr = sb[i];
+ } else if (i < sa.length()) {
+ chr = sa[i];
+ }
+ }
+
+ dst[i] = chr;
+ }
+
+ return dst;
+ }
+ case Variant::PACKED_INT32_ARRAY: {
+ const Vector<int32_t> *arr_a = Object::cast_to<Vector<int32_t>>(a);
+ const Vector<int32_t> *arr_b = Object::cast_to<Vector<int32_t>>(b);
+ int32_t sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<int32_t> v;
+ v.resize(sz);
+ {
+ int32_t *vw = v.ptrw();
+ const int32_t *ar = arr_a->ptr();
+ const int32_t *br = arr_b->ptr();
+
+ Variant va;
+ for (int32_t i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_INT64_ARRAY: {
+ const Vector<int64_t> *arr_a = Object::cast_to<Vector<int64_t>>(a);
+ const Vector<int64_t> *arr_b = Object::cast_to<Vector<int64_t>>(b);
+ int64_t sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<int64_t> v;
+ v.resize(sz);
+ {
+ int64_t *vw = v.ptrw();
+ const int64_t *ar = arr_a->ptr();
+ const int64_t *br = arr_b->ptr();
+
+ Variant va;
+ for (int64_t i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_FLOAT32_ARRAY: {
+ const Vector<float> *arr_a = Object::cast_to<Vector<float>>(a);
+ const Vector<float> *arr_b = Object::cast_to<Vector<float>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<float> v;
+ v.resize(sz);
+ {
+ float *vw = v.ptrw();
+ const float *ar = arr_a->ptr();
+ const float *br = arr_b->ptr();
+
+ Variant va;
+ for (int i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ const Vector<double> *arr_a = Object::cast_to<Vector<double>>(a);
+ const Vector<double> *arr_b = Object::cast_to<Vector<double>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<double> v;
+ v.resize(sz);
+ {
+ double *vw = v.ptrw();
+ const double *ar = arr_a->ptr();
+ const double *br = arr_b->ptr();
+
+ Variant va;
+ for (int i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_VECTOR2_ARRAY: {
+ const Vector<Vector2> *arr_a = Object::cast_to<Vector<Vector2>>(a);
+ const Vector<Vector2> *arr_b = Object::cast_to<Vector<Vector2>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<Vector2> v;
+ v.resize(sz);
+ {
+ Vector2 *vw = v.ptrw();
+ const Vector2 *ar = arr_a->ptr();
+ const Vector2 *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_VECTOR3_ARRAY: {
+ const Vector<Vector3> *arr_a = Object::cast_to<Vector<Vector3>>(a);
+ const Vector<Vector3> *arr_b = Object::cast_to<Vector<Vector3>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<Vector3> v;
+ v.resize(sz);
+ {
+ Vector3 *vw = v.ptrw();
+ const Vector3 *ar = arr_a->ptr();
+ const Vector3 *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_COLOR_ARRAY: {
+ const Vector<Color> *arr_a = Object::cast_to<Vector<Color>>(a);
+ const Vector<Color> *arr_b = Object::cast_to<Vector<Color>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<Color> v;
+ v.resize(sz);
+ {
+ Color *vw = v.ptrw();
+ const Color *ar = arr_a->ptr();
+ const Color *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ return v;
+ }
+ }
+ default: {
+ return c < 0.5 ? a : b;
+ }
+ }
+}
+
Animation::Animation() {}
Animation::~Animation() {
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 46a88df130..49c8fa4c22 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -496,6 +496,12 @@ public:
void optimize(real_t p_allowed_velocity_err = 0.01, real_t p_allowed_angular_err = 0.01, int p_precision = 3);
void compress(uint32_t p_page_size = 8192, uint32_t p_fps = 120, float p_split_tolerance = 4.0); // 4.0 seems to be the split tolerance sweet spot from many tests
+ // Helper math functions for Variant.
+ static Variant add_variant(const Variant &a, const Variant &b);
+ static Variant subtract_variant(const Variant &a, const Variant &b);
+ static Variant blend_variant(const Variant &a, const Variant &b, float c);
+ static Variant interpolate_variant(const Variant &a, const Variant &b, float c);
+
Animation();
~Animation();
};
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 3d9e4e4a63..bbc4029764 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -272,13 +272,15 @@ Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignmen
buffer->set_direction(p_direction);
buffer->set_orientation(p_orientation);
buffer->add_string(p_text, Ref<Font>(this), p_font_size);
- if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- buffer->set_horizontal_alignment(p_alignment);
- buffer->set_width(p_width);
- buffer->set_flags(p_jst_flags);
- }
cache.insert(hash, buffer);
}
+
+ buffer->set_width(p_width);
+ buffer->set_horizontal_alignment(p_alignment);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ buffer->set_flags(p_jst_flags);
+ }
+
return buffer->get_size();
}
diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index 0afca95de0..de3d502102 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -254,7 +254,20 @@ void ImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_ma
mesh.unref();
}
-void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle) {
+#define VERTEX_SKIN_FUNC(bone_count, vert_idx, read_array, write_array, transform_array, bone_array, weight_array) \
+ Vector3 transformed_vert = Vector3(); \
+ for (unsigned int weight_idx = 0; weight_idx < bone_count; weight_idx++) { \
+ int bone_idx = bone_array[vert_idx * bone_count + weight_idx]; \
+ float w = weight_array[vert_idx * bone_count + weight_idx]; \
+ if (w < FLT_EPSILON) { \
+ continue; \
+ } \
+ ERR_FAIL_INDEX(bone_idx, static_cast<int>(transform_array.size())); \
+ transformed_vert += transform_array[bone_idx].xform(read_array[vert_idx]) * w; \
+ } \
+ write_array[vert_idx] = transformed_vert;
+
+void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_bone_transform_array) {
if (!SurfaceTool::simplify_scale_func) {
return;
}
@@ -265,6 +278,12 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
return;
}
+ LocalVector<Transform3D> bone_transform_vector;
+ for (int i = 0; i < p_bone_transform_array.size(); i++) {
+ ERR_FAIL_COND(p_bone_transform_array[i].get_type() != Variant::TRANSFORM3D);
+ bone_transform_vector.push_back(p_bone_transform_array[i]);
+ }
+
for (int i = 0; i < surfaces.size(); i++) {
if (surfaces[i].primitive != Mesh::PRIMITIVE_TRIANGLES) {
continue;
@@ -276,6 +295,8 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
Vector<Vector3> normals = surfaces[i].arrays[RS::ARRAY_NORMAL];
Vector<Vector2> uvs = surfaces[i].arrays[RS::ARRAY_TEX_UV];
Vector<Vector2> uv2s = surfaces[i].arrays[RS::ARRAY_TEX_UV2];
+ Vector<int> bones = surfaces[i].arrays[RS::ARRAY_BONES];
+ Vector<float> weights = surfaces[i].arrays[RS::ARRAY_WEIGHTS];
unsigned int index_count = indices.size();
unsigned int vertex_count = vertices.size();
@@ -301,6 +322,22 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
}
+ if (bones.size() > 0 && weights.size() && bone_transform_vector.size() > 0) {
+ Vector3 *vertices_ptrw = vertices.ptrw();
+
+ // Apply bone transforms to regular surface.
+ unsigned int bone_weight_length = surfaces[i].flags & Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS ? 8 : 4;
+
+ const int *bo = bones.ptr();
+ const float *we = weights.ptr();
+
+ for (unsigned int j = 0; j < vertex_count; j++) {
+ VERTEX_SKIN_FUNC(bone_weight_length, j, vertices_ptr, vertices_ptrw, bone_transform_vector, bo, we)
+ }
+
+ vertices_ptr = vertices.ptr();
+ }
+
float normal_merge_threshold = Math::cos(Math::deg_to_rad(p_normal_merge_angle));
float normal_pre_split_threshold = Math::cos(Math::deg_to_rad(MIN(180.0f, p_normal_split_angle * 2.0f)));
float normal_split_threshold = Math::cos(Math::deg_to_rad(p_normal_split_angle));
@@ -1246,7 +1283,7 @@ void ImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_surface_name", "surface_idx", "name"), &ImporterMesh::set_surface_name);
ClassDB::bind_method(D_METHOD("set_surface_material", "surface_idx", "material"), &ImporterMesh::set_surface_material);
- ClassDB::bind_method(D_METHOD("generate_lods", "normal_merge_angle", "normal_split_angle"), &ImporterMesh::generate_lods);
+ ClassDB::bind_method(D_METHOD("generate_lods", "normal_merge_angle", "normal_split_angle", "bone_transform_array"), &ImporterMesh::generate_lods);
ClassDB::bind_method(D_METHOD("get_mesh", "base_mesh"), &ImporterMesh::get_mesh, DEFVAL(Ref<ArrayMesh>()));
ClassDB::bind_method(D_METHOD("clear"), &ImporterMesh::clear);
diff --git a/scene/resources/importer_mesh.h b/scene/resources/importer_mesh.h
index dce2638c19..088a77edd1 100644
--- a/scene/resources/importer_mesh.h
+++ b/scene/resources/importer_mesh.h
@@ -112,7 +112,7 @@ public:
void set_surface_material(int p_surface, const Ref<Material> &p_material);
- void generate_lods(float p_normal_merge_angle, float p_normal_split_angle);
+ void generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array);
void create_shadow_mesh();
Ref<ImporterMesh> get_shadow_mesh() const;
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 448ff74a53..c1e30dd93c 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -156,17 +156,7 @@ Material::~Material() {
bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
if (shader.is_valid()) {
- StringName pr = shader->remap_uniform(p_name);
- if (!pr) {
- String n = p_name;
- if (n.find("shader_parameter/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_parameter/", "");
- } else if (n.find("shader_uniform/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_uniform/", "");
- } else if (n.find("param/") == 0) { //backwards compatibility
- pr = n.substr(6, n.length());
- }
- }
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
set_shader_parameter(pr, p_value);
return true;
@@ -178,25 +168,9 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_uniform(p_name);
- if (!pr) {
- String n = p_name;
- if (n.find("shader_parameter/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_parameter/", "");
- } else if (n.find("shader_uniform/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_uniform/", "");
- } else if (n.find("param/") == 0) { //backwards compatibility
- pr = n.substr(6, n.length());
- }
- }
-
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
- HashMap<StringName, Variant>::ConstIterator E = param_cache.find(pr);
- if (E) {
- r_ret = E->value;
- } else {
- r_ret = Variant();
- }
+ r_ret = get_shader_parameter(pr);
return true;
}
}
@@ -238,6 +212,7 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
PropertyInfo info;
info.usage = PROPERTY_USAGE_GROUP;
info.name = last_group.capitalize();
+ info.hint_string = "shader_parameter/";
List<PropertyInfo> none_subgroup;
none_subgroup.push_back(info);
@@ -252,6 +227,7 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
PropertyInfo info;
info.usage = PROPERTY_USAGE_SUBGROUP;
info.name = last_subgroup.capitalize();
+ info.hint_string = "shader_parameter/";
List<PropertyInfo> subgroup;
subgroup.push_back(info);
@@ -271,39 +247,42 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
PropertyInfo info;
info.usage = PROPERTY_USAGE_GROUP;
- info.name = "Shader Param";
+ info.name = "Shader Parameters";
+ info.hint_string = "shader_parameter/";
groups["<None>"]["<None>"].push_back(info);
}
PropertyInfo info = E->get();
- info.name = info.name;
+ info.name = "shader_parameter/" + info.name;
groups[last_group][last_subgroup].push_back(info);
}
- // Sort groups alphabetically.
- List<UniformProp> props;
+ List<String> group_names;
for (HashMap<String, HashMap<String, List<PropertyInfo>>>::Iterator group = groups.begin(); group; ++group) {
- for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = group->value.begin(); subgroup; ++subgroup) {
- for (List<PropertyInfo>::Element *item = subgroup->value.front(); item; item = item->next()) {
- if (subgroup->key == "<None>") {
- props.push_back({ group->key, item->get() });
- } else {
- props.push_back({ group->key + "::" + subgroup->key, item->get() });
- }
- }
- }
+ group_names.push_back(group->key);
}
- props.sort_custom<UniformPropComparator>();
+ group_names.sort();
- for (List<UniformProp>::Element *E = props.front(); E; E = E->next()) {
- p_list->push_back(E->get().info);
+ for (const String &group_name : group_names) {
+ List<String> subgroup_names;
+ HashMap<String, List<PropertyInfo>> &subgroups = groups[group_name];
+ for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = subgroups.begin(); subgroup; ++subgroup) {
+ subgroup_names.push_back(subgroup->key);
+ }
+ subgroup_names.sort();
+ for (const String &subgroup_name : subgroup_names) {
+ List<PropertyInfo> &prop_infos = subgroups[subgroup_name];
+ for (List<PropertyInfo>::Element *item = prop_infos.front(); item; item = item->next()) {
+ p_list->push_back(item->get());
+ }
+ }
}
}
}
bool ShaderMaterial::_property_can_revert(const StringName &p_name) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_uniform(p_name);
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr);
Variant current_value;
@@ -316,7 +295,7 @@ bool ShaderMaterial::_property_can_revert(const StringName &p_name) const {
bool ShaderMaterial::_property_get_revert(const StringName &p_name, Variant &r_property) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_uniform(p_name);
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
r_property = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr);
return true;
@@ -924,6 +903,7 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_BILLBOARD_KEEP_SCALE]) {
code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
}
+ code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n";
} break;
case BILLBOARD_FIXED_Y: {
code += " MODELVIEW_MATRIX = VIEW_MATRIX * mat4(vec4(normalize(cross(vec3(0.0, 1.0, 0.0), INV_VIEW_MATRIX[2].xyz)), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(normalize(cross(INV_VIEW_MATRIX[0].xyz, vec3(0.0, 1.0, 0.0))), 0.0), MODEL_MATRIX[3]);\n";
@@ -931,6 +911,7 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_BILLBOARD_KEEP_SCALE]) {
code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
}
+ code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n";
} break;
case BILLBOARD_PARTICLES: {
//make billboard
@@ -939,6 +920,8 @@ void BaseMaterial3D::_update_shader() {
code += " mat_world = mat_world * mat4(vec4(cos(INSTANCE_CUSTOM.x), -sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
//set modelview
code += " MODELVIEW_MATRIX = VIEW_MATRIX * mat_world;\n";
+ //set modelview normal
+ code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n";
//handle animation
code += " float h_frames = float(particles_anim_h_frames);\n";
@@ -949,7 +932,7 @@ void BaseMaterial3D::_update_shader() {
code += " particle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n";
code += " } else {\n";
code += " particle_frame = mod(particle_frame, particle_total_frames);\n";
- code += " }";
+ code += " }\n";
code += " UV /= vec2(h_frames, v_frames);\n";
code += " UV += vec2(mod(particle_frame, h_frames) / h_frames, floor((particle_frame + 0.5) / h_frames) / v_frames);\n";
} break;
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 6c81293ee3..dd9589c577 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -84,17 +84,6 @@ class ShaderMaterial : public Material {
HashMap<StringName, Variant> param_cache;
- struct UniformProp {
- String str;
- PropertyInfo info;
- };
-
- struct UniformPropComparator {
- bool operator()(const UniformProp &p_a, const UniformProp &p_b) const {
- return p_a.str.naturalnocasecmp_to(p_b.str) < 0;
- }
- };
-
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 280477ebfa..ee61f0ac55 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -262,6 +262,19 @@ public:
VARIANT_ENUM_CAST(PlaneMesh::Orientation)
+/*
+ A flat rectangle, inherits from PlaneMesh but defaults to facing the Z-plane.
+*/
+class QuadMesh : public PlaneMesh {
+ GDCLASS(QuadMesh, PlaneMesh);
+
+public:
+ QuadMesh() {
+ set_orientation(FACE_Z);
+ set_size(Size2(1, 1));
+ }
+};
+
/**
A prism shapen, handy for ramps, triangles, etc.
*/
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index d267e6520e..57be142a95 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -87,15 +87,44 @@ public:
virtual bool is_text_shader() const;
- _FORCE_INLINE_ StringName remap_uniform(const StringName &p_uniform) const {
+ // Finds the shader parameter name for the given property name, which should start with "shader_parameter/".
+ _FORCE_INLINE_ StringName remap_parameter(const StringName &p_property) const {
if (params_cache_dirty) {
get_shader_uniform_list(nullptr);
}
- const HashMap<StringName, StringName>::Iterator E = params_cache.find(p_uniform);
- if (E) {
- return E->value;
+ String n = p_property;
+
+ // Backwards compatibility with old shader parameter names.
+ // Note: The if statements are important to make sure we are only replacing text exactly at index 0.
+ if (n.find("param/") == 0) {
+ n = n.replace_first("param/", "shader_parameter/");
+ }
+ if (n.find("shader_param/") == 0) {
+ n = n.replace_first("shader_param/", "shader_parameter/");
+ }
+ if (n.find("shader_uniform/") == 0) {
+ n = n.replace_first("shader_uniform/", "shader_parameter/");
+ }
+
+ {
+ // Additional backwards compatibility for projects between #62972 and #64092 (about a month of v4.0 development).
+ // These projects did not have any prefix for shader uniforms due to a bug.
+ // This code should be removed during beta or rc of 4.0.
+ const HashMap<StringName, StringName>::Iterator E = params_cache.find(n);
+ if (E) {
+ return E->value;
+ }
+ }
+
+ if (n.begins_with("shader_parameter/")) {
+ n = n.replace_first("shader_parameter/", "");
+ const HashMap<StringName, StringName>::Iterator E = params_cache.find(n);
+ if (E) {
+ return E->value;
+ }
}
+
return StringName();
}
diff --git a/scene/resources/skeleton_modification_stack_2d.cpp b/scene/resources/skeleton_modification_stack_2d.cpp
index 068c756849..56234a8a14 100644
--- a/scene/resources/skeleton_modification_stack_2d.cpp
+++ b/scene/resources/skeleton_modification_stack_2d.cpp
@@ -182,11 +182,11 @@ void SkeletonModificationStack2D::delete_modification(int p_mod_idx) {
void SkeletonModificationStack2D::set_modification(int p_mod_idx, Ref<SkeletonModification2D> p_mod) {
ERR_FAIL_INDEX(p_mod_idx, modifications.size());
- if (p_mod == nullptr) {
- modifications.insert(p_mod_idx, nullptr);
+ if (p_mod.is_null()) {
+ modifications.write[p_mod_idx] = Ref<SkeletonModification2D>();
} else {
+ modifications.write[p_mod_idx] = p_mod;
p_mod->_setup_modification(this);
- modifications.insert(p_mod_idx, p_mod);
}
#ifdef TOOLS_ENABLED
diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp
index 1367ea86dd..61a0350440 100644
--- a/scene/resources/skeleton_profile.cpp
+++ b/scene/resources/skeleton_profile.cpp
@@ -566,7 +566,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[14].bone_name = "LeftThumbMetacarpal";
bones.write[14].bone_parent = "LeftHand";
- bones.write[14].reference_pose = Transform3D(0, -0.577, 0.816, 0.707, 0.577, 0.408, -0.707, 0.577, 0.408, -0.025, 0, 0);
+ bones.write[14].reference_pose = Transform3D(0, -0.577, 0.816, 0, 0.816, 0.577, -1, 0, 0, -0.025, 0.025, 0);
bones.write[14].handle_offset = Vector2(0.4, 0.8);
bones.write[14].group = "LeftHand";
@@ -686,7 +686,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[33].bone_name = "RightThumbMetacarpal";
bones.write[33].bone_parent = "RightHand";
- bones.write[33].reference_pose = Transform3D(0, 0.577, -0.816, -0.707, 0.577, 0.408, 0.707, 0.577, 0.408, 0.025, 0, 0);
+ bones.write[33].reference_pose = Transform3D(0, 0.577, -0.816, 0, 0.816, 0.577, 1, 0, 0, 0.025, 0.025, 0);
bones.write[33].handle_offset = Vector2(0.6, 0.8);
bones.write[33].group = "RightHand";
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index da4b8046a5..4e529de8ee 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -769,15 +769,6 @@ public:
class GradientTexture1D : public Texture2D {
GDCLASS(GradientTexture1D, Texture2D);
-public:
- struct Point {
- float offset = 0.0;
- Color color;
- bool operator<(const Point &p_ponit) const {
- return offset < p_ponit.offset;
- }
- };
-
private:
Ref<Gradient> gradient;
bool update_pending = false;
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 4116eaa196..3aba550f03 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -90,11 +90,10 @@ public:
struct Varying {
String name;
- VaryingMode mode;
- VaryingType type;
+ VaryingMode mode = VARYING_MODE_MAX;
+ VaryingType type = VARYING_TYPE_MAX;
- Varying() {
- }
+ Varying() {}
Varying(String p_name, VaryingMode p_mode, VaryingType p_type) :
name(p_name), mode(p_mode), type(p_type) {}
diff --git a/servers/SCsub b/servers/SCsub
index 2ce90e970b..788a368a4f 100644
--- a/servers/SCsub
+++ b/servers/SCsub
@@ -15,6 +15,7 @@ SConscript("text/SCsub")
SConscript("debugger/SCsub")
SConscript("extensions/SCsub")
SConscript("movie_writer/SCsub")
+SConscript("navigation/SCsub")
lib = env.add_library("servers", env.servers_sources)
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index dda8e29b6a..4b97bede56 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -678,6 +678,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("window_set_flag", "flag", "enabled", "window_id"), &DisplayServer::window_set_flag, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_get_flag", "flag", "window_id"), &DisplayServer::window_get_flag, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_window_buttons_offset", "offset", "window_id"), &DisplayServer::window_set_window_buttons_offset, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_get_safe_title_margins", "window_id"), &DisplayServer::window_get_safe_title_margins, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_request_attention", "window_id"), &DisplayServer::window_request_attention, DEFVAL(MAIN_WINDOW_ID));
@@ -823,6 +824,7 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(WINDOW_EVENT_CLOSE_REQUEST);
BIND_ENUM_CONSTANT(WINDOW_EVENT_GO_BACK_REQUEST);
BIND_ENUM_CONSTANT(WINDOW_EVENT_DPI_CHANGE);
+ BIND_ENUM_CONSTANT(WINDOW_EVENT_TITLEBAR_CHANGE);
BIND_ENUM_CONSTANT(VSYNC_DISABLED);
BIND_ENUM_CONSTANT(VSYNC_ENABLED);
diff --git a/servers/display_server.h b/servers/display_server.h
index ab4f9fc499..8eafccc040 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -336,6 +336,7 @@ public:
WINDOW_EVENT_CLOSE_REQUEST,
WINDOW_EVENT_GO_BACK_REQUEST,
WINDOW_EVENT_DPI_CHANGE,
+ WINDOW_EVENT_TITLEBAR_CHANGE,
};
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
@@ -380,7 +381,8 @@ public:
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) = 0;
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) = 0;
- virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const { return Vector2i(); };
+ virtual void window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window = MAIN_WINDOW_ID) {}
+ virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const { return Vector2i(); }
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const = 0;
diff --git a/servers/extensions/physics_server_2d_extension.cpp b/servers/extensions/physics_server_2d_extension.cpp
index 36f3be2468..e5920c78d4 100644
--- a/servers/extensions/physics_server_2d_extension.cpp
+++ b/servers/extensions/physics_server_2d_extension.cpp
@@ -189,7 +189,10 @@ void PhysicsServer2DExtension::_bind_methods() {
GDVIRTUAL_BIND(_area_get_transform, "area");
GDVIRTUAL_BIND(_area_set_collision_layer, "area", "layer");
+ GDVIRTUAL_BIND(_area_get_collision_layer, "area");
+
GDVIRTUAL_BIND(_area_set_collision_mask, "area", "mask");
+ GDVIRTUAL_BIND(_area_get_collision_mask, "area");
GDVIRTUAL_BIND(_area_set_monitorable, "area", "monitorable");
GDVIRTUAL_BIND(_area_set_pickable, "area", "pickable");
@@ -280,7 +283,7 @@ void PhysicsServer2DExtension::_bind_methods() {
GDVIRTUAL_BIND(_body_set_omit_force_integration, "body", "enable");
GDVIRTUAL_BIND(_body_is_omitting_force_integration, "body");
- GDVIRTUAL_BIND(_body_set_state_sync_callback, "body", "callback");
+ GDVIRTUAL_BIND(_body_set_state_sync_callback, "body", "callable");
GDVIRTUAL_BIND(_body_set_force_integration_callback, "body", "callable", "userdata");
GDVIRTUAL_BIND(_body_collide_shape, "body", "body_shape", "shape", "shape_xform", "motion", "results", "result_max", "result_count");
diff --git a/servers/extensions/physics_server_2d_extension.h b/servers/extensions/physics_server_2d_extension.h
index 3bd3d642c8..573b51ee12 100644
--- a/servers/extensions/physics_server_2d_extension.h
+++ b/servers/extensions/physics_server_2d_extension.h
@@ -94,7 +94,6 @@ public:
EXBIND1RC(Vector2, get_contact_local_position, int)
EXBIND1RC(Vector2, get_contact_local_normal, int)
EXBIND1RC(int, get_contact_local_shape, int)
-
EXBIND1RC(RID, get_contact_collider, int)
EXBIND1RC(Vector2, get_contact_collider_position, int)
EXBIND1RC(ObjectID, get_contact_collider_id, int)
@@ -183,13 +182,7 @@ public:
typedef PhysicsServer2D::MotionResult PhysicsServer2DExtensionMotionResult;
-struct PhysicsServer2DExtensionStateCallback {
- void *instance = nullptr;
- void (*callback)(void *p_instance, PhysicsDirectBodyState2D *p_state);
-};
-
GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionMotionResult)
-GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionStateCallback)
class PhysicsServer2DExtension : public PhysicsServer2D {
GDCLASS(PhysicsServer2DExtension, PhysicsServer2D);
@@ -275,8 +268,11 @@ public:
EXBIND2RC(Variant, area_get_param, RID, AreaParameter)
EXBIND1RC(Transform2D, area_get_transform, RID)
- EXBIND2(area_set_collision_mask, RID, uint32_t)
EXBIND2(area_set_collision_layer, RID, uint32_t)
+ EXBIND1RC(uint32_t, area_get_collision_layer, RID)
+
+ EXBIND2(area_set_collision_mask, RID, uint32_t)
+ EXBIND1RC(uint32_t, area_get_collision_mask, RID)
EXBIND2(area_set_monitorable, RID, bool)
EXBIND2(area_set_pickable, RID, bool)
@@ -376,13 +372,7 @@ public:
EXBIND2(body_set_omit_force_integration, RID, bool)
EXBIND1RC(bool, body_is_omitting_force_integration, RID)
- GDVIRTUAL2(_body_set_state_sync_callback, RID, GDNativePtr<PhysicsServer2DExtensionStateCallback>)
- void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override {
- PhysicsServer2DExtensionStateCallback callback;
- callback.callback = p_callback;
- callback.instance = p_instance;
- GDVIRTUAL_REQUIRED_CALL(_body_set_state_sync_callback, p_body, &callback);
- }
+ EXBIND2(body_set_state_sync_callback, RID, const Callable &)
EXBIND3(body_set_force_integration_callback, RID, const Callable &, const Variant &)
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override {
diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp
index 800284dc60..27f9ed2cb3 100644
--- a/servers/extensions/physics_server_3d_extension.cpp
+++ b/servers/extensions/physics_server_3d_extension.cpp
@@ -192,7 +192,10 @@ void PhysicsServer3DExtension::_bind_methods() {
GDVIRTUAL_BIND(_area_get_transform, "area");
GDVIRTUAL_BIND(_area_set_collision_layer, "area", "layer");
+ GDVIRTUAL_BIND(_area_get_collision_layer, "area");
+
GDVIRTUAL_BIND(_area_set_collision_mask, "area", "mask");
+ GDVIRTUAL_BIND(_area_get_collision_mask, "area");
GDVIRTUAL_BIND(_area_set_monitorable, "area", "monitorable");
GDVIRTUAL_BIND(_area_set_ray_pickable, "area", "enable");
@@ -284,7 +287,7 @@ void PhysicsServer3DExtension::_bind_methods() {
GDVIRTUAL_BIND(_body_set_omit_force_integration, "body", "enable");
GDVIRTUAL_BIND(_body_is_omitting_force_integration, "body");
- GDVIRTUAL_BIND(_body_set_state_sync_callback, "body", "callback");
+ GDVIRTUAL_BIND(_body_set_state_sync_callback, "body", "callable");
GDVIRTUAL_BIND(_body_set_force_integration_callback, "body", "callable", "userdata");
GDVIRTUAL_BIND(_body_set_ray_pickable, "body", "enable");
diff --git a/servers/extensions/physics_server_3d_extension.h b/servers/extensions/physics_server_3d_extension.h
index b6ed346a3d..57f2a2d790 100644
--- a/servers/extensions/physics_server_3d_extension.h
+++ b/servers/extensions/physics_server_3d_extension.h
@@ -192,14 +192,8 @@ public:
typedef PhysicsServer3D::MotionCollision PhysicsServer3DExtensionMotionCollision;
typedef PhysicsServer3D::MotionResult PhysicsServer3DExtensionMotionResult;
-struct PhysicsServer3DExtensionStateCallback {
- void *instance = nullptr;
- void (*callback)(void *p_instance, PhysicsDirectBodyState3D *p_state);
-};
-
GDVIRTUAL_NATIVE_PTR(PhysicsServer3DExtensionMotionCollision)
GDVIRTUAL_NATIVE_PTR(PhysicsServer3DExtensionMotionResult)
-GDVIRTUAL_NATIVE_PTR(PhysicsServer3DExtensionStateCallback)
class PhysicsServer3DExtension : public PhysicsServer3D {
GDCLASS(PhysicsServer3DExtension, PhysicsServer3D);
@@ -277,8 +271,11 @@ public:
EXBIND2RC(Variant, area_get_param, RID, AreaParameter)
EXBIND1RC(Transform3D, area_get_transform, RID)
- EXBIND2(area_set_collision_mask, RID, uint32_t)
EXBIND2(area_set_collision_layer, RID, uint32_t)
+ EXBIND1RC(uint32_t, area_get_collision_layer, RID)
+
+ EXBIND2(area_set_collision_mask, RID, uint32_t)
+ EXBIND1RC(uint32_t, area_get_collision_mask, RID)
EXBIND2(area_set_monitorable, RID, bool)
EXBIND2(area_set_ray_pickable, RID, bool)
@@ -380,13 +377,7 @@ public:
EXBIND2(body_set_omit_force_integration, RID, bool)
EXBIND1RC(bool, body_is_omitting_force_integration, RID)
- GDVIRTUAL2(_body_set_state_sync_callback, RID, GDNativePtr<PhysicsServer3DExtensionStateCallback>)
- void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override {
- PhysicsServer3DExtensionStateCallback callback;
- callback.callback = p_callback;
- callback.instance = p_instance;
- GDVIRTUAL_REQUIRED_CALL(_body_set_state_sync_callback, p_body, &callback);
- }
+ EXBIND2(body_set_state_sync_callback, RID, const Callable &)
EXBIND3(body_set_force_integration_callback, RID, const Callable &, const Variant &)
EXBIND2(body_set_ray_pickable, RID, bool)
diff --git a/servers/navigation/SCsub b/servers/navigation/SCsub
new file mode 100644
index 0000000000..86681f9c74
--- /dev/null
+++ b/servers/navigation/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/navigation/navigation_path_query_parameters_2d.cpp b/servers/navigation/navigation_path_query_parameters_2d.cpp
new file mode 100644
index 0000000000..574af90be1
--- /dev/null
+++ b/servers/navigation/navigation_path_query_parameters_2d.cpp
@@ -0,0 +1,144 @@
+/*************************************************************************/
+/* navigation_path_query_parameters_2d.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_path_query_parameters_2d.h"
+
+void NavigationPathQueryParameters2D::set_pathfinding_algorithm(const NavigationPathQueryParameters2D::PathfindingAlgorithm p_pathfinding_algorithm) {
+ switch (p_pathfinding_algorithm) {
+ case PATHFINDING_ALGORITHM_ASTAR: {
+ parameters.pathfinding_algorithm = NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
+ } break;
+ default: {
+ WARN_PRINT_ONCE("No match for used PathfindingAlgorithm - fallback to default");
+ parameters.pathfinding_algorithm = NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
+ } break;
+ }
+}
+
+NavigationPathQueryParameters2D::PathfindingAlgorithm NavigationPathQueryParameters2D::get_pathfinding_algorithm() const {
+ switch (parameters.pathfinding_algorithm) {
+ case NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR:
+ return PATHFINDING_ALGORITHM_ASTAR;
+ default:
+ WARN_PRINT_ONCE("No match for used PathfindingAlgorithm - fallback to default");
+ return PATHFINDING_ALGORITHM_ASTAR;
+ }
+}
+
+void NavigationPathQueryParameters2D::set_path_postprocessing(const NavigationPathQueryParameters2D::PathPostProcessing p_path_postprocessing) {
+ switch (p_path_postprocessing) {
+ case PATH_POSTPROCESSING_CORRIDORFUNNEL: {
+ parameters.path_postprocessing = NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ } break;
+ case PATH_POSTPROCESSING_EDGECENTERED: {
+ parameters.path_postprocessing = NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED;
+ } break;
+ default: {
+ WARN_PRINT_ONCE("No match for used PathPostProcessing - fallback to default");
+ parameters.path_postprocessing = NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ } break;
+ }
+}
+
+NavigationPathQueryParameters2D::PathPostProcessing NavigationPathQueryParameters2D::get_path_postprocessing() const {
+ switch (parameters.path_postprocessing) {
+ case NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL:
+ return PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ case NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED:
+ return PATH_POSTPROCESSING_EDGECENTERED;
+ default:
+ WARN_PRINT_ONCE("No match for used PathPostProcessing - fallback to default");
+ return PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ }
+}
+
+void NavigationPathQueryParameters2D::set_map(const RID &p_map) {
+ parameters.map = p_map;
+}
+
+const RID &NavigationPathQueryParameters2D::get_map() const {
+ return parameters.map;
+}
+
+void NavigationPathQueryParameters2D::set_start_position(const Vector2 p_start_position) {
+ parameters.start_position = Vector3(p_start_position.x, 0.0, p_start_position.y);
+}
+
+Vector2 NavigationPathQueryParameters2D::get_start_position() const {
+ return Vector2(parameters.start_position.x, parameters.start_position.z);
+}
+
+void NavigationPathQueryParameters2D::set_target_position(const Vector2 p_target_position) {
+ parameters.target_position = Vector3(p_target_position.x, 0.0, p_target_position.y);
+}
+
+Vector2 NavigationPathQueryParameters2D::get_target_position() const {
+ return Vector2(parameters.target_position.x, parameters.target_position.z);
+}
+
+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::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_pathfinding_algorithm", "pathfinding_algorithm"), &NavigationPathQueryParameters2D::set_pathfinding_algorithm);
+ ClassDB::bind_method(D_METHOD("get_pathfinding_algorithm"), &NavigationPathQueryParameters2D::get_pathfinding_algorithm);
+
+ ClassDB::bind_method(D_METHOD("set_path_postprocessing", "path_postprocessing"), &NavigationPathQueryParameters2D::set_path_postprocessing);
+ ClassDB::bind_method(D_METHOD("get_path_postprocessing"), &NavigationPathQueryParameters2D::get_path_postprocessing);
+
+ ClassDB::bind_method(D_METHOD("set_map", "map"), &NavigationPathQueryParameters2D::set_map);
+ ClassDB::bind_method(D_METHOD("get_map"), &NavigationPathQueryParameters2D::get_map);
+
+ ClassDB::bind_method(D_METHOD("set_start_position", "start_position"), &NavigationPathQueryParameters2D::set_start_position);
+ ClassDB::bind_method(D_METHOD("get_start_position"), &NavigationPathQueryParameters2D::get_start_position);
+
+ ClassDB::bind_method(D_METHOD("set_target_position", "target_position"), &NavigationPathQueryParameters2D::set_target_position);
+ ClassDB::bind_method(D_METHOD("get_target_position"), &NavigationPathQueryParameters2D::get_target_position);
+
+ 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);
+
+ 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");
+
+ BIND_ENUM_CONSTANT(PATHFINDING_ALGORITHM_ASTAR);
+
+ BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_CORRIDORFUNNEL);
+ BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_EDGECENTERED);
+}
diff --git a/servers/navigation/navigation_path_query_parameters_2d.h b/servers/navigation/navigation_path_query_parameters_2d.h
new file mode 100644
index 0000000000..c0ef337a27
--- /dev/null
+++ b/servers/navigation/navigation_path_query_parameters_2d.h
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* navigation_path_query_parameters_2d.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_PATH_QUERY_PARAMETERS_2D_H
+#define NAVIGATION_PATH_QUERY_PARAMETERS_2D_H
+
+#include "core/object/ref_counted.h"
+#include "servers/navigation/navigation_utilities.h"
+
+class NavigationPathQueryParameters2D : public RefCounted {
+ GDCLASS(NavigationPathQueryParameters2D, RefCounted);
+
+ NavigationUtilities::PathQueryParameters parameters;
+
+protected:
+ static void _bind_methods();
+
+public:
+ enum PathfindingAlgorithm {
+ PATHFINDING_ALGORITHM_ASTAR = 0,
+ };
+
+ enum PathPostProcessing {
+ PATH_POSTPROCESSING_CORRIDORFUNNEL = 0,
+ PATH_POSTPROCESSING_EDGECENTERED,
+ };
+
+ const NavigationUtilities::PathQueryParameters &get_parameters() const { return parameters; }
+
+ void set_pathfinding_algorithm(const PathfindingAlgorithm p_pathfinding_algorithm);
+ PathfindingAlgorithm get_pathfinding_algorithm() const;
+
+ void set_path_postprocessing(const PathPostProcessing p_path_postprocessing);
+ PathPostProcessing get_path_postprocessing() const;
+
+ void set_map(const RID &p_map);
+ const RID &get_map() const;
+
+ void set_start_position(const Vector2 p_start_position);
+ Vector2 get_start_position() const;
+
+ void set_target_position(const Vector2 p_target_position);
+ Vector2 get_target_position() const;
+
+ void set_navigation_layers(uint32_t p_navigation_layers);
+ uint32_t get_navigation_layers() const;
+};
+
+VARIANT_ENUM_CAST(NavigationPathQueryParameters2D::PathfindingAlgorithm);
+VARIANT_ENUM_CAST(NavigationPathQueryParameters2D::PathPostProcessing);
+
+#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
new file mode 100644
index 0000000000..b09448e82e
--- /dev/null
+++ b/servers/navigation/navigation_path_query_parameters_3d.cpp
@@ -0,0 +1,144 @@
+/*************************************************************************/
+/* navigation_path_query_parameters_3d.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_path_query_parameters_3d.h"
+
+void NavigationPathQueryParameters3D::set_pathfinding_algorithm(const NavigationPathQueryParameters3D::PathfindingAlgorithm p_pathfinding_algorithm) {
+ switch (p_pathfinding_algorithm) {
+ case PATHFINDING_ALGORITHM_ASTAR: {
+ parameters.pathfinding_algorithm = NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
+ } break;
+ default: {
+ WARN_PRINT_ONCE("No match for used PathfindingAlgorithm - fallback to default");
+ parameters.pathfinding_algorithm = NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
+ } break;
+ }
+}
+
+NavigationPathQueryParameters3D::PathfindingAlgorithm NavigationPathQueryParameters3D::get_pathfinding_algorithm() const {
+ switch (parameters.pathfinding_algorithm) {
+ case NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR:
+ return PATHFINDING_ALGORITHM_ASTAR;
+ default:
+ WARN_PRINT_ONCE("No match for used PathfindingAlgorithm - fallback to default");
+ return PATHFINDING_ALGORITHM_ASTAR;
+ }
+}
+
+void NavigationPathQueryParameters3D::set_path_postprocessing(const NavigationPathQueryParameters3D::PathPostProcessing p_path_postprocessing) {
+ switch (p_path_postprocessing) {
+ case PATH_POSTPROCESSING_CORRIDORFUNNEL: {
+ parameters.path_postprocessing = NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ } break;
+ case PATH_POSTPROCESSING_EDGECENTERED: {
+ parameters.path_postprocessing = NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED;
+ } break;
+ default: {
+ WARN_PRINT_ONCE("No match for used PathPostProcessing - fallback to default");
+ parameters.path_postprocessing = NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ } break;
+ }
+}
+
+NavigationPathQueryParameters3D::PathPostProcessing NavigationPathQueryParameters3D::get_path_postprocessing() const {
+ switch (parameters.path_postprocessing) {
+ case NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL:
+ return PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ case NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED:
+ return PATH_POSTPROCESSING_EDGECENTERED;
+ default:
+ WARN_PRINT_ONCE("No match for used PathPostProcessing - fallback to default");
+ return PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ }
+}
+
+void NavigationPathQueryParameters3D::set_map(const RID &p_map) {
+ parameters.map = p_map;
+}
+
+const RID &NavigationPathQueryParameters3D::get_map() const {
+ return parameters.map;
+}
+
+void NavigationPathQueryParameters3D::set_start_position(const Vector3 &p_start_position) {
+ parameters.start_position = p_start_position;
+}
+
+const Vector3 &NavigationPathQueryParameters3D::get_start_position() const {
+ return parameters.start_position;
+}
+
+void NavigationPathQueryParameters3D::set_target_position(const Vector3 &p_target_position) {
+ parameters.target_position = p_target_position;
+}
+
+const Vector3 &NavigationPathQueryParameters3D::get_target_position() const {
+ return parameters.target_position;
+}
+
+void NavigationPathQueryParameters3D::set_navigation_layers(uint32_t p_navigation_layers) {
+ parameters.navigation_layers = p_navigation_layers;
+}
+
+uint32_t NavigationPathQueryParameters3D::get_navigation_layers() const {
+ return parameters.navigation_layers;
+}
+
+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);
+
+ ClassDB::bind_method(D_METHOD("set_path_postprocessing", "path_postprocessing"), &NavigationPathQueryParameters3D::set_path_postprocessing);
+ ClassDB::bind_method(D_METHOD("get_path_postprocessing"), &NavigationPathQueryParameters3D::get_path_postprocessing);
+
+ ClassDB::bind_method(D_METHOD("set_map", "map"), &NavigationPathQueryParameters3D::set_map);
+ ClassDB::bind_method(D_METHOD("get_map"), &NavigationPathQueryParameters3D::get_map);
+
+ ClassDB::bind_method(D_METHOD("set_start_position", "start_position"), &NavigationPathQueryParameters3D::set_start_position);
+ ClassDB::bind_method(D_METHOD("get_start_position"), &NavigationPathQueryParameters3D::get_start_position);
+
+ ClassDB::bind_method(D_METHOD("set_target_position", "target_position"), &NavigationPathQueryParameters3D::set_target_position);
+ ClassDB::bind_method(D_METHOD("get_target_position"), &NavigationPathQueryParameters3D::get_target_position);
+
+ 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);
+
+ 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");
+
+ BIND_ENUM_CONSTANT(PATHFINDING_ALGORITHM_ASTAR);
+
+ BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_CORRIDORFUNNEL);
+ BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_EDGECENTERED);
+}
diff --git a/servers/navigation/navigation_path_query_parameters_3d.h b/servers/navigation/navigation_path_query_parameters_3d.h
new file mode 100644
index 0000000000..b4cf02fc79
--- /dev/null
+++ b/servers/navigation/navigation_path_query_parameters_3d.h
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* navigation_path_query_parameters_3d.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_PATH_QUERY_PARAMETERS_3D_H
+#define NAVIGATION_PATH_QUERY_PARAMETERS_3D_H
+
+#include "core/object/ref_counted.h"
+#include "servers/navigation/navigation_utilities.h"
+
+class NavigationPathQueryParameters3D : public RefCounted {
+ GDCLASS(NavigationPathQueryParameters3D, RefCounted);
+
+ NavigationUtilities::PathQueryParameters parameters;
+
+protected:
+ static void _bind_methods();
+
+public:
+ enum PathfindingAlgorithm {
+ PATHFINDING_ALGORITHM_ASTAR = 0,
+ };
+
+ enum PathPostProcessing {
+ PATH_POSTPROCESSING_CORRIDORFUNNEL = 0,
+ PATH_POSTPROCESSING_EDGECENTERED,
+ };
+
+ const NavigationUtilities::PathQueryParameters &get_parameters() const { return parameters; }
+
+ void set_pathfinding_algorithm(const PathfindingAlgorithm p_pathfinding_algorithm);
+ PathfindingAlgorithm get_pathfinding_algorithm() const;
+
+ void set_path_postprocessing(const PathPostProcessing p_path_postprocessing);
+ PathPostProcessing get_path_postprocessing() const;
+
+ void set_map(const RID &p_map);
+ const RID &get_map() const;
+
+ void set_start_position(const Vector3 &p_start_position);
+ const Vector3 &get_start_position() const;
+
+ void set_target_position(const Vector3 &p_target_position);
+ const Vector3 &get_target_position() const;
+
+ void set_navigation_layers(uint32_t p_navigation_layers);
+ uint32_t get_navigation_layers() const;
+};
+
+VARIANT_ENUM_CAST(NavigationPathQueryParameters3D::PathfindingAlgorithm);
+VARIANT_ENUM_CAST(NavigationPathQueryParameters3D::PathPostProcessing);
+
+#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
new file mode 100644
index 0000000000..23f001057b
--- /dev/null
+++ b/servers/navigation/navigation_path_query_result_2d.cpp
@@ -0,0 +1,46 @@
+/*************************************************************************/
+/* navigation_path_query_result_2d.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_path_query_result_2d.h"
+
+void NavigationPathQueryResult2D::set_path(const Vector<Vector2> &p_path) {
+ path = p_path;
+}
+
+const Vector<Vector2> &NavigationPathQueryResult2D::get_path() const {
+ return path;
+}
+
+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);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "path"), "set_path", "get_path");
+}
diff --git a/servers/navigation/navigation_path_query_result_2d.h b/servers/navigation/navigation_path_query_result_2d.h
new file mode 100644
index 0000000000..c98462016e
--- /dev/null
+++ b/servers/navigation/navigation_path_query_result_2d.h
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* navigation_path_query_result_2d.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_PATH_QUERY_RESULT_2D_H
+#define NAVIGATION_PATH_QUERY_RESULT_2D_H
+
+#include "core/object/ref_counted.h"
+#include "servers/navigation/navigation_utilities.h"
+
+class NavigationPathQueryResult2D : public RefCounted {
+ GDCLASS(NavigationPathQueryResult2D, RefCounted);
+
+ Vector<Vector2> path;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_path(const Vector<Vector2> &p_path);
+ const Vector<Vector2> &get_path() const;
+};
+
+#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
new file mode 100644
index 0000000000..8335d70c4b
--- /dev/null
+++ b/servers/navigation/navigation_path_query_result_3d.cpp
@@ -0,0 +1,46 @@
+/*************************************************************************/
+/* navigation_path_query_result_3d.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_path_query_result_3d.h"
+
+void NavigationPathQueryResult3D::set_path(const Vector<Vector3> &p_path) {
+ path = p_path;
+}
+
+const Vector<Vector3> &NavigationPathQueryResult3D::get_path() const {
+ return path;
+}
+
+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);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "path"), "set_path", "get_path");
+}
diff --git a/servers/navigation/navigation_path_query_result_3d.h b/servers/navigation/navigation_path_query_result_3d.h
new file mode 100644
index 0000000000..ff698c285f
--- /dev/null
+++ b/servers/navigation/navigation_path_query_result_3d.h
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* navigation_path_query_result_3d.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_PATH_QUERY_RESULT_3D_H
+#define NAVIGATION_PATH_QUERY_RESULT_3D_H
+
+#include "core/object/ref_counted.h"
+#include "servers/navigation/navigation_utilities.h"
+
+class NavigationPathQueryResult3D : public RefCounted {
+ GDCLASS(NavigationPathQueryResult3D, RefCounted);
+
+ Vector<Vector3> path;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_path(const Vector<Vector3> &p_path);
+ const Vector<Vector3> &get_path() const;
+};
+
+#endif // NAVIGATION_PATH_QUERY_RESULT_3D_H
diff --git a/servers/navigation/navigation_utilities.h b/servers/navigation/navigation_utilities.h
new file mode 100644
index 0000000000..bedcc16a67
--- /dev/null
+++ b/servers/navigation/navigation_utilities.h
@@ -0,0 +1,62 @@
+/*************************************************************************/
+/* navigation_utilities.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_UTILITIES_H
+#define NAVIGATION_UTILITIES_H
+
+#include "core/math/vector3.h"
+
+namespace NavigationUtilities {
+
+enum PathfindingAlgorithm {
+ PATHFINDING_ALGORITHM_ASTAR = 0,
+};
+
+enum PathPostProcessing {
+ PATH_POSTPROCESSING_CORRIDORFUNNEL = 0,
+ PATH_POSTPROCESSING_EDGECENTERED,
+};
+
+struct PathQueryParameters {
+ PathfindingAlgorithm pathfinding_algorithm = PATHFINDING_ALGORITHM_ASTAR;
+ PathPostProcessing path_postprocessing = PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ RID map;
+ Vector3 start_position = Vector3();
+ Vector3 target_position = Vector3();
+ uint32_t navigation_layers = 1;
+};
+
+struct PathQueryResult {
+ Vector<Vector3> path;
+};
+
+} //namespace NavigationUtilities
+
+#endif // NAVIGATION_UTILITIES_H
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index cec8b95225..04e5d2f6a1 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -243,6 +243,8 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_force_update", "map"), &NavigationServer2D::map_force_update);
+ ClassDB::bind_method(D_METHOD("query_path", "parameters", "result"), &NavigationServer2D::query_path);
+
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer2D::region_create);
ClassDB::bind_method(D_METHOD("region_set_enter_cost", "region", "enter_cost"), &NavigationServer2D::region_set_enter_cost);
ClassDB::bind_method(D_METHOD("region_get_enter_cost", "region"), &NavigationServer2D::region_get_enter_cost);
@@ -409,3 +411,12 @@ bool FORWARD_1_C(agent_is_map_changed, RID, p_agent, rid_to_rid);
void FORWARD_4_C(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata, rid_to_rid, obj_to_obj, sn_to_sn, var_to_var);
void FORWARD_1_C(free, RID, p_object, rid_to_rid);
+
+void NavigationServer2D::query_path(const Ref<NavigationPathQueryParameters2D> &p_query_parameters, Ref<NavigationPathQueryResult2D> p_query_result) const {
+ ERR_FAIL_COND(!p_query_parameters.is_valid());
+ ERR_FAIL_COND(!p_query_result.is_valid());
+
+ 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));
+}
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index b2ea4c28a0..54cfc6b14e 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -33,7 +33,10 @@
#include "core/object/class_db.h"
#include "core/templates/rid.h"
+
#include "scene/2d/navigation_region_2d.h"
+#include "servers/navigation/navigation_path_query_parameters_2d.h"
+#include "servers/navigation/navigation_path_query_result_2d.h"
// This server exposes the `NavigationServer3D` features in the 2D world.
class NavigationServer2D : public Object {
@@ -217,6 +220,8 @@ public:
/// Callback called at the end of the RVO process
virtual void agent_set_callback(RID p_agent, Object *p_receiver, StringName p_method, Variant p_udata = Variant()) const;
+ virtual void query_path(const Ref<NavigationPathQueryParameters2D> &p_query_parameters, Ref<NavigationPathQueryResult2D> p_query_result) const;
+
/// Destroy the `RID`
virtual void free(RID p_object) const;
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index bc0602e1df..783d32641e 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -62,6 +62,8 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_force_update", "map"), &NavigationServer3D::map_force_update);
+ ClassDB::bind_method(D_METHOD("query_path", "parameters", "result"), &NavigationServer3D::query_path);
+
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer3D::region_create);
ClassDB::bind_method(D_METHOD("region_set_enter_cost", "region", "enter_cost"), &NavigationServer3D::region_set_enter_cost);
ClassDB::bind_method(D_METHOD("region_get_enter_cost", "region"), &NavigationServer3D::region_get_enter_cost);
@@ -485,3 +487,14 @@ bool NavigationServer3D::get_debug_enabled() const {
return debug_enabled;
}
#endif // DEBUG_ENABLED
+
+///////////////////////////////////////////////////////
+
+void NavigationServer3D::query_path(const Ref<NavigationPathQueryParameters3D> &p_query_parameters, Ref<NavigationPathQueryResult3D> p_query_result) const {
+ ERR_FAIL_COND(!p_query_parameters.is_valid());
+ ERR_FAIL_COND(!p_query_result.is_valid());
+
+ const NavigationUtilities::PathQueryResult _query_result = _query_path(p_query_parameters->get_parameters());
+
+ p_query_result->set_path(_query_result.path);
+}
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index 02770794c6..0f537383a2 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -33,7 +33,10 @@
#include "core/object/class_db.h"
#include "core/templates/rid.h"
+
#include "scene/3d/navigation_region_3d.h"
+#include "servers/navigation/navigation_path_query_parameters_3d.h"
+#include "servers/navigation/navigation_path_query_result_3d.h"
/// This server uses the concept of internal mutability.
/// All the constant functions can be called in multithread because internally
@@ -41,6 +44,7 @@
///
/// Note: All the `set` functions are commands executed during the `sync` phase,
/// don't expect that a change is immediately propagated.
+
class NavigationServer3D : public Object {
GDCLASS(NavigationServer3D, Object);
@@ -243,6 +247,11 @@ public:
/// Note: This function is not thread safe.
virtual void process(real_t delta_time) = 0;
+ /// Returns a customized navigation path using a query parameters object
+ void query_path(const Ref<NavigationPathQueryParameters3D> &p_query_parameters, Ref<NavigationPathQueryResult3D> p_query_result) const;
+
+ virtual NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const = 0;
+
NavigationServer3D();
virtual ~NavigationServer3D();
diff --git a/servers/physics_2d/godot_body_2d.cpp b/servers/physics_2d/godot_body_2d.cpp
index ef6a6b1ae2..90124cd991 100644
--- a/servers/physics_2d/godot_body_2d.cpp
+++ b/servers/physics_2d/godot_body_2d.cpp
@@ -615,7 +615,7 @@ void GodotBody2D::integrate_velocities(real_t p_step) {
return;
}
- if (fi_callback_data || body_state_callback) {
+ if (fi_callback_data || body_state_callback.get_object()) {
get_space()->body_add_to_state_query_list(&direct_state_query_list);
}
@@ -673,11 +673,12 @@ void GodotBody2D::wakeup_neighbours() {
}
void GodotBody2D::call_queries() {
+ Variant direct_state_variant = get_direct_state();
+
if (fi_callback_data) {
if (!fi_callback_data->callable.get_object()) {
set_force_integration_callback(Callable());
} else {
- Variant direct_state_variant = get_direct_state();
const Variant *vp[2] = { &direct_state_variant, &fi_callback_data->udata };
Callable::CallError ce;
@@ -691,8 +692,11 @@ void GodotBody2D::call_queries() {
}
}
- if (body_state_callback) {
- (body_state_callback)(body_state_callback_instance, get_direct_state());
+ if (body_state_callback.get_object()) {
+ const Variant *vp[1] = { &direct_state_variant };
+ Callable::CallError ce;
+ Variant rv;
+ body_state_callback.callp(vp, 1, rv, ce);
}
}
@@ -713,9 +717,8 @@ bool GodotBody2D::sleep_test(real_t p_step) {
}
}
-void GodotBody2D::set_state_sync_callback(void *p_instance, PhysicsServer2D::BodyStateCallback p_callback) {
- body_state_callback_instance = p_instance;
- body_state_callback = p_callback;
+void GodotBody2D::set_state_sync_callback(const Callable &p_callable) {
+ body_state_callback = p_callable;
}
void GodotBody2D::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
diff --git a/servers/physics_2d/godot_body_2d.h b/servers/physics_2d/godot_body_2d.h
index 409940d4f8..86d42ae7f8 100644
--- a/servers/physics_2d/godot_body_2d.h
+++ b/servers/physics_2d/godot_body_2d.h
@@ -137,8 +137,7 @@ class GodotBody2D : public GodotCollisionObject2D {
Vector<Contact> contacts; //no contacts by default
int contact_count = 0;
- void *body_state_callback_instance = nullptr;
- PhysicsServer2D::BodyStateCallback body_state_callback = nullptr;
+ Callable body_state_callback;
struct ForceIntegrationCallbackData {
Callable callable;
@@ -156,7 +155,7 @@ class GodotBody2D : public GodotCollisionObject2D {
friend class GodotPhysicsDirectBodyState2D; // i give up, too many functions to expose
public:
- void set_state_sync_callback(void *p_instance, PhysicsServer2D::BodyStateCallback p_callback);
+ void set_state_sync_callback(const Callable &p_callable);
void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
GodotPhysicsDirectBodyState2D *get_direct_state();
diff --git a/servers/physics_2d/godot_collision_solver_2d.cpp b/servers/physics_2d/godot_collision_solver_2d.cpp
index 0d7b42b80d..52237539c0 100644
--- a/servers/physics_2d/godot_collision_solver_2d.cpp
+++ b/servers/physics_2d/godot_collision_solver_2d.cpp
@@ -34,7 +34,7 @@
#define collision_solver sat_2d_calculate_penetration
//#define collision_solver gjk_epa_calculate_penetration
-bool GodotCollisionSolver2D::solve_static_world_boundary(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
+bool GodotCollisionSolver2D::solve_static_world_boundary(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin) {
const GodotWorldBoundaryShape2D *world_boundary = static_cast<const GodotWorldBoundaryShape2D *>(p_shape_A);
if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) {
return false;
@@ -52,7 +52,9 @@ bool GodotCollisionSolver2D::solve_static_world_boundary(const GodotShape2D *p_s
bool found = false;
for (int i = 0; i < support_count; i++) {
+ supports[i] += p_margin * supports[i].normalized();
supports[i] = p_transform_B.xform(supports[i]);
+ supports[i] += p_motion_B;
real_t pd = n.dot(supports[i]);
if (pd >= d) {
continue;
@@ -227,17 +229,19 @@ bool GodotCollisionSolver2D::solve(const GodotShape2D *p_shape_A, const Transfor
if (type_A == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) {
if (type_B == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) {
+ WARN_PRINT_ONCE("Collisions between world boundaries are not supported.");
return false;
}
if (swap) {
- return solve_static_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
+ return solve_static_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_motion_A, p_result_callback, p_userdata, true, p_margin_A);
} else {
- return solve_static_world_boundary(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
+ return solve_static_world_boundary(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_motion_B, p_result_callback, p_userdata, false, p_margin_B);
}
} else if (type_A == PhysicsServer2D::SHAPE_SEPARATION_RAY) {
if (type_B == PhysicsServer2D::SHAPE_SEPARATION_RAY) {
+ WARN_PRINT_ONCE("Collisions between two rays are not supported.");
return false; //no ray-ray
}
@@ -249,6 +253,7 @@ bool GodotCollisionSolver2D::solve(const GodotShape2D *p_shape_A, const Transfor
} else if (concave_B) {
if (concave_A) {
+ WARN_PRINT_ONCE("Collisions between two concave shapes are not supported.");
return false;
}
diff --git a/servers/physics_2d/godot_collision_solver_2d.h b/servers/physics_2d/godot_collision_solver_2d.h
index bd90641f04..3aac2751e0 100644
--- a/servers/physics_2d/godot_collision_solver_2d.h
+++ b/servers/physics_2d/godot_collision_solver_2d.h
@@ -38,7 +38,7 @@ public:
typedef void (*CallbackResult)(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata);
private:
- static bool solve_static_world_boundary(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
+ static bool solve_static_world_boundary(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0);
static bool concave_callback(void *p_userdata, GodotShape2D *p_convex);
static bool solve_concave(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
static bool solve_separation_ray(const GodotShape2D *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis = nullptr, real_t p_margin = 0);
diff --git a/servers/physics_2d/godot_physics_server_2d.cpp b/servers/physics_2d/godot_physics_server_2d.cpp
index cec31bdc31..6ce8175e6c 100644
--- a/servers/physics_2d/godot_physics_server_2d.cpp
+++ b/servers/physics_2d/godot_physics_server_2d.cpp
@@ -485,6 +485,20 @@ void GodotPhysicsServer2D::area_set_monitorable(RID p_area, bool p_monitorable)
area->set_monitorable(p_monitorable);
}
+void GodotPhysicsServer2D::area_set_collision_layer(RID p_area, uint32_t p_layer) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_collision_layer(p_layer);
+}
+
+uint32_t GodotPhysicsServer2D::area_get_collision_layer(RID p_area) const {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, 0);
+
+ return area->get_collision_layer();
+}
+
void GodotPhysicsServer2D::area_set_collision_mask(RID p_area, uint32_t p_mask) {
GodotArea2D *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
@@ -492,11 +506,11 @@ void GodotPhysicsServer2D::area_set_collision_mask(RID p_area, uint32_t p_mask)
area->set_collision_mask(p_mask);
}
-void GodotPhysicsServer2D::area_set_collision_layer(RID p_area, uint32_t p_layer) {
+uint32_t GodotPhysicsServer2D::area_get_collision_mask(RID p_area) const {
GodotArea2D *area = area_owner.get_or_null(p_area);
- ERR_FAIL_COND(!area);
+ ERR_FAIL_COND_V(!area, 0);
- area->set_collision_layer(p_layer);
+ return area->get_collision_mask();
}
void GodotPhysicsServer2D::area_set_monitor_callback(RID p_area, const Callable &p_callback) {
@@ -951,10 +965,10 @@ int GodotPhysicsServer2D::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
-void GodotPhysicsServer2D::body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) {
+void GodotPhysicsServer2D::body_set_state_sync_callback(RID p_body, const Callable &p_callable) {
GodotBody2D *body = body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
- body->set_state_sync_callback(p_instance, p_callback);
+ body->set_state_sync_callback(p_callable);
}
void GodotPhysicsServer2D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
diff --git a/servers/physics_2d/godot_physics_server_2d.h b/servers/physics_2d/godot_physics_server_2d.h
index 20e492d87a..b96677700c 100644
--- a/servers/physics_2d/godot_physics_server_2d.h
+++ b/servers/physics_2d/godot_physics_server_2d.h
@@ -151,8 +151,12 @@ public:
virtual Variant area_get_param(RID p_area, AreaParameter p_param) const override;
virtual Transform2D area_get_transform(RID p_area) const override;
virtual void area_set_monitorable(RID p_area, bool p_monitorable) override;
- virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override;
+
virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override;
+ virtual uint32_t area_get_collision_layer(RID p_area) const override;
+
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override;
+ virtual uint32_t area_get_collision_mask(RID p_area) const override;
virtual void area_set_monitor_callback(RID p_area, const Callable &p_callback) override;
virtual void area_set_area_monitor_callback(RID p_area, const Callable &p_callback) override;
@@ -243,7 +247,7 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
- virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override;
+ virtual void body_set_state_sync_callback(RID p_body, const Callable &p_callable) override;
virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override;
diff --git a/servers/physics_3d/godot_body_3d.cpp b/servers/physics_3d/godot_body_3d.cpp
index b632f7f461..19f065c319 100644
--- a/servers/physics_3d/godot_body_3d.cpp
+++ b/servers/physics_3d/godot_body_3d.cpp
@@ -674,7 +674,7 @@ void GodotBody3D::integrate_velocities(real_t p_step) {
return;
}
- if (fi_callback_data || body_state_callback) {
+ if (fi_callback_data || body_state_callback.get_object()) {
get_space()->body_add_to_state_query_list(&direct_state_query_list);
}
@@ -756,11 +756,12 @@ void GodotBody3D::wakeup_neighbours() {
}
void GodotBody3D::call_queries() {
+ Variant direct_state_variant = get_direct_state();
+
if (fi_callback_data) {
if (!fi_callback_data->callable.get_object()) {
set_force_integration_callback(Callable());
} else {
- Variant direct_state_variant = get_direct_state();
const Variant *vp[2] = { &direct_state_variant, &fi_callback_data->udata };
Callable::CallError ce;
@@ -770,8 +771,11 @@ void GodotBody3D::call_queries() {
}
}
- if (body_state_callback_instance) {
- (body_state_callback)(body_state_callback_instance, get_direct_state());
+ if (body_state_callback.get_object()) {
+ const Variant *vp[1] = { &direct_state_variant };
+ Callable::CallError ce;
+ Variant rv;
+ body_state_callback.callp(vp, 1, rv, ce);
}
}
@@ -792,9 +796,8 @@ bool GodotBody3D::sleep_test(real_t p_step) {
}
}
-void GodotBody3D::set_state_sync_callback(void *p_instance, PhysicsServer3D::BodyStateCallback p_callback) {
- body_state_callback_instance = p_instance;
- body_state_callback = p_callback;
+void GodotBody3D::set_state_sync_callback(const Callable &p_callable) {
+ body_state_callback = p_callable;
}
void GodotBody3D::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
diff --git a/servers/physics_3d/godot_body_3d.h b/servers/physics_3d/godot_body_3d.h
index 2153ca4e91..412cbebc7d 100644
--- a/servers/physics_3d/godot_body_3d.h
+++ b/servers/physics_3d/godot_body_3d.h
@@ -131,8 +131,7 @@ class GodotBody3D : public GodotCollisionObject3D {
Vector<Contact> contacts; //no contacts by default
int contact_count = 0;
- void *body_state_callback_instance = nullptr;
- PhysicsServer3D::BodyStateCallback body_state_callback = nullptr;
+ Callable body_state_callback;
struct ForceIntegrationCallbackData {
Callable callable;
@@ -150,7 +149,7 @@ class GodotBody3D : public GodotCollisionObject3D {
friend class GodotPhysicsDirectBodyState3D; // i give up, too many functions to expose
public:
- void set_state_sync_callback(void *p_instance, PhysicsServer3D::BodyStateCallback p_callback);
+ void set_state_sync_callback(const Callable &p_callable);
void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
GodotPhysicsDirectBodyState3D *get_direct_state();
diff --git a/servers/physics_3d/godot_collision_solver_3d.cpp b/servers/physics_3d/godot_collision_solver_3d.cpp
index 094d77a582..9fe0e3eb84 100644
--- a/servers/physics_3d/godot_collision_solver_3d.cpp
+++ b/servers/physics_3d/godot_collision_solver_3d.cpp
@@ -370,12 +370,15 @@ bool GodotCollisionSolver3D::solve_static(const GodotShape3D *p_shape_A, const T
if (type_A == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) {
if (type_B == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) {
+ WARN_PRINT_ONCE("Collisions between world boundaries are not supported.");
return false;
}
if (type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY) {
+ WARN_PRINT_ONCE("Collisions between world boundaries and rays are not supported.");
return false;
}
if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) {
+ WARN_PRINT_ONCE("Collisions between world boundaries and soft bodies are not supported.");
return false;
}
@@ -387,6 +390,7 @@ bool GodotCollisionSolver3D::solve_static(const GodotShape3D *p_shape_A, const T
} else if (type_A == PhysicsServer3D::SHAPE_SEPARATION_RAY) {
if (type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY) {
+ WARN_PRINT_ONCE("Collisions between rays are not supported.");
return false;
}
@@ -398,7 +402,7 @@ bool GodotCollisionSolver3D::solve_static(const GodotShape3D *p_shape_A, const T
} else if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) {
if (type_A == PhysicsServer3D::SHAPE_SOFT_BODY) {
- // Soft Body / Soft Body not supported.
+ WARN_PRINT_ONCE("Collisions between soft bodies are not supported.");
return false;
}
@@ -410,6 +414,7 @@ bool GodotCollisionSolver3D::solve_static(const GodotShape3D *p_shape_A, const T
} else if (concave_B) {
if (concave_A) {
+ WARN_PRINT_ONCE("Collisions between two concave shapes are not supported.");
return false;
}
diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp
index b028c00a31..f3a589d469 100644
--- a/servers/physics_3d/godot_physics_server_3d.cpp
+++ b/servers/physics_3d/godot_physics_server_3d.cpp
@@ -387,6 +387,13 @@ void GodotPhysicsServer3D::area_set_collision_layer(RID p_area, uint32_t p_layer
area->set_collision_layer(p_layer);
}
+uint32_t GodotPhysicsServer3D::area_get_collision_layer(RID p_area) const {
+ GodotArea3D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, 0);
+
+ return area->get_collision_layer();
+}
+
void GodotPhysicsServer3D::area_set_collision_mask(RID p_area, uint32_t p_mask) {
GodotArea3D *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
@@ -394,6 +401,13 @@ void GodotPhysicsServer3D::area_set_collision_mask(RID p_area, uint32_t p_mask)
area->set_collision_mask(p_mask);
}
+uint32_t GodotPhysicsServer3D::area_get_collision_mask(RID p_area) const {
+ GodotArea3D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, 0);
+
+ return area->get_collision_mask();
+}
+
void GodotPhysicsServer3D::area_set_monitorable(RID p_area, bool p_monitorable) {
GodotArea3D *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
@@ -877,10 +891,10 @@ int GodotPhysicsServer3D::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
-void GodotPhysicsServer3D::body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) {
+void GodotPhysicsServer3D::body_set_state_sync_callback(RID p_body, const Callable &p_callable) {
GodotBody3D *body = body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
- body->set_state_sync_callback(p_instance, p_callback);
+ body->set_state_sync_callback(p_callable);
}
void GodotPhysicsServer3D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
diff --git a/servers/physics_3d/godot_physics_server_3d.h b/servers/physics_3d/godot_physics_server_3d.h
index b429f23a0c..e3e649da57 100644
--- a/servers/physics_3d/godot_physics_server_3d.h
+++ b/servers/physics_3d/godot_physics_server_3d.h
@@ -148,8 +148,11 @@ public:
virtual void area_set_ray_pickable(RID p_area, bool p_enable) override;
- virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override;
virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override;
+ virtual uint32_t area_get_collision_layer(RID p_area) const override;
+
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override;
+ virtual uint32_t area_get_collision_mask(RID p_area) const override;
virtual void area_set_monitorable(RID p_area, bool p_monitorable) override;
@@ -242,7 +245,7 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
- virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override;
+ virtual void body_set_state_sync_callback(RID p_body, const Callable &p_callable) override;
virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) override;
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index abaa473017..21be311637 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -652,7 +652,10 @@ void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("area_clear_shapes", "area"), &PhysicsServer2D::area_clear_shapes);
ClassDB::bind_method(D_METHOD("area_set_collision_layer", "area", "layer"), &PhysicsServer2D::area_set_collision_layer);
+ ClassDB::bind_method(D_METHOD("area_get_collision_layer", "area"), &PhysicsServer2D::area_get_collision_layer);
+
ClassDB::bind_method(D_METHOD("area_set_collision_mask", "area", "mask"), &PhysicsServer2D::area_set_collision_mask);
+ ClassDB::bind_method(D_METHOD("area_get_collision_mask", "area"), &PhysicsServer2D::area_get_collision_mask);
ClassDB::bind_method(D_METHOD("area_set_param", "area", "param", "value"), &PhysicsServer2D::area_set_param);
ClassDB::bind_method(D_METHOD("area_set_transform", "area", "transform"), &PhysicsServer2D::area_set_transform);
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index d5b4dc05e6..a3feb97d5d 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -332,8 +332,11 @@ public:
virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const = 0;
virtual Transform2D area_get_transform(RID p_area) const = 0;
- virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0;
virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) = 0;
+ virtual uint32_t area_get_collision_layer(RID p_area) const = 0;
+
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0;
+ virtual uint32_t area_get_collision_mask(RID p_area) const = 0;
virtual void area_set_monitorable(RID p_area, bool p_monitorable) = 0;
virtual void area_set_pickable(RID p_area, bool p_pickable) = 0;
@@ -470,10 +473,7 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0;
virtual bool body_is_omitting_force_integration(RID p_body) const = 0;
- // Callback for C++ use only.
- typedef void (*BodyStateCallback)(void *p_instance, PhysicsDirectBodyState2D *p_state);
- virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) = 0;
-
+ virtual void body_set_state_sync_callback(RID p_body, const Callable &p_callable) = 0;
virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0;
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) = 0;
@@ -490,7 +490,7 @@ public:
bool collide_separation_ray = false;
HashSet<RID> exclude_bodies;
HashSet<ObjectID> exclude_objects;
- bool recovery_as_collision = false;
+ bool recovery_as_collision = false; // Don't report margin recovery as collision by default, only used for floor snapping.
MotionParameters() {}
diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h
index d080aac438..14a6a5c2a1 100644
--- a/servers/physics_server_2d_wrap_mt.h
+++ b/servers/physics_server_2d_wrap_mt.h
@@ -156,8 +156,11 @@ public:
FUNC2RC(Variant, area_get_param, RID, AreaParameter);
FUNC1RC(Transform2D, area_get_transform, RID);
- FUNC2(area_set_collision_mask, RID, uint32_t);
FUNC2(area_set_collision_layer, RID, uint32_t);
+ FUNC1RC(uint32_t, area_get_collision_layer, RID);
+
+ FUNC2(area_set_collision_mask, RID, uint32_t);
+ FUNC1RC(uint32_t, area_get_collision_mask, RID);
FUNC2(area_set_monitorable, RID, bool);
FUNC2(area_set_pickable, RID, bool);
@@ -249,7 +252,7 @@ public:
FUNC2(body_set_omit_force_integration, RID, bool);
FUNC1RC(bool, body_is_omitting_force_integration, RID);
- FUNC3(body_set_state_sync_callback, RID, void *, BodyStateCallback);
+ FUNC2(body_set_state_sync_callback, RID, const Callable &);
FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &);
bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override {
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index b4f30d7649..24cc7e8459 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -720,7 +720,10 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("area_clear_shapes", "area"), &PhysicsServer3D::area_clear_shapes);
ClassDB::bind_method(D_METHOD("area_set_collision_layer", "area", "layer"), &PhysicsServer3D::area_set_collision_layer);
+ ClassDB::bind_method(D_METHOD("area_get_collision_layer", "area"), &PhysicsServer3D::area_get_collision_layer);
+
ClassDB::bind_method(D_METHOD("area_set_collision_mask", "area", "mask"), &PhysicsServer3D::area_set_collision_mask);
+ ClassDB::bind_method(D_METHOD("area_get_collision_mask", "area"), &PhysicsServer3D::area_get_collision_mask);
ClassDB::bind_method(D_METHOD("area_set_param", "area", "param", "value"), &PhysicsServer3D::area_set_param);
ClassDB::bind_method(D_METHOD("area_set_transform", "area", "transform"), &PhysicsServer3D::area_set_transform);
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 1308e4cd36..b21c4e9249 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -364,8 +364,11 @@ public:
virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const = 0;
virtual Transform3D area_get_transform(RID p_area) const = 0;
- virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0;
virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) = 0;
+ virtual uint32_t area_get_collision_layer(RID p_area) const = 0;
+
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0;
+ virtual uint32_t area_get_collision_mask(RID p_area) const = 0;
virtual void area_set_monitorable(RID p_area, bool p_monitorable) = 0;
@@ -508,10 +511,7 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0;
virtual bool body_is_omitting_force_integration(RID p_body) const = 0;
- // Callback for C++ use only.
- typedef void (*BodyStateCallback)(void *p_instance, PhysicsDirectBodyState3D *p_state);
- virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) = 0;
-
+ virtual void body_set_state_sync_callback(RID p_body, const Callable &p_callable) = 0;
virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) = 0;
@@ -527,7 +527,7 @@ public:
bool collide_separation_ray = false;
HashSet<RID> exclude_bodies;
HashSet<ObjectID> exclude_objects;
- bool recovery_as_collision = false;
+ bool recovery_as_collision = false; // Don't report margin recovery as collision by default, only used for floor snapping.
MotionParameters() {}
diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h
index ed4546b240..1d5fa95bfb 100644
--- a/servers/physics_server_3d_wrap_mt.h
+++ b/servers/physics_server_3d_wrap_mt.h
@@ -157,8 +157,11 @@ public:
FUNC2RC(Variant, area_get_param, RID, AreaParameter);
FUNC1RC(Transform3D, area_get_transform, RID);
- FUNC2(area_set_collision_mask, RID, uint32_t);
FUNC2(area_set_collision_layer, RID, uint32_t);
+ FUNC1RC(uint32_t, area_get_collision_layer, RID);
+
+ FUNC2(area_set_collision_mask, RID, uint32_t);
+ FUNC1RC(uint32_t, area_get_collision_mask, RID);
FUNC2(area_set_monitorable, RID, bool);
FUNC2(area_set_ray_pickable, RID, bool);
@@ -252,7 +255,7 @@ public:
FUNC2(body_set_omit_force_integration, RID, bool);
FUNC1RC(bool, body_is_omitting_force_integration, RID);
- FUNC3(body_set_state_sync_callback, RID, void *, BodyStateCallback);
+ FUNC2(body_set_state_sync_callback, RID, const Callable &);
FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &);
FUNC2(body_set_ray_pickable, RID, bool);
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index b9667f338c..1356fedb82 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -145,7 +145,6 @@ void register_server_types() {
GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionShapeResult, "RID rid;ObjectID collider_id;Object *collider;int shape");
GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionShapeRestInfo, "Vector2 point;Vector2 normal;RID rid;ObjectID collider_id;int shape;Vector2 linear_velocity");
GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionMotionResult, "Vector2 travel;Vector2 remainder;Vector2 collision_point;Vector2 collision_normal;Vector2 collider_velocity;real_t collision_depth;real_t collision_safe_fraction;real_t collision_unsafe_fraction;int collision_local_shape;ObjectID collider_id;RID collider;int collider_shape");
- GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionStateCallback, "void *instance;void (*callback)(void *p_instance, PhysicsDirectBodyState2D *p_state)");
GDREGISTER_CLASS(PhysicsServer3DManager);
Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3DManager", PhysicsServer3DManager::get_singleton(), "PhysicsServer3DManager"));
@@ -161,10 +160,14 @@ void register_server_types() {
GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionShapeRestInfo, "Vector3 point;Vector3 normal;RID rid;ObjectID collider_id;int shape;Vector3 linear_velocity");
GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionMotionCollision, "Vector3 position;Vector3 normal;Vector3 collider_velocity;real_t depth;int local_shape;ObjectID collider_id;RID collider;int collider_shape");
GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionMotionResult, "Vector3 travel;Vector3 remainder;real_t collision_safe_fraction;real_t collision_unsafe_fraction;PhysicsServer3DExtensionMotionCollision collisions[32];int collision_count");
- GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionStateCallback, "void *instance;void (*callback)(void *p_instance, PhysicsDirectBodyState3D *p_state)");
GDREGISTER_ABSTRACT_CLASS(NavigationServer2D);
GDREGISTER_ABSTRACT_CLASS(NavigationServer3D);
+ GDREGISTER_CLASS(NavigationPathQueryParameters2D);
+ GDREGISTER_CLASS(NavigationPathQueryParameters3D);
+ GDREGISTER_CLASS(NavigationPathQueryResult2D);
+ GDREGISTER_CLASS(NavigationPathQueryResult3D);
+
GDREGISTER_CLASS(XRServer);
GDREGISTER_CLASS(CameraServer);
diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h
index 4a2a947b94..e41373ed37 100644
--- a/servers/rendering/dummy/rasterizer_scene_dummy.h
+++ b/servers/rendering/dummy/rasterizer_scene_dummy.h
@@ -180,7 +180,7 @@ public:
void voxel_gi_set_quality(RS::VoxelGIQuality) override {}
- void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_info = nullptr) override {}
+ void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_info = nullptr) override {}
void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {}
void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) override {}
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index aa9772a483..c5818d9290 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -189,7 +189,7 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *
RenderingServerDefault::redraw_request();
}
- if (ci->commands != nullptr) {
+ if (ci->commands != nullptr || ci->copy_back_buffer) {
ci->final_transform = xform;
ci->final_modulate = modulate * ci->self_modulate;
ci->global_rect_cache = global_rect;
diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h
index 78d4ded617..8e04191e35 100644
--- a/servers/rendering/renderer_compositor.h
+++ b/servers/rendering/renderer_compositor.h
@@ -34,7 +34,7 @@
#include "servers/rendering/environment/renderer_fog.h"
#include "servers/rendering/environment/renderer_gi.h"
#include "servers/rendering/renderer_canvas_render.h"
-#include "servers/rendering/renderer_scene.h"
+#include "servers/rendering/rendering_method.h"
#include "servers/rendering/storage/camera_attributes_storage.h"
#include "servers/rendering/storage/light_storage.h"
#include "servers/rendering/storage/material_storage.h"
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index ceba43ae8f..307af99e91 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -1261,6 +1261,7 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P
light_data_dirty = true;
for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) {
sky_scene_state.directional_lights[i].enabled = false;
+ sky_scene_state.last_frame_directional_lights[i].enabled = false;
}
}
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 dec5e23558..35953a7120 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -477,6 +477,13 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
prev_material_uniform_set = material_uniform_set;
}
+ if ((surf->owner->base_flags & (INSTANCE_DATA_FLAG_MULTIMESH | INSTANCE_DATA_FLAG_PARTICLES)) == INSTANCE_DATA_FLAG_MULTIMESH) {
+ mesh_storage->_multimesh_get_motion_vectors_offsets(surf->owner->data->base, push_constant.multimesh_motion_vectors_current_offset, push_constant.multimesh_motion_vectors_previous_offset);
+ } else {
+ push_constant.multimesh_motion_vectors_current_offset = 0;
+ push_constant.multimesh_motion_vectors_previous_offset = 0;
+ }
+
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant));
uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : element_info.repeat;
@@ -574,47 +581,21 @@ void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_p
void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers;
+ RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID();
+ RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID();
- //Projection projection = p_render_data->cam_projection;
- //projection.flip_y(); // Vulkan and modern APIs use Y-Down
- Projection correction;
- correction.set_depth_correction(p_flip_y);
- correction.add_jitter_offset(p_render_data->taa_jitter);
- Projection projection = correction * p_render_data->cam_projection;
-
- //store camera into ubo
- RendererRD::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix);
- RendererRD::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
- RendererRD::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix);
- RendererRD::MaterialStorage::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.view_matrix);
-
- for (uint32_t v = 0; v < p_render_data->view_count; v++) {
- projection = correction * p_render_data->view_projection[v];
- RendererRD::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix_view[v]);
- RendererRD::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix_view[v]);
-
- scene_state.ubo.eye_offset[v][0] = p_render_data->view_eye_offset[v].x;
- scene_state.ubo.eye_offset[v][1] = p_render_data->view_eye_offset[v].y;
- scene_state.ubo.eye_offset[v][2] = p_render_data->view_eye_offset[v].z;
- scene_state.ubo.eye_offset[v][3] = 0.0;
+ // May do this earlier in RenderSceneRenderRD::render_scene
+ if (p_index >= (int)scene_state.uniform_buffers.size()) {
+ uint32_t from = scene_state.uniform_buffers.size();
+ scene_state.uniform_buffers.resize(p_index + 1);
+ for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) {
+ scene_state.uniform_buffers[i] = p_render_data->scene_data->create_uniform_buffer();
+ }
}
- scene_state.ubo.taa_jitter[0] = p_render_data->taa_jitter.x;
- scene_state.ubo.taa_jitter[1] = p_render_data->taa_jitter.y;
-
- scene_state.ubo.z_far = p_render_data->z_far;
- scene_state.ubo.z_near = p_render_data->z_near;
+ p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers);
- scene_state.ubo.pancake_shadows = p_pancake_shadows;
-
- RendererRD::MaterialStorage::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel);
-
- Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
- scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
- scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
+ // now do implementation UBO
scene_state.ubo.cluster_shift = get_shift_from_power_of_2(p_render_data->cluster_size);
scene_state.ubo.max_cluster_element_count_div_32 = p_render_data->cluster_max_elements / 32;
@@ -625,22 +606,8 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
scene_state.ubo.cluster_width = cluster_screen_width;
}
- if (p_render_data->shadow_atlas.is_valid()) {
- Vector2 sas = shadow_atlas_get_size(p_render_data->shadow_atlas);
- scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x;
- scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y;
- }
- {
- Vector2 dss = directional_shadow_get_size();
- scene_state.ubo.directional_shadow_pixel_size[0] = 1.0 / dss.x;
- scene_state.ubo.directional_shadow_pixel_size[1] = 1.0 / dss.y;
- }
- //time global variables
- scene_state.ubo.time = time;
-
scene_state.ubo.gi_upscale_for_msaa = false;
scene_state.ubo.volumetric_fog_enabled = false;
- scene_state.ubo.fog_enabled = false;
if (rd.is_valid()) {
if (rd->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
@@ -668,59 +635,8 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
}
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
- scene_state.ubo.use_ambient_light = true;
- scene_state.ubo.ambient_light_color_energy[0] = 1;
- scene_state.ubo.ambient_light_color_energy[1] = 1;
- scene_state.ubo.ambient_light_color_energy[2] = 1;
- scene_state.ubo.ambient_light_color_energy[3] = 1.0;
- scene_state.ubo.use_ambient_cubemap = false;
- scene_state.ubo.use_reflection_cubemap = false;
scene_state.ubo.ss_effects_flags = 0;
-
} else if (is_environment(p_render_data->environment)) {
- RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
- RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
-
- float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
-
- scene_state.ubo.ambient_light_color_energy[3] = bg_energy_multiplier;
-
- scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment);
-
- //ambient
- if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
- Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
- color = color.srgb_to_linear();
-
- scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier;
- scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier;
- scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier;
- scene_state.ubo.use_ambient_light = true;
- scene_state.ubo.use_ambient_cubemap = false;
- } else {
- float energy = environment_get_ambient_light_energy(p_render_data->environment);
- Color color = environment_get_ambient_light(p_render_data->environment);
- color = color.srgb_to_linear();
- scene_state.ubo.ambient_light_color_energy[0] = color.r * energy;
- scene_state.ubo.ambient_light_color_energy[1] = color.g * energy;
- scene_state.ubo.ambient_light_color_energy[2] = color.b * energy;
-
- Basis sky_transform = environment_get_sky_orientation(p_render_data->environment);
- sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis;
- RendererRD::MaterialStorage::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
-
- scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
- scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
- }
-
- //specular
- RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->environment);
- if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) {
- scene_state.ubo.use_reflection_cubemap = true;
- } else {
- scene_state.ubo.use_reflection_cubemap = false;
- }
-
scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_channel_affect(p_render_data->environment);
scene_state.ubo.ssao_light_affect = environment_get_ssao_direct_light_affect(p_render_data->environment);
uint32_t ss_flags = 0;
@@ -729,97 +645,19 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
ss_flags |= environment_get_ssil_enabled(p_render_data->environment) ? 2 : 0;
}
scene_state.ubo.ss_effects_flags = ss_flags;
-
- scene_state.ubo.fog_enabled = environment_get_fog_enabled(p_render_data->environment);
- scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment);
- scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment);
- scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
- scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);
-
- Color fog_color = environment_get_fog_light_color(p_render_data->environment).srgb_to_linear();
- float fog_energy = environment_get_fog_light_energy(p_render_data->environment);
-
- scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
- scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
- scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
-
- scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment);
-
} else {
- if (p_render_data->reflection_probe.is_valid() && RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
- scene_state.ubo.use_ambient_light = false;
- } else {
- scene_state.ubo.use_ambient_light = true;
- Color clear_color = p_default_bg_color;
- clear_color = clear_color.srgb_to_linear();
- scene_state.ubo.ambient_light_color_energy[0] = clear_color.r;
- scene_state.ubo.ambient_light_color_energy[1] = clear_color.g;
- scene_state.ubo.ambient_light_color_energy[2] = clear_color.b;
- scene_state.ubo.ambient_light_color_energy[3] = 1.0;
- }
-
- scene_state.ubo.use_ambient_cubemap = false;
- scene_state.ubo.use_reflection_cubemap = false;
scene_state.ubo.ss_effects_flags = 0;
}
- if (p_render_data->camera_attributes.is_valid()) {
- scene_state.ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
- scene_state.ubo.IBL_exposure_normalization = 1.0;
- if (is_environment(p_render_data->environment)) {
- RID sky_rid = environment_get_sky(p_render_data->environment);
- if (sky_rid.is_valid()) {
- float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes) * environment_get_bg_intensity(p_render_data->environment) / _render_buffers_get_luminance_multiplier();
- scene_state.ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, sky.sky_get_baked_exposure(sky_rid));
- }
- }
- } else if (scene_state.ubo.emissive_exposure_normalization > 0.0) {
- // This branch is triggered when using render_material().
- // Emissive is set outside the function, so don't set it.
- // IBL isn't used don't set it.
- } else {
- scene_state.ubo.emissive_exposure_normalization = 1.0;
- scene_state.ubo.IBL_exposure_normalization = 1.0;
- }
-
- scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active();
- scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount();
- scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit();
-
- if (rd.is_valid()) {
- if (rd->get_use_taa() || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
- memcpy(&scene_state.prev_ubo, &scene_state.ubo, sizeof(SceneState::UBO));
-
- Projection prev_correction;
- prev_correction.set_depth_correction(true);
- prev_correction.add_jitter_offset(p_render_data->prev_taa_jitter);
- Projection prev_projection = prev_correction * p_render_data->prev_cam_projection;
-
- //store camera into ubo
- RendererRD::MaterialStorage::store_camera(prev_projection, scene_state.prev_ubo.projection_matrix);
- RendererRD::MaterialStorage::store_camera(prev_projection.inverse(), scene_state.prev_ubo.inv_projection_matrix);
- RendererRD::MaterialStorage::store_transform(p_render_data->prev_cam_transform, scene_state.prev_ubo.inv_view_matrix);
- RendererRD::MaterialStorage::store_transform(p_render_data->prev_cam_transform.affine_inverse(), scene_state.prev_ubo.view_matrix);
-
- for (uint32_t v = 0; v < p_render_data->view_count; v++) {
- prev_projection = prev_correction * p_render_data->view_projection[v];
- RendererRD::MaterialStorage::store_camera(prev_projection, scene_state.prev_ubo.projection_matrix_view[v]);
- RendererRD::MaterialStorage::store_camera(prev_projection.inverse(), scene_state.prev_ubo.inv_projection_matrix_view[v]);
- }
- scene_state.prev_ubo.taa_jitter[0] = p_render_data->prev_taa_jitter.x;
- scene_state.prev_ubo.taa_jitter[1] = p_render_data->prev_taa_jitter.y;
- scene_state.prev_ubo.time -= time_step;
+ if (p_index >= (int)scene_state.implementation_uniform_buffers.size()) {
+ uint32_t from = scene_state.implementation_uniform_buffers.size();
+ scene_state.implementation_uniform_buffers.resize(p_index + 1);
+ for (uint32_t i = from; i < scene_state.implementation_uniform_buffers.size(); i++) {
+ scene_state.implementation_uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO));
}
}
- if (p_index >= (int)scene_state.uniform_buffers.size()) {
- uint32_t from = scene_state.uniform_buffers.size();
- scene_state.uniform_buffers.resize(p_index + 1);
- for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) {
- scene_state.uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO) * 2);
- }
- }
- RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO) * 2, &scene_state.ubo_data, RD::BARRIER_MASK_RASTER);
+ RD::get_singleton()->buffer_update(scene_state.implementation_uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
}
void RenderForwardClustered::_update_instance_data_buffer(RenderListType p_render_list) {
@@ -924,7 +762,7 @@ _FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primit
static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 };
return (p_indices - subtractor[p_primitive]) / divisor[p_primitive];
}
-void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi, bool p_using_opaque_gi, bool p_append) {
+void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, uint32_t p_color_pass_flags = 0, bool p_using_sdfgi, bool p_using_opaque_gi, bool p_append) {
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
if (p_render_list == RENDER_LIST_OPAQUE) {
@@ -935,9 +773,9 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
}
uint32_t lightmap_captures_used = 0;
- Plane near_plane = Plane(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->cam_transform.origin);
- near_plane.d += p_render_data->cam_projection.get_z_near();
- float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near();
+ Plane near_plane = Plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin);
+ near_plane.d += p_render_data->scene_data->cam_projection.get_z_near();
+ float z_max = p_render_data->scene_data->cam_projection.get_z_far() - p_render_data->scene_data->cam_projection.get_z_near();
RenderList *rl = &render_list[p_render_list];
_update_dirty_geometry_instances();
@@ -968,7 +806,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
float fade_alpha = 1.0;
if (inst->fade_near || inst->fade_far) {
- float fade_dist = inst->transform.origin.distance_to(p_render_data->cam_transform.origin);
+ float fade_dist = inst->transform.origin.distance_to(p_render_data->scene_data->cam_transform.origin);
// Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
if (inst->fade_far && fade_dist > inst->fade_far_begin) {
fade_alpha = Math::smoothstep(0.0f, 1.0f, 1.0f - (fade_dist - inst->fade_far_begin) / (inst->fade_far_end - inst->fade_far_begin));
@@ -1063,13 +901,13 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
// LOD
- if (p_render_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
+ if (p_render_data->scene_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
//lod
- Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal);
- Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal);
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->scene_data->lod_camera_plane.normal);
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->scene_data->lod_camera_plane.normal);
- float distance_min = p_render_data->lod_camera_plane.distance_to(lod_support_min);
- float distance_max = p_render_data->lod_camera_plane.distance_to(lod_support_max);
+ float distance_min = p_render_data->scene_data->lod_camera_plane.distance_to(lod_support_min);
+ float distance_max = p_render_data->scene_data->lod_camera_plane.distance_to(lod_support_max);
float distance = 0.0;
@@ -1082,12 +920,12 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
distance = -distance_max;
}
- if (p_render_data->cam_orthogonal) {
+ if (p_render_data->scene_data->cam_orthogonal) {
distance = 1.0;
}
uint32_t indices;
- surf->sort.lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices);
+ surf->sort.lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, &indices);
if (p_render_data->render_info) {
indices = _indices_to_primitives(surf->primitive, indices);
if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
@@ -1149,6 +987,12 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
scene_state.used_depth_texture = true;
}
+ if (p_color_pass_flags & COLOR_PASS_FLAG_MOTION_VECTORS) {
+ if ((flags & (INSTANCE_DATA_FLAG_MULTIMESH | INSTANCE_DATA_FLAG_PARTICLES)) == INSTANCE_DATA_FLAG_MULTIMESH && RendererRD::MeshStorage::get_singleton()->_multimesh_enable_motion_vectors(inst->data->base)) {
+ inst->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(inst->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ }
+ }
+
} else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) {
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) {
rl->add_element(surf);
@@ -1220,9 +1064,18 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RENDER_TIMESTAMP("Setup 3D Scene");
- //scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size;
- scene_state.ubo.directional_light_count = 0;
- scene_state.ubo.opaque_prepass_threshold = 0.99f;
+ // check if we need motion vectors
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
+ p_render_data->scene_data->calculate_motion_vectors = true;
+ } else if (rb.is_valid() && rb->get_use_taa()) {
+ p_render_data->scene_data->calculate_motion_vectors = true;
+ } else {
+ p_render_data->scene_data->calculate_motion_vectors = false;
+ }
+
+ //p_render_data->scene_data->subsurface_scatter_width = subsurface_scatter_size;
+ p_render_data->scene_data->directional_light_count = 0;
+ p_render_data->scene_data->opaque_prepass_threshold = 0.99f;
Size2i screen_size;
RID color_framebuffer;
@@ -1285,7 +1138,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
};
}
- if (p_render_data->view_count > 1) {
+ if (p_render_data->scene_data->view_count > 1) {
color_pass_flags |= COLOR_PASS_FLAG_MULTIVIEW;
}
@@ -1309,20 +1162,17 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
ERR_FAIL(); //bug?
}
- scene_state.ubo.viewport_size[0] = screen_size.x;
- scene_state.ubo.viewport_size[1] = screen_size.y;
-
- scene_state.ubo.emissive_exposure_normalization = -1.0;
+ p_render_data->scene_data->emissive_exposure_normalization = -1.0;
RD::get_singleton()->draw_command_begin_label("Render Setup");
- _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->cam_transform);
+ _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->scene_data->cam_transform);
_setup_voxelgis(*p_render_data->voxel_gi_instances);
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
_update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
- _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, using_sdfgi, using_sdfgi || using_voxelgi);
+ _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, color_pass_flags, using_sdfgi, using_sdfgi || using_voxelgi);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
_fill_instance_data(RENDER_LIST_OPAQUE, p_render_data->render_info ? p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE] : (int *)nullptr);
@@ -1396,20 +1246,20 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
RENDER_TIMESTAMP("Setup Sky");
RD::get_singleton()->draw_command_begin_label("Setup Sky");
- Projection projection = p_render_data->cam_projection;
+ Projection projection = p_render_data->scene_data->cam_projection;
if (p_render_data->reflection_probe.is_valid()) {
Projection correction;
correction.set_depth_correction(true);
- projection = correction * p_render_data->cam_projection;
+ projection = correction * p_render_data->scene_data->cam_projection;
}
- sky.setup(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->cam_transform, screen_size, this);
+ sky.setup(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->scene_data->cam_transform, screen_size, this);
sky_energy_multiplier *= bg_energy_multiplier;
RID sky_rid = environment_get_sky(p_render_data->environment);
if (sky_rid.is_valid()) {
- sky.update(p_render_data->environment, projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ sky.update(p_render_data->environment, projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
} else {
// do not try to draw sky if invalid
@@ -1448,7 +1298,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID());
bool finish_depth = using_ssao || using_sdfgi || using_voxelgi;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
_render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear);
RD::get_singleton()->draw_command_end_label();
@@ -1488,8 +1338,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_begin_label("Render Opaque Pass");
- scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
- scene_state.ubo.opaque_prepass_threshold = 0.0f;
+ p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count;
+ p_render_data->scene_data->opaque_prepass_threshold = 0.0f;
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, rb.is_valid());
@@ -1518,7 +1368,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
}
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
_render_list_with_threads(&render_list_params, color_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
if (will_continue_color && using_separate_specular) {
// close the specular framebuffer, as it's no longer used
@@ -1536,7 +1386,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
Projection dc;
dc.set_depth_correction(true);
- Projection cm = (dc * p_render_data->cam_projection) * Projection(p_render_data->cam_transform.affine_inverse());
+ Projection cm = (dc * p_render_data->scene_data->cam_projection) * Projection(p_render_data->scene_data->cam_transform.affine_inverse());
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
RD::get_singleton()->draw_command_begin_label("Debug VoxelGIs");
for (int i = 0; i < (int)p_render_data->voxel_gi_instances->size(); i++) {
@@ -1554,10 +1404,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
Projection dc;
dc.set_depth_correction(true);
Projection cms[RendererSceneRender::MAX_RENDER_VIEWS];
- for (uint32_t v = 0; v < p_render_data->view_count; v++) {
- cms[v] = (dc * p_render_data->view_projection[v]) * Projection(p_render_data->cam_transform.affine_inverse());
+ for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) {
+ cms[v] = (dc * p_render_data->scene_data->view_projection[v]) * Projection(p_render_data->scene_data->cam_transform.affine_inverse());
}
- _debug_sdfgi_probes(rb, color_only_framebuffer, p_render_data->view_count, cms, will_continue_color, will_continue_depth);
+ _debug_sdfgi_probes(rb, color_only_framebuffer, p_render_data->scene_data->view_count, cms, will_continue_color, will_continue_depth);
}
if (draw_sky || draw_sky_fog_only) {
@@ -1568,10 +1418,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (p_render_data->reflection_probe.is_valid()) {
Projection correction;
correction.set_depth_correction(true);
- Projection projection = correction * p_render_data->cam_projection;
- sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, 1, &projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ Projection projection = correction * p_render_data->scene_data->cam_projection;
+ sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
} else {
- sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
}
RD::get_singleton()->draw_command_end_label();
}
@@ -1598,7 +1448,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (using_sss) {
RENDER_TIMESTAMP("Sub-Surface Scattering");
RD::get_singleton()->draw_command_begin_label("Process Sub-Surface Scattering");
- _process_sss(rb, p_render_data->cam_projection);
+ _process_sss(rb, p_render_data->scene_data->cam_projection);
RD::get_singleton()->draw_command_end_label();
}
@@ -1606,15 +1456,15 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RENDER_TIMESTAMP("Screen-Space Reflections");
RD::get_singleton()->draw_command_begin_label("Process Screen-Space Reflections");
RID specular_views[RendererSceneRender::MAX_RENDER_VIEWS];
- for (uint32_t v = 0; v < p_render_data->view_count; v++) {
+ for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) {
specular_views[v] = rb_data->get_specular(v);
}
- _process_ssr(rb, color_only_framebuffer, normal_roughness_views, rb_data->get_specular(), specular_views, p_render_data->environment, p_render_data->view_projection, p_render_data->view_eye_offset, rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED);
+ _process_ssr(rb, color_only_framebuffer, normal_roughness_views, rb_data->get_specular(), specular_views, p_render_data->environment, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED);
RD::get_singleton()->draw_command_end_label();
} else {
//just mix specular back
RENDER_TIMESTAMP("Merge Specular");
- copy_effects->merge_specular(color_only_framebuffer, rb_data->get_specular(), rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED ? RID() : rb->get_internal_texture(), RID(), p_render_data->view_count);
+ copy_effects->merge_specular(color_only_framebuffer, rb_data->get_specular(), rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED ? RID() : rb->get_internal_texture(), RID(), p_render_data->scene_data->view_count);
}
}
@@ -1639,7 +1489,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
{
uint32_t transparent_color_pass_flags = (color_pass_flags | COLOR_PASS_FLAG_TRANSPARENT) & ~(COLOR_PASS_FLAG_SEPARATE_SPECULAR);
RID alpha_framebuffer = rb_data.is_valid() ? rb_data->get_color_pass_fb(transparent_color_pass_flags) : color_only_framebuffer;
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, transparent_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, transparent_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
_render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
}
@@ -1670,7 +1520,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (rb.is_valid() && taa && rb->get_use_taa()) {
RENDER_TIMESTAMP("TAA")
- taa->process(rb, _render_buffers_get_color_format(), p_render_data->z_near, p_render_data->z_far);
+ taa->process(rb, _render_buffers_get_color_format(), p_render_data->scene_data->z_near, p_render_data->scene_data->z_far);
}
if (rb.is_valid()) {
@@ -1691,39 +1541,41 @@ void RenderForwardClustered::_render_shadow_begin() {
scene_state.instance_data[RENDER_LIST_SECONDARY].clear();
}
-void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RendererScene::RenderInfo *p_render_info) {
+void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info) {
uint32_t shadow_pass_index = scene_state.shadow_passes.size();
SceneState::ShadowPass shadow_pass;
+ RenderSceneDataRD scene_data;
+ scene_data.cam_projection = p_projection;
+ scene_data.cam_transform = p_transform;
+ scene_data.view_projection[0] = p_projection;
+ scene_data.z_far = p_zfar;
+ scene_data.z_near = 0.0;
+ scene_data.lod_camera_plane = p_camera_plane;
+ scene_data.lod_distance_multiplier = p_lod_distance_multiplier;
+ scene_data.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
+ scene_data.opaque_prepass_threshold = 0.1f;
+
RenderDataRD render_data;
- render_data.cam_projection = p_projection;
- render_data.cam_transform = p_transform;
- render_data.view_projection[0] = p_projection;
- render_data.z_far = p_zfar;
- render_data.z_near = 0.0;
+ render_data.scene_data = &scene_data;
render_data.cluster_size = 1;
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
- render_data.lod_camera_plane = p_camera_plane;
- render_data.lod_distance_multiplier = p_lod_distance_multiplier;
render_data.render_info = p_render_info;
- scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
- scene_state.ubo.opaque_prepass_threshold = 0.1f;
-
_setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index);
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
- render_data.screen_mesh_lod_threshold = 0.0;
+ scene_data.screen_mesh_lod_threshold = 0.0;
} else {
- render_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
+ scene_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
}
PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW;
uint32_t render_list_from = render_list[RENDER_LIST_SECONDARY].elements.size();
- _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, false, false, true);
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, 0, false, false, true);
uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
_fill_instance_data(RENDER_LIST_SECONDARY, p_render_info ? p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW] : (int *)nullptr, render_list_from, render_list_size, false);
@@ -1742,8 +1594,8 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete
shadow_pass.camera_plane = p_camera_plane;
- shadow_pass.screen_mesh_lod_threshold = render_data.screen_mesh_lod_threshold;
- shadow_pass.lod_distance_multiplier = render_data.lod_distance_multiplier;
+ shadow_pass.screen_mesh_lod_threshold = scene_data.screen_mesh_lod_threshold;
+ shadow_pass.lod_distance_multiplier = scene_data.lod_distance_multiplier;
shadow_pass.framebuffer = p_framebuffer;
shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE);
@@ -1786,19 +1638,22 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
+ RenderSceneDataRD scene_data;
+ scene_data.cam_projection = p_cam_projection;
+ scene_data.cam_transform = p_cam_transform;
+ scene_data.view_projection[0] = p_cam_projection;
+ scene_data.z_near = 0.0;
+ scene_data.z_far = p_cam_projection.get_z_far();
+ scene_data.dual_paraboloid_side = 0;
+ scene_data.opaque_prepass_threshold = 0.0;
+
RenderDataRD render_data;
- render_data.cam_projection = p_cam_projection;
- render_data.cam_transform = p_cam_transform;
- render_data.view_projection[0] = p_cam_projection;
- render_data.z_near = 0.0;
- render_data.z_far = p_cam_projection.get_z_far();
+ render_data.scene_data = &scene_data;
render_data.cluster_size = 1;
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
_update_render_base_uniform_set();
- scene_state.ubo.dual_paraboloid_side = 0;
- scene_state.ubo.opaque_prepass_threshold = 0.0;
_setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false);
@@ -1825,21 +1680,23 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform
RD::get_singleton()->draw_command_begin_label("Render 3D Material");
+ RenderSceneDataRD scene_data;
+ scene_data.cam_projection = p_cam_projection;
+ scene_data.cam_transform = p_cam_transform;
+ scene_data.view_projection[0] = p_cam_projection;
+ scene_data.dual_paraboloid_side = 0;
+ scene_data.material_uv2_mode = false;
+ scene_data.opaque_prepass_threshold = 0.0f;
+ scene_data.emissive_exposure_normalization = p_exposure_normalization;
+
RenderDataRD render_data;
- render_data.cam_projection = p_cam_projection;
- render_data.cam_transform = p_cam_transform;
- render_data.view_projection[0] = p_cam_projection;
+ render_data.scene_data = &scene_data;
render_data.cluster_size = 1;
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
_update_render_base_uniform_set();
- scene_state.ubo.dual_paraboloid_side = 0;
- scene_state.ubo.material_uv2_mode = false;
- scene_state.ubo.opaque_prepass_threshold = 0.0f;
- scene_state.ubo.emissive_exposure_normalization = p_exposure_normalization;
-
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
@@ -1875,18 +1732,20 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance
RD::get_singleton()->draw_command_begin_label("Render UV2");
+ RenderSceneDataRD scene_data;
+ scene_data.dual_paraboloid_side = 0;
+ scene_data.material_uv2_mode = true;
+ scene_data.opaque_prepass_threshold = 0.0;
+ scene_data.emissive_exposure_normalization = -1.0;
+
RenderDataRD render_data;
+ render_data.scene_data = &scene_data;
render_data.cluster_size = 1;
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
_update_render_base_uniform_set();
- scene_state.ubo.dual_paraboloid_side = 0;
- scene_state.ubo.material_uv2_mode = true;
- scene_state.ubo.opaque_prepass_threshold = 0.0;
- scene_state.ubo.emissive_exposure_normalization = -1.0;
-
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
@@ -1946,7 +1805,10 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
RD::get_singleton()->draw_command_begin_label("Render SDFGI Voxel");
+ RenderSceneDataRD scene_data;
+
RenderDataRD render_data;
+ render_data.scene_data = &scene_data;
render_data.cluster_size = 1;
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
@@ -1987,26 +1849,26 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
fb_size.x = p_size[right_axis];
fb_size.y = p_size[up_axis];
- render_data.cam_transform.origin = center + axis * half_extents;
- render_data.cam_transform.basis.set_column(0, right);
- render_data.cam_transform.basis.set_column(1, up);
- render_data.cam_transform.basis.set_column(2, axis);
+ scene_data.cam_transform.origin = center + axis * half_extents;
+ scene_data.cam_transform.basis.set_column(0, right);
+ scene_data.cam_transform.basis.set_column(1, up);
+ scene_data.cam_transform.basis.set_column(2, axis);
- //print_line("pass: " + itos(i) + " xform " + render_data.cam_transform);
+ //print_line("pass: " + itos(i) + " xform " + scene_data.cam_transform);
float h_size = half_extents[right_axis];
float v_size = half_extents[up_axis];
float d_size = half_extents[i] * 2.0;
- render_data.cam_projection.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size);
+ scene_data.cam_projection.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size);
//print_line("pass: " + itos(i) + " cam hsize: " + rtos(h_size) + " vsize: " + rtos(v_size) + " dsize " + rtos(d_size));
Transform3D to_bounds;
to_bounds.origin = p_bounds.position;
to_bounds.basis.scale(p_bounds.size);
- RendererRD::MaterialStorage::store_transform(to_bounds.affine_inverse() * render_data.cam_transform, scene_state.ubo.sdf_to_bounds);
+ RendererRD::MaterialStorage::store_transform(to_bounds.affine_inverse() * scene_data.cam_transform, scene_state.ubo.sdf_to_bounds);
- scene_state.ubo.emissive_exposure_normalization = p_exposure_normalization;
+ scene_data.emissive_exposure_normalization = p_exposure_normalization;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture);
@@ -2248,6 +2110,13 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
{
RD::Uniform u;
u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.append_id(scene_state.implementation_uniform_buffers[p_index]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
RID instance_buffer = scene_state.instance_buffer[p_render_list];
if (instance_buffer == RID()) {
@@ -2264,16 +2133,15 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
}
RD::Uniform u;
- u.binding = 2;
+ u.binding = 3;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.append_id(radiance_texture);
uniforms.push_back(u);
}
-
{
RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID();
RD::Uniform u;
- u.binding = 3;
+ u.binding = 4;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
if (ref_texture.is_valid()) {
u.append_id(ref_texture);
@@ -2282,10 +2150,9 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
uniforms.push_back(u);
}
-
{
RD::Uniform u;
- u.binding = 4;
+ u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture;
if (p_render_data && p_render_data->shadow_atlas.is_valid()) {
@@ -2299,7 +2166,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 5;
+ u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) {
u.append_id(directional_shadow_get_texture());
@@ -2310,7 +2177,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 6;
+ u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
@@ -2329,7 +2196,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 7;
+ u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) {
@@ -2349,7 +2216,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
{
RD::Uniform u;
- u.binding = 8;
+ u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
RID cb = (p_render_data && p_render_data->cluster_buffer.is_valid()) ? p_render_data->cluster_buffer : scene_shader.default_vec4_xform_buffer;
u.append_id(cb);
@@ -2358,7 +2225,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
{
RD::Uniform u;
- u.binding = 9;
+ u.binding = 10;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture;
if (rb.is_valid() && rb->has_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH)) {
@@ -2371,7 +2238,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 10;
+ u.binding = 11;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID bbt = rb_data.is_valid() ? rb->get_back_buffer_texture() : RID();
RID texture = bbt.is_valid() ? bbt : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
@@ -2380,110 +2247,108 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
- {
- RD::Uniform u;
- u.binding = 11;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = rb_data.is_valid() && rb_data->has_normal_roughness() ? rb_data->get_normal_roughness() : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_NORMAL);
- u.append_id(texture);
- uniforms.push_back(u);
- }
+ RD::Uniform u;
+ u.binding = 12;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = rb_data.is_valid() && rb_data->has_normal_roughness() ? rb_data->get_normal_roughness() : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_NORMAL);
+ u.append_id(texture);
+ uniforms.push_back(u);
+ }
- {
- RD::Uniform u;
- u.binding = 12;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID aot = rb_data.is_valid() ? rb->get_ao_texture() : RID();
- RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
- u.append_id(texture);
- uniforms.push_back(u);
- }
+ {
+ RD::Uniform u;
+ u.binding = 13;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID aot = rb_data.is_valid() ? rb->get_ao_texture() : RID();
+ RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ u.append_id(texture);
+ uniforms.push_back(u);
+ }
- {
- RD::Uniform u;
- u.binding = 13;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
- u.append_id(texture);
- uniforms.push_back(u);
- }
+ {
+ RD::Uniform u;
+ u.binding = 14;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ u.append_id(texture);
+ uniforms.push_back(u);
+ }
- {
- RD::Uniform u;
- u.binding = 14;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
- u.append_id(texture);
- uniforms.push_back(u);
+ {
+ RD::Uniform u;
+ u.binding = 15;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ u.append_id(texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 16;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID t;
+ if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ t = sdfgi->lightprobe_texture;
}
- {
- RD::Uniform u;
- u.binding = 15;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID t;
- if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
- Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
- t = sdfgi->lightprobe_texture;
- }
- if (t.is_null()) {
- t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
- }
- u.append_id(t);
- uniforms.push_back(u);
+ if (t.is_null()) {
+ t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
}
- {
- RD::Uniform u;
- u.binding = 16;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID t;
- if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
- Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
- t = sdfgi->occlusion_texture;
- }
- if (t.is_null()) {
- t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
- }
- u.append_id(t);
- uniforms.push_back(u);
+ u.append_id(t);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 17;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID t;
+ if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ t = sdfgi->occlusion_texture;
}
- {
- RD::Uniform u;
- u.binding = 17;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- RID voxel_gi;
- if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_GI)) {
- Ref<RendererRD::GI::RenderBuffersGI> rbgi = rb->get_custom_data(RB_SCOPE_GI);
- voxel_gi = rbgi->get_voxel_gi_buffer();
- }
- u.append_id(voxel_gi.is_valid() ? voxel_gi : render_buffers_get_default_voxel_gi_buffer());
- uniforms.push_back(u);
+ if (t.is_null()) {
+ t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
}
- {
- RD::Uniform u;
- u.binding = 18;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID vfog = RID();
- if (rb_data.is_valid() && rb->has_custom_data(RB_SCOPE_FOG)) {
- Ref<RendererRD::Fog::VolumetricFog> fog = rb->get_custom_data(RB_SCOPE_FOG);
- vfog = fog->fog_map;
- if (vfog.is_null()) {
- vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
- }
- } else {
+ u.append_id(t);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 18;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ RID voxel_gi;
+ if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_GI)) {
+ Ref<RendererRD::GI::RenderBuffersGI> rbgi = rb->get_custom_data(RB_SCOPE_GI);
+ voxel_gi = rbgi->get_voxel_gi_buffer();
+ }
+ u.append_id(voxel_gi.is_valid() ? voxel_gi : render_buffers_get_default_voxel_gi_buffer());
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 19;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID vfog = RID();
+ if (rb_data.is_valid() && rb->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<RendererRD::Fog::VolumetricFog> fog = rb->get_custom_data(RB_SCOPE_FOG);
+ vfog = fog->fog_map;
+ if (vfog.is_null()) {
vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
}
- u.append_id(vfog);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 19;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID ssil = rb_data.is_valid() ? rb->get_ssil_texture() : RID();
- RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
- u.append_id(texture);
- uniforms.push_back(u);
+ } else {
+ vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
}
+ u.append_id(vfog);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 20;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID ssil = rb_data.is_valid() ? rb->get_ssil_texture() : RID();
+ RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ u.append_id(texture);
+ uniforms.push_back(u);
}
return UniformSetCacheRD::get_singleton()->get_cache_vec(scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET, uniforms);
@@ -2503,6 +2368,13 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
RD::Uniform u;
u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.append_id(scene_state.implementation_uniform_buffers[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
RID instance_buffer = scene_state.instance_buffer[RENDER_LIST_SECONDARY];
if (instance_buffer == RID()) {
@@ -2515,7 +2387,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
// No radiance texture.
RID radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
RD::Uniform u;
- u.binding = 2;
+ u.binding = 3;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.append_id(radiance_texture);
uniforms.push_back(u);
@@ -2525,7 +2397,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
// No reflection atlas.
RID ref_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK);
RD::Uniform u;
- u.binding = 3;
+ u.binding = 4;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.append_id(ref_texture);
uniforms.push_back(u);
@@ -2534,7 +2406,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
// No shadow atlas.
RD::Uniform u;
- u.binding = 4;
+ u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
u.append_id(texture);
@@ -2544,7 +2416,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
// No directional shadow atlas.
RD::Uniform u;
- u.binding = 5;
+ u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
u.append_id(texture);
@@ -2554,7 +2426,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
// No Lightmaps
RD::Uniform u;
- u.binding = 6;
+ u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
@@ -2568,7 +2440,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
// No VoxelGIs
RD::Uniform u;
- u.binding = 7;
+ u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
@@ -2581,7 +2453,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
RD::Uniform u;
- u.binding = 8;
+ u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
RID cb = scene_shader.default_vec4_xform_buffer;
u.append_id(cb);
@@ -2593,28 +2465,28 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 9;
+ u.binding = 10;
u.append_id(p_albedo_texture);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 10;
+ u.binding = 11;
u.append_id(p_emission_texture);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 11;
+ u.binding = 12;
u.append_id(p_emission_aniso_texture);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 12;
+ u.binding = 13;
u.append_id(p_geom_facing_texture);
uniforms.push_back(u);
}
@@ -2925,6 +2797,7 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p
ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
} else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_PARTICLES;
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
@@ -3195,6 +3068,9 @@ RenderForwardClustered::~RenderForwardClustered() {
for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) {
RD::get_singleton()->free(scene_state.uniform_buffers[i]);
}
+ for (uint32_t i = 0; i < scene_state.implementation_uniform_buffers.size(); i++) {
+ RD::get_singleton()->free(scene_state.implementation_uniform_buffers[i]);
+ }
RD::get_singleton()->free(scene_state.lightmap_buffer);
RD::get_singleton()->free(scene_state.lightmap_capture_buffer);
for (uint32_t i = 0; i < RENDER_LIST_MAX; i++) {
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index 35379cd69b..cde241f231 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -37,7 +37,7 @@
#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
-#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/utilities.h"
#define RB_SCOPE_FORWARD_CLUSTERED SNAME("forward_clustered")
@@ -231,13 +231,14 @@ class RenderForwardClustered : public RendererSceneRenderRD {
};
enum {
- INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5,
- INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6,
- INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7,
- INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
- INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
- INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
- INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11,
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
+ INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
+ INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 6,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 8,
+ INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 9,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 10,
+ INSTANCE_DATA_FLAG_PARTICLES = 1 << 11,
INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
@@ -249,61 +250,22 @@ class RenderForwardClustered : public RendererSceneRenderRD {
};
struct SceneState {
- // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code
+ // This struct is loaded into Set 1 - Binding 1, populated at start of rendering a frame, must match with shader code
struct UBO {
- float projection_matrix[16];
- float inv_projection_matrix[16];
- float inv_view_matrix[16];
- float view_matrix[16];
-
- float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
- float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
- float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4];
-
- float viewport_size[2];
- float screen_pixel_size[2];
-
uint32_t cluster_shift;
uint32_t cluster_width;
uint32_t cluster_type_size;
uint32_t max_cluster_element_count_div_32;
- float directional_penumbra_shadow_kernel[128]; //32 vec4s
- float directional_soft_shadow_kernel[128];
- float penumbra_shadow_kernel[128];
- float soft_shadow_kernel[128];
-
- float ambient_light_color_energy[4];
-
- float ambient_color_sky_mix;
- uint32_t use_ambient_light;
- uint32_t use_ambient_cubemap;
- uint32_t use_reflection_cubemap;
-
- float radiance_inverse_xform[12];
-
- float shadow_atlas_pixel_size[2];
- float directional_shadow_pixel_size[2];
-
- uint32_t directional_light_count;
- float dual_paraboloid_side;
- float z_far;
- float z_near;
-
uint32_t ss_effects_flags;
float ssao_light_affect;
float ssao_ao_affect;
- uint32_t roughness_limiter_enabled;
-
- float roughness_limiter_amount;
- float roughness_limiter_limit;
- float opaque_prepass_threshold;
- uint32_t roughness_limiter_pad;
+ uint32_t pad1;
float sdf_to_bounds[16];
int32_t sdf_offset[3];
- uint32_t material_uv2_mode;
+ uint32_t pad2;
int32_t sdf_size[3];
uint32_t gi_upscale_for_msaa;
@@ -312,32 +274,13 @@ class RenderForwardClustered : public RendererSceneRenderRD {
float volumetric_fog_inv_length;
float volumetric_fog_detail_spread;
uint32_t volumetric_fog_pad;
-
- // Fog
- uint32_t fog_enabled;
- float fog_density;
- float fog_height;
- float fog_height_density;
-
- float fog_light_color[3];
- float fog_sun_scatter;
-
- float fog_aerial_perspective;
-
- float time;
- float reflection_multiplier;
-
- uint32_t pancake_shadows;
-
- float taa_jitter[2];
- float emissive_exposure_normalization; // Needed to normalize emissive when using physical units.
- float IBL_exposure_normalization;
};
struct PushConstant {
uint32_t base_index; //
uint32_t uv_offset; //packed
- uint32_t pad[2];
+ uint32_t multimesh_motion_vectors_current_offset;
+ uint32_t multimesh_motion_vectors_previous_offset;
};
struct InstanceData {
@@ -350,11 +293,10 @@ class RenderForwardClustered : public RendererSceneRenderRD {
float lightmap_uv_scale[4];
};
- UBO ubo_data[2];
- UBO &ubo = ubo_data[0];
- UBO &prev_ubo = ubo_data[1];
+ UBO ubo;
LocalVector<RID> uniform_buffers;
+ LocalVector<RID> implementation_uniform_buffers;
LightmapData lightmaps[MAX_LIGHTMAPS];
RID lightmap_ids[MAX_LIGHTMAPS];
@@ -429,7 +371,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
void _update_instance_data_buffer(RenderListType p_render_list);
void _fill_instance_data(RenderListType p_render_list, int *p_render_info = nullptr, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
- void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, bool p_append = false);
+ void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, bool p_append = false);
HashMap<Size2i, RID> sdfgi_framebuffer_size_cache;
@@ -622,7 +564,7 @@ protected:
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
virtual void _render_shadow_begin() override;
- virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RendererScene::RenderInfo *p_render_info = nullptr) override;
+ virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr) override;
virtual void _render_shadow_process() override;
virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override;
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
index c2f56eb164..a9a9fa94de 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -32,7 +32,7 @@
#define SCENE_SHADER_FORWARD_CLUSTERED_H
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
-#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl.gen.h"
namespace RendererSceneRenderImplementation {
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 46d90e75fb..6c1b69148c 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -504,8 +504,20 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RENDER_TIMESTAMP("Setup 3D Scene");
- scene_state.ubo.directional_light_count = 0;
- scene_state.ubo.opaque_prepass_threshold = 0.0;
+ /* TODO
+ // check if we need motion vectors
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
+ p_render_data->scene_data->calculate_motion_vectors = true;
+ } else if (render target has velocity override) { // TODO
+ p_render_data->scene_data->calculate_motion_vectors = true;
+ } else {
+ p_render_data->scene_data->calculate_motion_vectors = false;
+ }
+ */
+ p_render_data->scene_data->calculate_motion_vectors = false; // for now, not yet supported...
+
+ p_render_data->scene_data->directional_light_count = 0;
+ p_render_data->scene_data->opaque_prepass_threshold = 0.0;
// We can only use our full subpass approach if we're:
// - not reading from SCREEN_TEXTURE/DEPTH_TEXTURE
@@ -581,13 +593,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
ERR_FAIL(); //bug?
}
- scene_state.ubo.viewport_size[0] = screen_size.x;
- scene_state.ubo.viewport_size[1] = screen_size.y;
- scene_state.ubo.emissive_exposure_normalization = -1.0;
+ p_render_data->scene_data->emissive_exposure_normalization = -1.0;
RD::get_singleton()->draw_command_begin_label("Render Setup");
- _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->cam_transform);
+ _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->scene_data->cam_transform);
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
_update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
@@ -658,20 +668,20 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
RENDER_TIMESTAMP("Setup Sky");
RD::get_singleton()->draw_command_begin_label("Setup Sky");
- Projection projection = p_render_data->cam_projection;
+ Projection projection = p_render_data->scene_data->cam_projection;
if (p_render_data->reflection_probe.is_valid()) {
Projection correction;
correction.set_depth_correction(true);
- projection = correction * p_render_data->cam_projection;
+ projection = correction * p_render_data->scene_data->cam_projection;
}
- sky.setup(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->cam_transform, screen_size, this);
+ sky.setup(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->scene_data->cam_transform, screen_size, this);
sky_energy_multiplier *= bg_energy_multiplier;
RID sky_rid = environment_get_sky(p_render_data->environment);
if (sky_rid.is_valid()) {
- sky.update(p_render_data->environment, projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ sky.update(p_render_data->environment, projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
} else {
// do not try to draw sky if invalid
@@ -694,10 +704,10 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (p_render_data->reflection_probe.is_valid()) {
Projection correction;
correction.set_depth_correction(true);
- Projection projection = correction * p_render_data->cam_projection;
- sky.update_res_buffers(p_render_data->environment, 1, &projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ Projection projection = correction * p_render_data->scene_data->cam_projection;
+ sky.update_res_buffers(p_render_data->environment, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
} else {
- sky.update_res_buffers(p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ sky.update_res_buffers(p_render_data->environment, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
}
RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
@@ -719,7 +729,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS;
}
- if (!is_environment(p_render_data->environment) || environment_get_fog_enabled(p_render_data->environment)) {
+ if (!is_environment(p_render_data->environment) || !environment_get_fog_enabled(p_render_data->environment)) {
spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_FOG;
}
}
@@ -734,7 +744,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RD::get_singleton()->draw_command_begin_label("Render Opaque Subpass");
- scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
+ p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count;
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid());
@@ -765,7 +775,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
render_list_params.framebuffer_format = fb_format;
if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
// secondary command buffers need more testing at this time
@@ -793,10 +803,10 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (p_render_data->reflection_probe.is_valid()) {
Projection correction;
correction.set_depth_correction(true);
- Projection projection = correction * p_render_data->cam_projection;
- sky.draw(draw_list, p_render_data->environment, framebuffer, 1, &projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ Projection projection = correction * p_render_data->scene_data->cam_projection;
+ sky.draw(draw_list, p_render_data->environment, framebuffer, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
} else {
- sky.draw(draw_list, p_render_data->environment, framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ sky.draw(draw_list, p_render_data->environment, framebuffer, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
}
RD::get_singleton()->draw_command_end_label(); // Draw Sky Subpass
@@ -832,7 +842,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (using_subpass_transparent) {
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR_TRANSPARENT, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR_TRANSPARENT, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
render_list_params.framebuffer_format = fb_format;
if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
// secondary command buffers need more testing at this time
@@ -871,7 +881,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
render_list_params.framebuffer_format = fb_format;
if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
// secondary command buffers need more testing at this time
@@ -919,7 +929,7 @@ void RenderForwardMobile::_render_shadow_begin() {
render_list[RENDER_LIST_SECONDARY].clear();
}
-void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RendererScene::RenderInfo *p_render_info) {
+void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info) {
uint32_t shadow_pass_index = scene_state.shadow_passes.size();
SceneState::ShadowPass shadow_pass;
@@ -928,26 +938,29 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_instances.size();
p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = p_instances.size();
}
+
+ RenderSceneDataRD scene_data;
+ scene_data.cam_projection = p_projection;
+ scene_data.cam_transform = p_transform;
+ scene_data.view_projection[0] = p_projection;
+ scene_data.z_near = 0.0;
+ scene_data.z_far = p_zfar;
+ scene_data.lod_camera_plane = p_camera_plane;
+ scene_data.lod_distance_multiplier = p_lod_distance_multiplier;
+ scene_data.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
+ scene_data.opaque_prepass_threshold = 0.1;
+
RenderDataRD render_data;
- render_data.cam_projection = p_projection;
- render_data.cam_transform = p_transform;
- render_data.view_projection[0] = p_projection;
- render_data.z_near = 0.0;
- render_data.z_far = p_zfar;
+ render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
render_data.render_info = p_render_info;
- render_data.lod_camera_plane = p_camera_plane;
- render_data.lod_distance_multiplier = p_lod_distance_multiplier;
-
- scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
- scene_state.ubo.opaque_prepass_threshold = 0.1;
_setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index);
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
- render_data.screen_mesh_lod_threshold = 0.0;
+ scene_data.screen_mesh_lod_threshold = 0.0;
} else {
- render_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
+ scene_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
}
PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW;
@@ -972,8 +985,8 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete
shadow_pass.camera_plane = p_camera_plane;
- shadow_pass.screen_mesh_lod_threshold = render_data.screen_mesh_lod_threshold;
- shadow_pass.lod_distance_multiplier = render_data.lod_distance_multiplier;
+ shadow_pass.screen_mesh_lod_threshold = scene_data.screen_mesh_lod_threshold;
+ shadow_pass.lod_distance_multiplier = scene_data.lod_distance_multiplier;
shadow_pass.framebuffer = p_framebuffer;
shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE);
@@ -1020,15 +1033,17 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
_update_render_base_uniform_set();
- scene_state.ubo.dual_paraboloid_side = 0;
- scene_state.ubo.material_uv2_mode = false;
- scene_state.ubo.opaque_prepass_threshold = 0.0f;
- scene_state.ubo.emissive_exposure_normalization = p_exposure_normalization;
+ RenderSceneDataRD scene_data;
+ scene_data.cam_projection = p_cam_projection;
+ scene_data.cam_transform = p_cam_transform;
+ scene_data.view_projection[0] = p_cam_projection;
+ scene_data.dual_paraboloid_side = 0;
+ scene_data.material_uv2_mode = false;
+ scene_data.opaque_prepass_threshold = 0.0f;
+ scene_data.emissive_exposure_normalization = p_exposure_normalization;
RenderDataRD render_data;
- render_data.cam_projection = p_cam_projection;
- render_data.cam_transform = p_cam_transform;
- render_data.view_projection[0] = p_cam_projection;
+ render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -1067,11 +1082,13 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
_update_render_base_uniform_set();
- scene_state.ubo.dual_paraboloid_side = 0;
- scene_state.ubo.material_uv2_mode = true;
- scene_state.ubo.emissive_exposure_normalization = -1.0;
+ RenderSceneDataRD scene_data;
+ scene_data.dual_paraboloid_side = 0;
+ scene_data.material_uv2_mode = true;
+ scene_data.emissive_exposure_normalization = -1.0;
RenderDataRD render_data;
+ render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -1138,15 +1155,18 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
_update_render_base_uniform_set();
- scene_state.ubo.dual_paraboloid_side = 0;
- scene_state.ubo.opaque_prepass_threshold = 0.0;
+
+ RenderSceneDataRD scene_data;
+ scene_data.cam_projection = p_cam_projection;
+ scene_data.cam_transform = p_cam_transform;
+ scene_data.view_projection[0] = p_cam_projection;
+ scene_data.z_near = 0.0;
+ scene_data.z_far = p_cam_projection.get_z_far();
+ scene_data.dual_paraboloid_side = 0;
+ scene_data.opaque_prepass_threshold = 0.0;
RenderDataRD render_data;
- render_data.cam_projection = p_cam_projection;
- render_data.cam_transform = p_cam_transform;
- render_data.view_projection[0] = p_cam_projection;
- render_data.z_near = 0.0;
- render_data.z_far = p_cam_projection.get_z_far();
+ render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
_setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false);
@@ -1385,9 +1405,9 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
}
uint32_t lightmap_captures_used = 0;
- Plane near_plane(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->cam_transform.origin);
- near_plane.d += p_render_data->cam_projection.get_z_near();
- float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near();
+ Plane near_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin);
+ near_plane.d += p_render_data->scene_data->cam_projection.get_z_near();
+ float z_max = p_render_data->scene_data->cam_projection.get_z_far() - p_render_data->scene_data->cam_projection.get_z_near();
RenderList *rl = &render_list[p_render_list];
@@ -1466,13 +1486,13 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
// LOD
- if (p_render_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
+ if (p_render_data->scene_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
//lod
- Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal);
- Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal);
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->scene_data->lod_camera_plane.normal);
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->scene_data->lod_camera_plane.normal);
- float distance_min = p_render_data->lod_camera_plane.distance_to(lod_support_min);
- float distance_max = p_render_data->lod_camera_plane.distance_to(lod_support_max);
+ float distance_min = p_render_data->scene_data->lod_camera_plane.distance_to(lod_support_min);
+ float distance_max = p_render_data->scene_data->lod_camera_plane.distance_to(lod_support_max);
float distance = 0.0;
@@ -1485,12 +1505,12 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
distance = -distance_max;
}
- if (p_render_data->cam_orthogonal) {
+ if (p_render_data->scene_data->cam_orthogonal) {
distance = 1.0;
}
uint32_t indices;
- surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices);
+ surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, &indices);
if (p_render_data->render_info) {
indices = _indices_to_primitives(surf->primitive, indices);
if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
@@ -1562,184 +1582,20 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
}
void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
- //!BAS! need to go through this and find out what we don't need anymore
-
- // This populates our UBO with main scene data that is pushed into set 1
-
- //Projection projection = p_render_data->cam_projection;
- //projection.flip_y(); // Vulkan and modern APIs use Y-Down
- Projection correction;
- correction.set_depth_correction(p_flip_y);
- Projection projection = correction * p_render_data->cam_projection;
-
- //store camera into ubo
- RendererRD::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix);
- RendererRD::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
- RendererRD::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix);
- RendererRD::MaterialStorage::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.view_matrix);
-
- for (uint32_t v = 0; v < p_render_data->view_count; v++) {
- projection = correction * p_render_data->view_projection[v];
- RendererRD::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix_view[v]);
- RendererRD::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix_view[v]);
-
- scene_state.ubo.eye_offset[v][0] = p_render_data->view_eye_offset[v].x;
- scene_state.ubo.eye_offset[v][1] = p_render_data->view_eye_offset[v].y;
- scene_state.ubo.eye_offset[v][2] = p_render_data->view_eye_offset[v].z;
- scene_state.ubo.eye_offset[v][3] = 0.0;
- }
-
- scene_state.ubo.z_far = p_render_data->z_far;
- scene_state.ubo.z_near = p_render_data->z_near;
-
- scene_state.ubo.pancake_shadows = p_pancake_shadows;
-
- RendererRD::MaterialStorage::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel);
-
- Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
- scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
- scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
-
- if (p_render_data->shadow_atlas.is_valid()) {
- Vector2 sas = shadow_atlas_get_size(p_render_data->shadow_atlas);
- scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x;
- scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y;
- }
- {
- Vector2 dss = directional_shadow_get_size();
- scene_state.ubo.directional_shadow_pixel_size[0] = 1.0 / dss.x;
- scene_state.ubo.directional_shadow_pixel_size[1] = 1.0 / dss.y;
- }
-
- //time global variables
- scene_state.ubo.time = time;
-
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
- scene_state.ubo.use_ambient_light = true;
- scene_state.ubo.ambient_light_color_energy[0] = 1;
- scene_state.ubo.ambient_light_color_energy[1] = 1;
- scene_state.ubo.ambient_light_color_energy[2] = 1;
- scene_state.ubo.ambient_light_color_energy[3] = 1.0;
- scene_state.ubo.use_ambient_cubemap = false;
- scene_state.ubo.use_reflection_cubemap = false;
- scene_state.ubo.ssao_enabled = false;
-
- } else if (is_environment(p_render_data->environment)) {
- RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
- RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
-
- float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
-
- scene_state.ubo.ambient_light_color_energy[3] = bg_energy_multiplier;
-
- scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment);
-
- //ambient
- if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
- Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
- color = color.srgb_to_linear();
-
- scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier;
- scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier;
- scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier;
- scene_state.ubo.use_ambient_light = true;
- scene_state.ubo.use_ambient_cubemap = false;
- } else {
- float energy = environment_get_ambient_light_energy(p_render_data->environment);
- Color color = environment_get_ambient_light(p_render_data->environment);
- color = color.srgb_to_linear();
- scene_state.ubo.ambient_light_color_energy[0] = color.r * energy;
- scene_state.ubo.ambient_light_color_energy[1] = color.g * energy;
- scene_state.ubo.ambient_light_color_energy[2] = color.b * energy;
-
- Basis sky_transform = environment_get_sky_orientation(p_render_data->environment);
- sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis;
- RendererRD::MaterialStorage::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
-
- scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
- scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
- }
-
- //specular
- RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->environment);
- if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) {
- scene_state.ubo.use_reflection_cubemap = true;
- } else {
- scene_state.ubo.use_reflection_cubemap = false;
- }
-
- scene_state.ubo.ssao_enabled = p_opaque_render_buffers && environment_get_ssao_enabled(p_render_data->environment);
- scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_channel_affect(p_render_data->environment);
- scene_state.ubo.ssao_light_affect = environment_get_ssao_direct_light_affect(p_render_data->environment);
-
- scene_state.ubo.fog_enabled = environment_get_fog_enabled(p_render_data->environment);
- scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment);
- scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment);
- scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
- scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);
-
- Color fog_color = environment_get_fog_light_color(p_render_data->environment).srgb_to_linear();
- float fog_energy = environment_get_fog_light_energy(p_render_data->environment);
-
- scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
- scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
- scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
-
- scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment);
-
- } else {
- if (p_render_data->reflection_probe.is_valid() && RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
- scene_state.ubo.use_ambient_light = false;
- } else {
- scene_state.ubo.use_ambient_light = true;
- Color clear_color = p_default_bg_color;
- clear_color = clear_color.srgb_to_linear();
- scene_state.ubo.ambient_light_color_energy[0] = clear_color.r;
- scene_state.ubo.ambient_light_color_energy[1] = clear_color.g;
- scene_state.ubo.ambient_light_color_energy[2] = clear_color.b;
- scene_state.ubo.ambient_light_color_energy[3] = 1.0;
- }
-
- scene_state.ubo.use_ambient_cubemap = false;
- scene_state.ubo.use_reflection_cubemap = false;
- scene_state.ubo.ssao_enabled = false;
- }
-
- if (p_render_data->camera_attributes.is_valid()) {
- scene_state.ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
- scene_state.ubo.IBL_exposure_normalization = 1.0;
- if (is_environment(p_render_data->environment)) {
- RID sky_rid = environment_get_sky(p_render_data->environment);
- if (sky_rid.is_valid()) {
- float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes) * environment_get_bg_intensity(p_render_data->environment) / _render_buffers_get_luminance_multiplier();
- scene_state.ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, sky.sky_get_baked_exposure(sky_rid));
- }
- }
- } else if (scene_state.ubo.emissive_exposure_normalization > 0.0) {
- // This branch is triggered when using render_material().
- // Emissive is set outside the function, so don't set it.
- // IBL isn't used don't set it.
- } else {
- scene_state.ubo.emissive_exposure_normalization = 1.0;
- scene_state.ubo.IBL_exposure_normalization = 1.0;
- }
-
- scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active();
- scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount();
- scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit();
+ Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers;
+ RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID();
+ RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID();
+ // May do this earlier in RenderSceneRenderRD::render_scene
if (p_index >= (int)scene_state.uniform_buffers.size()) {
uint32_t from = scene_state.uniform_buffers.size();
scene_state.uniform_buffers.resize(p_index + 1);
- render_pass_uniform_sets.resize(p_index + 1);
for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) {
- scene_state.uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO));
+ scene_state.uniform_buffers[i] = p_render_data->scene_data->create_uniform_buffer();
}
}
- RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
+
+ p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers);
}
void RenderForwardMobile::_fill_element_info(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements) {
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index da1cd85fb3..1b31d2749d 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -209,7 +209,7 @@ protected:
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
virtual void _render_shadow_begin() override;
- virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RendererScene::RenderInfo *p_render_info = nullptr) override;
+ virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr) override;
virtual void _render_shadow_process() override;
virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override;
@@ -252,75 +252,6 @@ protected:
/* Scene state */
struct SceneState {
- // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code
- struct UBO {
- float projection_matrix[16];
- float inv_projection_matrix[16];
- float inv_view_matrix[16];
- float view_matrix[16];
-
- float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
- float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
- float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4];
-
- float viewport_size[2];
- float screen_pixel_size[2];
-
- float directional_penumbra_shadow_kernel[128]; //32 vec4s
- float directional_soft_shadow_kernel[128];
- float penumbra_shadow_kernel[128];
- float soft_shadow_kernel[128];
-
- float ambient_light_color_energy[4];
-
- float ambient_color_sky_mix;
- uint32_t use_ambient_light;
- uint32_t use_ambient_cubemap;
- uint32_t use_reflection_cubemap;
-
- float radiance_inverse_xform[12];
-
- float shadow_atlas_pixel_size[2];
- float directional_shadow_pixel_size[2];
-
- uint32_t directional_light_count;
- float dual_paraboloid_side;
- float z_far;
- float z_near;
-
- uint32_t ssao_enabled;
- float ssao_light_affect;
- float ssao_ao_affect;
- uint32_t roughness_limiter_enabled;
-
- float roughness_limiter_amount;
- float roughness_limiter_limit;
- float opaque_prepass_threshold;
- uint32_t roughness_limiter_pad;
-
- // Fog
- uint32_t fog_enabled;
- float fog_density;
- float fog_height;
- float fog_height_density;
-
- float fog_light_color[3];
- float fog_sun_scatter;
-
- float fog_aerial_perspective;
- uint32_t material_uv2_mode;
-
- float time;
- float reflection_multiplier;
-
- uint32_t pancake_shadows;
- float emissive_exposure_normalization; // Needed to normalize emissive when using physical units.
- float IBL_exposure_normalization; // Adjusts for baked exposure.
- uint32_t pad3;
- };
-
- UBO ubo;
-
LocalVector<RID> uniform_buffers;
// !BAS! We need to change lightmaps, we're not going to do this with a buffer but pushing the used lightmap in
@@ -442,13 +373,14 @@ protected:
// check which ones of these apply, probably all except GI and SDFGI
enum {
- INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5,
- INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6,
- INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7,
- INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
- INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
- INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
- INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11,
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
+ INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
+ INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 6,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 8,
+ INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 9,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 10,
+ INSTANCE_DATA_FLAG_PARTICLES = 1 << 11,
INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index 21270d7c62..f67665a02f 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -32,7 +32,7 @@
#define SCENE_SHADER_FORWARD_MOBILE_H
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
-#include "servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl.gen.h"
namespace RendererSceneRenderImplementation {
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index ab3e3ebe51..0210151420 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -1362,9 +1362,12 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
default_repeat = p_default_repeat;
}
- //fill the list until rendering is possible.
- bool material_screen_texture_found = false;
Item *ci = p_item_list;
+
+ //fill the list until rendering is possible.
+ bool material_screen_texture_cached = false;
+ bool material_screen_texture_mipmaps_cached = false;
+
Rect2 back_buffer_rect;
bool backbuffer_copy = false;
bool backbuffer_gen_mipmaps = false;
@@ -1393,10 +1396,12 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
CanvasMaterialData *md = static_cast<CanvasMaterialData *>(material_storage->material_get_data(material, RendererRD::MaterialStorage::SHADER_TYPE_2D));
if (md && md->shader_data->valid) {
if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) {
- if (!material_screen_texture_found) {
+ if (!material_screen_texture_cached) {
backbuffer_copy = true;
back_buffer_rect = Rect2();
backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps;
+ } else if (!material_screen_texture_mipmaps_cached) {
+ backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps;
}
}
@@ -1486,7 +1491,15 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
backbuffer_copy = false;
backbuffer_gen_mipmaps = false;
- material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
+ material_screen_texture_cached = true; // After a backbuffer copy, screen texture makes no further copies.
+ material_screen_texture_mipmaps_cached = backbuffer_gen_mipmaps;
+ }
+
+ if (backbuffer_gen_mipmaps) {
+ texture_storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, back_buffer_rect);
+
+ backbuffer_gen_mipmaps = false;
+ material_screen_texture_mipmaps_cached = true;
}
items[item_count++] = ci;
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index e7abcf5674..f169692ea0 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -299,14 +299,19 @@ RendererCompositorRD::RendererCompositorRD() {
fog = memnew(RendererRD::Fog);
canvas = memnew(RendererCanvasRenderRD());
- back_end = (bool)(int)GLOBAL_GET("rendering/vulkan/rendering/back_end");
+ String rendering_method = GLOBAL_GET("rendering/renderer/rendering_method");
uint64_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
- if (back_end || textures_per_stage < 48) {
+ if (rendering_method == "mobile" || textures_per_stage < 48) {
scene = memnew(RendererSceneRenderImplementation::RenderForwardMobile());
- } else { // back_end == false
+ if (rendering_method == "forward_plus") {
+ WARN_PRINT_ONCE("Platform supports less than 48 textures per stage which is less than required by the Clustered renderer. Defaulting to Mobile renderer.");
+ }
+ } else if (rendering_method == "forward_plus") {
// default to our high end renderer
scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered());
+ } else {
+ ERR_FAIL_MSG("Cannot instantiate RenderingDevice-based renderer with renderer type " + rendering_method);
}
scene->init();
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index e2b06bc92f..ac1daad05c 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -1492,7 +1492,7 @@ void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataR
bool can_use_storage = _render_buffers_can_be_storage();
Size2i size = rb->get_internal_size();
- for (uint32_t v = 0; v < p_render_data->view_count; v++) {
+ for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) {
RID depth_texture = rb->get_depth_texture(v);
RID depth_back_texture = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH, v, 0);
@@ -1544,9 +1544,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
buffers.depth_texture = rb->get_depth_texture(i);
// In stereo p_render_data->z_near and p_render_data->z_far can be offset for our combined frustrum
- float z_near = p_render_data->view_projection[i].get_z_near();
- float z_far = p_render_data->view_projection[i].get_z_far();
- bokeh_dof->bokeh_dof_compute(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->cam_orthogonal);
+ float z_near = p_render_data->scene_data->view_projection[i].get_z_near();
+ float z_far = p_render_data->scene_data->view_projection[i].get_z_far();
+ bokeh_dof->bokeh_dof_compute(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->scene_data->cam_orthogonal);
};
} else {
// Set framebuffers.
@@ -1567,9 +1567,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
buffers.base_fb = FramebufferCacheRD::get_singleton()->get_cache(buffers.base_texture); // TODO move this into bokeh_dof_raster, we can do this internally
// In stereo p_render_data->z_near and p_render_data->z_far can be offset for our combined frustrum
- float z_near = p_render_data->view_projection[i].get_z_near();
- float z_far = p_render_data->view_projection[i].get_z_far();
- bokeh_dof->bokeh_dof_raster(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->cam_orthogonal);
+ float z_near = p_render_data->scene_data->view_projection[i].get_z_near();
+ float z_far = p_render_data->scene_data->view_projection[i].get_z_far();
+ bokeh_dof->bokeh_dof_raster(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->scene_data->cam_orthogonal);
}
}
RD::get_singleton()->draw_command_end_label();
@@ -2901,8 +2901,8 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
render_state.shadows.clear();
render_state.directional_shadows.clear();
- Plane camera_plane(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->cam_transform.origin);
- float lod_distance_multiplier = p_render_data->cam_projection.get_lod_multiplier();
+ Plane camera_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin);
+ float lod_distance_multiplier = p_render_data->scene_data->cam_projection.get_lod_multiplier();
{
for (int i = 0; i < render_state.render_shadow_count; i++) {
LightInstance *li = light_instance_owner.get_or_null(render_state.render_shadows[i].light);
@@ -2918,7 +2918,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//cube shadows are rendered in their own way
for (uint32_t i = 0; i < render_state.cube_shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info);
+ _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info);
}
if (render_state.directional_shadows.size()) {
@@ -2948,11 +2948,11 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//render directional shadows
for (uint32_t i = 0; i < render_state.directional_shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false, p_render_data->render_info);
+ _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false, p_render_data->render_info);
}
//render positional shadows
for (uint32_t i = 0; i < render_state.shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true, p_render_data->render_info);
+ _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true, p_render_data->render_info);
}
_render_shadow_process();
@@ -2960,7 +2960,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//start GI
if (render_gi) {
- gi.process_gi(p_render_data->render_buffers, p_normal_roughness_slices, p_voxel_gi_buffer, p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->view_eye_offset, p_render_data->cam_transform, *p_render_data->voxel_gi_instances);
+ gi.process_gi(p_render_data->render_buffers, p_normal_roughness_slices, p_voxel_gi_buffer, p_render_data->environment, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances);
}
//Do shadow rendering (in parallel with GI)
@@ -2999,17 +2999,17 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
}
RID depth_texture = rb->get_depth_texture();
- ss_effects->downsample_depth(depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, size, p_render_data->cam_projection);
+ ss_effects->downsample_depth(depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, size, p_render_data->scene_data->cam_projection);
}
if (p_use_ssao) {
// TODO make these proper stereo
- _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->cam_projection);
+ _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection);
}
if (p_use_ssil) {
// TODO make these proper stereo
- _process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->cam_projection, p_render_data->cam_transform);
+ _process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform);
}
}
@@ -3017,7 +3017,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL);
if (current_cluster_builder) {
- current_cluster_builder->begin(p_render_data->cam_transform, p_render_data->cam_projection, !p_render_data->reflection_probe.is_valid());
+ current_cluster_builder->begin(p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, !p_render_data->reflection_probe.is_valid());
}
bool using_shadows = true;
@@ -3028,13 +3028,13 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
}
} else {
//do not render reflections when rendering a reflection probe
- _setup_reflections(p_render_data, *p_render_data->reflection_probes, p_render_data->cam_transform.affine_inverse(), p_render_data->environment);
+ _setup_reflections(p_render_data, *p_render_data->reflection_probes, p_render_data->scene_data->cam_transform.affine_inverse(), p_render_data->environment);
}
uint32_t directional_light_count = 0;
uint32_t positional_light_count = 0;
- _setup_lights(p_render_data, *p_render_data->lights, p_render_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
- _setup_decals(*p_render_data->decals, p_render_data->cam_transform.affine_inverse());
+ _setup_lights(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
+ _setup_decals(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse());
p_render_data->directional_light_count = directional_light_count;
@@ -3051,12 +3051,12 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
}
}
if (is_volumetric_supported()) {
- _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count, *p_render_data->fog_volumes);
+ _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count, *p_render_data->fog_volumes);
}
}
}
-void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) {
+void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RenderingMethod::RenderInfo *r_render_info) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
// getting this here now so we can direct call a bunch of things more easily
@@ -3066,33 +3066,62 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
ERR_FAIL_COND(rb.is_null());
}
- //assign render data
- RenderDataRD render_data;
+ // setup scene data
+ RenderSceneDataRD scene_data;
{
- render_data.render_buffers = rb;
-
// Our first camera is used by default
- render_data.cam_transform = p_camera_data->main_transform;
- render_data.cam_projection = p_camera_data->main_projection;
- render_data.cam_orthogonal = p_camera_data->is_orthogonal;
- render_data.taa_jitter = p_camera_data->taa_jitter;
+ scene_data.cam_transform = p_camera_data->main_transform;
+ scene_data.cam_projection = p_camera_data->main_projection;
+ scene_data.cam_orthogonal = p_camera_data->is_orthogonal;
+ scene_data.taa_jitter = p_camera_data->taa_jitter;
- render_data.view_count = p_camera_data->view_count;
+ scene_data.view_count = p_camera_data->view_count;
for (uint32_t v = 0; v < p_camera_data->view_count; v++) {
- render_data.view_eye_offset[v] = p_camera_data->view_offset[v].origin;
- render_data.view_projection[v] = p_camera_data->view_projection[v];
+ scene_data.view_eye_offset[v] = p_camera_data->view_offset[v].origin;
+ scene_data.view_projection[v] = p_camera_data->view_projection[v];
}
- render_data.prev_cam_transform = p_prev_camera_data->main_transform;
- render_data.prev_cam_projection = p_prev_camera_data->main_projection;
- render_data.prev_taa_jitter = p_prev_camera_data->taa_jitter;
+ scene_data.prev_cam_transform = p_prev_camera_data->main_transform;
+ scene_data.prev_cam_projection = p_prev_camera_data->main_projection;
+ scene_data.prev_taa_jitter = p_prev_camera_data->taa_jitter;
for (uint32_t v = 0; v < p_camera_data->view_count; v++) {
- render_data.prev_view_projection[v] = p_prev_camera_data->view_projection[v];
+ scene_data.prev_view_projection[v] = p_prev_camera_data->view_projection[v];
+ }
+
+ scene_data.z_near = p_camera_data->main_projection.get_z_near();
+ scene_data.z_far = p_camera_data->main_projection.get_z_far();
+
+ // this should be the same for all cameras..
+ scene_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier();
+ scene_data.lod_camera_plane = Plane(-p_camera_data->main_transform.basis.get_column(Vector3::AXIS_Z), p_camera_data->main_transform.get_origin());
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
+ scene_data.screen_mesh_lod_threshold = 0.0;
+ } else {
+ scene_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
+ }
+
+ if (p_shadow_atlas.is_valid()) {
+ Vector2 sas = shadow_atlas_get_size(p_shadow_atlas);
+ scene_data.shadow_atlas_pixel_size.x = 1.0 / sas.x;
+ scene_data.shadow_atlas_pixel_size.y = 1.0 / sas.y;
}
+ {
+ Vector2 dss = directional_shadow_get_size();
+ scene_data.directional_shadow_pixel_size.x = 1.0 / dss.x;
+ scene_data.directional_shadow_pixel_size.y = 1.0 / dss.y;
+ }
+
+ scene_data.time = time;
+ scene_data.time_step = time_step;
+ }
- render_data.z_near = p_camera_data->main_projection.get_z_near();
- render_data.z_far = p_camera_data->main_projection.get_z_far();
+ //assign render data
+ RenderDataRD render_data;
+ {
+ render_data.render_buffers = rb;
+ render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
render_data.lights = &p_lights;
@@ -3108,16 +3137,6 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
render_data.reflection_probe = p_reflection_probe;
render_data.reflection_probe_pass = p_reflection_probe_pass;
- // this should be the same for all cameras..
- render_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier();
- render_data.lod_camera_plane = Plane(-p_camera_data->main_transform.basis.get_column(Vector3::AXIS_Z), p_camera_data->main_transform.get_origin());
-
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
- render_data.screen_mesh_lod_threshold = 0.0;
- } else {
- render_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
- }
-
render_state.render_shadows = p_render_shadows;
render_state.render_shadow_count = p_render_shadow_count;
render_state.render_sdfgi_regions = p_render_sdfgi_regions;
@@ -3134,7 +3153,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
render_data.voxel_gi_instances = &empty;
}
- //sdfgi first
+ // sdfgi first
if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
float exposure_normalization = 1.0;
@@ -3191,12 +3210,12 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
if (sdfgi.is_valid()) {
sdfgi->update_cascades();
- sdfgi->pre_process_gi(render_data.cam_transform, &render_data, this);
+ sdfgi->pre_process_gi(scene_data.cam_transform, &render_data, this);
sdfgi->update_light();
}
}
- gi.setup_voxel_gi_instances(&render_data, render_data.render_buffers, render_data.cam_transform, *render_data.voxel_gi_instances, render_state.voxel_gi_count, this);
+ gi.setup_voxel_gi_instances(&render_data, render_data.render_buffers, scene_data.cam_transform, *render_data.voxel_gi_instances, render_state.voxel_gi_count, this);
}
render_state.depth_prepass_used = false;
@@ -3246,7 +3265,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
view_rids.push_back(rb->get_internal_texture(v));
}
- sdfgi->debug_draw(render_data.view_count, render_data.view_projection, render_data.cam_transform, size.x, size.y, rb->get_render_target(), source_texture, view_rids);
+ sdfgi->debug_draw(scene_data.view_count, scene_data.view_projection, scene_data.cam_transform, size.x, size.y, rb->get_render_target(), source_texture, view_rids);
}
}
}
@@ -3278,12 +3297,12 @@ void RendererSceneRenderRD::_debug_draw_cluster(Ref<RenderSceneBuffersRD> p_rend
}
}
-void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RendererScene::RenderInfo *p_render_info) {
+void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info) {
LightInstance *light_instance = light_instance_owner.get_or_null(p_light);
ERR_FAIL_COND(!light_instance);
Rect2i atlas_rect;
- uint32_t atlas_size;
+ uint32_t atlas_size = 1;
RID atlas_fb;
bool using_dual_paraboloid = false;
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index d47394989f..82dc2fd09f 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -46,30 +46,14 @@
#include "servers/rendering/renderer_rd/environment/sky.h"
#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
-#include "servers/rendering/renderer_scene.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
+#include "servers/rendering/rendering_method.h"
struct RenderDataRD {
Ref<RenderSceneBuffersRD> render_buffers;
-
- Transform3D cam_transform;
- Projection cam_projection;
- Vector2 taa_jitter;
- bool cam_orthogonal = false;
-
- // For stereo rendering
- uint32_t view_count = 1;
- Vector3 view_eye_offset[RendererSceneRender::MAX_RENDER_VIEWS];
- Projection view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
-
- Transform3D prev_cam_transform;
- Projection prev_cam_projection;
- Vector2 prev_taa_jitter;
- Projection prev_view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
-
- float z_near = 0.0;
- float z_far = 0.0;
+ RenderSceneDataRD *scene_data;
const PagedArray<RenderGeometryInstance *> *instances = nullptr;
const PagedArray<RID> *lights = nullptr;
@@ -85,10 +69,6 @@ struct RenderDataRD {
RID reflection_probe;
int reflection_probe_pass = 0;
- float lod_distance_multiplier = 0.0;
- Plane lod_camera_plane;
- float screen_mesh_lod_threshold = 0.0;
-
RID cluster_buffer;
uint32_t cluster_size = 0;
uint32_t cluster_max_elements = 0;
@@ -96,7 +76,7 @@ struct RenderDataRD {
uint32_t directional_light_count = 0;
bool directional_light_soft_shadows = false;
- RendererScene::RenderInfo *render_info = nullptr;
+ RenderingMethod::RenderInfo *render_info = nullptr;
};
class RendererSceneRenderRD : public RendererSceneRender {
@@ -121,7 +101,7 @@ protected:
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0;
virtual void _render_shadow_begin() = 0;
- virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RendererScene::RenderInfo *p_render_info = nullptr) = 0;
+ virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr) = 0;
virtual void _render_shadow_process() = 0;
virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) = 0;
@@ -598,16 +578,9 @@ private:
uint64_t scene_pass = 0;
uint64_t shadow_atlas_realloc_tolerance_msec = 500;
- /* !BAS! is this used anywhere?
- struct SDFGICosineNeighbour {
- uint32_t neighbour;
- float weight;
- };
- */
-
uint32_t max_cluster_elements = 512;
- void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RendererScene::RenderInfo *p_render_info = nullptr);
+ void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr);
/* Volumetric Fog */
@@ -627,6 +600,10 @@ public:
RendererRD::GI *get_gi() { return &gi; }
+ /* SKY */
+
+ RendererRD::SkyRD *get_sky() { return &sky; }
+
/* SHADOW ATLAS API */
virtual RID shadow_atlas_create() override;
@@ -969,7 +946,7 @@ public:
virtual void update_uniform_sets(){};
- virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override;
+ virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) override;
virtual void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
diff --git a/servers/rendering/renderer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub
index d352743908..5405985741 100644
--- a/servers/rendering/renderer_rd/shaders/SCsub
+++ b/servers/rendering/renderer_rd/shaders/SCsub
@@ -18,3 +18,5 @@ if "RD_GLSL" in env["BUILDERS"]:
SConscript("effects/SCsub")
SConscript("environment/SCsub")
+SConscript("forward_clustered/SCsub")
+SConscript("forward_mobile/SCsub")
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 459d798a80..a3734a7218 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -597,7 +597,7 @@ void main() {
#ifdef MODE_LIGHT_ONLY
color = vec4(0.0);
-#else
+#elif !defined(MODE_UNSHADED)
color *= canvas_data.canvas_modulation;
#endif
diff --git a/servers/rendering/renderer_rd/shaders/effects/SCsub b/servers/rendering/renderer_rd/shaders/effects/SCsub
index 741da8fe69..f06a2d86e2 100644
--- a/servers/rendering/renderer_rd/shaders/effects/SCsub
+++ b/servers/rendering/renderer_rd/shaders/effects/SCsub
@@ -4,7 +4,7 @@ Import("env")
if "RD_GLSL" in env["BUILDERS"]:
# find all include files
- gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")]
# find all shader code(all glsl files excluding our include files)
glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
index bdf84bb03a..fe770ac065 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
@@ -186,6 +186,7 @@ void main() {
uv += pixel_size * 0.5; //half pixel to read centers
vec4 color = texture(color_texture, uv);
+ float initial_blur = color.a;
float accum = 1.0;
float radius = params.blur_scale;
@@ -193,8 +194,8 @@ void main() {
vec2 suv = uv + vec2(cos(ang), sin(ang)) * pixel_size * radius;
vec4 sample_color = texture(color_texture, suv);
float sample_size = abs(sample_color.a);
- if (sample_color.a > color.a) {
- sample_size = clamp(sample_size, 0.0, abs(color.a) * 2.0);
+ if (sample_color.a > initial_blur) {
+ sample_size = clamp(sample_size, 0.0, abs(initial_blur) * 2.0);
}
float m = smoothstep(radius - 0.5, radius + 0.5, sample_size);
diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
index a2bdc2e90e..1b487835d2 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
@@ -221,12 +221,9 @@ void main() {
vec4 sample_color = texture(source_color, uv_adj);
sample_color.a = texture(source_weight, uv_adj).r;
- float limit;
-
- if (sample_color.a < color.a) {
- limit = abs(sample_color.a);
- } else {
- limit = abs(color.a);
+ float limit = abs(sample_color.a);
+ if (sample_color.a > color.a) {
+ limit = clamp(limit, 0.0, abs(color.a) * 2.0);
}
limit -= DEPTH_GAP;
diff --git a/servers/rendering/renderer_rd/shaders/environment/SCsub b/servers/rendering/renderer_rd/shaders/environment/SCsub
index 741da8fe69..f06a2d86e2 100644
--- a/servers/rendering/renderer_rd/shaders/environment/SCsub
+++ b/servers/rendering/renderer_rd/shaders/environment/SCsub
@@ -4,7 +4,7 @@ Import("env")
if "RD_GLSL" in env["BUILDERS"]:
# find all include files
- gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")]
# find all shader code(all glsl files excluding our include files)
glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub b/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub
new file mode 100644
index 0000000000..f06a2d86e2
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+Import("env")
+
+if "RD_GLSL" in env["BUILDERS"]:
+ # find all include files
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")]
+
+ # find all shader code(all glsl files excluding our include files)
+ glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
+
+ # make sure we recompile shaders if include files change
+ env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#glsl_builders.py"])
+
+ # compile shaders
+ for glsl_file in glsl_files:
+ env.RD_GLSL(glsl_file)
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index 26b96b358f..d41474118d 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -129,7 +129,7 @@ invariant gl_Position;
#GLOBALS
-void vertex_shader(in uint instance_index, in bool is_multimesh, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) {
+void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) {
vec4 instance_custom = vec4(0.0);
#if defined(COLOR_USED)
color_interp = color_attrib;
@@ -208,7 +208,7 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in SceneData sc
}
}
- uint offset = stride * gl_InstanceIndex;
+ uint offset = stride * (gl_InstanceIndex + multimesh_offset);
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
@@ -326,10 +326,6 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in SceneData sc
vertex_interp = vertex;
-#ifdef MOTION_VECTORS
- screen_pos = projection_matrix * vec4(vertex_interp, 1.0);
-#endif
-
#ifdef NORMAL_USED
normal_interp = normal;
#endif
@@ -367,6 +363,10 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in SceneData sc
gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
#endif
+#ifdef MOTION_VECTORS
+ screen_pos = gl_Position;
+#endif
+
#ifdef MODE_RENDER_DEPTH
if (scene_data.pancake_shadows) {
if (gl_Position.z <= 0.00001) {
@@ -397,13 +397,13 @@ void main() {
mat4 model_matrix = instances.data[instance_index].transform;
#if defined(MOTION_VECTORS)
global_time = scene_data_block.prev_data.time;
- vertex_shader(instance_index, is_multimesh, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position);
+ vertex_shader(instance_index, is_multimesh, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position);
global_time = scene_data_block.data.time;
- vertex_shader(instance_index, is_multimesh, scene_data_block.data, model_matrix, screen_position);
+ vertex_shader(instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
#else
global_time = scene_data_block.data.time;
vec4 screen_position;
- vertex_shader(instance_index, is_multimesh, scene_data_block.data, model_matrix, screen_position);
+ vertex_shader(instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
#endif
}
@@ -553,7 +553,7 @@ layout(location = 0) out vec4 frag_color;
layout(location = 2) out vec2 motion_vector;
#endif
-#include "scene_forward_aa_inc.glsl"
+#include "../scene_forward_aa_inc.glsl"
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
@@ -562,20 +562,20 @@ layout(location = 2) out vec2 motion_vector;
#define SPECULAR_SCHLICK_GGX
#endif
-#include "scene_forward_lights_inc.glsl"
+#include "../scene_forward_lights_inc.glsl"
-#include "scene_forward_gi_inc.glsl"
+#include "../scene_forward_gi_inc.glsl"
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
#ifndef MODE_RENDER_DEPTH
vec4 volumetric_fog_process(vec2 screen_uv, float z) {
- vec3 fog_pos = vec3(screen_uv, z * scene_data_block.data.volumetric_fog_inv_length);
+ vec3 fog_pos = vec3(screen_uv, z * implementation_data.volumetric_fog_inv_length);
if (fog_pos.z < 0.0) {
return vec4(0.0);
} else if (fog_pos.z < 1.0) {
- fog_pos.z = pow(fog_pos.z, scene_data_block.data.volumetric_fog_detail_spread);
+ fog_pos.z = pow(fog_pos.z, implementation_data.volumetric_fog_detail_spread);
}
return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos);
@@ -821,7 +821,7 @@ void fragment_shader(in SceneData scene_data) {
fog = fog_process(vertex);
}
- if (scene_data.volumetric_fog_enabled) {
+ if (implementation_data.volumetric_fog_enabled) {
vec4 volumetric_fog = volumetric_fog_process(screen_uv, -vertex.z);
if (scene_data.fog_enabled) {
//must use the full blending equation here to blend fogs
@@ -849,8 +849,8 @@ void fragment_shader(in SceneData scene_data) {
#ifndef MODE_RENDER_DEPTH
- uvec2 cluster_pos = uvec2(gl_FragCoord.xy) >> scene_data.cluster_shift;
- uint cluster_offset = (scene_data.cluster_width * cluster_pos.y + cluster_pos.x) * (scene_data.max_cluster_element_count_div_32 + 32);
+ uvec2 cluster_pos = uvec2(gl_FragCoord.xy) >> implementation_data.cluster_shift;
+ uint cluster_offset = (implementation_data.cluster_width * cluster_pos.y + cluster_pos.x) * (implementation_data.max_cluster_element_count_div_32 + 32);
uint cluster_z = uint(clamp((-vertex.z / scene_data.z_far) * 32.0, 0.0, 31.0));
@@ -860,14 +860,14 @@ void fragment_shader(in SceneData scene_data) {
{ // process decals
- uint cluster_decal_offset = cluster_offset + scene_data.cluster_type_size * 2;
+ uint cluster_decal_offset = cluster_offset + implementation_data.cluster_type_size * 2;
uint item_min;
uint item_max;
uint item_from;
uint item_to;
- cluster_get_item_range(cluster_decal_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+ cluster_get_item_range(cluster_decal_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
item_from = subgroupBroadcastFirst(subgroupMin(item_from));
@@ -1256,7 +1256,7 @@ void fragment_shader(in SceneData scene_data) {
vec2 coord;
- if (scene_data.gi_upscale_for_msaa) {
+ if (implementation_data.gi_upscale_for_msaa) {
vec2 base_coord = screen_uv;
vec2 closest_coord = base_coord;
#ifdef USE_MULTIVIEW
@@ -1298,10 +1298,10 @@ void fragment_shader(in SceneData scene_data) {
}
#endif // !USE_LIGHTMAP
- if (bool(scene_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO)) {
+ if (bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO)) {
float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r;
ao = min(ao, ssao);
- ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect);
+ ao_light_affect = mix(ao_light_affect, max(ao_light_affect, implementation_data.ssao_light_affect), implementation_data.ssao_ao_affect);
}
{ // process reflections
@@ -1309,14 +1309,14 @@ void fragment_shader(in SceneData scene_data) {
vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
- uint cluster_reflection_offset = cluster_offset + scene_data.cluster_type_size * 3;
+ uint cluster_reflection_offset = cluster_offset + implementation_data.cluster_type_size * 3;
uint item_min;
uint item_max;
uint item_from;
uint item_to;
- cluster_get_item_range(cluster_reflection_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+ cluster_get_item_range(cluster_reflection_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
item_from = subgroupBroadcastFirst(subgroupMin(item_from));
@@ -1380,7 +1380,7 @@ void fragment_shader(in SceneData scene_data) {
// convert ao to direct light ao
ao = mix(1.0, ao, ao_light_affect);
- if (bool(scene_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL)) {
+ if (bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL)) {
vec4 ssil = textureLod(sampler2D(ssil_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv, 0.0);
ambient_light *= 1.0 - ssil.a;
ambient_light += ssil.rgb * albedo.rgb;
@@ -1748,7 +1748,7 @@ void fragment_shader(in SceneData scene_data) {
uint item_from;
uint item_to;
- cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+ cluster_get_item_range(cluster_omni_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
item_from = subgroupBroadcastFirst(subgroupMin(item_from));
@@ -1812,14 +1812,14 @@ void fragment_shader(in SceneData scene_data) {
{ //spot lights
- uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size;
+ uint cluster_spot_offset = cluster_offset + implementation_data.cluster_type_size;
uint item_min;
uint item_max;
uint item_from;
uint item_to;
- cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+ cluster_get_item_range(cluster_spot_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
item_from = subgroupBroadcastFirst(subgroupMin(item_from));
@@ -1909,8 +1909,8 @@ void fragment_shader(in SceneData scene_data) {
#ifdef MODE_RENDER_SDF
{
- vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz;
- ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size));
+ vec3 local_pos = (implementation_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz;
+ ivec3 grid_pos = implementation_data.sdf_offset + ivec3(local_pos * vec3(implementation_data.sdf_size));
uint albedo16 = 0x1; //solid flag
albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
index 45484b8c47..e8e2dce990 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
@@ -17,8 +17,9 @@
#extension GL_EXT_multiview : enable
#endif
-#include "cluster_data_inc.glsl"
-#include "decal_data_inc.glsl"
+#include "../cluster_data_inc.glsl"
+#include "../decal_data_inc.glsl"
+#include "../scene_data_inc.glsl"
#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
#ifndef NORMAL_USED
@@ -29,8 +30,8 @@
layout(push_constant, std430) uniform DrawCall {
uint instance_index;
uint uv_offset;
- uint pad0;
- uint pad1;
+ uint multimesh_motion_vectors_current_offset;
+ uint multimesh_motion_vectors_previous_offset;
}
draw_call;
@@ -38,7 +39,7 @@ draw_call;
/* Set 0: Base Pass (never changes) */
-#include "light_data_inc.glsl"
+#include "../light_data_inc.glsl"
#define SAMPLER_NEAREST_CLAMP 0
#define SAMPLER_LINEAR_CLAMP 1
@@ -175,62 +176,27 @@ sdfgi;
/* Set 1: Render Pass (changes per render pass) */
-struct SceneData {
- mat4 projection_matrix;
- mat4 inv_projection_matrix;
- mat4 inv_view_matrix;
- mat4 view_matrix;
-
- // only used for multiview
- mat4 projection_matrix_view[MAX_VIEWS];
- mat4 inv_projection_matrix_view[MAX_VIEWS];
- vec4 eye_offset[MAX_VIEWS];
-
- vec2 viewport_size;
- vec2 screen_pixel_size;
+layout(set = 1, binding = 0, std140) uniform SceneDataBlock {
+ SceneData data;
+ SceneData prev_data;
+}
+scene_data_block;
+struct ImplementationData {
uint cluster_shift;
uint cluster_width;
uint cluster_type_size;
uint max_cluster_element_count_div_32;
- // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted.
- vec4 directional_penumbra_shadow_kernel[32];
- vec4 directional_soft_shadow_kernel[32];
- vec4 penumbra_shadow_kernel[32];
- vec4 soft_shadow_kernel[32];
-
- vec4 ambient_light_color_energy;
-
- float ambient_color_sky_mix;
- bool use_ambient_light;
- bool use_ambient_cubemap;
- bool use_reflection_cubemap;
-
- mat3 radiance_inverse_xform;
-
- vec2 shadow_atlas_pixel_size;
- vec2 directional_shadow_pixel_size;
-
- uint directional_light_count;
- float dual_paraboloid_side;
- float z_far;
- float z_near;
-
uint ss_effects_flags;
float ssao_light_affect;
float ssao_ao_affect;
- bool roughness_limiter_enabled;
-
- float roughness_limiter_amount;
- float roughness_limiter_limit;
- float opaque_prepass_threshold;
- uint roughness_limiter_pad;
+ uint pad1;
mat4 sdf_to_bounds;
ivec3 sdf_offset;
- bool material_uv2_mode;
+ uint pad2;
ivec3 sdf_size;
bool gi_upscale_for_msaa;
@@ -239,31 +205,14 @@ struct SceneData {
float volumetric_fog_inv_length;
float volumetric_fog_detail_spread;
uint volumetric_fog_pad;
-
- bool fog_enabled;
- float fog_density;
- float fog_height;
- float fog_height_density;
-
- vec3 fog_light_color;
- float fog_sun_scatter;
-
- float fog_aerial_perspective;
-
- float time;
- float reflection_multiplier; // one normally, zero when rendering reflections
-
- bool pancake_shadows;
- vec2 taa_jitter;
- float emissive_exposure_normalization;
- float IBL_exposure_normalization;
};
-layout(set = 1, binding = 0, std140) uniform SceneDataBlock {
- SceneData data;
- SceneData prev_data;
+layout(set = 1, binding = 1, std140) uniform ImplementationDataBlock {
+ ImplementationData data;
}
-scene_data_block;
+implementation_data_block;
+
+#define implementation_data implementation_data_block.data
struct InstanceData {
mat4 transform;
@@ -275,42 +224,42 @@ struct InstanceData {
vec4 lightmap_uv_scale;
};
-layout(set = 1, binding = 1, std430) buffer restrict readonly InstanceDataBuffer {
+layout(set = 1, binding = 2, std430) buffer restrict readonly InstanceDataBuffer {
InstanceData data[];
}
instances;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
-layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap;
+layout(set = 1, binding = 3) uniform textureCubeArray radiance_cubemap;
#else
-layout(set = 1, binding = 2) uniform textureCube radiance_cubemap;
+layout(set = 1, binding = 3) uniform textureCube radiance_cubemap;
#endif
-layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas;
+layout(set = 1, binding = 4) uniform textureCubeArray reflection_atlas;
-layout(set = 1, binding = 4) uniform texture2D shadow_atlas;
+layout(set = 1, binding = 5) uniform texture2D shadow_atlas;
-layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas;
+layout(set = 1, binding = 6) uniform texture2D directional_shadow_atlas;
-layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
+layout(set = 1, binding = 7) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
-layout(set = 1, binding = 7) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
+layout(set = 1, binding = 8) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
-layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer {
+layout(set = 1, binding = 9, std430) buffer restrict readonly ClusterBuffer {
uint data[];
}
cluster_buffer;
#ifdef MODE_RENDER_SDF
-layout(r16ui, set = 1, binding = 9) uniform restrict writeonly uimage3D albedo_volume_grid;
-layout(r32ui, set = 1, binding = 10) uniform restrict writeonly uimage3D emission_grid;
-layout(r32ui, set = 1, binding = 11) uniform restrict writeonly uimage3D emission_aniso_grid;
-layout(r32ui, set = 1, binding = 12) uniform restrict uimage3D geom_facing_grid;
+layout(r16ui, set = 1, binding = 10) uniform restrict writeonly uimage3D albedo_volume_grid;
+layout(r32ui, set = 1, binding = 11) uniform restrict writeonly uimage3D emission_grid;
+layout(r32ui, set = 1, binding = 12) uniform restrict writeonly uimage3D emission_aniso_grid;
+layout(r32ui, set = 1, binding = 13) uniform restrict uimage3D geom_facing_grid;
//still need to be present for shaders that use it, so remap them to something
#define depth_buffer shadow_atlas
@@ -319,21 +268,21 @@ layout(r32ui, set = 1, binding = 12) uniform restrict uimage3D geom_facing_grid;
#else
-layout(set = 1, binding = 9) uniform texture2D depth_buffer;
-layout(set = 1, binding = 10) uniform texture2D color_buffer;
+layout(set = 1, binding = 10) uniform texture2D depth_buffer;
+layout(set = 1, binding = 11) uniform texture2D color_buffer;
#ifdef USE_MULTIVIEW
-layout(set = 1, binding = 11) uniform texture2DArray normal_roughness_buffer;
-layout(set = 1, binding = 13) uniform texture2DArray ambient_buffer;
-layout(set = 1, binding = 14) uniform texture2DArray reflection_buffer;
+layout(set = 1, binding = 12) uniform texture2DArray normal_roughness_buffer;
+layout(set = 1, binding = 14) uniform texture2DArray ambient_buffer;
+layout(set = 1, binding = 15) uniform texture2DArray reflection_buffer;
#else // USE_MULTIVIEW
-layout(set = 1, binding = 11) uniform texture2D normal_roughness_buffer;
-layout(set = 1, binding = 13) uniform texture2D ambient_buffer;
-layout(set = 1, binding = 14) uniform texture2D reflection_buffer;
+layout(set = 1, binding = 12) uniform texture2D normal_roughness_buffer;
+layout(set = 1, binding = 14) uniform texture2D ambient_buffer;
+layout(set = 1, binding = 15) uniform texture2D reflection_buffer;
#endif
-layout(set = 1, binding = 12) uniform texture2D ao_buffer;
-layout(set = 1, binding = 15) uniform texture2DArray sdfgi_lightprobe_texture;
-layout(set = 1, binding = 16) uniform texture3D sdfgi_occlusion_cascades;
+layout(set = 1, binding = 13) uniform texture2D ao_buffer;
+layout(set = 1, binding = 16) uniform texture2DArray sdfgi_lightprobe_texture;
+layout(set = 1, binding = 17) uniform texture3D sdfgi_occlusion_cascades;
struct VoxelGIData {
mat4 xform; // 64 - 64
@@ -350,14 +299,14 @@ struct VoxelGIData {
float exposure_normalization; // 4 - 112
};
-layout(set = 1, binding = 17, std140) uniform VoxelGIs {
+layout(set = 1, binding = 18, std140) uniform VoxelGIs {
VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
}
voxel_gi_instances;
-layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture;
+layout(set = 1, binding = 19) uniform texture3D volumetric_fog_texture;
-layout(set = 1, binding = 19) uniform texture2D ssil_buffer;
+layout(set = 1, binding = 20) uniform texture2D ssil_buffer;
#endif
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub b/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub
new file mode 100644
index 0000000000..f06a2d86e2
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+Import("env")
+
+if "RD_GLSL" in env["BUILDERS"]:
+ # find all include files
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")]
+
+ # find all shader code(all glsl files excluding our include files)
+ glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
+
+ # make sure we recompile shaders if include files change
+ env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#glsl_builders.py"])
+
+ # compile shaders
+ for glsl_file in glsl_files:
+ env.RD_GLSL(glsl_file)
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index 5a5ada7231..a109fd4d75 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -101,7 +101,7 @@ layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms
#ifdef MODE_DUAL_PARABOLOID
-layout(location = 8) out highp float dp_clip;
+layout(location = 9) out highp float dp_clip;
#endif
@@ -450,7 +450,7 @@ layout(location = 6) mediump in vec3 binormal_interp;
#ifdef MODE_DUAL_PARABOLOID
-layout(location = 8) highp in float dp_clip;
+layout(location = 9) highp in float dp_clip;
#endif
@@ -519,7 +519,7 @@ layout(location = 0) out mediump vec4 frag_color;
#endif // RENDER DEPTH
-#include "scene_forward_aa_inc.glsl"
+#include "../scene_forward_aa_inc.glsl"
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
@@ -528,7 +528,7 @@ layout(location = 0) out mediump vec4 frag_color;
#define SPECULAR_SCHLICK_GGX
#endif
-#include "scene_forward_lights_inc.glsl"
+#include "../scene_forward_lights_inc.glsl"
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
index 3a9c52f5bc..5e4999fa0f 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
@@ -5,7 +5,8 @@
#extension GL_EXT_multiview : enable
#endif
-#include "decal_data_inc.glsl"
+#include "../decal_data_inc.glsl"
+#include "../scene_data_inc.glsl"
#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
#ifndef NORMAL_USED
@@ -32,7 +33,7 @@ draw_call;
/* Set 0: Base Pass (never changes) */
-#include "light_data_inc.glsl"
+#include "../light_data_inc.glsl"
#define SAMPLER_NEAREST_CLAMP 0
#define SAMPLER_LINEAR_CLAMP 1
@@ -127,75 +128,9 @@ global_shader_uniforms;
/* Set 1: Render Pass (changes per render pass) */
-struct SceneData {
- highp mat4 projection_matrix;
- highp mat4 inv_projection_matrix;
- highp mat4 inv_view_matrix;
- highp mat4 view_matrix;
-
- // only used for multiview
- highp mat4 projection_matrix_view[MAX_VIEWS];
- highp mat4 inv_projection_matrix_view[MAX_VIEWS];
- highp vec4 eye_offset[MAX_VIEWS];
-
- highp vec2 viewport_size;
- highp vec2 screen_pixel_size;
-
- // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted.
- highp vec4 directional_penumbra_shadow_kernel[32];
- highp vec4 directional_soft_shadow_kernel[32];
- highp vec4 penumbra_shadow_kernel[32];
- highp vec4 soft_shadow_kernel[32];
-
- mediump vec4 ambient_light_color_energy;
-
- mediump float ambient_color_sky_mix;
- bool use_ambient_light;
- bool use_ambient_cubemap;
- bool use_reflection_cubemap;
-
- mediump mat3 radiance_inverse_xform;
-
- highp vec2 shadow_atlas_pixel_size;
- highp vec2 directional_shadow_pixel_size;
-
- uint directional_light_count;
- mediump float dual_paraboloid_side;
- highp float z_far;
- highp float z_near;
-
- bool ssao_enabled;
- mediump float ssao_light_affect;
- mediump float ssao_ao_affect;
- bool roughness_limiter_enabled;
-
- mediump float roughness_limiter_amount;
- mediump float roughness_limiter_limit;
- mediump float opaque_prepass_threshold;
- uint roughness_limiter_pad;
-
- bool fog_enabled;
- highp float fog_density;
- highp float fog_height;
- highp float fog_height_density;
-
- mediump vec3 fog_light_color;
- mediump float fog_sun_scatter;
-
- mediump float fog_aerial_perspective;
- bool material_uv2_mode;
-
- highp float time;
- mediump float reflection_multiplier; // one normally, zero when rendering reflections
-
- bool pancake_shadows;
- float emissive_exposure_normalization;
- float IBL_exposure_normalization;
- uint pad3;
-};
-
layout(set = 1, binding = 0, std140) uniform SceneDataBlock {
SceneData data;
+ SceneData prev_data;
}
scene_data_block;
diff --git a/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl
new file mode 100644
index 0000000000..048257e9ef
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl
@@ -0,0 +1,69 @@
+// Scene data stores all our 3D rendering globals for a frame such as our matrices
+// where this information is independent of the different RD implementations.
+// This enables us to use this UBO in our main scene render shaders but also in
+// effects that need access to this data.
+
+struct SceneData {
+ highp mat4 projection_matrix;
+ highp mat4 inv_projection_matrix;
+ highp mat4 inv_view_matrix;
+ highp mat4 view_matrix;
+
+ // only used for multiview
+ highp mat4 projection_matrix_view[MAX_VIEWS];
+ highp mat4 inv_projection_matrix_view[MAX_VIEWS];
+ highp vec4 eye_offset[MAX_VIEWS];
+
+ highp vec2 viewport_size;
+ highp vec2 screen_pixel_size;
+
+ // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted.
+ highp vec4 directional_penumbra_shadow_kernel[32];
+ highp vec4 directional_soft_shadow_kernel[32];
+ highp vec4 penumbra_shadow_kernel[32];
+ highp vec4 soft_shadow_kernel[32];
+
+ mediump mat3 radiance_inverse_xform;
+
+ mediump vec4 ambient_light_color_energy;
+
+ mediump float ambient_color_sky_mix;
+ bool use_ambient_light;
+ bool use_ambient_cubemap;
+ bool use_reflection_cubemap;
+
+ highp vec2 shadow_atlas_pixel_size;
+ highp vec2 directional_shadow_pixel_size;
+
+ uint directional_light_count;
+ mediump float dual_paraboloid_side;
+ highp float z_far;
+ highp float z_near;
+
+ bool roughness_limiter_enabled;
+ mediump float roughness_limiter_amount;
+ mediump float roughness_limiter_limit;
+ mediump float opaque_prepass_threshold;
+
+ bool fog_enabled;
+ highp float fog_density;
+ highp float fog_height;
+ highp float fog_height_density;
+
+ mediump vec3 fog_light_color;
+ mediump float fog_sun_scatter;
+
+ mediump float fog_aerial_perspective;
+ highp float time;
+ mediump float reflection_multiplier; // one normally, zero when rendering reflections
+ bool material_uv2_mode;
+
+ vec2 taa_jitter;
+ float emissive_exposure_normalization;
+ float IBL_exposure_normalization;
+
+ bool pancake_shadows;
+ uint pad1;
+ uint pad2;
+ uint pad3;
+};
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h
index 82d609291c..4b34cc74cb 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h
@@ -34,6 +34,7 @@
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
+#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/storage/light_storage.h"
#include "servers/rendering/storage/utilities.h"
@@ -235,7 +236,7 @@ public:
const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
- return light_owner.owns(light->projector);
+ return TextureStorage::get_singleton()->owns_texture(light->projector);
}
_FORCE_INLINE_ bool light_is_negative(RID p_light) const {
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index 49e3543ba5..1827b73507 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "mesh_storage.h"
+#include "../../rendering_server_globals.h"
using namespace RendererRD;
@@ -1211,7 +1212,13 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
if (multimesh->data_cache_dirty_regions) {
memdelete_arr(multimesh->data_cache_dirty_regions);
multimesh->data_cache_dirty_regions = nullptr;
- multimesh->data_cache_used_dirty_regions = 0;
+ multimesh->data_cache_dirty_region_count = 0;
+ }
+
+ if (multimesh->previous_data_cache_dirty_regions) {
+ memdelete_arr(multimesh->previous_data_cache_dirty_regions);
+ multimesh->previous_data_cache_dirty_regions = nullptr;
+ multimesh->previous_data_cache_dirty_region_count = 0;
}
multimesh->instances = p_instances;
@@ -1228,14 +1235,67 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
multimesh->aabb = AABB();
multimesh->aabb_dirty = false;
multimesh->visible_instances = MIN(multimesh->visible_instances, multimesh->instances);
+ multimesh->motion_vectors_current_offset = 0;
+ multimesh->motion_vectors_previous_offset = 0;
+ multimesh->motion_vectors_last_change = -1;
if (multimesh->instances) {
- multimesh->buffer = RD::get_singleton()->storage_buffer_create(multimesh->instances * multimesh->stride_cache * 4);
+ uint32_t buffer_size = multimesh->instances * multimesh->stride_cache * sizeof(float);
+ if (multimesh->motion_vectors_enabled) {
+ buffer_size *= 2;
+ }
+ multimesh->buffer = RD::get_singleton()->storage_buffer_create(buffer_size);
}
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH);
}
+bool MeshStorage::_multimesh_enable_motion_vectors(RID p_multimesh) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, false);
+
+ if (multimesh->motion_vectors_enabled) {
+ return false;
+ }
+
+ multimesh->motion_vectors_enabled = true;
+
+ multimesh->motion_vectors_current_offset = 0;
+ multimesh->motion_vectors_previous_offset = 0;
+ multimesh->motion_vectors_last_change = -1;
+
+ if (!multimesh->data_cache.is_empty()) {
+ multimesh->data_cache.append_array(multimesh->data_cache);
+ }
+
+ if (multimesh->buffer_set) {
+ RD::get_singleton()->barrier();
+ Vector<uint8_t> buffer_data = RD::get_singleton()->buffer_get_data(multimesh->buffer);
+ if (!multimesh->data_cache.is_empty()) {
+ memcpy(buffer_data.ptrw(), multimesh->data_cache.ptr(), buffer_data.size());
+ }
+
+ RD::get_singleton()->free(multimesh->buffer);
+ uint32_t buffer_size = multimesh->instances * multimesh->stride_cache * sizeof(float) * 2;
+ multimesh->buffer = RD::get_singleton()->storage_buffer_create(buffer_size);
+ RD::get_singleton()->buffer_update(multimesh->buffer, 0, buffer_data.size(), buffer_data.ptr(), RD::BARRIER_MASK_NO_BARRIER);
+ RD::get_singleton()->buffer_update(multimesh->buffer, buffer_data.size(), buffer_data.size(), buffer_data.ptr());
+ multimesh->uniform_set_3d = RID(); // Cleared by dependency
+ return true;
+ }
+ return false; // Update the transforms uniform set cache
+}
+
+void MeshStorage::_multimesh_get_motion_vectors_offsets(RID p_multimesh, uint32_t &r_current_offset, uint32_t &r_prev_offset) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ r_current_offset = multimesh->motion_vectors_current_offset;
+ if (RSG::rasterizer->get_frame_number() - multimesh->motion_vectors_last_change >= 2) {
+ multimesh->motion_vectors_previous_offset = multimesh->motion_vectors_current_offset;
+ }
+ r_prev_offset = multimesh->motion_vectors_previous_offset;
+}
+
int MeshStorage::multimesh_get_instance_count(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND_V(!multimesh, 0);
@@ -1261,7 +1321,7 @@ void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
//need to re-create AABB unfortunately, calling this has a penalty
if (multimesh->buffer_set) {
Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
- const uint8_t *r = buffer.ptr();
+ const uint8_t *r = buffer.ptr() + multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float);
const float *data = reinterpret_cast<const float *>(r);
_multimesh_re_create_aabb(multimesh, data, multimesh->instances);
}
@@ -1276,10 +1336,14 @@ void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const {
if (multimesh->data_cache.size() > 0) {
return; //already local
}
- ERR_FAIL_COND(multimesh->data_cache.size() > 0);
+
// this means that the user wants to load/save individual elements,
// for this, the data must reside on CPU, so just copy it there.
- multimesh->data_cache.resize(multimesh->instances * multimesh->stride_cache);
+ uint32_t buffer_size = multimesh->instances * multimesh->stride_cache;
+ if (multimesh->motion_vectors_enabled) {
+ buffer_size *= 2;
+ }
+ multimesh->data_cache.resize(buffer_size);
{
float *w = multimesh->data_cache.ptrw();
@@ -1290,15 +1354,48 @@ void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const {
memcpy(w, r, buffer.size());
}
} else {
- memset(w, 0, (size_t)multimesh->instances * multimesh->stride_cache * sizeof(float));
+ memset(w, 0, buffer_size * sizeof(float));
}
}
uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
multimesh->data_cache_dirty_regions = memnew_arr(bool, data_cache_dirty_region_count);
- for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
- multimesh->data_cache_dirty_regions[i] = false;
+ memset(multimesh->data_cache_dirty_regions, 0, data_cache_dirty_region_count * sizeof(bool));
+ multimesh->data_cache_dirty_region_count = 0;
+
+ multimesh->previous_data_cache_dirty_regions = memnew_arr(bool, data_cache_dirty_region_count);
+ memset(multimesh->previous_data_cache_dirty_regions, 0, data_cache_dirty_region_count * sizeof(bool));
+ multimesh->previous_data_cache_dirty_region_count = 0;
+}
+
+void MeshStorage::_multimesh_update_motion_vectors_data_cache(MultiMesh *multimesh) {
+ ERR_FAIL_COND(multimesh->data_cache.is_empty());
+
+ if (!multimesh->motion_vectors_enabled) {
+ return;
+ }
+
+ uint32_t frame = RSG::rasterizer->get_frame_number();
+ if (multimesh->motion_vectors_last_change != frame) {
+ multimesh->motion_vectors_previous_offset = multimesh->motion_vectors_current_offset;
+ multimesh->motion_vectors_current_offset = multimesh->instances - multimesh->motion_vectors_current_offset;
+ multimesh->motion_vectors_last_change = frame;
+
+ if (multimesh->previous_data_cache_dirty_region_count > 0) {
+ uint8_t *data = (uint8_t *)multimesh->data_cache.ptrw();
+ uint32_t current_ofs = multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float);
+ uint32_t previous_ofs = multimesh->motion_vectors_previous_offset * multimesh->stride_cache * sizeof(float);
+ uint32_t visible_instances = multimesh->visible_instances >= 0 ? multimesh->visible_instances : multimesh->instances;
+ uint32_t visible_region_count = visible_instances == 0 ? 0 : (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+ uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float);
+ uint32_t size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float);
+ for (uint32_t i = 0; i < visible_region_count; i++) {
+ if (multimesh->previous_data_cache_dirty_regions[i]) {
+ uint32_t offset = i * region_size;
+ memcpy(data + current_ofs + offset, data + previous_ofs + offset, MIN(region_size, size - offset));
+ }
+ }
+ }
}
- multimesh->data_cache_used_dirty_regions = 0;
}
void MeshStorage::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) {
@@ -1309,7 +1406,7 @@ void MeshStorage::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool
#endif
if (!multimesh->data_cache_dirty_regions[region_index]) {
multimesh->data_cache_dirty_regions[region_index] = true;
- multimesh->data_cache_used_dirty_regions++;
+ multimesh->data_cache_dirty_region_count++;
}
if (p_aabb) {
@@ -1330,7 +1427,7 @@ void MeshStorage::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, b
for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
if (!multimesh->data_cache_dirty_regions[i]) {
multimesh->data_cache_dirty_regions[i] = true;
- multimesh->data_cache_used_dirty_regions++;
+ multimesh->data_cache_dirty_region_count++;
}
}
}
@@ -1395,11 +1492,12 @@ void MeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index,
ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D);
_multimesh_make_local(multimesh);
+ _multimesh_update_motion_vectors_data_cache(multimesh);
{
float *w = multimesh->data_cache.ptrw();
- float *dataptr = w + p_index * multimesh->stride_cache;
+ float *dataptr = w + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache;
dataptr[0] = p_transform.basis.rows[0][0];
dataptr[1] = p_transform.basis.rows[0][1];
@@ -1425,11 +1523,12 @@ void MeshStorage::multimesh_instance_set_transform_2d(RID p_multimesh, int p_ind
ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D);
_multimesh_make_local(multimesh);
+ _multimesh_update_motion_vectors_data_cache(multimesh);
{
float *w = multimesh->data_cache.ptrw();
- float *dataptr = w + p_index * multimesh->stride_cache;
+ float *dataptr = w + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache;
dataptr[0] = p_transform.columns[0][0];
dataptr[1] = p_transform.columns[1][0];
@@ -1451,11 +1550,12 @@ void MeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, con
ERR_FAIL_COND(!multimesh->uses_colors);
_multimesh_make_local(multimesh);
+ _multimesh_update_motion_vectors_data_cache(multimesh);
{
float *w = multimesh->data_cache.ptrw();
- float *dataptr = w + p_index * multimesh->stride_cache + multimesh->color_offset_cache;
+ float *dataptr = w + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache + multimesh->color_offset_cache;
dataptr[0] = p_color.r;
dataptr[1] = p_color.g;
@@ -1473,11 +1573,12 @@ void MeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_inde
ERR_FAIL_COND(!multimesh->uses_custom_data);
_multimesh_make_local(multimesh);
+ _multimesh_update_motion_vectors_data_cache(multimesh);
{
float *w = multimesh->data_cache.ptrw();
- float *dataptr = w + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache;
+ float *dataptr = w + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache + multimesh->custom_data_offset_cache;
dataptr[0] = p_color.r;
dataptr[1] = p_color.g;
@@ -1514,7 +1615,7 @@ Transform3D MeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p
{
const float *r = multimesh->data_cache.ptr();
- const float *dataptr = r + p_index * multimesh->stride_cache;
+ const float *dataptr = r + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache;
t.basis.rows[0][0] = dataptr[0];
t.basis.rows[0][1] = dataptr[1];
@@ -1545,7 +1646,7 @@ Transform2D MeshStorage::multimesh_instance_get_transform_2d(RID p_multimesh, in
{
const float *r = multimesh->data_cache.ptr();
- const float *dataptr = r + p_index * multimesh->stride_cache;
+ const float *dataptr = r + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache;
t.columns[0][0] = dataptr[0];
t.columns[1][0] = dataptr[1];
@@ -1570,7 +1671,7 @@ Color MeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) co
{
const float *r = multimesh->data_cache.ptr();
- const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->color_offset_cache;
+ const float *dataptr = r + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache + multimesh->color_offset_cache;
c.r = dataptr[0];
c.g = dataptr[1];
@@ -1593,7 +1694,7 @@ Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_ind
{
const float *r = multimesh->data_cache.ptr();
- const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache;
+ const float *dataptr = r + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache + multimesh->custom_data_offset_cache;
c.r = dataptr[0];
c.g = dataptr[1];
@@ -1609,25 +1710,26 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b
ERR_FAIL_COND(!multimesh);
ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache));
+ if (multimesh->motion_vectors_enabled) {
+ uint32_t frame = RSG::rasterizer->get_frame_number();
+
+ if (multimesh->motion_vectors_last_change != frame) {
+ multimesh->motion_vectors_previous_offset = multimesh->motion_vectors_current_offset;
+ multimesh->motion_vectors_current_offset = multimesh->instances - multimesh->motion_vectors_current_offset;
+ multimesh->motion_vectors_last_change = frame;
+ }
+ }
+
{
const float *r = p_buffer.ptr();
- RD::get_singleton()->buffer_update(multimesh->buffer, 0, p_buffer.size() * sizeof(float), r);
+ RD::get_singleton()->buffer_update(multimesh->buffer, multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float), p_buffer.size() * sizeof(float), r);
multimesh->buffer_set = true;
}
if (multimesh->data_cache.size()) {
- //if we have a data cache, just update it
- multimesh->data_cache = p_buffer;
- {
- //clear dirty since nothing will be dirty anymore
- uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
- for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
- multimesh->data_cache_dirty_regions[i] = false;
- }
- multimesh->data_cache_used_dirty_regions = 0;
- }
-
- _multimesh_mark_all_dirty(multimesh, false, true); //update AABB
+ float *cache_data = multimesh->data_cache.ptrw();
+ memcpy(cache_data + (multimesh->motion_vectors_current_offset * multimesh->stride_cache), p_buffer.ptr(), p_buffer.size() * sizeof(float));
+ _multimesh_mark_all_dirty(multimesh, true, true); //update AABB
} else if (multimesh->mesh.is_valid()) {
//if we have a mesh set, we need to re-generate the AABB from the new data
const float *data = p_buffer.ptr();
@@ -1642,20 +1744,19 @@ Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
ERR_FAIL_COND_V(!multimesh, Vector<float>());
if (multimesh->buffer.is_null()) {
return Vector<float>();
- } else if (multimesh->data_cache.size()) {
- return multimesh->data_cache;
} else {
- //get from memory
-
- Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
Vector<float> ret;
ret.resize(multimesh->instances * multimesh->stride_cache);
- {
- float *w = ret.ptrw();
- const uint8_t *r = buffer.ptr();
- memcpy(w, r, buffer.size());
- }
+ float *w = ret.ptrw();
+ if (multimesh->data_cache.size()) {
+ const uint8_t *r = (uint8_t *)multimesh->data_cache.ptr() + multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float);
+ memcpy(w, r, ret.size() * sizeof(float));
+ } else {
+ Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
+ const uint8_t *r = buffer.ptr() + multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float);
+ memcpy(w, r, ret.size() * sizeof(float));
+ }
return ret;
}
}
@@ -1698,36 +1799,38 @@ void MeshStorage::_update_dirty_multimeshes() {
MultiMesh *multimesh = multimesh_dirty_list;
if (multimesh->data_cache.size()) { //may have been cleared, so only process if it exists
- const float *data = multimesh->data_cache.ptr();
uint32_t visible_instances = multimesh->visible_instances >= 0 ? multimesh->visible_instances : multimesh->instances;
+ uint32_t buffer_offset = multimesh->motion_vectors_current_offset * multimesh->stride_cache;
+ const float *data = multimesh->data_cache.ptr() + buffer_offset;
- if (multimesh->data_cache_used_dirty_regions) {
+ uint32_t total_dirty_regions = multimesh->data_cache_dirty_region_count + multimesh->previous_data_cache_dirty_region_count;
+ if (total_dirty_regions != 0) {
uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
uint32_t visible_region_count = visible_instances == 0 ? 0 : (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float);
-
- if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) {
+ if (total_dirty_regions > 32 || total_dirty_regions > visible_region_count / 2) {
//if there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much
- RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * (uint32_t)multimesh->stride_cache * (uint32_t)sizeof(float)), data);
+ RD::get_singleton()->buffer_update(multimesh->buffer, buffer_offset * sizeof(float), MIN(visible_region_count * region_size, multimesh->instances * (uint32_t)multimesh->stride_cache * (uint32_t)sizeof(float)), data);
} else {
//not that many regions? update them all
for (uint32_t i = 0; i < visible_region_count; i++) {
- if (multimesh->data_cache_dirty_regions[i]) {
+ if (multimesh->data_cache_dirty_regions[i] || multimesh->previous_data_cache_dirty_regions[i]) {
uint32_t offset = i * region_size;
uint32_t size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float);
uint32_t region_start_index = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * i;
- RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[region_start_index]);
+ RD::get_singleton()->buffer_update(multimesh->buffer, buffer_offset * sizeof(float) + offset, MIN(region_size, size - offset), &data[region_start_index], RD::BARRIER_MASK_NO_BARRIER);
}
}
+ RD::get_singleton()->barrier(RD::BARRIER_MASK_NO_BARRIER, RD::BARRIER_MASK_ALL);
}
- for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
- multimesh->data_cache_dirty_regions[i] = false;
- }
+ memcpy(multimesh->previous_data_cache_dirty_regions, multimesh->data_cache_dirty_regions, data_cache_dirty_region_count * sizeof(bool));
+ memset(multimesh->data_cache_dirty_regions, 0, data_cache_dirty_region_count * sizeof(bool));
- multimesh->data_cache_used_dirty_regions = 0;
+ multimesh->previous_data_cache_dirty_region_count = multimesh->data_cache_dirty_region_count;
+ multimesh->data_cache_dirty_region_count = 0;
}
if (multimesh->aabb_dirty) {
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
index 5c0d019c15..622f3911c7 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
@@ -205,13 +205,19 @@ private:
AABB aabb;
bool aabb_dirty = false;
bool buffer_set = false;
+ bool motion_vectors_enabled = false;
+ uint32_t motion_vectors_current_offset = 0;
+ uint32_t motion_vectors_previous_offset = 0;
+ uint64_t motion_vectors_last_change = -1;
uint32_t stride_cache = 0;
uint32_t color_offset_cache = 0;
uint32_t custom_data_offset_cache = 0;
Vector<float> data_cache; //used if individual setting is used
bool *data_cache_dirty_regions = nullptr;
- uint32_t data_cache_used_dirty_regions = 0;
+ uint32_t data_cache_dirty_region_count = 0;
+ bool *previous_data_cache_dirty_regions = nullptr;
+ uint32_t previous_data_cache_dirty_region_count = 0;
RID buffer; //storage buffer
RID uniform_set_3d;
@@ -228,6 +234,7 @@ private:
MultiMesh *multimesh_dirty_list = nullptr;
_FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const;
+ _FORCE_INLINE_ void _multimesh_update_motion_vectors_data_cache(MultiMesh *multimesh);
_FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb);
_FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb);
_FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
@@ -579,6 +586,8 @@ public:
virtual AABB multimesh_get_aabb(RID p_multimesh) const override;
void _update_dirty_multimeshes();
+ bool _multimesh_enable_motion_vectors(RID p_multimesh);
+ void _multimesh_get_motion_vectors_offsets(RID p_multimesh, uint32_t &r_current_offset, uint32_t &r_prev_offset);
_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
index adaf075f80..1975eec7b0 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
@@ -35,8 +35,8 @@
#include "servers/rendering/renderer_rd/effects/vrs.h"
#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h"
-#include "servers/rendering/renderer_scene.h"
#include "servers/rendering/rendering_device.h"
+#include "servers/rendering/rendering_method.h"
#include "servers/rendering/storage/render_scene_buffers.h"
// These can be retired in due time
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
new file mode 100644
index 0000000000..f925f87cbe
--- /dev/null
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
@@ -0,0 +1,246 @@
+/*************************************************************************/
+/* render_scene_data_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "render_scene_data_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
+#include "servers/rendering/rendering_server_default.h"
+
+RID RenderSceneDataRD::create_uniform_buffer() {
+ return RD::get_singleton()->uniform_buffer_create(sizeof(UBODATA));
+}
+
+void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_flip_y, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers) {
+ RendererSceneRenderRD *render_scene_render = RendererSceneRenderRD::get_singleton();
+
+ UBODATA ubo_data;
+ memset(&ubo_data, 0, sizeof(UBODATA));
+
+ // just for easy access..
+ UBO &ubo = ubo_data.ubo;
+ UBO &prev_ubo = ubo_data.prev_ubo;
+
+ Projection correction;
+ correction.set_depth_correction(p_flip_y);
+ correction.add_jitter_offset(taa_jitter);
+ Projection projection = correction * cam_projection;
+
+ //store camera into ubo
+ RendererRD::MaterialStorage::store_camera(projection, ubo.projection_matrix);
+ RendererRD::MaterialStorage::store_camera(projection.inverse(), ubo.inv_projection_matrix);
+ RendererRD::MaterialStorage::store_transform(cam_transform, ubo.inv_view_matrix);
+ RendererRD::MaterialStorage::store_transform(cam_transform.affine_inverse(), ubo.view_matrix);
+
+ for (uint32_t v = 0; v < view_count; v++) {
+ projection = correction * view_projection[v];
+ RendererRD::MaterialStorage::store_camera(projection, ubo.projection_matrix_view[v]);
+ RendererRD::MaterialStorage::store_camera(projection.inverse(), ubo.inv_projection_matrix_view[v]);
+
+ ubo.eye_offset[v][0] = view_eye_offset[v].x;
+ ubo.eye_offset[v][1] = view_eye_offset[v].y;
+ ubo.eye_offset[v][2] = view_eye_offset[v].z;
+ ubo.eye_offset[v][3] = 0.0;
+ }
+
+ ubo.taa_jitter[0] = taa_jitter.x;
+ ubo.taa_jitter[1] = taa_jitter.y;
+
+ ubo.z_far = z_far;
+ ubo.z_near = z_near;
+
+ ubo.pancake_shadows = p_pancake_shadows;
+
+ RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->directional_penumbra_shadow_kernel_get(), ubo.directional_penumbra_shadow_kernel);
+ RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->directional_soft_shadow_kernel_get(), ubo.directional_soft_shadow_kernel);
+ RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->penumbra_shadow_kernel_get(), ubo.penumbra_shadow_kernel);
+ RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->soft_shadow_kernel_get(), ubo.soft_shadow_kernel);
+
+ ubo.viewport_size[0] = p_screen_size.x;
+ ubo.viewport_size[1] = p_screen_size.y;
+
+ Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
+ ubo.screen_pixel_size[0] = screen_pixel_size.x;
+ ubo.screen_pixel_size[1] = screen_pixel_size.y;
+
+ ubo.shadow_atlas_pixel_size[0] = shadow_atlas_pixel_size.x;
+ ubo.shadow_atlas_pixel_size[1] = shadow_atlas_pixel_size.y;
+
+ ubo.directional_shadow_pixel_size[0] = directional_shadow_pixel_size.x;
+ ubo.directional_shadow_pixel_size[1] = directional_shadow_pixel_size.y;
+
+ ubo.time = time;
+
+ ubo.directional_light_count = directional_light_count;
+ ubo.dual_paraboloid_side = dual_paraboloid_side;
+ ubo.opaque_prepass_threshold = opaque_prepass_threshold;
+ ubo.material_uv2_mode = material_uv2_mode;
+
+ ubo.fog_enabled = false;
+
+ if (p_debug_mode == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
+ ubo.use_ambient_light = true;
+ ubo.ambient_light_color_energy[0] = 1;
+ ubo.ambient_light_color_energy[1] = 1;
+ ubo.ambient_light_color_energy[2] = 1;
+ ubo.ambient_light_color_energy[3] = 1.0;
+ ubo.use_ambient_cubemap = false;
+ ubo.use_reflection_cubemap = false;
+ } else if (p_env.is_valid()) {
+ RS::EnvironmentBG env_bg = render_scene_render->environment_get_background(p_env);
+ RS::EnvironmentAmbientSource ambient_src = render_scene_render->environment_get_ambient_source(p_env);
+
+ float bg_energy_multiplier = render_scene_render->environment_get_bg_energy_multiplier(p_env);
+
+ ubo.ambient_light_color_energy[3] = bg_energy_multiplier;
+
+ ubo.ambient_color_sky_mix = render_scene_render->environment_get_ambient_sky_contribution(p_env);
+
+ //ambient
+ if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
+ Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : render_scene_render->environment_get_bg_color(p_env);
+ color = color.srgb_to_linear();
+
+ ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier;
+ ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier;
+ ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier;
+ ubo.use_ambient_light = true;
+ ubo.use_ambient_cubemap = false;
+ } else {
+ float energy = render_scene_render->environment_get_ambient_light_energy(p_env);
+ Color color = render_scene_render->environment_get_ambient_light(p_env);
+ color = color.srgb_to_linear();
+ ubo.ambient_light_color_energy[0] = color.r * energy;
+ ubo.ambient_light_color_energy[1] = color.g * energy;
+ ubo.ambient_light_color_energy[2] = color.b * energy;
+
+ Basis sky_transform = render_scene_render->environment_get_sky_orientation(p_env);
+ sky_transform = sky_transform.inverse() * cam_transform.basis;
+ RendererRD::MaterialStorage::store_transform_3x3(sky_transform, ubo.radiance_inverse_xform);
+
+ ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
+ ubo.use_ambient_light = ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
+ }
+
+ //specular
+ RS::EnvironmentReflectionSource ref_src = render_scene_render->environment_get_reflection_source(p_env);
+ if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) {
+ ubo.use_reflection_cubemap = true;
+ } else {
+ ubo.use_reflection_cubemap = false;
+ }
+
+ ubo.fog_enabled = render_scene_render->environment_get_fog_enabled(p_env);
+ ubo.fog_density = render_scene_render->environment_get_fog_density(p_env);
+ ubo.fog_height = render_scene_render->environment_get_fog_height(p_env);
+ ubo.fog_height_density = render_scene_render->environment_get_fog_height_density(p_env);
+ ubo.fog_aerial_perspective = render_scene_render->environment_get_fog_aerial_perspective(p_env);
+
+ Color fog_color = render_scene_render->environment_get_fog_light_color(p_env).srgb_to_linear();
+ float fog_energy = render_scene_render->environment_get_fog_light_energy(p_env);
+
+ ubo.fog_light_color[0] = fog_color.r * fog_energy;
+ ubo.fog_light_color[1] = fog_color.g * fog_energy;
+ ubo.fog_light_color[2] = fog_color.b * fog_energy;
+
+ ubo.fog_sun_scatter = render_scene_render->environment_get_fog_sun_scatter(p_env);
+ } else {
+ if (p_reflection_probe_instance.is_valid() && RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(p_reflection_probe_instance)) {
+ ubo.use_ambient_light = false;
+ } else {
+ ubo.use_ambient_light = true;
+ Color clear_color = p_default_bg_color;
+ clear_color = clear_color.srgb_to_linear();
+ ubo.ambient_light_color_energy[0] = clear_color.r;
+ ubo.ambient_light_color_energy[1] = clear_color.g;
+ ubo.ambient_light_color_energy[2] = clear_color.b;
+ ubo.ambient_light_color_energy[3] = 1.0;
+ }
+
+ ubo.use_ambient_cubemap = false;
+ ubo.use_reflection_cubemap = false;
+ }
+
+ if (p_camera_attributes.is_valid()) {
+ ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes);
+ ubo.IBL_exposure_normalization = 1.0;
+ if (p_env.is_valid()) {
+ RID sky_rid = render_scene_render->environment_get_sky(p_env);
+ if (sky_rid.is_valid()) {
+ float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes) * render_scene_render->environment_get_bg_intensity(p_env) / p_luminance_multiplier;
+ ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, render_scene_render->get_sky()->sky_get_baked_exposure(sky_rid));
+ }
+ }
+ } else if (emissive_exposure_normalization > 0.0) {
+ // This branch is triggered when using render_material().
+ // Emissive is set outside the function.
+ ubo.emissive_exposure_normalization = emissive_exposure_normalization;
+ // IBL isn't used don't set it.
+ } else {
+ ubo.emissive_exposure_normalization = 1.0;
+ ubo.IBL_exposure_normalization = 1.0;
+ }
+
+ ubo.roughness_limiter_enabled = p_opaque_render_buffers && render_scene_render->screen_space_roughness_limiter_is_active();
+ ubo.roughness_limiter_amount = render_scene_render->screen_space_roughness_limiter_get_amount();
+ ubo.roughness_limiter_limit = render_scene_render->screen_space_roughness_limiter_get_limit();
+
+ if (calculate_motion_vectors) {
+ // Q : Should we make a complete copy or should we define a separate UBO with just the components we need?
+ memcpy(&prev_ubo, &ubo, sizeof(UBO));
+
+ Projection prev_correction;
+ prev_correction.set_depth_correction(true);
+ prev_correction.add_jitter_offset(prev_taa_jitter);
+ Projection prev_projection = prev_correction * prev_cam_projection;
+
+ //store camera into ubo
+ RendererRD::MaterialStorage::store_camera(prev_projection, prev_ubo.projection_matrix);
+ RendererRD::MaterialStorage::store_camera(prev_projection.inverse(), prev_ubo.inv_projection_matrix);
+ RendererRD::MaterialStorage::store_transform(prev_cam_transform, prev_ubo.inv_view_matrix);
+ RendererRD::MaterialStorage::store_transform(prev_cam_transform.affine_inverse(), prev_ubo.view_matrix);
+
+ for (uint32_t v = 0; v < view_count; v++) {
+ prev_projection = prev_correction * view_projection[v];
+ RendererRD::MaterialStorage::store_camera(prev_projection, prev_ubo.projection_matrix_view[v]);
+ RendererRD::MaterialStorage::store_camera(prev_projection.inverse(), prev_ubo.inv_projection_matrix_view[v]);
+ }
+ prev_ubo.taa_jitter[0] = prev_taa_jitter.x;
+ prev_ubo.taa_jitter[1] = prev_taa_jitter.y;
+ prev_ubo.time -= time_step;
+ }
+
+ uniform_buffer = p_uniform_buffer;
+ RD::get_singleton()->buffer_update(uniform_buffer, 0, sizeof(UBODATA), &ubo, RD::BARRIER_MASK_RASTER);
+}
+
+RID RenderSceneDataRD::get_uniform_buffer() {
+ return uniform_buffer;
+}
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
new file mode 100644
index 0000000000..c2dc7d5f4c
--- /dev/null
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
@@ -0,0 +1,157 @@
+/*************************************************************************/
+/* render_scene_data_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RENDER_SCENE_DATA_RD_H
+#define RENDER_SCENE_DATA_RD_H
+
+#include "render_scene_buffers_rd.h"
+#include "servers/rendering/renderer_scene_render.h"
+#include "servers/rendering/rendering_device.h"
+
+// This is a container for data related to rendering a single frame of a viewport where we load this data into a UBO
+// that can be used by the main scene shader but also by various effects.
+
+class RenderSceneDataRD {
+public:
+ bool calculate_motion_vectors = false;
+
+ Transform3D cam_transform;
+ Projection cam_projection;
+ Vector2 taa_jitter;
+ bool cam_orthogonal = false;
+
+ // For stereo rendering
+ uint32_t view_count = 1;
+ Vector3 view_eye_offset[RendererSceneRender::MAX_RENDER_VIEWS];
+ Projection view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
+
+ Transform3D prev_cam_transform;
+ Projection prev_cam_projection;
+ Vector2 prev_taa_jitter;
+ Projection prev_view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
+
+ float z_near = 0.0;
+ float z_far = 0.0;
+
+ float lod_distance_multiplier = 0.0;
+ Plane lod_camera_plane;
+ float screen_mesh_lod_threshold = 0.0;
+
+ uint32_t directional_light_count = 0;
+ float dual_paraboloid_side = 0.0;
+ float opaque_prepass_threshold = 0.0;
+ bool material_uv2_mode = false;
+ float emissive_exposure_normalization = 0.0;
+
+ Size2 shadow_atlas_pixel_size;
+ Size2 directional_shadow_pixel_size;
+
+ float time;
+ float time_step;
+
+ RID create_uniform_buffer();
+ void update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_flip_y, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers);
+ RID get_uniform_buffer();
+
+private:
+ RID uniform_buffer; // loaded into this uniform buffer (supplied externally)
+
+ // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code
+ struct UBO {
+ float projection_matrix[16];
+ float inv_projection_matrix[16];
+ float inv_view_matrix[16];
+ float view_matrix[16];
+
+ float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
+ float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
+ float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4];
+
+ float viewport_size[2];
+ float screen_pixel_size[2];
+
+ float directional_penumbra_shadow_kernel[128]; //32 vec4s
+ float directional_soft_shadow_kernel[128];
+ float penumbra_shadow_kernel[128];
+ float soft_shadow_kernel[128];
+
+ float radiance_inverse_xform[12];
+
+ float ambient_light_color_energy[4];
+
+ float ambient_color_sky_mix;
+ uint32_t use_ambient_light;
+ uint32_t use_ambient_cubemap;
+ uint32_t use_reflection_cubemap;
+
+ float shadow_atlas_pixel_size[2];
+ float directional_shadow_pixel_size[2];
+
+ uint32_t directional_light_count;
+ float dual_paraboloid_side;
+ float z_far;
+ float z_near;
+
+ uint32_t roughness_limiter_enabled;
+ float roughness_limiter_amount;
+ float roughness_limiter_limit;
+ float opaque_prepass_threshold;
+
+ // Fog
+ uint32_t fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
+
+ float fog_light_color[3];
+ float fog_sun_scatter;
+
+ float fog_aerial_perspective;
+ float time;
+ float reflection_multiplier;
+ uint32_t material_uv2_mode;
+
+ float taa_jitter[2];
+ float emissive_exposure_normalization; // Needed to normalize emissive when using physical units.
+ float IBL_exposure_normalization; // Adjusts for baked exposure.
+
+ uint32_t pancake_shadows;
+ uint32_t pad1;
+ uint32_t pad2;
+ uint32_t pad3;
+ };
+
+ struct UBODATA {
+ UBO ubo;
+ UBO prev_ubo;
+ };
+};
+
+#endif // RENDER_SCENE_DATA_RD_H
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index b87b4d4a0f..800a742cb6 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -795,6 +795,8 @@ void TextureStorage::texture_2d_layered_initialize(RID p_texture, const Vector<R
case RS::TEXTURE_LAYERED_CUBEMAP_ARRAY: {
texture.rd_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
} break;
+ default:
+ ERR_FAIL(); // Shouldn't happen, silence warnings.
}
texture.rd_format = ret_format.format;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 04dedc0646..c2dece8b46 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -2910,7 +2910,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
}
}
-void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_camera_data, const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, RID p_force_camera_attributes, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows, RendererScene::RenderInfo *r_render_info) {
+void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_camera_data, const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, RID p_force_camera_attributes, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows, RenderingMethod::RenderInfo *r_render_info) {
Instance *render_reflection_probe = instance_owner.get_or_null(p_reflection_probe); //if null, not rendering to it
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index c799553f87..fedaac99b1 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -39,13 +39,13 @@
#include "core/templates/pass_func.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
-#include "servers/rendering/renderer_scene.h"
#include "servers/rendering/renderer_scene_occlusion_cull.h"
#include "servers/rendering/renderer_scene_render.h"
+#include "servers/rendering/rendering_method.h"
#include "servers/rendering/storage/utilities.h"
#include "servers/xr/xr_interface.h"
-class RendererSceneCull : public RendererScene {
+class RendererSceneCull : public RenderingMethod {
public:
RendererSceneRender *scene_render = nullptr;
@@ -1058,7 +1058,7 @@ public:
void _render_scene(const RendererSceneRender::CameraData *p_camera_data, const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, RID p_force_camera_attributes, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows = true, RenderInfo *r_render_info = nullptr);
void render_empty_scene(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_scenario, RID p_shadow_atlas);
- void render_camera(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, bool p_use_taa, float p_screen_mesh_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RendererScene::RenderInfo *r_render_info = nullptr);
+ void render_camera(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, bool p_use_taa, float p_screen_mesh_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderingMethod::RenderInfo *r_render_info = nullptr);
void update_dirty_instances();
void render_particle_colliders();
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 9aa4108412..34f4980f05 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -34,7 +34,7 @@
#include "core/math/projection.h"
#include "core/templates/paged_array.h"
#include "servers/rendering/renderer_geometry_instance.h"
-#include "servers/rendering/renderer_scene.h"
+#include "servers/rendering/rendering_method.h"
#include "servers/rendering/storage/environment_storage.h"
#include "storage/render_scene_buffers.h"
#include "storage/utilities.h"
@@ -320,7 +320,7 @@ public:
void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_vaspect);
};
- virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) = 0;
+ virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) = 0;
virtual void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) = 0;
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index eacd9bbbc2..2b05e23a96 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -179,7 +179,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
// to compensate for the loss of sharpness.
const float texture_mipmap_bias = log2f(MIN(scaling_3d_scale, 1.0)) + p_viewport->texture_mipmap_bias;
- p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->get_view_count());
+ p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->view_count);
}
}
}
@@ -220,7 +220,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
timestamp_vp_map[rt_id] = p_viewport->self;
}
- if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") {
+ if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
// This is currently needed for GLES to keep the current window being rendered to up to date
DisplayServer::get_singleton()->gl_window_make_current(p_viewport->viewport_to_screen);
}
@@ -616,14 +616,7 @@ void RendererViewport::draw_viewports() {
if (xr_interface.is_valid()) {
// Override our size, make sure it matches our required size and is created as a stereo target
Size2 xr_size = xr_interface->get_render_target_size();
-
- // Would have been nice if we could call viewport_set_size here,
- // but alas that takes our RID and we now have our pointer,
- // also we only check if view_count changes in render_target_set_size so we need to call that for this to reliably change
- vp->occlusion_buffer_dirty = vp->occlusion_buffer_dirty || (vp->size != xr_size);
- vp->size = xr_size;
- uint32_t view_count = xr_interface->get_view_count();
- RSG::texture_storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count);
+ _viewport_set_size(vp, xr_size.width, xr_size.height, xr_interface->get_view_count());
// Inform xr interface we're about to render its viewport, if this returns false we don't render
visible = xr_interface->pre_draw_viewport(vp->render_target);
@@ -686,12 +679,17 @@ void RendererViewport::draw_viewports() {
// commit our eyes
Vector<BlitToScreen> blits = xr_interface->post_draw_viewport(vp->render_target, vp->viewport_to_screen_rect);
if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && blits.size() > 0) {
- if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
- blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
- }
+ if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") {
+ RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blits.ptr(), blits.size());
+ RSG::rasterizer->end_frame(true);
+ } else {
+ if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
+ blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
+ }
- for (int b = 0; b < blits.size(); b++) {
- blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]);
+ for (int b = 0; b < blits.size(); b++) {
+ blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]);
+ }
}
}
} else {
@@ -777,7 +775,13 @@ void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
}
viewport->use_xr = p_use_xr;
- _configure_3d_render_buffers(viewport);
+
+ // Re-configure the 3D render buffers when disabling XR. They'll get
+ // re-configured when enabling XR in draw_viewports().
+ if (!p_use_xr) {
+ viewport->view_count = 1;
+ _configure_3d_render_buffers(viewport);
+ }
}
void RendererViewport::viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode) {
@@ -823,34 +827,27 @@ void RendererViewport::viewport_set_scaling_3d_scale(RID p_viewport, float p_sca
_configure_3d_render_buffers(viewport);
}
-uint32_t RendererViewport::Viewport::get_view_count() {
- uint32_t view_count = 1;
-
- if (use_xr && XRServer::get_singleton() != nullptr) {
- Ref<XRInterface> xr_interface;
-
- xr_interface = XRServer::get_singleton()->get_primary_interface();
- if (xr_interface.is_valid()) {
- view_count = xr_interface->get_view_count();
- }
- }
-
- return view_count;
-}
-
void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) {
ERR_FAIL_COND(p_width < 0 && p_height < 0);
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
+ ERR_FAIL_COND_MSG(viewport->use_xr, "Cannot set viewport size when using XR");
- viewport->size = Size2(p_width, p_height);
+ _viewport_set_size(viewport, p_width, p_height, 1);
+}
- uint32_t view_count = viewport->get_view_count();
- RSG::texture_storage->render_target_set_size(viewport->render_target, p_width, p_height, view_count);
- _configure_3d_render_buffers(viewport);
+void RendererViewport::_viewport_set_size(Viewport *p_viewport, int p_width, int p_height, uint32_t p_view_count) {
+ Size2i new_size(p_width, p_height);
+ if (p_viewport->size != new_size || p_viewport->view_count != p_view_count) {
+ p_viewport->size = new_size;
+ p_viewport->view_count = p_view_count;
- viewport->occlusion_buffer_dirty = true;
+ RSG::texture_storage->render_target_set_size(p_viewport->render_target, p_width, p_height, p_view_count);
+ _configure_3d_render_buffers(p_viewport);
+
+ p_viewport->occlusion_buffer_dirty = true;
+ }
}
void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
@@ -890,7 +887,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_
// If using OpenGL we can optimize this operation by rendering directly to system_fbo
// instead of rendering to fbo and copying to system_fbo after
if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
- RSG::texture_storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->get_view_count());
+ RSG::texture_storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->view_count);
RSG::texture_storage->render_target_set_position(viewport->render_target, p_rect.position.x, p_rect.position.y);
}
@@ -900,7 +897,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_
// if render_direct_to_screen was used, reset size and position
if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
RSG::texture_storage->render_target_set_position(viewport->render_target, 0, 0);
- RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count());
+ RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->view_count);
}
viewport->viewport_to_screen_rect = Rect2();
@@ -919,7 +916,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool
// if disabled, reset render_target size and position
if (!p_enable) {
RSG::texture_storage->render_target_set_position(viewport->render_target, 0, 0);
- RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count());
+ RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->view_count);
}
RSG::texture_storage->render_target_set_direct_to_screen(viewport->render_target, p_enable);
@@ -927,7 +924,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool
// if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation
if (RSG::rasterizer->is_low_end() && viewport->viewport_to_screen_rect != Rect2() && p_enable) {
- RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y, viewport->get_view_count());
+ RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y, viewport->view_count);
RSG::texture_storage->render_target_set_position(viewport->render_target, viewport->viewport_to_screen_rect.position.x, viewport->viewport_to_screen_rect.position.y);
}
}
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index a123c70372..55058a30b8 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -34,8 +34,8 @@
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
-#include "servers/rendering/renderer_scene.h"
#include "servers/rendering/renderer_scene_render.h"
+#include "servers/rendering/rendering_method.h"
#include "servers/rendering_server.h"
#include "servers/xr/xr_interface.h"
#include "storage/render_scene_buffers.h"
@@ -54,6 +54,7 @@ public:
Size2i internal_size;
Size2i size;
+ uint32_t view_count;
RID camera;
RID scenario;
@@ -147,9 +148,10 @@ public:
HashMap<RID, CanvasData> canvas_map;
- RendererScene::RenderInfo render_info;
+ RenderingMethod::RenderInfo render_info;
Viewport() {
+ view_count = 1;
update_mode = RS::VIEWPORT_UPDATE_WHEN_VISIBLE;
clear_mode = RS::VIEWPORT_CLEAR_ALWAYS;
transparent_bg = false;
@@ -176,8 +178,6 @@ public:
time_gpu_begin = 0;
time_gpu_end = 0;
}
-
- uint32_t get_view_count();
};
HashMap<String, RID> timestamp_vp_map;
@@ -196,6 +196,7 @@ public:
private:
Vector<Viewport *> _sort_active_viewports();
+ void _viewport_set_size(Viewport *p_viewport, int p_width, int p_height, uint32_t p_view_count);
void _configure_3d_render_buffers(Viewport *p_viewport);
void _draw_3d(Viewport *p_viewport);
void _draw_viewport(Viewport *p_viewport);
diff --git a/servers/rendering/renderer_scene.cpp b/servers/rendering/rendering_method.cpp
index b3fdd88626..16a4e35ad3 100644
--- a/servers/rendering/renderer_scene.cpp
+++ b/servers/rendering/rendering_method.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* renderer_scene.cpp */
+/* rendering_method.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "renderer_scene.h"
+#include "rendering_method.h"
-RendererScene::RendererScene() {
+RenderingMethod::RenderingMethod() {
}
-RendererScene::~RendererScene() {
+RenderingMethod::~RenderingMethod() {
}
diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/rendering_method.h
index 29c65fcffb..a178b00424 100644
--- a/servers/rendering/renderer_scene.h
+++ b/servers/rendering/rendering_method.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* renderer_scene.h */
+/* rendering_method.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,14 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef RENDERER_SCENE_H
-#define RENDERER_SCENE_H
+#ifndef RENDERING_METHOD_H
+#define RENDERING_METHOD_H
#include "servers/rendering/storage/render_scene_buffers.h"
#include "servers/rendering_server.h"
#include "servers/xr/xr_interface.h"
-class RendererScene {
+class RenderingMethod {
public:
virtual RID camera_allocate() = 0;
virtual void camera_initialize(RID p_rid) = 0;
@@ -318,8 +318,8 @@ public:
virtual bool free(RID p_rid) = 0;
- RendererScene();
- virtual ~RendererScene();
+ RenderingMethod();
+ virtual ~RenderingMethod();
};
-#endif // RENDERER_SCENE_H
+#endif // RENDERING_METHOD_H
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index dfe16431bd..5ee29d5e2a 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -550,7 +550,7 @@ public:
#undef server_name
#undef ServerName
//from now on, calls forwarded to this singleton
-#define ServerName RendererScene
+#define ServerName RenderingMethod
#define server_name RSG::scene
/* CAMERA API */
@@ -649,7 +649,7 @@ public:
#undef server_name
#undef ServerName
//from now on, calls forwarded to this singleton
-#define ServerName RendererScene
+#define ServerName RenderingMethod
#define server_name RSG::scene
FUNC2(directional_shadow_atlas_set_size, int, bool)
@@ -739,7 +739,7 @@ public:
#undef server_name
#undef ServerName
-#define ServerName RendererScene
+#define ServerName RenderingMethod
#define server_name RSG::scene
FUNCRIDSPLIT(scenario)
diff --git a/servers/rendering/rendering_server_globals.cpp b/servers/rendering/rendering_server_globals.cpp
index ce7383a03f..ca24042ef9 100644
--- a/servers/rendering/rendering_server_globals.cpp
+++ b/servers/rendering/rendering_server_globals.cpp
@@ -46,4 +46,4 @@ RendererCompositor *RenderingServerGlobals::rasterizer = nullptr;
RendererCanvasCull *RenderingServerGlobals::canvas = nullptr;
RendererViewport *RenderingServerGlobals::viewport = nullptr;
-RendererScene *RenderingServerGlobals::scene = nullptr;
+RenderingMethod *RenderingServerGlobals::scene = nullptr;
diff --git a/servers/rendering/rendering_server_globals.h b/servers/rendering/rendering_server_globals.h
index 6c4ab5a26e..23f3810ce8 100644
--- a/servers/rendering/rendering_server_globals.h
+++ b/servers/rendering/rendering_server_globals.h
@@ -35,7 +35,7 @@
#include "servers/rendering/environment/renderer_gi.h"
#include "servers/rendering/renderer_canvas_cull.h"
#include "servers/rendering/renderer_canvas_render.h"
-#include "servers/rendering/renderer_scene.h"
+#include "servers/rendering/rendering_method.h"
#include "servers/rendering/storage/camera_attributes_storage.h"
#include "servers/rendering/storage/light_storage.h"
#include "servers/rendering/storage/material_storage.h"
@@ -46,7 +46,7 @@
class RendererCanvasCull;
class RendererViewport;
-class RendererScene;
+class RenderingMethod;
class RenderingServerGlobals {
public:
@@ -66,7 +66,7 @@ public:
static RendererCanvasCull *canvas;
static RendererViewport *viewport;
- static RendererScene *scene;
+ static RenderingMethod *scene;
};
#define RSG RenderingServerGlobals
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 47cb38f268..cd063f91ac 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -340,6 +340,11 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_VELOCITY"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_COLOR"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_CUSTOM"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_POSITION"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_ROT_SCALE"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL);
@@ -385,6 +390,7 @@ ShaderTypes::ShaderTypes() {
emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("custom", ShaderLanguage::TYPE_VEC4));
emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("flags", ShaderLanguage::TYPE_UINT));
emit_vertex_func.return_type = ShaderLanguage::TYPE_BOOL; //whether it could emit
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].stage_functions["emit_subparticle"] = emit_vertex_func;
shader_modes[RS::SHADER_PARTICLES].functions["process"].stage_functions["emit_subparticle"] = emit_vertex_func;
}
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index aa3351c815..57378708ba 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -743,7 +743,7 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i
r_attrib_element_size = 0;
r_skin_element_size = 0;
- uint32_t *size_accum;
+ uint32_t *size_accum = nullptr;
for (int i = 0; i < RS::ARRAY_MAX; i++) {
r_offsets[i] = 0; // Reset
@@ -847,8 +847,12 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i
}
}
- r_offsets[i] = (*size_accum);
- (*size_accum) += elem_size;
+ if (size_accum != nullptr) {
+ r_offsets[i] = (*size_accum);
+ (*size_accum) += elem_size;
+ } else {
+ r_offsets[i] = 0;
+ }
}
}
@@ -1114,7 +1118,8 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
for (int j = 0; j < p_vertex_len; j++) {
const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]];
- w[j] = Vector3((v & 0x3FF) / 1023.0, ((v >> 10) & 0x3FF) / 1023.0, ((v >> 20) & 0x3FF) / 1023.0) * Vector3(2, 2, 2) - Vector3(1, 1, 1);
+
+ w[j] = Vector3::octahedron_decode(Vector2((v & 0xFFFF) / 65535.0, ((v >> 16) & 0xFFFF) / 65535.0));
}
ret[i] = arr;
@@ -1129,11 +1134,12 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
for (int j = 0; j < p_vertex_len; j++) {
const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]];
-
- w[j * 4 + 0] = ((v & 0x3FF) / 1023.0) * 2.0 - 1.0;
- w[j * 4 + 1] = (((v >> 10) & 0x3FF) / 1023.0) * 2.0 - 1.0;
- w[j * 4 + 2] = (((v >> 20) & 0x3FF) / 1023.0) * 2.0 - 1.0;
- w[j * 4 + 3] = ((v >> 30) / 3.0) * 2.0 - 1.0;
+ float tangent_sign;
+ Vector3 res = Vector3::octahedron_tangent_decode(Vector2((v & 0xFFFF) / 65535.0, ((v >> 16) & 0xFFFF) / 65535.0), &tangent_sign);
+ w[j * 4 + 0] = res.x;
+ w[j * 4 + 1] = res.y;
+ w[j * 4 + 2] = res.z;
+ w[j * 4 + 3] = tangent_sign;
}
ret[i] = arr;
@@ -2861,18 +2867,12 @@ void RenderingServer::init() {
GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048);
- GLOBAL_DEF_RST_BASIC("rendering/vulkan/rendering/back_end", 0);
- GLOBAL_DEF_RST_BASIC("rendering/vulkan/rendering/back_end.mobile", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/vulkan/rendering/back_end",
- PropertyInfo(Variant::INT,
- "rendering/vulkan/rendering/back_end",
- PROPERTY_HINT_ENUM, "Forward Clustered (Supports Desktop Only),Forward Mobile (Supports Desktop and Mobile)"));
// Already defined in RenderingDeviceVulkan::initialize which runs before this code.
// We re-define them here just for doctool's sake. Make sure to keep default values in sync.
- GLOBAL_DEF("rendering/vulkan/staging_buffer/block_size_kb", 256);
- GLOBAL_DEF("rendering/vulkan/staging_buffer/max_size_mb", 128);
- GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64);
- GLOBAL_DEF("rendering/vulkan/descriptor_pools/max_descriptors_per_pool", 64);
+ GLOBAL_DEF("rendering/rendering_device/staging_buffer/block_size_kb", 256);
+ GLOBAL_DEF("rendering/rendering_device/staging_buffer/max_size_mb", 128);
+ GLOBAL_DEF("rendering/rendering_device/staging_buffer/texture_upload_region_size_px", 64);
+ GLOBAL_DEF("rendering/rendering_device/descriptor_pools/max_descriptors_per_pool", 64);
GLOBAL_DEF("rendering/shader_compiler/shader_cache/enabled", true);
GLOBAL_DEF("rendering/shader_compiler/shader_cache/compress", true);
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index ebd35b0f75..7a8a298dbd 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -1550,8 +1550,8 @@ PackedInt32Array TextServerExtension::string_get_word_breaks(const String &p_str
return PackedInt32Array();
}
-int TextServerExtension::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
- int ret;
+int64_t TextServerExtension::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
+ int64_t ret;
if (GDVIRTUAL_CALL(is_confusable, p_string, p_dict, ret)) {
return ret;
}
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index 700d08f7d7..fbaa4961e1 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -508,9 +508,9 @@ public:
TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
GDVIRTUAL3RC(TypedArray<Vector2i>, parse_structured_text, StructuredTextParser, const Array &, const String &);
- virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
+ virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
virtual bool spoof_check(const String &p_string) const override;
- GDVIRTUAL2RC(int, is_confusable, const String &, const PackedStringArray &);
+ GDVIRTUAL2RC(int64_t, is_confusable, const String &, const PackedStringArray &);
GDVIRTUAL1RC(bool, spoof_check, const String &);
TextServerExtension();
diff --git a/servers/text_server.h b/servers/text_server.h
index b62d418fc8..a0624c2c05 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -485,7 +485,7 @@ public:
// String functions.
virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const = 0;
- virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const { return -1; };
+ 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; };
virtual String strip_diacritics(const String &p_string) const;
diff --git a/tests/core/math/test_basis.h b/tests/core/math/test_basis.h
index ae8ca4acde..b6493c5726 100644
--- a/tests/core/math/test_basis.h
+++ b/tests/core/math/test_basis.h
@@ -47,7 +47,7 @@ enum RotOrder {
EulerZYX
};
-Vector3 deg2rad(const Vector3 &p_rotation) {
+Vector3 deg_to_rad(const Vector3 &p_rotation) {
return p_rotation / 180.0 * Math_PI;
}
@@ -155,7 +155,7 @@ void test_rotation(Vector3 deg_original_euler, RotOrder rot_order) {
// are correct.
// Euler to rotation
- const Vector3 original_euler = deg2rad(deg_original_euler);
+ const Vector3 original_euler = deg_to_rad(deg_original_euler);
const Basis to_rotation = EulerToBasis(rot_order, original_euler);
// Euler from rotation
@@ -281,6 +281,59 @@ TEST_CASE("[Stress][Basis] Euler conversions") {
}
}
}
+
+TEST_CASE("[Basis] Set axis angle") {
+ Vector3 axis;
+ real_t angle;
+ real_t pi = (real_t)Math_PI;
+
+ // Testing the singularity when the angle is 0°.
+ Basis identity(1, 0, 0, 0, 1, 0, 0, 0, 1);
+ identity.get_axis_angle(axis, angle);
+ CHECK(angle == 0);
+
+ // Testing the singularity when the angle is 180°.
+ Basis singularityPi(-1, 0, 0, 0, 1, 0, 0, 0, -1);
+ singularityPi.get_axis_angle(axis, angle);
+ CHECK(Math::is_equal_approx(angle, pi));
+
+ // Testing reversing the an axis (of an 30° angle).
+ float cos30deg = Math::cos(Math::deg_to_rad((real_t)30.0));
+ Basis z_positive(cos30deg, -0.5, 0, 0.5, cos30deg, 0, 0, 0, 1);
+ Basis z_negative(cos30deg, 0.5, 0, -0.5, cos30deg, 0, 0, 0, 1);
+
+ z_positive.get_axis_angle(axis, angle);
+ CHECK(Math::is_equal_approx(angle, Math::deg_to_rad((real_t)30.0)));
+ CHECK(axis == Vector3(0, 0, 1));
+
+ z_negative.get_axis_angle(axis, angle);
+ CHECK(Math::is_equal_approx(angle, Math::deg_to_rad((real_t)30.0)));
+ CHECK(axis == Vector3(0, 0, -1));
+
+ // Testing a rotation of 90° on x-y-z.
+ Basis x90deg(1, 0, 0, 0, 0, -1, 0, 1, 0);
+ x90deg.get_axis_angle(axis, angle);
+ CHECK(Math::is_equal_approx(angle, pi / (real_t)2));
+ CHECK(axis == Vector3(1, 0, 0));
+
+ Basis y90deg(0, 0, 1, 0, 1, 0, -1, 0, 0);
+ y90deg.get_axis_angle(axis, angle);
+ CHECK(axis == Vector3(0, 1, 0));
+
+ Basis z90deg(0, -1, 0, 1, 0, 0, 0, 0, 1);
+ z90deg.get_axis_angle(axis, angle);
+ CHECK(axis == Vector3(0, 0, 1));
+
+ // Regression test: checks that the method returns a small angle (not 0).
+ Basis tiny(1, 0, 0, 0, 0.9999995, -0.001, 0, 001, 0.9999995); // The min angle possible with float is 0.001rad.
+ tiny.get_axis_angle(axis, angle);
+ CHECK(Math::is_equal_approx(angle, (real_t)0.001, (real_t)0.0001));
+
+ // Regression test: checks that the method returns an angle which is a number (not NaN)
+ Basis bugNan(1.00000024, 0, 0.000100001693, 0, 1, 0, -0.000100009143, 0, 1.00000024);
+ bugNan.get_axis_angle(axis, angle);
+ CHECK(!Math::is_nan(angle));
+}
} // namespace TestBasis
#endif // TEST_BASIS_H
diff --git a/tests/core/math/test_vector2.h b/tests/core/math/test_vector2.h
index 9b7800164a..0d7f1163e4 100644
--- a/tests/core/math/test_vector2.h
+++ b/tests/core/math/test_vector2.h
@@ -37,6 +37,14 @@
namespace TestVector2 {
+TEST_CASE("[Vector2] Constructor methods") {
+ const Vector2 vector_empty = Vector2();
+ const Vector2 vector_zero = Vector2(0.0, 0.0);
+ CHECK_MESSAGE(
+ vector_empty == vector_zero,
+ "Vector2 Constructor with no inputs should return a zero Vector2.");
+}
+
TEST_CASE("[Vector2] Angle methods") {
const Vector2 vector_x = Vector2(1, 0);
const Vector2 vector_y = Vector2(0, 1);
@@ -102,6 +110,9 @@ TEST_CASE("[Vector2] Interpolation methods") {
Vector2(1, 1).slerp(Vector2(), 0.5) == Vector2(0.5, 0.5),
"Vector2 slerp with one input as zero should behave like a regular lerp.");
CHECK_MESSAGE(
+ Vector2(4, 6).slerp(Vector2(8, 10), 0.5).is_equal_approx(Vector2(5.9076470794008017626, 8.07918879020090480697)),
+ "Vector2 slerp should work as expected.");
+ CHECK_MESSAGE(
Math::is_equal_approx(vector1.slerp(vector2, 0.5).length(), (real_t)4.31959610746631919),
"Vector2 slerp with different length input should return a vector with an interpolated length.");
CHECK_MESSAGE(
@@ -171,6 +182,15 @@ TEST_CASE("[Vector2] Normalization methods") {
CHECK_MESSAGE(
Vector2(1, 1).normalized().is_equal_approx(Vector2(Math_SQRT12, Math_SQRT12)),
"Vector2 normalized should work as expected.");
+
+ Vector2 vector = Vector2(3.2, -5.4);
+ vector.normalize();
+ CHECK_MESSAGE(
+ vector == Vector2(3.2, -5.4).normalized(),
+ "Vector2 normalize should convert same way as Vector2 normalized.");
+ CHECK_MESSAGE(
+ vector.is_equal_approx(Vector2(0.509802390301732898898, -0.860291533634174266891)),
+ "Vector2 normalize should work as expected.");
}
TEST_CASE("[Vector2] Operators") {
@@ -276,12 +296,14 @@ TEST_CASE("[Vector2] Other methods") {
CHECK_MESSAGE(
Math::is_equal_approx(vector.aspect(), (real_t)1.2 / (real_t)3.4),
"Vector2 aspect should work as expected.");
+
CHECK_MESSAGE(
vector.direction_to(Vector2()).is_equal_approx(-vector.normalized()),
"Vector2 direction_to should work as expected.");
CHECK_MESSAGE(
Vector2(1, 1).direction_to(Vector2(2, 2)).is_equal_approx(Vector2(Math_SQRT12, Math_SQRT12)),
"Vector2 direction_to should work as expected.");
+
CHECK_MESSAGE(
vector.posmod(2).is_equal_approx(Vector2(1.2, 1.4)),
"Vector2 posmod should work as expected.");
@@ -294,10 +316,21 @@ TEST_CASE("[Vector2] Other methods") {
CHECK_MESSAGE(
(-vector).posmodv(Vector2(2, 3)).is_equal_approx(Vector2(0.8, 2.6)),
"Vector2 posmodv should work as expected.");
+
+ CHECK_MESSAGE(
+ vector.rotated(Math_TAU).is_equal_approx(Vector2(1.2, 3.4)),
+ "Vector2 rotated should work as expected.");
CHECK_MESSAGE(
vector.rotated(Math_TAU / 4).is_equal_approx(Vector2(-3.4, 1.2)),
"Vector2 rotated should work as expected.");
CHECK_MESSAGE(
+ vector.rotated(Math_TAU / 3).is_equal_approx(Vector2(-3.544486372867091398996, -0.660769515458673623883)),
+ "Vector2 rotated should work as expected.");
+ CHECK_MESSAGE(
+ vector.rotated(Math_TAU / 2).is_equal_approx(vector.rotated(Math_TAU / -2)),
+ "Vector2 rotated should work as expected.");
+
+ CHECK_MESSAGE(
vector.snapped(Vector2(1, 1)) == Vector2(1, 3),
"Vector2 snapped to integers should be the same as rounding.");
CHECK_MESSAGE(
@@ -306,23 +339,57 @@ TEST_CASE("[Vector2] Other methods") {
CHECK_MESSAGE(
vector.snapped(Vector2(0.25, 0.25)) == Vector2(1.25, 3.5),
"Vector2 snapped to 0.25 should give exact results.");
+
+ CHECK_MESSAGE(
+ Vector2(1.2, 2.5).is_equal_approx(vector.min(Vector2(3.0, 2.5))),
+ "Vector2 min should return expected value.");
+
+ CHECK_MESSAGE(
+ Vector2(5.3, 3.4).is_equal_approx(vector.max(Vector2(5.3, 2.0))),
+ "Vector2 max should return expected value.");
}
TEST_CASE("[Vector2] Plane methods") {
const Vector2 vector = Vector2(1.2, 3.4);
const Vector2 vector_y = Vector2(0, 1);
+ const Vector2 vector_normal = Vector2(0.95879811270838721622267, 0.2840883296913739899919);
+ const Vector2 vector_non_normal = Vector2(5.4, 1.6);
CHECK_MESSAGE(
vector.bounce(vector_y) == Vector2(1.2, -3.4),
"Vector2 bounce on a plane with normal of the Y axis should.");
CHECK_MESSAGE(
+ vector.bounce(vector_normal).is_equal_approx(Vector2(-2.85851197982345523329, 2.197477931904161412358)),
+ "Vector2 bounce with normal should return expected value.");
+ CHECK_MESSAGE(
vector.reflect(vector_y) == Vector2(-1.2, 3.4),
"Vector2 reflect on a plane with normal of the Y axis should.");
CHECK_MESSAGE(
+ vector.reflect(vector_normal).is_equal_approx(Vector2(2.85851197982345523329, -2.197477931904161412358)),
+ "Vector2 reflect with normal should return expected value.");
+ CHECK_MESSAGE(
vector.project(vector_y) == Vector2(0, 3.4),
- "Vector2 projected on the X axis should only give the Y component.");
+ "Vector2 projected on the Y axis should only give the Y component.");
+ CHECK_MESSAGE(
+ vector.project(vector_normal).is_equal_approx(Vector2(2.0292559899117276166, 0.60126103404791929382)),
+ "Vector2 projected on a normal should return expected value.");
CHECK_MESSAGE(
vector.slide(vector_y) == Vector2(1.2, 0),
"Vector2 slide on a plane with normal of the Y axis should set the Y to zero.");
+ CHECK_MESSAGE(
+ vector.slide(vector_normal).is_equal_approx(Vector2(-0.8292559899117276166456, 2.798738965952080706179)),
+ "Vector2 slide with normal should return expected value.");
+ // There's probably a better way to test these ones?
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ vector.bounce(vector_non_normal).is_equal_approx(Vector2()),
+ "Vector2 bounce should return empty Vector2 with non-normalised input.");
+ CHECK_MESSAGE(
+ vector.reflect(vector_non_normal).is_equal_approx(Vector2()),
+ "Vector2 reflect should return empty Vector2 with non-normalised input.");
+ CHECK_MESSAGE(
+ vector.slide(vector_non_normal).is_equal_approx(Vector2()),
+ "Vector2 slide should return empty Vector2 with non-normalised input.");
+ ERR_PRINT_ON;
}
TEST_CASE("[Vector2] Rounding methods") {
@@ -367,12 +434,20 @@ TEST_CASE("[Vector2] Rounding methods") {
TEST_CASE("[Vector2] Linear algebra methods") {
const Vector2 vector_x = Vector2(1, 0);
const Vector2 vector_y = Vector2(0, 1);
+ const Vector2 a = Vector2(3.5, 8.5);
+ const Vector2 b = Vector2(5.2, 4.6);
CHECK_MESSAGE(
vector_x.cross(vector_y) == 1,
"Vector2 cross product of X and Y should give 1.");
CHECK_MESSAGE(
vector_y.cross(vector_x) == -1,
"Vector2 cross product of Y and X should give negative 1.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(a.cross(b), (real_t)-28.1),
+ "Vector2 cross should return expected value.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(Vector2(-a.x, a.y).cross(Vector2(b.x, -b.y)), (real_t)-28.1),
+ "Vector2 cross should return expected value.");
CHECK_MESSAGE(
vector_x.dot(vector_y) == 0.0,
@@ -383,6 +458,12 @@ TEST_CASE("[Vector2] Linear algebra methods") {
CHECK_MESSAGE(
(vector_x * 10).dot(vector_x * 10) == 100.0,
"Vector2 dot product of same direction vectors should behave as expected.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(a.dot(b), (real_t)57.3),
+ "Vector2 dot should return expected value.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(Vector2(-a.x, a.y).dot(Vector2(b.x, -b.y)), (real_t)-57.3),
+ "Vector2 dot should return expected value.");
}
} // namespace TestVector2
diff --git a/tests/core/math/test_vector2i.h b/tests/core/math/test_vector2i.h
index 841bb793a4..49b0632e3c 100644
--- a/tests/core/math/test_vector2i.h
+++ b/tests/core/math/test_vector2i.h
@@ -37,6 +37,14 @@
namespace TestVector2i {
+TEST_CASE("[Vector2i] Constructor methods") {
+ const Vector2i vector_empty = Vector2i();
+ const Vector2i vector_zero = Vector2i(0, 0);
+ CHECK_MESSAGE(
+ vector_empty == vector_zero,
+ "Vector2i Constructor with no inputs should return a zero Vector2i.");
+}
+
TEST_CASE("[Vector2i] Axis methods") {
Vector2i vector = Vector2i(2, 3);
CHECK_MESSAGE(
@@ -121,6 +129,14 @@ TEST_CASE("[Vector2i] Other methods") {
CHECK_MESSAGE(
Math::is_equal_approx(vector.aspect(), (real_t)1.0 / (real_t)3.0),
"Vector2i aspect should work as expected.");
+
+ CHECK_MESSAGE(
+ Vector2i(1, 2) == vector.min(Vector2i(3, 2)),
+ "Vector2i min should return expected value.");
+
+ CHECK_MESSAGE(
+ Vector2i(5, 3) == vector.max(Vector2i(5, 2)),
+ "Vector2i max should return expected value.");
}
TEST_CASE("[Vector2i] Abs and sign methods") {
diff --git a/tests/core/math/test_vector3.h b/tests/core/math/test_vector3.h
index 6f99fada2b..52118fa943 100644
--- a/tests/core/math/test_vector3.h
+++ b/tests/core/math/test_vector3.h
@@ -39,6 +39,14 @@
namespace TestVector3 {
+TEST_CASE("[Vector3] Constructor methods") {
+ const Vector3 vector_empty = Vector3();
+ const Vector3 vector_zero = Vector3(0.0, 0.0, 0.0);
+ CHECK_MESSAGE(
+ vector_empty == vector_zero,
+ "Vector3 Constructor with no inputs should return a zero Vector3.");
+}
+
TEST_CASE("[Vector3] Angle methods") {
const Vector3 vector_x = Vector3(1, 0, 0);
const Vector3 vector_y = Vector3(0, 1, 0);
@@ -123,6 +131,9 @@ TEST_CASE("[Vector3] Interpolation methods") {
Vector3(1, 1, 1).slerp(Vector3(), 0.5) == Vector3(0.5, 0.5, 0.5),
"Vector3 slerp with one input as zero should behave like a regular lerp.");
CHECK_MESSAGE(
+ Vector3(4, 6, 2).slerp(Vector3(8, 10, 3), 0.5).is_equal_approx(Vector3(5.90194219811429941053, 8.06758688849378394534, 2.558307894718317120038)),
+ "Vector3 slerp should work as expected.");
+ CHECK_MESSAGE(
Math::is_equal_approx(vector1.slerp(vector2, 0.5).length(), (real_t)6.25831088708303172),
"Vector3 slerp with different length input should return a vector with an interpolated length.");
CHECK_MESSAGE(
@@ -195,6 +206,15 @@ TEST_CASE("[Vector3] Normalization methods") {
CHECK_MESSAGE(
Vector3(1, 1, 1).normalized().is_equal_approx(Vector3(Math_SQRT13, Math_SQRT13, Math_SQRT13)),
"Vector3 normalized should work as expected.");
+
+ Vector3 vector = Vector3(3.2, -5.4, 6);
+ vector.normalize();
+ CHECK_MESSAGE(
+ vector == Vector3(3.2, -5.4, 6).normalized(),
+ "Vector3 normalize should convert same way as Vector3 normalized.");
+ CHECK_MESSAGE(
+ vector.is_equal_approx(Vector3(0.368522751763902980457, -0.621882143601586279522, 0.6909801595573180883585)),
+ "Vector3 normalize should work as expected.");
}
TEST_CASE("[Vector3] Operators") {
@@ -318,10 +338,21 @@ TEST_CASE("[Vector3] Other methods") {
CHECK_MESSAGE(
(-vector).posmodv(Vector3(2, 3, 4)).is_equal_approx(Vector3(0.8, 2.6, 2.4)),
"Vector3 posmodv should work as expected.");
+
+ CHECK_MESSAGE(
+ vector.rotated(Vector3(0, 1, 0), Math_TAU).is_equal_approx(vector),
+ "Vector3 rotated should work as expected.");
CHECK_MESSAGE(
vector.rotated(Vector3(0, 1, 0), Math_TAU / 4).is_equal_approx(Vector3(5.6, 3.4, -1.2)),
"Vector3 rotated should work as expected.");
CHECK_MESSAGE(
+ vector.rotated(Vector3(1, 0, 0), Math_TAU / 3).is_equal_approx(Vector3(1.2, -6.54974226119285642, 0.1444863728670914)),
+ "Vector3 rotated should work as expected.");
+ CHECK_MESSAGE(
+ vector.rotated(Vector3(0, 0, 1), Math_TAU / 2).is_equal_approx(vector.rotated(Vector3(0, 0, 1), Math_TAU / -2)),
+ "Vector3 rotated should work as expected.");
+
+ CHECK_MESSAGE(
vector.snapped(Vector3(1, 1, 1)) == Vector3(1, 3, 6),
"Vector3 snapped to integers should be the same as rounding.");
CHECK_MESSAGE(
@@ -332,18 +363,44 @@ TEST_CASE("[Vector3] Other methods") {
TEST_CASE("[Vector3] Plane methods") {
const Vector3 vector = Vector3(1.2, 3.4, 5.6);
const Vector3 vector_y = Vector3(0, 1, 0);
+ const Vector3 vector_normal = Vector3(0.88763458893247992491, 0.26300284116517923701, 0.37806658417494515320);
+ const Vector3 vector_non_normal = Vector3(5.4, 1.6, 2.3);
CHECK_MESSAGE(
vector.bounce(vector_y) == Vector3(1.2, -3.4, 5.6),
"Vector3 bounce on a plane with normal of the Y axis should.");
CHECK_MESSAGE(
+ vector.bounce(vector_normal).is_equal_approx(Vector3(-6.0369629829775736287, 1.25571467171034855444, 2.517589840583626047)),
+ "Vector3 bounce with normal should return expected value.");
+ CHECK_MESSAGE(
vector.reflect(vector_y) == Vector3(-1.2, 3.4, -5.6),
"Vector3 reflect on a plane with normal of the Y axis should.");
CHECK_MESSAGE(
+ vector.reflect(vector_normal).is_equal_approx(Vector3(6.0369629829775736287, -1.25571467171034855444, -2.517589840583626047)),
+ "Vector3 reflect with normal should return expected value.");
+ CHECK_MESSAGE(
vector.project(vector_y) == Vector3(0, 3.4, 0),
- "Vector3 projected on the X axis should only give the Y component.");
+ "Vector3 projected on the Y axis should only give the Y component.");
+ CHECK_MESSAGE(
+ vector.project(vector_normal).is_equal_approx(Vector3(3.61848149148878681437, 1.0721426641448257227776, 1.54120507970818697649)),
+ "Vector3 projected on a normal should return expected value.");
CHECK_MESSAGE(
vector.slide(vector_y) == Vector3(1.2, 0, 5.6),
"Vector3 slide on a plane with normal of the Y axis should set the Y to zero.");
+ CHECK_MESSAGE(
+ vector.slide(vector_normal).is_equal_approx(Vector3(-2.41848149148878681437, 2.32785733585517427722237, 4.0587949202918130235)),
+ "Vector3 slide with normal should return expected value.");
+ // There's probably a better way to test these ones?
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ vector.bounce(vector_non_normal).is_equal_approx(Vector3()),
+ "Vector3 bounce should return empty Vector3 with non-normalised input.");
+ CHECK_MESSAGE(
+ vector.reflect(vector_non_normal).is_equal_approx(Vector3()),
+ "Vector3 reflect should return empty Vector3 with non-normalised input.");
+ CHECK_MESSAGE(
+ vector.slide(vector_non_normal).is_equal_approx(Vector3()),
+ "Vector3 slide should return empty Vector3 with non-normalised input.");
+ ERR_PRINT_ON;
}
TEST_CASE("[Vector3] Rounding methods") {
@@ -389,6 +446,8 @@ TEST_CASE("[Vector3] Linear algebra methods") {
const Vector3 vector_x = Vector3(1, 0, 0);
const Vector3 vector_y = Vector3(0, 1, 0);
const Vector3 vector_z = Vector3(0, 0, 1);
+ const Vector3 a = Vector3(3.5, 8.5, 2.3);
+ const Vector3 b = Vector3(5.2, 4.6, 7.8);
CHECK_MESSAGE(
vector_x.cross(vector_y) == vector_z,
"Vector3 cross product of X and Y should give Z.");
@@ -401,6 +460,12 @@ TEST_CASE("[Vector3] Linear algebra methods") {
CHECK_MESSAGE(
vector_z.cross(vector_x) == vector_y,
"Vector3 cross product of Z and X should give Y.");
+ CHECK_MESSAGE(
+ a.cross(b).is_equal_approx(Vector3(55.72, -15.34, -28.1)),
+ "Vector3 cross should return expected value.");
+ CHECK_MESSAGE(
+ Vector3(-a.x, a.y, -a.z).cross(Vector3(b.x, -b.y, b.z)).is_equal_approx(Vector3(55.72, 15.34, -28.1)),
+ "Vector2 cross should return expected value.");
CHECK_MESSAGE(
vector_x.dot(vector_y) == 0.0,
@@ -411,6 +476,12 @@ TEST_CASE("[Vector3] Linear algebra methods") {
CHECK_MESSAGE(
(vector_x * 10).dot(vector_x * 10) == 100.0,
"Vector3 dot product of same direction vectors should behave as expected.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(a.dot(b), (real_t)75.24),
+ "Vector3 dot should return expected value.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(Vector3(-a.x, a.y, -a.z).dot(Vector3(b.x, -b.y, b.z)), (real_t)-75.24),
+ "Vector3 dot should return expected value.");
}
} // namespace TestVector3
diff --git a/tests/core/math/test_vector3i.h b/tests/core/math/test_vector3i.h
index b1c6944eba..6c52781556 100644
--- a/tests/core/math/test_vector3i.h
+++ b/tests/core/math/test_vector3i.h
@@ -36,6 +36,14 @@
namespace TestVector3i {
+TEST_CASE("[Vector3i] Constructor methods") {
+ const Vector3i vector_empty = Vector3i();
+ const Vector3i vector_zero = Vector3i(0, 0, 0);
+ CHECK_MESSAGE(
+ vector_empty == vector_zero,
+ "Vector3i Constructor with no inputs should return a zero Vector3i.");
+}
+
TEST_CASE("[Vector3i] Axis methods") {
Vector3i vector = Vector3i(1, 2, 3);
CHECK_MESSAGE(
diff --git a/tests/core/math/test_vector4.h b/tests/core/math/test_vector4.h
index ccf991401b..25ec8929b8 100644
--- a/tests/core/math/test_vector4.h
+++ b/tests/core/math/test_vector4.h
@@ -38,6 +38,14 @@
namespace TestVector4 {
+TEST_CASE("[Vector4] Constructor methods") {
+ const Vector4 vector_empty = Vector4();
+ const Vector4 vector_zero = Vector4(0.0, 0.0, 0.0, 0.0);
+ CHECK_MESSAGE(
+ vector_empty == vector_zero,
+ "Vector4 Constructor with no inputs should return a zero Vector4.");
+}
+
TEST_CASE("[Vector4] Axis methods") {
Vector4 vector = Vector4(1.2, 3.4, 5.6, -0.9);
CHECK_MESSAGE(
diff --git a/tests/core/math/test_vector4i.h b/tests/core/math/test_vector4i.h
index ac63001b24..e106099914 100644
--- a/tests/core/math/test_vector4i.h
+++ b/tests/core/math/test_vector4i.h
@@ -36,6 +36,14 @@
namespace TestVector4i {
+TEST_CASE("[Vector4i] Constructor methods") {
+ const Vector4i vector_empty = Vector4i();
+ const Vector4i vector_zero = Vector4i(0, 0, 0, 0);
+ CHECK_MESSAGE(
+ vector_empty == vector_zero,
+ "Vector4i Constructor with no inputs should return a zero Vector4i.");
+}
+
TEST_CASE("[Vector4i] Axis methods") {
Vector4i vector = Vector4i(1, 2, 3, 4);
CHECK_MESSAGE(
diff --git a/thirdparty/README.md b/thirdparty/README.md
index df54f8cf36..b5775db38a 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -214,7 +214,7 @@ Files extracted from upstream source:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 5.1.0 (f1f2be776bcd994fa9262622e1a7098a066e5cf7, 2022)
+- Version: 5.2.0 (4a1d891c6317d2c83e5f3c2607ec5f5ccedffcde, 2022)
- License: MIT
Files extracted from upstream source:
@@ -276,7 +276,7 @@ Files extracted from upstream source:
## libpng
- Upstream: http://libpng.org/pub/png/libpng.html
-- Version: 1.6.37 (a40189cf881e9f0db80511c382292a5604c3c3d1, 2019)
+- Version: 1.6.38 (0a158f3506502dfa23edfc42790dfaed82efba17, 2022)
- License: libpng/zlib
Files extracted from upstream source:
diff --git a/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh b/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh
index e52a617c86..eef89a2879 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh
@@ -206,7 +206,7 @@ struct Coverage
template <typename IterableOut,
hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
- void intersect_set (const hb_set_t &glyphs, IterableOut &intersect_glyphs) const
+ void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
{
switch (u.format)
{
diff --git a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh
index 886babd2d1..82fd48dc50 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh
@@ -88,7 +88,7 @@ struct CoverageFormat1_3
template <typename IterableOut,
hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
- void intersect_set (const hb_set_t &glyphs, IterableOut &intersect_glyphs) const
+ void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
{
unsigned count = glyphArray.len;
for (unsigned i = 0; i < count; i++)
diff --git a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh
index 4ddb2a73e4..974d094633 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh
@@ -140,7 +140,7 @@ struct CoverageFormat2_4
template <typename IterableOut,
hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
- void intersect_set (const hb_set_t &glyphs, IterableOut &intersect_glyphs) const
+ void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
{
for (const auto& range : rangeRecord)
{
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh
index bfe6b36afd..49e76e7750 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh
@@ -58,8 +58,7 @@ struct Anchor
return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
}
return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer))));
- case 3: return_trace (bool (reinterpret_cast<Anchor *> (u.format3.copy (c->serializer,
- c->plan->layout_variation_idx_map))));
+ case 3: return_trace (u.format3.subset (c));
default:return_trace (false);
}
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh
index d77b4699be..2e30ab33c3 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh
@@ -41,24 +41,54 @@ struct AnchorFormat3
*y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
}
- AnchorFormat3* copy (hb_serialize_context_t *c,
- const hb_map_t *layout_variation_idx_map) const
+ bool subset (hb_subset_context_t *c) const
{
- TRACE_SERIALIZE (this);
- if (!layout_variation_idx_map) return_trace (nullptr);
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out)) return_trace (false);
+ if (unlikely (!c->serializer->embed (format))) return_trace (false);
+ if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false);
+ if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false);
- auto *out = c->embed<AnchorFormat3> (this);
- if (unlikely (!out)) return_trace (nullptr);
+ unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+ if (c->plan->layout_variation_idx_delta_map->has (x_varidx))
+ {
+ int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (x_varidx));
+ if (delta != 0)
+ {
+ if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+ }
+ }
- out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
- out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
+ unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+ if (c->plan->layout_variation_idx_delta_map->has (y_varidx))
+ {
+ int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (y_varidx));
+ if (delta != 0)
+ {
+ if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+ }
+ }
+
+ if (c->plan->all_axes_pinned)
+ return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
+
+ if (!c->serializer->embed (xDeviceTable)) return_trace (false);
+ if (!c->serializer->embed (yDeviceTable)) return_trace (false);
+
+ out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map);
+ out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map);
return_trace (out);
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
- (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices);
- (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices);
+ (this+xDeviceTable).collect_variation_indices (c);
+ (this+yDeviceTable).collect_variation_indices (c);
}
};
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh
index e16c06729d..408197454f 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh
@@ -22,7 +22,8 @@ template<typename Iterator, typename SrcLookup>
static void SinglePos_serialize (hb_serialize_context_t *c,
const SrcLookup *src,
Iterator it,
- const hb_map_t *layout_variation_idx_map);
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
+ bool all_axes_pinned);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh
index 7a514453ae..a7d489d2a5 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh
@@ -9,7 +9,7 @@ struct MarkRecord
{
friend struct MarkArray;
- protected:
+ public:
HBUINT16 klass; /* Class defined for this mark */
Offset16To<Anchor>
markAnchor; /* Offset to Anchor table--from
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh
index 3cb207281d..ddf7313f94 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh
@@ -127,6 +127,12 @@ struct PairPosFormat1_3
out->valueFormat[1] = newFormats.second;
}
+ if (c->plan->all_axes_pinned)
+ {
+ out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags ();
+ out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags ();
+ }
+
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ hb_zip (this+coverage, pairSet)
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
index a80fe0c226..83b093b988 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -274,13 +274,19 @@ struct PairPosFormat2_4
out->valueFormat1 = newFormats.first;
out->valueFormat2 = newFormats.second;
+ if (c->plan->all_axes_pinned)
+ {
+ out->valueFormat1 = out->valueFormat1.drop_device_table_flags ();
+ out->valueFormat2 = out->valueFormat2.drop_device_table_flags ();
+ }
+
for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
{
for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
{
unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
- valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map);
- valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map);
+ valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], c->plan->layout_variation_idx_delta_map);
+ valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], c->plan->layout_variation_idx_delta_map);
}
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
index 4578fbd1d6..aa48d933c3 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
@@ -163,7 +163,7 @@ struct PairSet
newFormats,
len1,
&glyph_map,
- c->plan->layout_variation_idx_map
+ c->plan->layout_variation_idx_delta_map
};
const PairValueRecord *record = &firstPairValueRecord;
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh
index bd95abde16..3222477764 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh
@@ -34,7 +34,7 @@ struct PairValueRecord
const ValueFormat *newFormats;
unsigned len1; /* valueFormats[0].get_len() */
const hb_map_t *glyph_map;
- const hb_map_t *layout_variation_idx_map;
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map;
};
bool subset (hb_subset_context_t *c,
@@ -50,12 +50,12 @@ struct PairValueRecord
closure->valueFormats[0].copy_values (s,
closure->newFormats[0],
closure->base, &values[0],
- closure->layout_variation_idx_map);
+ closure->layout_variation_idx_delta_map);
closure->valueFormats[1].copy_values (s,
closure->newFormats[1],
closure->base,
&values[closure->len1],
- closure->layout_variation_idx_map);
+ closure->layout_variation_idx_delta_map);
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh
index 702f578b3c..6dce3e6343 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh
@@ -38,12 +38,16 @@ struct SinglePos
void serialize (hb_serialize_context_t *c,
const SrcLookup* src,
Iterator glyph_val_iter_pairs,
- const hb_map_t *layout_variation_idx_map)
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
+ bool all_axes_pinned)
{
if (unlikely (!c->extend_min (u.format))) return;
unsigned format = 2;
ValueFormat new_format = src->get_value_format ();
+ if (all_axes_pinned)
+ new_format = new_format.drop_device_table_flags ();
+
if (glyph_val_iter_pairs)
format = get_format (glyph_val_iter_pairs);
@@ -53,13 +57,13 @@ struct SinglePos
src,
glyph_val_iter_pairs,
new_format,
- layout_variation_idx_map);
+ layout_variation_idx_delta_map);
return;
case 2: u.format2.serialize (c,
src,
glyph_val_iter_pairs,
new_format,
- layout_variation_idx_map);
+ layout_variation_idx_delta_map);
return;
default:return;
}
@@ -84,8 +88,9 @@ static void
SinglePos_serialize (hb_serialize_context_t *c,
const SrcLookup *src,
Iterator it,
- const hb_map_t *layout_variation_idx_map)
-{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_map); }
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
+ bool all_axes_pinned)
+{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); }
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
index 7cbdf6dc6c..5a9dd58a63 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
@@ -87,7 +87,7 @@ struct SinglePosFormat1
const SrcLookup *src,
Iterator it,
ValueFormat newFormat,
- const hb_map_t *layout_variation_idx_map)
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map)
{
if (unlikely (!c->extend_min (this))) return;
if (unlikely (!c->check_assign (valueFormat,
@@ -96,7 +96,7 @@ struct SinglePosFormat1
for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second))
{
- src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map);
+ src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map);
// Only serialize the first entry in the iterator, the rest are assumed to
// be the same.
break;
@@ -126,7 +126,7 @@ struct SinglePosFormat1
;
bool ret = bool (it);
- SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
+ SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
return_trace (ret);
}
};
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
index 518fa9dcb0..8a6e8a42a6 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
@@ -99,7 +99,7 @@ struct SinglePosFormat2
const SrcLookup *src,
Iterator it,
ValueFormat newFormat,
- const hb_map_t *layout_variation_idx_map)
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map)
{
auto out = c->extend_min (this);
if (unlikely (!out)) return;
@@ -109,7 +109,7 @@ struct SinglePosFormat2
+ it
| hb_map (hb_second)
| hb_apply ([&] (hb_array_t<const Value> _)
- { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); })
+ { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); })
;
auto glyphs =
@@ -141,7 +141,7 @@ struct SinglePosFormat2
;
bool ret = bool (it);
- SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
+ SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
return_trace (ret);
}
};
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh
index b29f287bce..26a40f01a3 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh
@@ -59,6 +59,24 @@ struct ValueFormat : HBUINT16
unsigned int get_len () const { return hb_popcount ((unsigned int) *this); }
unsigned int get_size () const { return get_len () * Value::static_size; }
+ hb_vector_t<unsigned> get_device_table_indices () const {
+ unsigned i = 0;
+ hb_vector_t<unsigned> result;
+ unsigned format = *this;
+
+ if (format & xPlacement) i++;
+ if (format & yPlacement) i++;
+ if (format & xAdvance) i++;
+ if (format & yAdvance) i++;
+
+ if (format & xPlaDevice) result.push (i++);
+ if (format & yPlaDevice) result.push (i++);
+ if (format & xAdvDevice) result.push (i++);
+ if (format & yAdvDevice) result.push (i++);
+
+ return result;
+ }
+
bool apply_value (hb_ot_apply_context_t *c,
const void *base,
const Value *values,
@@ -145,30 +163,50 @@ struct ValueFormat : HBUINT16
unsigned int new_format,
const void *base,
const Value *values,
- const hb_map_t *layout_variation_idx_map) const
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
{
unsigned int format = *this;
if (!format) return;
- if (format & xPlacement) copy_value (c, new_format, xPlacement, *values++);
- if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++);
- if (format & xAdvance) copy_value (c, new_format, xAdvance, *values++);
- if (format & yAdvance) copy_value (c, new_format, yAdvance, *values++);
+ HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr;
+ if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++);
+ if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++);
+ if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++);
+ if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++);
- if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
- if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
- if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
- if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
+ if (format & xPlaDevice)
+ {
+ add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map);
+ copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice);
+ }
+
+ if (format & yPlaDevice)
+ {
+ add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map);
+ copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice);
+ }
+
+ if (format & xAdvDevice)
+ {
+ add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map);
+ copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice);
+ }
+
+ if (format & yAdvDevice)
+ {
+ add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map);
+ copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice);
+ }
}
- void copy_value (hb_serialize_context_t *c,
- unsigned int new_format,
- Flags flag,
- Value value) const
+ HBINT16* copy_value (hb_serialize_context_t *c,
+ unsigned int new_format,
+ Flags flag,
+ Value value) const
{
// Filter by new format.
- if (!(new_format & flag)) return;
- c->copy (value);
+ if (!(new_format & flag)) return nullptr;
+ return reinterpret_cast<HBINT16 *> (c->copy (value));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
@@ -183,31 +221,40 @@ struct ValueFormat : HBUINT16
if (format & yAdvance) i++;
if (format & xPlaDevice)
{
- (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+ (base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
if (format & ValueFormat::yPlaDevice)
{
- (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+ (base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
if (format & ValueFormat::xAdvDevice)
{
- (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+ (base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
if (format & ValueFormat::yAdvDevice)
{
- (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+ (base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
}
+ unsigned drop_device_table_flags () const
+ {
+ unsigned format = *this;
+ for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1)
+ format = format & ~flag;
+
+ return format;
+ }
+
private:
bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
{
@@ -236,9 +283,27 @@ struct ValueFormat : HBUINT16
return *static_cast<const Offset16To<Device> *> (value);
}
+ void add_delta_to_value (HBINT16 *value,
+ const void *base,
+ const Value *src_value,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
+ {
+ if (!value) return;
+ unsigned varidx = (base + get_device (src_value)).get_variation_index ();
+ hb_pair_t<unsigned, int> *varidx_delta;
+ if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return;
+
+ *value += hb_second (*varidx_delta);
+ }
+
bool copy_device (hb_serialize_context_t *c, const void *base,
- const Value *src_value, const hb_map_t *layout_variation_idx_map) const
+ const Value *src_value,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
+ unsigned int new_format, Flags flag) const
{
+ // Filter by new format.
+ if (!(new_format & flag)) return true;
+
Value *dst_value = c->copy (*src_value);
if (!dst_value) return false;
@@ -246,7 +311,7 @@ struct ValueFormat : HBUINT16
*dst_value = 0;
c->push ();
- if ((base + get_device (src_value)).copy (c, layout_variation_idx_map))
+ if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map))
{
c->add_link (*dst_value, c->pop_pack ());
return true;
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh
index 98f2f5fe7a..852ca3eac5 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh
@@ -35,19 +35,17 @@ struct MultipleSubst
}
}
- /* TODO This function is unused and not updated to 24bit GIDs. Should be done by using
- * iterators. While at it perhaps using iterator of arrays of hb_codepoint_t instead. */
+ template<typename Iterator,
+ hb_requires (hb_is_sorted_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c,
- hb_sorted_array_t<const HBGlyphID16> glyphs,
- hb_array_t<const unsigned int> substitute_len_list,
- hb_array_t<const HBGlyphID16> substitute_glyphs_list)
+ Iterator it)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (u.format))) return_trace (false);
unsigned int format = 1;
u.format = format;
switch (u.format) {
- case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
+ case 1: return_trace (u.format1.serialize (c, it));
default:return_trace (false);
}
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
index 89a04ec3b1..3b4bd11694 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
@@ -71,22 +71,31 @@ struct MultipleSubstFormat1_2
return_trace ((this+sequence[index]).apply (c));
}
+ template<typename Iterator,
+ hb_requires (hb_is_sorted_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c,
- hb_sorted_array_t<const HBGlyphID16> glyphs,
- hb_array_t<const unsigned int> substitute_len_list,
- hb_array_t<const HBGlyphID16> substitute_glyphs_list)
+ Iterator it)
{
TRACE_SERIALIZE (this);
+ auto sequences =
+ + it
+ | hb_map (hb_second)
+ ;
+ auto glyphs =
+ + it
+ | hb_map_retains_sorting (hb_first)
+ ;
if (unlikely (!c->extend_min (this))) return_trace (false);
- if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
- for (unsigned int i = 0; i < glyphs.length; i++)
+
+ if (unlikely (!sequence.serialize (c, sequences.length))) return_trace (false);
+
+ for (auto& pair : hb_zip (sequences, sequence))
{
- unsigned int substitute_len = substitute_len_list[i];
- if (unlikely (!sequence[i]
- .serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
+ if (unlikely (!pair.second
+ .serialize_serialize (c, pair.first)))
return_trace (false);
- substitute_glyphs_list += substitute_len;
}
+
return_trace (coverage.serialize_serialize (c, glyphs));
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
index 4b17243d81..13665d7ba1 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
@@ -42,6 +42,11 @@ struct SingleSubstFormat1_3
hb_codepoint_t d = deltaGlyphID;
hb_codepoint_t mask = get_mask ();
+ /* Help fuzzer avoid this function as much. */
+ unsigned pop = (this+coverage).get_population ();
+ if (pop >= mask)
+ return;
+
hb_set_t intersection;
(this+coverage).intersect_set (c->parent_active_glyphs (), intersection);
@@ -52,7 +57,7 @@ struct SingleSubstFormat1_3
hb_codepoint_t max_before = intersection.get_max ();
hb_codepoint_t min_after = (min_before + d) & mask;
hb_codepoint_t max_after = (max_before + d) & mask;
- if ((this+coverage).get_population () >= max_before - min_before &&
+ if (pop >= max_before - min_before &&
((min_before <= min_after && min_after <= max_before) ||
(min_before <= max_after && max_after <= max_before)))
return;
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
index fb1e90d03e..5416299754 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
@@ -41,7 +41,6 @@ struct SingleSubstFormat2_4
| hb_map (hb_second)
| hb_sink (c->output)
;
-
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh
index 320685b868..d49dcc0e0f 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh
@@ -119,19 +119,16 @@ struct SubstLookup : Lookup
return_trace (false);
}
- bool serialize_multiple (hb_serialize_context_t *c,
- uint32_t lookup_props,
- hb_sorted_array_t<const HBGlyphID16> glyphs,
- hb_array_t<const unsigned int> substitute_len_list,
- hb_array_t<const HBGlyphID16> substitute_glyphs_list)
+ template<typename Iterator,
+ hb_requires (hb_is_sorted_iterator (Iterator))>
+ bool serialize (hb_serialize_context_t *c,
+ uint32_t lookup_props,
+ Iterator it)
{
TRACE_SERIALIZE (this);
if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
if (c->push<SubTable> ()->u.multiple.
- serialize (c,
- glyphs,
- substitute_len_list,
- substitute_glyphs_list))
+ serialize (c, it))
{
c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
return_trace (true);
diff --git a/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
index 98c2ee4e73..fc8e309bc9 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
@@ -105,6 +105,67 @@ struct CompositeGlyphRecord
}
}
+ unsigned compile_with_deltas (const contour_point_t &p_delta,
+ char *out) const
+ {
+ const HBINT8 *p = &StructAfter<const HBINT8> (flags);
+#ifndef HB_NO_BEYOND_64K
+ if (flags & GID_IS_24BIT)
+ p += HBGlyphID24::static_size;
+ else
+#endif
+ p += HBGlyphID16::static_size;
+
+ unsigned len = get_size ();
+ unsigned len_before_val = (const char *)p - (const char *)this;
+ if (flags & ARG_1_AND_2_ARE_WORDS)
+ {
+ // no overflow, copy and update value with deltas
+ memcpy (out, this, len);
+
+ const HBINT16 *px = reinterpret_cast<const HBINT16 *> (p);
+ HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val);
+ o[0] = px[0] + roundf (p_delta.x);
+ o[1] = px[1] + roundf (p_delta.y);
+ }
+ else
+ {
+ int new_x = p[0] + roundf (p_delta.x);
+ int new_y = p[1] + roundf (p_delta.y);
+ if (new_x <= 127 && new_x >= -128 &&
+ new_y <= 127 && new_y >= -128)
+ {
+ memcpy (out, this, len);
+ HBINT8 *o = reinterpret_cast<HBINT8 *> (out + len_before_val);
+ o[0] = new_x;
+ o[1] = new_y;
+ }
+ else
+ {
+ // int8 overflows after deltas applied
+ memcpy (out, this, len_before_val);
+
+ //update flags
+ CompositeGlyphRecord *o = reinterpret_cast<CompositeGlyphRecord *> (out);
+ o->flags = flags | ARG_1_AND_2_ARE_WORDS;
+ out += len_before_val;
+
+ HBINT16 new_value;
+ new_value = new_x;
+ memcpy (out, &new_value, HBINT16::static_size);
+ out += HBINT16::static_size;
+
+ new_value = new_y;
+ memcpy (out, &new_value, HBINT16::static_size);
+ out += HBINT16::static_size;
+
+ memcpy (out, p+2, len - len_before_val - 2);
+ len += 2;
+ }
+ }
+ return len;
+ }
+
protected:
bool scaled_offsets () const
{ return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
@@ -288,6 +349,63 @@ struct CompositeGlyph
return;
glyph_chain.set_overlaps_flag ();
}
+
+ bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes,
+ const contour_point_vector_t &deltas,
+ hb_bytes_t &dest_bytes /* OUT */)
+ {
+ if (source_bytes.length <= GlyphHeader::static_size ||
+ header.numberOfContours != -1)
+ {
+ dest_bytes = hb_bytes_t ();
+ return true;
+ }
+
+ unsigned source_len = source_bytes.length - GlyphHeader::static_size;
+
+ /* try to allocate more memories than source glyph bytes
+ * in case that there might be an overflow for int8 value
+ * and we would need to use int16 instead */
+ char *o = (char *) hb_calloc (source_len + source_len/2, sizeof (char));
+ if (unlikely (!o)) return false;
+
+ const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size);
+ auto it = composite_iter_t (hb_bytes_t ((const char *)c, source_len), c);
+
+ char *p = o;
+ unsigned i = 0, source_comp_len = 0;
+ for (const auto &component : it)
+ {
+ /* last 4 points in deltas are phantom points and should not be included */
+ if (i >= deltas.length - 4) return false;
+
+ unsigned comp_len = component.get_size ();
+ if (component.is_anchored ())
+ {
+ memcpy (p, &component, comp_len);
+ p += comp_len;
+ }
+ else
+ {
+ unsigned new_len = component.compile_with_deltas (deltas[i], p);
+ p += new_len;
+ }
+ i++;
+ source_comp_len += comp_len;
+ }
+
+ //copy instructions if any
+ if (source_len > source_comp_len)
+ {
+ unsigned instr_len = source_len - source_comp_len;
+ memcpy (p, (const char *)c + source_comp_len, instr_len);
+ p += instr_len;
+ }
+
+ unsigned len = p - o;
+ dest_bytes = hb_bytes_t (o, len);
+ return true;
+ }
};
diff --git a/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
index 3efe538f37..afcb5dc834 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
@@ -72,12 +72,117 @@ struct Glyph
}
}
+ void update_mtx (const hb_subset_plan_t *plan,
+ int xMin, int yMax,
+ const contour_point_vector_t &all_points) const
+ {
+ hb_codepoint_t new_gid = 0;
+ if (!plan->new_gid_for_old_gid (gid, &new_gid))
+ return;
+
+ unsigned len = all_points.length;
+ float leftSideX = all_points[len - 4].x;
+ float rightSideX = all_points[len - 3].x;
+ float topSideY = all_points[len - 2].y;
+ float bottomSideY = all_points[len - 1].y;
+
+ int hori_aw = roundf (rightSideX - leftSideX);
+ if (hori_aw < 0) hori_aw = 0;
+ int lsb = roundf (xMin - leftSideX);
+ plan->hmtx_map->set (new_gid, hb_pair (hori_aw, lsb));
+
+ int vert_aw = roundf (topSideY - bottomSideY);
+ if (vert_aw < 0) vert_aw = 0;
+ int tsb = roundf (topSideY - yMax);
+ plan->vmtx_map->set (new_gid, hb_pair (vert_aw, tsb));
+ }
+
+ bool compile_header_bytes (const hb_subset_plan_t *plan,
+ const contour_point_vector_t &all_points,
+ hb_bytes_t &dest_bytes /* OUT */) const
+ {
+ GlyphHeader *glyph_header = nullptr;
+ if (all_points.length > 4)
+ {
+ glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
+ if (unlikely (!glyph_header)) return false;
+ }
+
+ int xMin, xMax;
+ xMin = xMax = roundf (all_points[0].x);
+
+ int yMin, yMax;
+ yMin = yMax = roundf (all_points[0].y);
+
+ for (unsigned i = 1; i < all_points.length - 4; i++)
+ {
+ float rounded_x = roundf (all_points[i].x);
+ float rounded_y = roundf (all_points[i].y);
+ xMin = hb_min (xMin, rounded_x);
+ xMax = hb_max (xMax, rounded_x);
+ yMin = hb_min (yMin, rounded_y);
+ yMax = hb_max (yMax, rounded_y);
+ }
+
+ update_mtx (plan, xMin, yMax, all_points);
+
+ /*for empty glyphs: all_points only include phantom points.
+ *just update metrics and then return */
+ if (all_points.length == 4)
+ return true;
+
+ glyph_header->numberOfContours = header->numberOfContours;
+ glyph_header->xMin = xMin;
+ glyph_header->yMin = yMin;
+ glyph_header->xMax = xMax;
+ glyph_header->yMax = yMax;
+
+ dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
+ return true;
+ }
+
+ bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
+ hb_font_t *font,
+ const glyf_accelerator_t &glyf,
+ hb_bytes_t &dest_start, /* IN/OUT */
+ hb_bytes_t &dest_end /* OUT */) const
+ {
+ contour_point_vector_t all_points, deltas;
+ get_points (font, glyf, all_points, &deltas, false);
+
+ switch (type) {
+ case COMPOSITE:
+ if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
+ deltas,
+ dest_end))
+ return false;
+ break;
+ case SIMPLE:
+ if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
+ plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
+ dest_end))
+ return false;
+ break;
+ default:
+ /* set empty bytes for empty glyph
+ * do not use source glyph's pointers */
+ dest_start = hb_bytes_t ();
+ dest_end = hb_bytes_t ();
+ break;
+ }
+
+ return compile_header_bytes (plan, all_points, dest_start);
+ }
+
+
/* Note: Recursively calls itself.
* all_points includes phantom points
*/
template <typename accelerator_t>
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
contour_point_vector_t &all_points /* OUT */,
+ contour_point_vector_t *deltas = nullptr, /* OUT */
+ bool use_my_metrics = true,
bool phantom_only = false,
unsigned int depth = 0) const
{
@@ -130,10 +235,28 @@ struct Glyph
phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
}
+ if (deltas != nullptr && depth == 0 && type == COMPOSITE)
+ {
+ if (unlikely (!deltas->resize (points.length))) return false;
+ for (unsigned i = 0 ; i < points.length; i++)
+ deltas->arrayZ[i] = points.arrayZ[i];
+ }
+
#ifndef HB_NO_VAR
glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ());
#endif
+ // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
+ // with child glyphs' points
+ if (deltas != nullptr && depth == 0 && type == COMPOSITE)
+ {
+ for (unsigned i = 0 ; i < points.length; i++)
+ {
+ deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x;
+ deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y;
+ }
+ }
+
switch (type) {
case SIMPLE:
if (!inplace)
@@ -148,11 +271,11 @@ struct Glyph
comp_points.reset ();
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
.get_points (font, glyf_accelerator, comp_points,
- phantom_only, depth + 1)))
+ deltas, use_my_metrics, phantom_only, depth + 1)))
return false;
/* Copy phantom points from component if USE_MY_METRICS flag set */
- if (item.is_use_my_metrics ())
+ if (use_my_metrics && item.is_use_my_metrics ())
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
diff --git a/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
index 6df978cf13..b99665d6a0 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
@@ -206,6 +206,132 @@ struct SimpleGlyph
&& read_points (p, points_, end, &contour_point_t::y,
FLAG_Y_SHORT, FLAG_Y_SAME);
}
+
+ static void encode_coord (int value,
+ uint8_t &flag,
+ const simple_glyph_flag_t short_flag,
+ const simple_glyph_flag_t same_flag,
+ hb_vector_t<uint8_t> &coords /* OUT */)
+ {
+ if (value == 0)
+ {
+ flag |= same_flag;
+ }
+ else if (value >= -255 && value <= 255)
+ {
+ flag |= short_flag;
+ if (value > 0) flag |= same_flag;
+ else value = -value;
+
+ coords.push ((uint8_t)value);
+ }
+ else
+ {
+ int16_t val = value;
+ coords.push (val >> 8);
+ coords.push (val & 0xff);
+ }
+ }
+
+ static void encode_flag (uint8_t &flag,
+ uint8_t &repeat,
+ uint8_t &lastflag,
+ hb_vector_t<uint8_t> &flags /* OUT */)
+ {
+ if (flag == lastflag && repeat != 255)
+ {
+ repeat = repeat + 1;
+ if (repeat == 1)
+ {
+ flags.push(flag);
+ }
+ else
+ {
+ unsigned len = flags.length;
+ flags[len-2] = flag | FLAG_REPEAT;
+ flags[len-1] = repeat;
+ }
+ }
+ else
+ {
+ repeat = 0;
+ flags.push (flag);
+ }
+ lastflag = flag;
+ }
+
+ bool compile_bytes_with_deltas (const contour_point_vector_t &all_points,
+ bool no_hinting,
+ hb_bytes_t &dest_bytes /* OUT */)
+ {
+ if (header.numberOfContours == 0 || all_points.length <= 4)
+ {
+ dest_bytes = hb_bytes_t ();
+ return true;
+ }
+ //convert absolute values to relative values
+ unsigned num_points = all_points.length - 4;
+ hb_vector_t<hb_pair_t<int, int>> deltas;
+ deltas.resize (num_points);
+
+ for (unsigned i = 0; i < num_points; i++)
+ {
+ deltas[i].first = i == 0 ? roundf (all_points[i].x) : roundf (all_points[i].x) - roundf (all_points[i-1].x);
+ deltas[i].second = i == 0 ? roundf (all_points[i].y) : roundf (all_points[i].y) - roundf (all_points[i-1].y);
+ }
+
+ hb_vector_t<uint8_t> flags, x_coords, y_coords;
+ flags.alloc (num_points);
+ x_coords.alloc (2*num_points);
+ y_coords.alloc (2*num_points);
+
+ uint8_t lastflag = 0, repeat = 0;
+
+ for (unsigned i = 0; i < num_points; i++)
+ {
+ uint8_t flag = all_points[i].flag;
+ flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
+
+ encode_coord (deltas[i].first, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
+ encode_coord (deltas[i].second, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
+ if (i == 0) lastflag = flag + 1; //make lastflag != flag for the first point
+ encode_flag (flag, repeat, lastflag, flags);
+ }
+
+ unsigned len_before_instrs = 2 * header.numberOfContours + 2;
+ unsigned len_instrs = instructions_length ();
+ unsigned total_len = len_before_instrs + flags.length + x_coords.length + y_coords.length;
+
+ if (!no_hinting)
+ total_len += len_instrs;
+
+ char *p = (char *) hb_calloc (total_len, sizeof (char));
+ if (unlikely (!p)) return false;
+
+ const char *src = bytes.arrayZ + GlyphHeader::static_size;
+ char *cur = p;
+ memcpy (p, src, len_before_instrs);
+
+ cur += len_before_instrs;
+ src += len_before_instrs;
+
+ if (!no_hinting)
+ {
+ memcpy (cur, src, len_instrs);
+ cur += len_instrs;
+ }
+
+ memcpy (cur, flags.arrayZ, flags.length);
+ cur += flags.length;
+
+ memcpy (cur, x_coords.arrayZ, x_coords.length);
+ cur += x_coords.length;
+
+ memcpy (cur, y_coords.arrayZ, y_coords.length);
+
+ dest_bytes = hb_bytes_t (p, total_len);
+ return true;
+ }
};
diff --git a/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
index 7ae8fe3078..7ddefc5a91 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
@@ -6,6 +6,9 @@
namespace OT {
+
+struct glyf_accelerator_t;
+
namespace glyf_impl {
@@ -55,6 +58,17 @@ struct SubsetGlyph
return_trace (true);
}
+ bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
+ hb_font_t *font,
+ const glyf_accelerator_t &glyf)
+ { return source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); }
+
+ void free_compiled_bytes ()
+ {
+ dest_start.fini ();
+ dest_end.fini ();
+ }
+
void drop_hints_bytes ()
{ source_glyph.drop_hints_bytes (dest_start, dest_end); }
diff --git a/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh b/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh
index f51f7a81fc..181c33d06d 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh
@@ -16,7 +16,7 @@ template<typename IteratorIn, typename IteratorOut,
hb_requires (hb_is_source_of (IteratorIn, unsigned int)),
hb_requires (hb_is_sink_of (IteratorOut, unsigned))>
static void
-_write_loca (IteratorIn it, bool short_offsets, IteratorOut dest)
+_write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest)
{
unsigned right_shift = short_offsets ? 1 : 0;
unsigned int offset = 0;
diff --git a/thirdparty/harfbuzz/src/OT/glyf/glyf.hh b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
index bcaf44fc1e..be2cb1d0dc 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
@@ -24,7 +24,6 @@ namespace OT {
*/
#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
-
struct glyf
{
friend struct glyf_accelerator_t;
@@ -75,6 +74,9 @@ struct glyf
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
_populate_subset_glyphs (c->plan, &glyphs);
+ if (!c->plan->pinned_at_default)
+ _compile_subset_glyphs_with_deltas (c->plan, &glyphs);
+
auto padded_offsets =
+ hb_iter (glyphs)
| hb_map (&glyf_impl::SubsetGlyph::padded_size)
@@ -93,6 +95,8 @@ struct glyf
}
+ if (!c->plan->pinned_at_default)
+ _free_compiled_subset_glyphs (&glyphs);
if (unlikely (c->serializer->in_error ())) return_trace (false);
return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
padded_offsets,
@@ -102,6 +106,16 @@ struct glyf
void
_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
+
+ void
+ _compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
+ hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
+
+ void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> *glyphs) const
+ {
+ for (auto _ : *glyphs)
+ _.free_compiled_bytes ();
+ }
protected:
UnsizedArrayOf<HBUINT8>
@@ -166,7 +180,7 @@ struct glyf_accelerator_t
contour_point_vector_t all_points;
bool phantom_only = !consumer.is_consuming_contour_points ();
- if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only)))
+ if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, phantom_only)))
return false;
if (consumer.is_consuming_contour_points ())
@@ -389,6 +403,30 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
;
}
+inline void
+glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
+ hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const
+{
+ OT::glyf_accelerator_t glyf (plan->source);
+ hb_font_t *font = hb_font_create (plan->source);
+
+ hb_vector_t<hb_variation_t> vars;
+ vars.alloc (plan->user_axes_location->get_population ());
+
+ for (auto _ : *plan->user_axes_location)
+ {
+ hb_variation_t var;
+ var.tag = _.first;
+ var.value = _.second;
+ vars.push (var);
+ }
+
+ hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ());
+ for (auto& subset_glyph : *glyphs)
+ const_cast<glyf_impl::SubsetGlyph &> (subset_glyph).compile_bytes_with_deltas (plan, font, glyf);
+
+ hb_font_destroy (font);
+}
} /* namespace OT */
diff --git a/thirdparty/harfbuzz/src/graph/classdef-graph.hh b/thirdparty/harfbuzz/src/graph/classdef-graph.hh
new file mode 100644
index 0000000000..0bda76ac2f
--- /dev/null
+++ b/thirdparty/harfbuzz/src/graph/classdef-graph.hh
@@ -0,0 +1,216 @@
+/*
+ * Copyright © 2022 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "graph.hh"
+#include "../hb-ot-layout-common.hh"
+
+#ifndef GRAPH_CLASSDEF_GRAPH_HH
+#define GRAPH_CLASSDEF_GRAPH_HH
+
+namespace graph {
+
+struct ClassDefFormat1 : public OT::ClassDefFormat1_3<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ constexpr unsigned min_size = OT::ClassDefFormat1_3<SmallTypes>::min_size;
+ if (vertex_len < min_size) return false;
+ return vertex_len >= min_size + classValue.get_size () - classValue.len.get_size ();
+ }
+};
+
+struct ClassDefFormat2 : public OT::ClassDefFormat2_4<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ constexpr unsigned min_size = OT::ClassDefFormat2_4<SmallTypes>::min_size;
+ if (vertex_len < min_size) return false;
+ return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
+ }
+};
+
+struct ClassDef : public OT::ClassDef
+{
+ template<typename It>
+ static bool add_class_def (gsubgpos_graph_context_t& c,
+ unsigned parent_id,
+ unsigned link_position,
+ It glyph_and_class,
+ unsigned max_size)
+ {
+ unsigned class_def_prime_id = c.graph.new_node (nullptr, nullptr);
+ auto& class_def_prime_vertex = c.graph.vertices_[class_def_prime_id];
+ if (!make_class_def (c, glyph_and_class, class_def_prime_id, max_size))
+ return false;
+
+ auto* class_def_link = c.graph.vertices_[parent_id].obj.real_links.push ();
+ class_def_link->width = SmallTypes::size;
+ class_def_link->objidx = class_def_prime_id;
+ class_def_link->position = link_position;
+ class_def_prime_vertex.parents.push (parent_id);
+
+ return true;
+ }
+
+ template<typename It>
+ static bool make_class_def (gsubgpos_graph_context_t& c,
+ It glyph_and_class,
+ unsigned dest_obj,
+ unsigned max_size)
+ {
+ char* buffer = (char*) hb_calloc (1, max_size);
+ hb_serialize_context_t serializer (buffer, max_size);
+ OT::ClassDef_serialize (&serializer, glyph_and_class);
+ serializer.end_serialize ();
+ if (serializer.in_error ())
+ {
+ hb_free (buffer);
+ return false;
+ }
+
+ hb_bytes_t class_def_copy = serializer.copy_bytes ();
+ c.add_buffer ((char *) class_def_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+
+ auto& obj = c.graph.vertices_[dest_obj].obj;
+ obj.head = (char *) class_def_copy.arrayZ;
+ obj.tail = obj.head + class_def_copy.length;
+
+ hb_free (buffer);
+ return true;
+ }
+
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < OT::ClassDef::min_size) return false;
+ switch (u.format)
+ {
+ case 1: return ((ClassDefFormat1*)this)->sanitize (vertex);
+ case 2: return ((ClassDefFormat2*)this)->sanitize (vertex);
+#ifndef HB_NO_BORING_EXPANSION
+ // Not currently supported
+ case 3:
+ case 4:
+#endif
+ default: return false;
+ }
+ }
+};
+
+
+struct class_def_size_estimator_t
+{
+ template<typename It>
+ class_def_size_estimator_t (It glyph_and_class)
+ : gids_consecutive (true), num_ranges_per_class (), glyphs_per_class ()
+ {
+ unsigned last_gid = (unsigned) -1;
+ for (auto p : + glyph_and_class)
+ {
+ unsigned gid = p.first;
+ unsigned klass = p.second;
+
+ if (last_gid != (unsigned) -1 && gid != last_gid + 1)
+ gids_consecutive = false;
+ last_gid = gid;
+
+ hb_set_t* glyphs;
+ if (glyphs_per_class.has (klass, &glyphs) && glyphs) {
+ glyphs->add (gid);
+ continue;
+ }
+
+ hb_set_t new_glyphs;
+ new_glyphs.add (gid);
+ glyphs_per_class.set (klass, std::move (new_glyphs));
+ }
+
+ if (in_error ()) return;
+
+ for (unsigned klass : glyphs_per_class.keys ())
+ {
+ if (!klass) continue; // class 0 doesn't get encoded.
+
+ const hb_set_t& glyphs = glyphs_per_class.get (klass);
+ hb_codepoint_t start = HB_SET_VALUE_INVALID;
+ hb_codepoint_t end = HB_SET_VALUE_INVALID;
+
+ unsigned count = 0;
+ while (glyphs.next_range (&start, &end))
+ count++;
+
+ num_ranges_per_class.set (klass, count);
+ }
+ }
+
+ // Incremental increase in the Coverage and ClassDef table size
+ // (worst case) if all glyphs associated with 'klass' were added.
+ unsigned incremental_coverage_size (unsigned klass) const
+ {
+ // Coverage takes 2 bytes per glyph worst case,
+ return 2 * glyphs_per_class.get (klass).get_population ();
+ }
+
+ // Incremental increase in the Coverage and ClassDef table size
+ // (worst case) if all glyphs associated with 'klass' were added.
+ unsigned incremental_class_def_size (unsigned klass) const
+ {
+ // ClassDef takes 6 bytes per range
+ unsigned class_def_2_size = 6 * num_ranges_per_class.get (klass);
+ if (gids_consecutive)
+ {
+ // ClassDef1 takes 2 bytes per glyph, but only can be used
+ // when gids are consecutive.
+ return hb_min (2 * glyphs_per_class.get (klass).get_population (), class_def_2_size);
+ }
+
+ return class_def_2_size;
+ }
+
+ bool in_error ()
+ {
+ if (num_ranges_per_class.in_error ()) return true;
+ if (glyphs_per_class.in_error ()) return true;
+
+ for (const hb_set_t& s : glyphs_per_class.values ())
+ {
+ if (s.in_error ()) return true;
+ }
+ return false;
+ }
+
+ private:
+ bool gids_consecutive;
+ hb_hashmap_t<unsigned, unsigned> num_ranges_per_class;
+ hb_hashmap_t<unsigned, hb_set_t> glyphs_per_class;
+};
+
+
+}
+
+#endif // GRAPH_CLASSDEF_GRAPH_HH
diff --git a/thirdparty/harfbuzz/src/graph/coverage-graph.hh b/thirdparty/harfbuzz/src/graph/coverage-graph.hh
index 1d9fd0eb5b..3c1022f090 100644
--- a/thirdparty/harfbuzz/src/graph/coverage-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/coverage-graph.hh
@@ -56,6 +56,78 @@ struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4<SmallTypes
struct Coverage : public OT::Layout::Common::Coverage
{
+ static Coverage* clone_coverage (gsubgpos_graph_context_t& c,
+ unsigned coverage_id,
+ unsigned new_parent_id,
+ unsigned link_position,
+ unsigned start, unsigned end)
+
+ {
+ unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
+ auto& coverage_v = c.graph.vertices_[coverage_id];
+ Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+ if (!coverage_table || !coverage_table->sanitize (coverage_v))
+ return nullptr;
+
+ auto new_coverage =
+ + hb_zip (coverage_table->iter (), hb_range ())
+ | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
+ return p.second >= start && p.second < end;
+ })
+ | hb_map_retains_sorting (hb_first)
+ ;
+
+ return add_coverage (c, new_parent_id, link_position, new_coverage, coverage_size);
+ }
+
+ template<typename It>
+ static Coverage* add_coverage (gsubgpos_graph_context_t& c,
+ unsigned parent_id,
+ unsigned link_position,
+ It glyphs,
+ unsigned max_size)
+ {
+ unsigned coverage_prime_id = c.graph.new_node (nullptr, nullptr);
+ auto& coverage_prime_vertex = c.graph.vertices_[coverage_prime_id];
+ if (!make_coverage (c, glyphs, coverage_prime_id, max_size))
+ return nullptr;
+
+ auto* coverage_link = c.graph.vertices_[parent_id].obj.real_links.push ();
+ coverage_link->width = SmallTypes::size;
+ coverage_link->objidx = coverage_prime_id;
+ coverage_link->position = link_position;
+ coverage_prime_vertex.parents.push (parent_id);
+
+ return (Coverage*) coverage_prime_vertex.obj.head;
+ }
+
+ template<typename It>
+ static bool make_coverage (gsubgpos_graph_context_t& c,
+ It glyphs,
+ unsigned dest_obj,
+ unsigned max_size)
+ {
+ char* buffer = (char*) hb_calloc (1, max_size);
+ hb_serialize_context_t serializer (buffer, max_size);
+ OT::Layout::Common::Coverage_serialize (&serializer, glyphs);
+ serializer.end_serialize ();
+ if (serializer.in_error ())
+ {
+ hb_free (buffer);
+ return false;
+ }
+
+ hb_bytes_t coverage_copy = serializer.copy_bytes ();
+ c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+
+ auto& obj = c.graph.vertices_[dest_obj].obj;
+ obj.head = (char *) coverage_copy.arrayZ;
+ obj.tail = obj.head + coverage_copy.length;
+
+ hb_free (buffer);
+ return true;
+ }
+
bool sanitize (graph_t::vertex_t& vertex) const
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
diff --git a/thirdparty/harfbuzz/src/graph/graph.hh b/thirdparty/harfbuzz/src/graph/graph.hh
index b3aef558a2..64878a84a4 100644
--- a/thirdparty/harfbuzz/src/graph/graph.hh
+++ b/thirdparty/harfbuzz/src/graph/graph.hh
@@ -49,6 +49,51 @@ struct graph_t
unsigned end = 0;
unsigned priority = 0;
+ void normalize ()
+ {
+ obj.real_links.qsort ();
+ for (auto& l : obj.real_links)
+ {
+ for (unsigned i = 0; i < l.width; i++)
+ {
+ obj.head[l.position + i] = 0;
+ }
+ }
+ }
+
+ bool equals (const vertex_t& other,
+ const graph_t& graph,
+ const graph_t& other_graph,
+ unsigned depth) const
+ {
+ if (!(as_bytes () == other.as_bytes ()))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "vertex [%lu] bytes != [%lu] bytes, depth = %u",
+ table_size (),
+ other.table_size (),
+ depth);
+
+ auto a = as_bytes ();
+ auto b = other.as_bytes ();
+ while (a || b)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " 0x%x %s 0x%x", *a, (*a == *b) ? "==" : "!=", *b);
+ a++;
+ b++;
+ }
+ return false;
+ }
+
+ return links_equal (obj.real_links, other.obj.real_links, graph, other_graph, depth);
+ }
+
+ hb_bytes_t as_bytes () const
+ {
+ return hb_bytes_t (obj.head, table_size ());
+ }
+
friend void swap (vertex_t& a, vertex_t& b)
{
hb_swap (a.obj, b.obj);
@@ -60,6 +105,18 @@ struct graph_t
hb_swap (a.priority, b.priority);
}
+ hb_hashmap_t<unsigned, unsigned>
+ position_to_index_map () const
+ {
+ hb_hashmap_t<unsigned, unsigned> result;
+
+ for (const auto& l : obj.real_links) {
+ result.set (l.position, l.objidx);
+ }
+
+ return result;
+ }
+
bool is_shared () const
{
return parents.length > 1;
@@ -84,7 +141,7 @@ struct graph_t
{
for (unsigned i = 0; i < obj.real_links.length; i++)
{
- auto& link = obj.real_links[i];
+ auto& link = obj.real_links.arrayZ[i];
if (link.objidx != child_index)
continue;
@@ -155,6 +212,57 @@ struct graph_t
return -table_size;
}
+
+ private:
+ bool links_equal (const hb_vector_t<hb_serialize_context_t::object_t::link_t>& this_links,
+ const hb_vector_t<hb_serialize_context_t::object_t::link_t>& other_links,
+ const graph_t& graph,
+ const graph_t& other_graph,
+ unsigned depth) const
+ {
+ auto a = this_links.iter ();
+ auto b = other_links.iter ();
+
+ while (a && b)
+ {
+ const auto& link_a = *a;
+ const auto& link_b = *b;
+
+ if (link_a.width != link_b.width ||
+ link_a.is_signed != link_b.is_signed ||
+ link_a.whence != link_b.whence ||
+ link_a.position != link_b.position ||
+ link_a.bias != link_b.bias)
+ return false;
+
+ if (!graph.vertices_[link_a.objidx].equals (
+ other_graph.vertices_[link_b.objidx], graph, other_graph, depth + 1))
+ return false;
+
+ a++;
+ b++;
+ }
+
+ if (bool (a) != bool (b))
+ return false;
+
+ return true;
+ }
+ };
+
+ template <typename T>
+ struct vertex_and_table_t
+ {
+ vertex_and_table_t () : index (0), vertex (nullptr), table (nullptr)
+ {}
+
+ unsigned index;
+ vertex_t* vertex;
+ T* table;
+
+ operator bool () {
+ return table && vertex;
+ }
};
/*
@@ -169,7 +277,8 @@ struct graph_t
: parents_invalid (true),
distance_invalid (true),
positions_invalid (true),
- successful (true)
+ successful (true),
+ buffers ()
{
num_roots_for_space_.push (1);
bool removed_nil = false;
@@ -201,6 +310,20 @@ struct graph_t
~graph_t ()
{
vertices_.fini ();
+ for (char* b : buffers)
+ hb_free (b);
+ }
+
+ bool operator== (const graph_t& other) const
+ {
+ return root ().equals (other.root (), *this, other, 0);
+ }
+
+ // Sorts links of all objects in a consistent manner and zeroes all offsets.
+ void normalize ()
+ {
+ for (auto& v : vertices_.writer ())
+ v.normalize ();
}
bool in_error () const
@@ -228,6 +351,27 @@ struct graph_t
return vertices_[i].obj;
}
+ void add_buffer (char* buffer)
+ {
+ buffers.push (buffer);
+ }
+
+ /*
+ * Adds a 16 bit link from parent_id to child_id
+ */
+ template<typename T>
+ void add_link (T* offset,
+ unsigned parent_id,
+ unsigned child_id)
+ {
+ auto& v = vertices_[parent_id];
+ auto* link = v.obj.real_links.push ();
+ link->width = 2;
+ link->objidx = child_id;
+ link->position = (char*) offset - (char*) v.obj.head;
+ vertices_[child_id].parents.push (parent_id);
+ }
+
/*
* Generates a new topological sorting of graph ordered by the shortest
* distance to each node if positions are marked as invalid.
@@ -345,13 +489,43 @@ struct graph_t
}
}
- unsigned index_for_offset(unsigned node_idx, const void* offset) const
+ template <typename T, typename ...Ts>
+ vertex_and_table_t<T> as_table (unsigned parent, const void* offset, Ts... ds)
+ {
+ return as_table_from_index<T> (index_for_offset (parent, offset), std::forward<Ts>(ds)...);
+ }
+
+ template <typename T, typename ...Ts>
+ vertex_and_table_t<T> as_table_from_index (unsigned index, Ts... ds)
+ {
+ if (index >= vertices_.length)
+ return vertex_and_table_t<T> ();
+
+ vertex_and_table_t<T> r;
+ r.vertex = &vertices_[index];
+ r.table = (T*) r.vertex->obj.head;
+ r.index = index;
+ if (!r.table)
+ return vertex_and_table_t<T> ();
+
+ if (!r.table->sanitize (*(r.vertex), std::forward<Ts>(ds)...))
+ return vertex_and_table_t<T> ();
+
+ return r;
+ }
+
+ // Finds the object id of the object pointed to by the offset at 'offset'
+ // within object[node_idx].
+ unsigned index_for_offset (unsigned node_idx, const void* offset) const
{
const auto& node = object (node_idx);
if (offset < node.head || offset >= node.tail) return -1;
- for (const auto& link : node.real_links)
+ unsigned length = node.real_links.length;
+ for (unsigned i = 0; i < length; i++)
{
+ // Use direct access for increased performance, this is a hot method.
+ const auto& link = node.real_links.arrayZ[i];
if (offset != node.head + link.position)
continue;
return link.objidx;
@@ -360,6 +534,24 @@ struct graph_t
return -1;
}
+ // Finds the object id of the object pointed to by the offset at 'offset'
+ // within object[node_idx]. Ensures that the returned object is safe to mutate.
+ // That is, if the original child object is shared by parents other than node_idx
+ // it will be duplicated and the duplicate will be returned instead.
+ unsigned mutable_index_for_offset (unsigned node_idx, const void* offset)
+ {
+ unsigned child_idx = index_for_offset (node_idx, offset);
+ auto& child = vertices_[child_idx];
+ for (unsigned p : child.parents)
+ {
+ if (p != node_idx) {
+ return duplicate (node_idx, child_idx);
+ }
+ }
+
+ return child_idx;
+ }
+
/*
* Assign unique space numbers to each connected subgraph of 24 bit and/or 32 bit offset(s).
@@ -1039,6 +1231,7 @@ struct graph_t
bool positions_invalid;
bool successful;
hb_vector_t<unsigned> num_roots_for_space_;
+ hb_vector_t<char*> buffers;
};
}
diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc b/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc
index e0ff6ff85f..b2044426d4 100644
--- a/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc
+++ b/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc
@@ -33,8 +33,7 @@ gsubgpos_graph_context_t::gsubgpos_graph_context_t (hb_tag_t table_tag_,
: table_tag (table_tag_),
graph (graph_),
lookup_list_index (0),
- lookups (),
- buffers ()
+ lookups ()
{
if (table_tag_ != HB_OT_TAG_GPOS
&& table_tag_ != HB_OT_TAG_GSUB)
@@ -53,7 +52,7 @@ unsigned gsubgpos_graph_context_t::create_node (unsigned size)
if (!buffer)
return -1;
- buffers.push (buffer);
+ add_buffer (buffer);
return graph.new_node (buffer, buffer + size);
}
diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh b/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh
index 49b24198ff..9fe9662e64 100644
--- a/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh
+++ b/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh
@@ -40,22 +40,16 @@ struct gsubgpos_graph_context_t
graph_t& graph;
unsigned lookup_list_index;
hb_hashmap_t<unsigned, graph::Lookup*> lookups;
- hb_vector_t<char*> buffers;
+
HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_,
graph_t& graph_);
- ~gsubgpos_graph_context_t ()
- {
- for (char* b : buffers)
- hb_free (b);
- }
-
HB_INTERNAL unsigned create_node (unsigned size);
void add_buffer (char* buffer)
{
- buffers.push (buffer);
+ graph.add_buffer (buffer);
}
private:
diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh b/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
index afa1152c44..a93e7d1c73 100644
--- a/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
@@ -29,6 +29,7 @@
#include "../OT/Layout/GSUB/ExtensionSubst.hh"
#include "gsubgpos-context.hh"
#include "pairpos-graph.hh"
+#include "markbasepos-graph.hh"
#ifndef GRAPH_GSUBGPOS_GRAPH_HH
#define GRAPH_GSUBGPOS_GRAPH_HH
@@ -121,10 +122,12 @@ struct Lookup : public OT::Lookup
if (c.table_tag != HB_OT_TAG_GPOS)
return true;
- if (!is_ext && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair)
+ if (!is_ext &&
+ type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair &&
+ type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase)
return true;
- hb_vector_t<unsigned> all_new_subtables;
+ hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>> all_new_subtables;
for (unsigned i = 0; i < subTable.len; i++)
{
unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
@@ -133,39 +136,66 @@ struct Lookup : public OT::Lookup
ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
(ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
c.graph.object (ext_subtable_index).head;
- if (!extension->sanitize (c.graph.vertices_[ext_subtable_index]))
+ if (!extension || !extension->sanitize (c.graph.vertices_[ext_subtable_index]))
continue;
subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index);
type = extension->get_lookup_type ();
- if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair)
+ if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair
+ && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase)
continue;
}
- PairPos* pairPos = (PairPos*) c.graph.object (subtable_index).head;
- if (!pairPos->sanitize (c.graph.vertices_[subtable_index])) continue;
-
- hb_vector_t<unsigned> new_sub_tables = pairPos->split_subtables (c, subtable_index);
+ hb_vector_t<unsigned> new_sub_tables;
+ switch (type)
+ {
+ case 2:
+ new_sub_tables = split_subtable<PairPos> (c, subtable_index); break;
+ case 4:
+ new_sub_tables = split_subtable<MarkBasePos> (c, subtable_index); break;
+ default:
+ break;
+ }
if (new_sub_tables.in_error ()) return false;
- + new_sub_tables.iter() | hb_sink (all_new_subtables);
+ if (!new_sub_tables) continue;
+ hb_pair_t<unsigned, hb_vector_t<unsigned>>* entry = all_new_subtables.push ();
+ entry->first = i;
+ entry->second = std::move (new_sub_tables);
}
- if (all_new_subtables)
+ if (all_new_subtables) {
add_sub_tables (c, this_index, type, all_new_subtables);
+ }
return true;
}
+ template<typename T>
+ hb_vector_t<unsigned> split_subtable (gsubgpos_graph_context_t& c,
+ unsigned objidx)
+ {
+ T* sub_table = (T*) c.graph.object (objidx).head;
+ if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx]))
+ return hb_vector_t<unsigned> ();
+
+ return sub_table->split_subtables (c, objidx);
+ }
+
void add_sub_tables (gsubgpos_graph_context_t& c,
unsigned this_index,
unsigned type,
- hb_vector_t<unsigned>& subtable_indices)
+ hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids)
{
bool is_ext = is_extension (c.table_tag);
auto& v = c.graph.vertices_[this_index];
+ fix_existing_subtable_links (c, this_index, subtable_ids);
+
+ unsigned new_subtable_count = 0;
+ for (const auto& p : subtable_ids)
+ new_subtable_count += p.second.length;
size_t new_size = v.table_size ()
- + subtable_indices.length * OT::Offset16::static_size;
+ + new_subtable_count * OT::Offset16::static_size;
char* buffer = (char*) hb_calloc (1, new_size);
c.add_buffer (buffer);
memcpy (buffer, v.obj.head, v.table_size());
@@ -175,30 +205,61 @@ struct Lookup : public OT::Lookup
Lookup* new_lookup = (Lookup*) buffer;
- new_lookup->subTable.len = subTable.len + subtable_indices.length;
- unsigned offset_index = subTable.len;
- for (unsigned subtable_id : subtable_indices)
+ unsigned shift = 0;
+ new_lookup->subTable.len = subTable.len + new_subtable_count;
+ for (const auto& p : subtable_ids)
{
- if (is_ext)
+ unsigned offset_index = p.first + shift + 1;
+ shift += p.second.length;
+
+ for (unsigned subtable_id : p.second)
{
- unsigned ext_id = create_extension_subtable (c, subtable_id, type);
- c.graph.vertices_[subtable_id].parents.push (ext_id);
- subtable_id = ext_id;
+ if (is_ext)
+ {
+ unsigned ext_id = create_extension_subtable (c, subtable_id, type);
+ c.graph.vertices_[subtable_id].parents.push (ext_id);
+ subtable_id = ext_id;
+ }
+
+ auto* link = v.obj.real_links.push ();
+ link->width = 2;
+ link->objidx = subtable_id;
+ link->position = (char*) &new_lookup->subTable[offset_index++] -
+ (char*) new_lookup;
+ c.graph.vertices_[subtable_id].parents.push (this_index);
}
-
- auto* link = v.obj.real_links.push ();
- link->width = 2;
- link->objidx = subtable_id;
- link->position = (char*) &new_lookup->subTable[offset_index++] -
- (char*) new_lookup;
- c.graph.vertices_[subtable_id].parents.push (this_index);
}
+ // Repacker sort order depends on link order, which we've messed up so resort it.
+ v.obj.real_links.qsort ();
+
// The head location of the lookup has changed, invalidating the lookups map entry
// in the context. Update the map.
c.lookups.set (this_index, new_lookup);
}
+ void fix_existing_subtable_links (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids)
+ {
+ auto& v = c.graph.vertices_[this_index];
+ Lookup* lookup = (Lookup*) v.obj.head;
+
+ unsigned shift = 0;
+ for (const auto& p : subtable_ids)
+ {
+ unsigned insert_index = p.first + shift;
+ unsigned pos_offset = p.second.length * OT::Offset16::static_size;
+ unsigned insert_offset = (char*) &lookup->subTable[insert_index] - (char*) lookup;
+ shift += p.second.length;
+
+ for (auto& l : v.obj.all_links_writer ())
+ {
+ if (l.position > insert_offset) l.position += pos_offset;
+ }
+ }
+ }
+
unsigned create_extension_subtable (gsubgpos_graph_context_t& c,
unsigned subtable_index,
unsigned type)
@@ -281,7 +342,7 @@ struct GSTAR : public OT::GSUBGPOS
const auto& r = graph.root ();
GSTAR* gstar = (GSTAR*) r.obj.head;
- if (!gstar->sanitize (r))
+ if (!gstar || !gstar->sanitize (r))
return nullptr;
return gstar;
@@ -327,17 +388,16 @@ struct GSTAR : public OT::GSUBGPOS
hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
{
unsigned lookup_list_idx = get_lookup_list_index (graph);
-
const LookupList<Types>* lookupList =
(const LookupList<Types>*) graph.object (lookup_list_idx).head;
- if (!lookupList->sanitize (graph.vertices_[lookup_list_idx]))
+ if (!lookupList || !lookupList->sanitize (graph.vertices_[lookup_list_idx]))
return;
for (unsigned i = 0; i < lookupList->len; i++)
{
unsigned lookup_idx = graph.index_for_offset (lookup_list_idx, &(lookupList->arrayZ[i]));
Lookup* lookup = (Lookup*) graph.object (lookup_idx).head;
- if (!lookup->sanitize (graph.vertices_[lookup_idx])) continue;
+ if (!lookup || !lookup->sanitize (graph.vertices_[lookup_idx])) continue;
lookups.set (lookup_idx, lookup);
}
}
diff --git a/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh b/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh
new file mode 100644
index 0000000000..56fa812406
--- /dev/null
+++ b/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh
@@ -0,0 +1,507 @@
+/*
+ * Copyright © 2022 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#ifndef GRAPH_MARKBASEPOS_GRAPH_HH
+#define GRAPH_MARKBASEPOS_GRAPH_HH
+
+#include "split-helpers.hh"
+#include "coverage-graph.hh"
+#include "../OT/Layout/GPOS/MarkBasePos.hh"
+#include "../OT/Layout/GPOS/PosLookupSubTable.hh"
+
+namespace graph {
+
+struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix
+{
+ bool sanitize (graph_t::vertex_t& vertex, unsigned class_count) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < AnchorMatrix::min_size) return false;
+
+ return vertex_len >= AnchorMatrix::min_size +
+ OT::Offset16::static_size * class_count * this->rows;
+ }
+
+ bool shrink (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ unsigned old_class_count,
+ unsigned new_class_count)
+ {
+ if (new_class_count >= old_class_count) return false;
+ auto& o = c.graph.vertices_[this_index].obj;
+ unsigned base_count = rows;
+ o.tail = o.head +
+ AnchorMatrix::min_size +
+ OT::Offset16::static_size * base_count * new_class_count;
+
+ // Reposition links into the new indexing scheme.
+ for (auto& link : o.real_links.writer ())
+ {
+ unsigned index = (link.position - 2) / 2;
+ unsigned base = index / old_class_count;
+ unsigned klass = index % old_class_count;
+ if (klass >= new_class_count)
+ // should have already been removed
+ return false;
+
+ unsigned new_index = base * new_class_count + klass;
+
+ link.position = (char*) &(this->matrixZ[new_index]) - (char*) this;
+ }
+
+ return true;
+ }
+
+ unsigned clone (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ unsigned start,
+ unsigned end,
+ unsigned class_count)
+ {
+ unsigned base_count = rows;
+ unsigned new_class_count = end - start;
+ unsigned size = AnchorMatrix::min_size +
+ OT::Offset16::static_size * new_class_count * rows;
+ unsigned prime_id = c.create_node (size);
+ if (prime_id == (unsigned) -1) return -1;
+ AnchorMatrix* prime = (AnchorMatrix*) c.graph.object (prime_id).head;
+ prime->rows = base_count;
+
+ auto& o = c.graph.vertices_[this_index].obj;
+ int num_links = o.real_links.length;
+ for (int i = 0; i < num_links; i++)
+ {
+ const auto& link = o.real_links[i];
+ unsigned old_index = (link.position - 2) / OT::Offset16::static_size;
+ unsigned klass = old_index % class_count;
+ if (klass < start || klass >= end) continue;
+
+ unsigned base = old_index / class_count;
+ unsigned new_klass = klass - start;
+ unsigned new_index = base * new_class_count + new_klass;
+
+
+ unsigned child_idx = link.objidx;
+ c.graph.add_link (&(prime->matrixZ[new_index]),
+ prime_id,
+ child_idx);
+
+ auto& child = c.graph.vertices_[child_idx];
+ child.remove_parent (this_index);
+
+ o.real_links.remove (i);
+ num_links--;
+ i--;
+ }
+
+ return prime_id;
+ }
+};
+
+struct MarkArray : public OT::Layout::GPOS_impl::MarkArray
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ unsigned min_size = MarkArray::min_size;
+ if (vertex_len < min_size) return false;
+
+ return vertex_len >= get_size ();
+ }
+
+ bool shrink (gsubgpos_graph_context_t& c,
+ const hb_hashmap_t<unsigned, unsigned>& mark_array_links,
+ unsigned this_index,
+ unsigned new_class_count)
+ {
+ auto& o = c.graph.vertices_[this_index].obj;
+ for (const auto& link : o.real_links)
+ c.graph.vertices_[link.objidx].remove_parent (this_index);
+ o.real_links.reset ();
+
+ unsigned new_index = 0;
+ for (const auto& record : this->iter ())
+ {
+ unsigned klass = record.klass;
+ if (klass >= new_class_count) continue;
+
+ (*this)[new_index].klass = klass;
+ unsigned position = (char*) &record.markAnchor - (char*) this;
+ unsigned* objidx;
+ if (!mark_array_links.has (position, &objidx))
+ {
+ new_index++;
+ continue;
+ }
+
+ c.graph.add_link (&(*this)[new_index].markAnchor, this_index, *objidx);
+ new_index++;
+ }
+
+ this->len = new_index;
+ o.tail = o.head + MarkArray::min_size +
+ OT::Layout::GPOS_impl::MarkRecord::static_size * new_index;
+ return true;
+ }
+
+ unsigned clone (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ const hb_hashmap_t<unsigned, unsigned>& pos_to_index,
+ hb_set_t& marks,
+ unsigned start_class)
+ {
+ unsigned size = MarkArray::min_size +
+ OT::Layout::GPOS_impl::MarkRecord::static_size *
+ marks.get_population ();
+ unsigned prime_id = c.create_node (size);
+ if (prime_id == (unsigned) -1) return -1;
+ MarkArray* prime = (MarkArray*) c.graph.object (prime_id).head;
+ prime->len = marks.get_population ();
+
+
+ unsigned i = 0;
+ for (hb_codepoint_t mark : marks)
+ {
+ (*prime)[i].klass = (*this)[mark].klass - start_class;
+ unsigned offset_pos = (char*) &((*this)[mark].markAnchor) - (char*) this;
+ unsigned* anchor_index;
+ if (pos_to_index.has (offset_pos, &anchor_index))
+ c.graph.move_child (this_index,
+ &((*this)[mark].markAnchor),
+ prime_id,
+ &((*prime)[i].markAnchor));
+
+ i++;
+ }
+
+ return prime_id;
+ }
+};
+
+struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ return vertex_len >= MarkBasePosFormat1::static_size;
+ }
+
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+ {
+ hb_set_t visited;
+
+ const unsigned base_coverage_id = c.graph.index_for_offset (this_index, &baseCoverage);
+ const unsigned base_size =
+ OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size +
+ MarkArray::min_size +
+ AnchorMatrix::min_size +
+ c.graph.vertices_[base_coverage_id].table_size ();
+
+ hb_vector_t<class_info_t> class_to_info = get_class_info (c, this_index);
+
+ unsigned class_count = classCount;
+ auto base_array = c.graph.as_table<AnchorMatrix> (this_index,
+ &baseArray,
+ class_count);
+ if (!base_array) return hb_vector_t<unsigned> ();
+ unsigned base_count = base_array.table->rows;
+
+ unsigned partial_coverage_size = 4;
+ unsigned accumulated = base_size;
+ hb_vector_t<unsigned> split_points;
+
+ for (unsigned klass = 0; klass < class_count; klass++)
+ {
+ class_info_t& info = class_to_info[klass];
+ partial_coverage_size += OT::HBUINT16::static_size * info.marks.get_population ();
+ unsigned accumulated_delta =
+ OT::Layout::GPOS_impl::MarkRecord::static_size * info.marks.get_population () +
+ OT::Offset16::static_size * base_count;
+
+ for (unsigned objidx : info.child_indices)
+ accumulated_delta += c.graph.find_subgraph_size (objidx, visited);
+
+ accumulated += accumulated_delta;
+ unsigned total = accumulated + partial_coverage_size;
+
+ if (total >= (1 << 16))
+ {
+ split_points.push (klass);
+ accumulated = base_size + accumulated_delta;
+ partial_coverage_size = 4 + OT::HBUINT16::static_size * info.marks.get_population ();
+ visited.clear (); // node sharing isn't allowed between splits.
+ }
+ }
+
+
+ const unsigned mark_array_id = c.graph.index_for_offset (this_index, &markArray);
+ split_context_t split_context {
+ c,
+ this,
+ this_index,
+ std::move (class_to_info),
+ c.graph.vertices_[mark_array_id].position_to_index_map (),
+ };
+
+ return actuate_subtable_split<split_context_t> (split_context, split_points);
+ }
+
+ private:
+
+ struct class_info_t {
+ hb_set_t marks;
+ hb_vector_t<unsigned> child_indices;
+ };
+
+ struct split_context_t {
+ gsubgpos_graph_context_t& c;
+ MarkBasePosFormat1* thiz;
+ unsigned this_index;
+ hb_vector_t<class_info_t> class_to_info;
+ hb_hashmap_t<unsigned, unsigned> mark_array_links;
+
+ hb_set_t marks_for (unsigned start, unsigned end)
+ {
+ hb_set_t marks;
+ for (unsigned klass = start; klass < end; klass++)
+ {
+ + class_to_info[klass].marks.iter ()
+ | hb_sink (marks)
+ ;
+ }
+ return marks;
+ }
+
+ unsigned original_count ()
+ {
+ return thiz->classCount;
+ }
+
+ unsigned clone_range (unsigned start, unsigned end)
+ {
+ return thiz->clone_range (*this, this->this_index, start, end);
+ }
+
+ bool shrink (unsigned count)
+ {
+ return thiz->shrink (*this, this->this_index, count);
+ }
+ };
+
+ hb_vector_t<class_info_t> get_class_info (gsubgpos_graph_context_t& c,
+ unsigned this_index)
+ {
+ hb_vector_t<class_info_t> class_to_info;
+
+ unsigned class_count= classCount;
+ class_to_info.resize (class_count);
+
+ auto mark_array = c.graph.as_table<MarkArray> (this_index, &markArray);
+ if (!mark_array) return hb_vector_t<class_info_t> ();
+ unsigned mark_count = mark_array.table->len;
+ for (unsigned mark = 0; mark < mark_count; mark++)
+ {
+ unsigned klass = (*mark_array.table)[mark].get_class ();
+ class_to_info[klass].marks.add (mark);
+ }
+
+ for (const auto& link : mark_array.vertex->obj.real_links)
+ {
+ unsigned mark = (link.position - 2) /
+ OT::Layout::GPOS_impl::MarkRecord::static_size;
+ unsigned klass = (*mark_array.table)[mark].get_class ();
+ class_to_info[klass].child_indices.push (link.objidx);
+ }
+
+ unsigned base_array_id =
+ c.graph.index_for_offset (this_index, &baseArray);
+ auto& base_array_v = c.graph.vertices_[base_array_id];
+
+ for (const auto& link : base_array_v.obj.real_links)
+ {
+ unsigned index = (link.position - 2) / OT::Offset16::static_size;
+ unsigned klass = index % class_count;
+ class_to_info[klass].child_indices.push (link.objidx);
+ }
+
+ return class_to_info;
+ }
+
+ bool shrink (split_context_t& sc,
+ unsigned this_index,
+ unsigned count)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " Shrinking MarkBasePosFormat1 (%u) to [0, %u).",
+ this_index,
+ count);
+
+ unsigned old_count = classCount;
+ if (count >= old_count)
+ return true;
+
+ classCount = count;
+
+ auto mark_coverage = sc.c.graph.as_table<Coverage> (this_index,
+ &markCoverage);
+ if (!mark_coverage) return false;
+ hb_set_t marks = sc.marks_for (0, count);
+ auto new_coverage =
+ + hb_zip (hb_range (), mark_coverage.table->iter ())
+ | hb_filter (marks, hb_first)
+ | hb_map_retains_sorting (hb_second)
+ ;
+ if (!Coverage::make_coverage (sc.c, + new_coverage,
+ mark_coverage.index,
+ 4 + 2 * marks.get_population ()))
+ return false;
+
+
+ auto base_array = sc.c.graph.as_table<AnchorMatrix> (this_index,
+ &baseArray,
+ old_count);
+ if (!base_array || !base_array.table->shrink (sc.c,
+ base_array.index,
+ old_count,
+ count))
+ return false;
+
+ auto mark_array = sc.c.graph.as_table<MarkArray> (this_index,
+ &markArray);
+ if (!mark_array || !mark_array.table->shrink (sc.c,
+ sc.mark_array_links,
+ mark_array.index,
+ count))
+ return false;
+
+ return true;
+ }
+
+ // Create a new MarkBasePos that has all of the data for classes from [start, end).
+ unsigned clone_range (split_context_t& sc,
+ unsigned this_index,
+ unsigned start, unsigned end) const
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " Cloning MarkBasePosFormat1 (%u) range [%u, %u).", this_index, start, end);
+
+ graph_t& graph = sc.c.graph;
+ unsigned prime_size = OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes>::static_size;
+
+ unsigned prime_id = sc.c.create_node (prime_size);
+ if (prime_id == (unsigned) -1) return -1;
+
+ MarkBasePosFormat1* prime = (MarkBasePosFormat1*) graph.object (prime_id).head;
+ prime->format = this->format;
+ unsigned new_class_count = end - start;
+ prime->classCount = new_class_count;
+
+ unsigned base_coverage_id =
+ graph.index_for_offset (sc.this_index, &baseCoverage);
+ graph.add_link (&(prime->baseCoverage), prime_id, base_coverage_id);
+ graph.duplicate (prime_id, base_coverage_id);
+
+ auto mark_coverage = sc.c.graph.as_table<Coverage> (this_index,
+ &markCoverage);
+ if (!mark_coverage) return false;
+ hb_set_t marks = sc.marks_for (start, end);
+ auto new_coverage =
+ + hb_zip (hb_range (), mark_coverage.table->iter ())
+ | hb_filter (marks, hb_first)
+ | hb_map_retains_sorting (hb_second)
+ ;
+ if (!Coverage::add_coverage (sc.c,
+ prime_id,
+ 2,
+ + new_coverage,
+ marks.get_population () * 2 + 4))
+ return -1;
+
+ auto mark_array =
+ graph.as_table <MarkArray> (sc.this_index, &markArray);
+ if (!mark_array) return -1;
+ unsigned new_mark_array =
+ mark_array.table->clone (sc.c,
+ mark_array.index,
+ sc.mark_array_links,
+ marks,
+ start);
+ graph.add_link (&(prime->markArray), prime_id, new_mark_array);
+
+ unsigned class_count = classCount;
+ auto base_array =
+ graph.as_table<AnchorMatrix> (sc.this_index, &baseArray, class_count);
+ if (!base_array) return -1;
+ unsigned new_base_array =
+ base_array.table->clone (sc.c,
+ base_array.index,
+ start, end, this->classCount);
+ graph.add_link (&(prime->baseArray), prime_id, new_base_array);
+
+ return prime_id;
+ }
+};
+
+
+struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
+{
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+ unsigned this_index)
+ {
+ switch (u.format) {
+ case 1:
+ return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, this_index);
+#ifndef HB_NO_BORING_EXPANSION
+ case 2: HB_FALLTHROUGH;
+ // Don't split 24bit PairPos's.
+#endif
+ default:
+ return hb_vector_t<unsigned> ();
+ }
+ }
+
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < u.format.get_size ()) return false;
+
+ switch (u.format) {
+ case 1:
+ return ((MarkBasePosFormat1*)(&u.format1))->sanitize (vertex);
+#ifndef HB_NO_BORING_EXPANSION
+ case 2: HB_FALLTHROUGH;
+#endif
+ default:
+ // We don't handle format 3 and 4 here.
+ return false;
+ }
+ }
+};
+
+
+}
+
+#endif // GRAPH_MARKBASEPOS_GRAPH_HH
diff --git a/thirdparty/harfbuzz/src/graph/pairpos-graph.hh b/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
index 3ca4fc701c..976b872329 100644
--- a/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
@@ -27,7 +27,9 @@
#ifndef GRAPH_PAIRPOS_GRAPH_HH
#define GRAPH_PAIRPOS_GRAPH_HH
+#include "split-helpers.hh"
#include "coverage-graph.hh"
+#include "classdef-graph.hh"
#include "../OT/Layout/GPOS/PairPos.hh"
#include "../OT/Layout/GPOS/PosLookupSubTable.hh"
@@ -51,68 +53,62 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
const unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
const unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
- const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size
- + coverage_size;
+ const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
+ unsigned partial_coverage_size = 4;
unsigned accumulated = base_size;
hb_vector_t<unsigned> split_points;
for (unsigned i = 0; i < pairSet.len; i++)
{
unsigned pair_set_index = pair_set_graph_index (c, this_index, i);
- accumulated += c.graph.find_subgraph_size (pair_set_index, visited);
- accumulated += SmallTypes::size; // for PairSet offset.
+ unsigned accumulated_delta =
+ c.graph.find_subgraph_size (pair_set_index, visited) +
+ SmallTypes::size; // for PairSet offset.
+ partial_coverage_size += OT::HBUINT16::static_size;
- // TODO(garretrieger): don't count the size of the largest pairset against the limit, since
- // it will be packed last in the order and does not contribute to
- // the 64kb limit.
+ accumulated += accumulated_delta;
+ unsigned total = accumulated + hb_min (partial_coverage_size, coverage_size);
- if (accumulated > (1 << 16))
+ if (total >= (1 << 16))
{
split_points.push (i);
- accumulated = base_size;
- visited.clear (); // Pretend node sharing isn't allowed between splits.
+ accumulated = base_size + accumulated_delta;
+ partial_coverage_size = 6;
+ visited.clear (); // node sharing isn't allowed between splits.
}
}
- return do_split (c, this_index, split_points);
+ split_context_t split_context {
+ c,
+ this,
+ this_index,
+ };
+
+ return actuate_subtable_split<split_context_t> (split_context, split_points);
}
private:
- // Split this PairPos into two or more PairPos's. split_points defines
- // the indices (first index to include in the new table) to split at.
- // Returns the object id's of the newly created PairPos subtables.
- hb_vector_t<unsigned> do_split (gsubgpos_graph_context_t& c,
- unsigned this_index,
- const hb_vector_t<unsigned> split_points)
- {
- hb_vector_t<unsigned> new_objects;
- if (!split_points)
- return new_objects;
+ struct split_context_t {
+ gsubgpos_graph_context_t& c;
+ PairPosFormat1* thiz;
+ unsigned this_index;
- for (unsigned i = 0; i < split_points.length; i++)
+ unsigned original_count ()
{
- unsigned start = split_points[i];
- unsigned end = (i < split_points.length - 1) ? split_points[i + 1] : pairSet.len;
- unsigned id = clone_range (c, this_index, start, end);
-
- if (id == (unsigned) -1)
- {
- new_objects.reset ();
- new_objects.allocated = -1; // mark error
- return new_objects;
- }
- new_objects.push (id);
+ return thiz->pairSet.len;
}
- if (!shrink (c, this_index, split_points[0]))
+ unsigned clone_range (unsigned start, unsigned end)
{
- new_objects.reset ();
- new_objects.allocated = -1; // mark error
+ return thiz->clone_range (this->c, this->this_index, start, end);
}
- return new_objects;
- }
+ bool shrink (unsigned count)
+ {
+ return thiz->shrink (this->c, this->this_index, count);
+ }
+ };
bool shrink (gsubgpos_graph_context_t& c,
unsigned this_index,
@@ -129,11 +125,12 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
pairSet.len = count;
c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size;
- unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+ unsigned coverage_id = c.graph.mutable_index_for_offset (this_index, &coverage);
unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
auto& coverage_v = c.graph.vertices_[coverage_id];
+
Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
- if (!coverage_table->sanitize (coverage_v))
+ if (!coverage_table || !coverage_table->sanitize (coverage_v))
return false;
auto new_coverage =
@@ -144,7 +141,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
| hb_map_retains_sorting (hb_first)
;
- return make_coverage (c, new_coverage, coverage_id, coverage_size);
+ return Coverage::make_coverage (c, new_coverage, coverage_id, coverage_size);
}
// Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
@@ -178,79 +175,431 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
}
unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
- unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
- auto& coverage_v = c.graph.vertices_[coverage_id];
- Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
- if (!coverage_table->sanitize (coverage_v))
- return false;
+ if (!Coverage::clone_coverage (c,
+ coverage_id,
+ pair_pos_prime_id,
+ 2,
+ start, end))
+ return -1;
- auto new_coverage =
- + hb_zip (coverage_table->iter (), hb_range ())
- | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
- return p.second >= start && p.second < end;
+ return pair_pos_prime_id;
+ }
+
+
+
+ unsigned pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const
+ {
+ return c.graph.index_for_offset (this_index, &pairSet[i]);
+ }
+};
+
+struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ size_t vertex_len = vertex.table_size ();
+ unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
+ if (vertex_len < min_size) return false;
+
+ const unsigned class1_count = class1Count;
+ return vertex_len >=
+ min_size + class1_count * get_class1_record_size ();
+ }
+
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+ {
+ const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
+ const unsigned class_def_2_size = size_of (c, this_index, &classDef2);
+ const Coverage* coverage = get_coverage (c, this_index);
+ const ClassDef* class_def_1 = get_class_def_1 (c, this_index);
+ auto gid_and_class =
+ + coverage->iter ()
+ | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
+ return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1->get_class (gid));
})
- | hb_map_retains_sorting (hb_first)
;
+ class_def_size_estimator_t estimator (gid_and_class);
+
+ const unsigned class1_count = class1Count;
+ const unsigned class2_count = class2Count;
+ const unsigned class1_record_size = get_class1_record_size ();
- unsigned coverage_prime_id = c.graph.new_node (nullptr, nullptr);
- auto& coverage_prime_vertex = c.graph.vertices_[coverage_prime_id];
- if (!make_coverage (c, new_coverage, coverage_prime_id, coverage_size))
+ const unsigned value_1_len = valueFormat1.get_len ();
+ const unsigned value_2_len = valueFormat2.get_len ();
+ const unsigned total_value_len = value_1_len + value_2_len;
+
+ unsigned accumulated = base_size;
+ unsigned coverage_size = 4;
+ unsigned class_def_1_size = 4;
+ unsigned max_coverage_size = coverage_size;
+ unsigned max_class_def_1_size = class_def_1_size;
+
+ hb_vector_t<unsigned> split_points;
+
+ hb_hashmap_t<unsigned, unsigned> device_tables = get_all_device_tables (c, this_index);
+ hb_vector_t<unsigned> format1_device_table_indices = valueFormat1.get_device_table_indices ();
+ hb_vector_t<unsigned> format2_device_table_indices = valueFormat2.get_device_table_indices ();
+ bool has_device_tables = bool(format1_device_table_indices) || bool(format2_device_table_indices);
+
+ hb_set_t visited;
+ for (unsigned i = 0; i < class1_count; i++)
+ {
+ unsigned accumulated_delta = class1_record_size;
+ coverage_size += estimator.incremental_coverage_size (i);
+ class_def_1_size += estimator.incremental_class_def_size (i);
+ max_coverage_size = hb_max (max_coverage_size, coverage_size);
+ max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size);
+
+ if (has_device_tables) {
+ for (unsigned j = 0; j < class2_count; j++)
+ {
+ unsigned value1_index = total_value_len * (class2_count * i + j);
+ unsigned value2_index = value1_index + value_1_len;
+ accumulated_delta += size_of_value_record_children (c,
+ device_tables,
+ format1_device_table_indices,
+ value1_index,
+ visited);
+ accumulated_delta += size_of_value_record_children (c,
+ device_tables,
+ format2_device_table_indices,
+ value2_index,
+ visited);
+ }
+ }
+
+ accumulated += accumulated_delta;
+ unsigned total = accumulated
+ + coverage_size + class_def_1_size + class_def_2_size
+ // The largest object will pack last and can exceed the size limit.
+ - hb_max (hb_max (coverage_size, class_def_1_size), class_def_2_size);
+ if (total >= (1 << 16))
+ {
+ split_points.push (i);
+ // split does not include i, so add the size for i when we reset the size counters.
+ accumulated = base_size + accumulated_delta;
+ coverage_size = 4 + estimator.incremental_coverage_size (i);
+ class_def_1_size = 4 + estimator.incremental_class_def_size (i);
+ visited.clear (); // node sharing isn't allowed between splits.
+ }
+ }
+
+ split_context_t split_context {
+ c,
+ this,
+ this_index,
+ class1_record_size,
+ total_value_len,
+ value_1_len,
+ value_2_len,
+ max_coverage_size,
+ max_class_def_1_size,
+ device_tables,
+ format1_device_table_indices,
+ format2_device_table_indices
+ };
+
+ return actuate_subtable_split<split_context_t> (split_context, split_points);
+ }
+ private:
+
+ struct split_context_t
+ {
+ gsubgpos_graph_context_t& c;
+ PairPosFormat2* thiz;
+ unsigned this_index;
+ unsigned class1_record_size;
+ unsigned value_record_len;
+ unsigned value1_record_len;
+ unsigned value2_record_len;
+ unsigned max_coverage_size;
+ unsigned max_class_def_size;
+
+ const hb_hashmap_t<unsigned, unsigned>& device_tables;
+ const hb_vector_t<unsigned>& format1_device_table_indices;
+ const hb_vector_t<unsigned>& format2_device_table_indices;
+
+ unsigned original_count ()
+ {
+ return thiz->class1Count;
+ }
+
+ unsigned clone_range (unsigned start, unsigned end)
+ {
+ return thiz->clone_range (*this, start, end);
+ }
+
+ bool shrink (unsigned count)
+ {
+ return thiz->shrink (*this, count);
+ }
+ };
+
+ size_t get_class1_record_size () const
+ {
+ const size_t class2_count = class2Count;
+ return
+ class2_count * (valueFormat1.get_size () + valueFormat2.get_size ());
+ }
+
+ unsigned clone_range (split_context_t& split_context,
+ unsigned start, unsigned end) const
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " Cloning PairPosFormat2 (%u) range [%u, %u).", split_context.this_index, start, end);
+
+ graph_t& graph = split_context.c.graph;
+
+ unsigned num_records = end - start;
+ unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size
+ + num_records * split_context.class1_record_size;
+
+ unsigned pair_pos_prime_id = split_context.c.create_node (prime_size);
+ if (pair_pos_prime_id == (unsigned) -1) return -1;
+
+ PairPosFormat2* pair_pos_prime =
+ (PairPosFormat2*) graph.object (pair_pos_prime_id).head;
+ pair_pos_prime->format = this->format;
+ pair_pos_prime->valueFormat1 = this->valueFormat1;
+ pair_pos_prime->valueFormat2 = this->valueFormat2;
+ pair_pos_prime->class1Count = num_records;
+ pair_pos_prime->class2Count = this->class2Count;
+ clone_class1_records (split_context,
+ pair_pos_prime_id,
+ start,
+ end);
+
+ unsigned coverage_id =
+ graph.index_for_offset (split_context.this_index, &coverage);
+ unsigned class_def_1_id =
+ graph.index_for_offset (split_context.this_index, &classDef1);
+ auto& coverage_v = graph.vertices_[coverage_id];
+ auto& class_def_1_v = graph.vertices_[class_def_1_id];
+ Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+ ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head;
+ if (!coverage_table
+ || !coverage_table->sanitize (coverage_v)
+ || !class_def_1_table
+ || !class_def_1_table->sanitize (class_def_1_v))
return -1;
- auto* coverage_link = c.graph.vertices_[pair_pos_prime_id].obj.real_links.push ();
- coverage_link->width = SmallTypes::size;
- coverage_link->objidx = coverage_prime_id;
- coverage_link->position = 2;
- coverage_prime_vertex.parents.push (pair_pos_prime_id);
+ auto klass_map =
+ + coverage_table->iter ()
+ | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
+ return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1_table->get_class (gid));
+ })
+ | hb_filter ([&] (hb_codepoint_t klass) {
+ return klass >= start && klass < end;
+ }, hb_second)
+ | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class) {
+ // Classes must be from 0...N so subtract start
+ return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid_and_class.first, gid_and_class.second - start);
+ })
+ ;
+
+ if (!Coverage::add_coverage (split_context.c,
+ pair_pos_prime_id,
+ 2,
+ + klass_map | hb_map_retains_sorting (hb_first),
+ split_context.max_coverage_size))
+ return -1;
+
+ // classDef1
+ if (!ClassDef::add_class_def (split_context.c,
+ pair_pos_prime_id,
+ 8,
+ + klass_map,
+ split_context.max_class_def_size))
+ return -1;
+
+ // classDef2
+ unsigned class_def_2_id =
+ graph.index_for_offset (split_context.this_index, &classDef2);
+ auto* class_def_link = graph.vertices_[pair_pos_prime_id].obj.real_links.push ();
+ class_def_link->width = SmallTypes::size;
+ class_def_link->objidx = class_def_2_id;
+ class_def_link->position = 10;
+ graph.vertices_[class_def_2_id].parents.push (pair_pos_prime_id);
+ graph.duplicate (pair_pos_prime_id, class_def_2_id);
return pair_pos_prime_id;
}
- template<typename It>
- bool make_coverage (gsubgpos_graph_context_t& c,
- It glyphs,
- unsigned dest_obj,
- unsigned max_size) const
+ void clone_class1_records (split_context_t& split_context,
+ unsigned pair_pos_prime_id,
+ unsigned start, unsigned end) const
{
- char* buffer = (char*) hb_calloc (1, max_size);
- hb_serialize_context_t serializer (buffer, max_size);
- Coverage_serialize (&serializer, glyphs);
- serializer.end_serialize ();
- if (serializer.in_error ())
+ PairPosFormat2* pair_pos_prime =
+ (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head;
+
+ char* start_addr = ((char*)&values[0]) + start * split_context.class1_record_size;
+ unsigned num_records = end - start;
+ memcpy (&pair_pos_prime->values[0],
+ start_addr,
+ num_records * split_context.class1_record_size);
+
+ if (!split_context.format1_device_table_indices
+ && !split_context.format2_device_table_indices)
+ // No device tables to move over.
+ return;
+
+ unsigned class2_count = class2Count;
+ for (unsigned i = start; i < end; i++)
{
- hb_free (buffer);
- return false;
+ for (unsigned j = 0; j < class2_count; j++)
+ {
+ unsigned value1_index = split_context.value_record_len * (class2_count * i + j);
+ unsigned value2_index = value1_index + split_context.value1_record_len;
+
+ unsigned new_value1_index = split_context.value_record_len * (class2_count * (i - start) + j);
+ unsigned new_value2_index = new_value1_index + split_context.value1_record_len;
+
+ transfer_device_tables (split_context,
+ pair_pos_prime_id,
+ split_context.format1_device_table_indices,
+ value1_index,
+ new_value1_index);
+
+ transfer_device_tables (split_context,
+ pair_pos_prime_id,
+ split_context.format2_device_table_indices,
+ value2_index,
+ new_value2_index);
+ }
}
+ }
- hb_bytes_t coverage_copy = serializer.copy_bytes ();
- c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+ void transfer_device_tables (split_context_t& split_context,
+ unsigned pair_pos_prime_id,
+ const hb_vector_t<unsigned>& device_table_indices,
+ unsigned old_value_record_index,
+ unsigned new_value_record_index) const
+ {
+ PairPosFormat2* pair_pos_prime =
+ (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head;
- auto& obj = c.graph.vertices_[dest_obj].obj;
- obj.head = (char *) coverage_copy.arrayZ;
- obj.tail = obj.head + coverage_copy.length;
+ for (unsigned i : device_table_indices)
+ {
+ OT::Offset16* record = (OT::Offset16*) &values[old_value_record_index + i];
+ unsigned record_position = ((char*) record) - ((char*) this);
+ if (!split_context.device_tables.has (record_position)) continue;
+
+ split_context.c.graph.move_child (
+ split_context.this_index,
+ record,
+ pair_pos_prime_id,
+ (OT::Offset16*) &pair_pos_prime->values[new_value_record_index + i]);
+ }
+ }
- hb_free (buffer);
- return true;
+ bool shrink (split_context_t& split_context,
+ unsigned count)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " Shrinking PairPosFormat2 (%u) to [0, %u).",
+ split_context.this_index,
+ count);
+ unsigned old_count = class1Count;
+ if (count >= old_count)
+ return true;
+
+ graph_t& graph = split_context.c.graph;
+ class1Count = count;
+ graph.vertices_[split_context.this_index].obj.tail -=
+ (old_count - count) * split_context.class1_record_size;
+
+ unsigned coverage_id =
+ graph.mutable_index_for_offset (split_context.this_index, &coverage);
+ unsigned class_def_1_id =
+ graph.mutable_index_for_offset (split_context.this_index, &classDef1);
+ auto& coverage_v = graph.vertices_[coverage_id];
+ auto& class_def_1_v = graph.vertices_[class_def_1_id];
+ Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+ ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head;
+ if (!coverage_table
+ || !coverage_table->sanitize (coverage_v)
+ || !class_def_1_table
+ || !class_def_1_table->sanitize (class_def_1_v))
+ return false;
+
+ auto klass_map =
+ + coverage_table->iter ()
+ | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
+ return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1_table->get_class (gid));
+ })
+ | hb_filter ([&] (hb_codepoint_t klass) {
+ return klass < count;
+ }, hb_second)
+ ;
+
+ if (!Coverage::make_coverage (split_context.c,
+ + klass_map | hb_map_retains_sorting (hb_first),
+ coverage_id,
+ coverage_v.table_size ()))
+ return false;
+
+ return ClassDef::make_class_def (split_context.c,
+ + klass_map,
+ class_def_1_id,
+ class_def_1_v.table_size ());
}
- unsigned pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const
+ hb_hashmap_t<unsigned, unsigned>
+ get_all_device_tables (gsubgpos_graph_context_t& c,
+ unsigned this_index) const
{
- return c.graph.index_for_offset (this_index, &pairSet[i]);
+ const auto& v = c.graph.vertices_[this_index];
+ return v.position_to_index_map ();
}
-};
-struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>
-{
- bool sanitize (graph_t::vertex_t& vertex) const
+ const Coverage* get_coverage (gsubgpos_graph_context_t& c,
+ unsigned this_index) const
{
- // TODO(garretrieger): implement me!
- return true;
+ unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+ auto& coverage_v = c.graph.vertices_[coverage_id];
+
+ Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+ if (!coverage_table || !coverage_table->sanitize (coverage_v))
+ return &Null(Coverage);
+ return coverage_table;
}
- hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+ const ClassDef* get_class_def_1 (gsubgpos_graph_context_t& c,
+ unsigned this_index) const
+ {
+ unsigned class_def_1_id = c.graph.index_for_offset (this_index, &classDef1);
+ auto& class_def_1_v = c.graph.vertices_[class_def_1_id];
+
+ ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head;
+ if (!class_def_1_table || !class_def_1_table->sanitize (class_def_1_v))
+ return &Null(ClassDef);
+ return class_def_1_table;
+ }
+
+ unsigned size_of_value_record_children (gsubgpos_graph_context_t& c,
+ const hb_hashmap_t<unsigned, unsigned>& device_tables,
+ const hb_vector_t<unsigned> device_table_indices,
+ unsigned value_record_index,
+ hb_set_t& visited)
+ {
+ unsigned size = 0;
+ for (unsigned i : device_table_indices)
+ {
+ OT::Layout::GPOS_impl::Value* record = &values[value_record_index + i];
+ unsigned record_position = ((char*) record) - ((char*) this);
+ unsigned* obj_idx;
+ if (!device_tables.has (record_position, &obj_idx)) continue;
+ size += c.graph.find_subgraph_size (*obj_idx, visited);
+ }
+ return size;
+ }
+
+ unsigned size_of (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ const void* offset) const
{
- // TODO(garretrieger): implement me!
- return hb_vector_t<unsigned> ();
+ const unsigned id = c.graph.index_for_offset (this_index, offset);
+ return c.graph.vertices_[id].table_size ();
}
};
diff --git a/thirdparty/harfbuzz/src/graph/split-helpers.hh b/thirdparty/harfbuzz/src/graph/split-helpers.hh
new file mode 100644
index 0000000000..61fd7c2d2f
--- /dev/null
+++ b/thirdparty/harfbuzz/src/graph/split-helpers.hh
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2022 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#ifndef GRAPH_SPLIT_HELPERS_HH
+#define GRAPH_SPLIT_HELPERS_HH
+
+namespace graph {
+
+template<typename Context>
+HB_INTERNAL
+hb_vector_t<unsigned> actuate_subtable_split (Context& split_context,
+ const hb_vector_t<unsigned>& split_points)
+{
+ hb_vector_t<unsigned> new_objects;
+ if (!split_points)
+ return new_objects;
+
+ for (unsigned i = 0; i < split_points.length; i++)
+ {
+ unsigned start = split_points[i];
+ unsigned end = (i < split_points.length - 1)
+ ? split_points[i + 1]
+ : split_context.original_count ();
+ unsigned id = split_context.clone_range (start, end);
+
+ if (id == (unsigned) -1)
+ {
+ new_objects.reset ();
+ new_objects.allocated = -1; // mark error
+ return new_objects;
+ }
+ new_objects.push (id);
+ }
+
+ if (!split_context.shrink (split_points[0]))
+ {
+ new_objects.reset ();
+ new_objects.allocated = -1; // mark error
+ }
+
+ return new_objects;
+}
+
+}
+
+#endif // GRAPH_SPLIT_HELPERS_HH
diff --git a/thirdparty/harfbuzz/src/graph/test-classdef-graph.cc b/thirdparty/harfbuzz/src/graph/test-classdef-graph.cc
new file mode 100644
index 0000000000..55854ff5c2
--- /dev/null
+++ b/thirdparty/harfbuzz/src/graph/test-classdef-graph.cc
@@ -0,0 +1,119 @@
+/*
+ * Copyright © 2022 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "gsubgpos-context.hh"
+#include "classdef-graph.hh"
+
+typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class_t;
+typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t;
+
+
+static bool incremental_size_is (const gid_and_class_list_t& list, unsigned klass,
+ unsigned cov_expected, unsigned class_def_expected)
+{
+ graph::class_def_size_estimator_t estimator (list.iter ());
+
+ unsigned result = estimator.incremental_coverage_size (klass);
+ if (result != cov_expected)
+ {
+ printf ("FAIL: coverage expected size %u but was %u\n", cov_expected, result);
+ return false;
+ }
+
+ result = estimator.incremental_class_def_size (klass);
+ if (result != class_def_expected)
+ {
+ printf ("FAIL: class def expected size %u but was %u\n", class_def_expected, result);
+ return false;
+ }
+
+ return true;
+}
+
+static void test_class_and_coverage_size_estimates ()
+{
+ gid_and_class_list_t empty = {
+ };
+ assert (incremental_size_is (empty, 0, 0, 0));
+ assert (incremental_size_is (empty, 1, 0, 0));
+
+ gid_and_class_list_t class_zero = {
+ {5, 0},
+ };
+ assert (incremental_size_is (class_zero, 0, 2, 0));
+
+ gid_and_class_list_t consecutive = {
+ {4, 0},
+ {5, 0},
+ {6, 1},
+ {7, 1},
+ {8, 2},
+ {9, 2},
+ {10, 2},
+ {11, 2},
+ };
+ assert (incremental_size_is (consecutive, 0, 4, 0));
+ assert (incremental_size_is (consecutive, 1, 4, 4));
+ assert (incremental_size_is (consecutive, 2, 8, 6));
+
+ gid_and_class_list_t non_consecutive = {
+ {4, 0},
+ {5, 0},
+
+ {6, 1},
+ {7, 1},
+
+ {9, 2},
+ {10, 2},
+ {11, 2},
+ {12, 2},
+ };
+ assert (incremental_size_is (non_consecutive, 0, 4, 0));
+ assert (incremental_size_is (non_consecutive, 1, 4, 6));
+ assert (incremental_size_is (non_consecutive, 2, 8, 6));
+
+ gid_and_class_list_t multiple_ranges = {
+ {4, 0},
+ {5, 0},
+
+ {6, 1},
+ {7, 1},
+
+ {9, 1},
+
+ {11, 1},
+ {12, 1},
+ {13, 1},
+ };
+ assert (incremental_size_is (multiple_ranges, 0, 4, 0));
+ assert (incremental_size_is (multiple_ranges, 1, 2 * 6, 3 * 6));
+}
+
+int
+main (int argc, char **argv)
+{
+ test_class_and_coverage_size_estimates ();
+}
diff --git a/thirdparty/harfbuzz/src/hb-array.hh b/thirdparty/harfbuzz/src/hb-array.hh
index 826a901819..5884007c19 100644
--- a/thirdparty/harfbuzz/src/hb-array.hh
+++ b/thirdparty/harfbuzz/src/hb-array.hh
@@ -342,7 +342,7 @@ struct hb_sorted_array_t :
unsigned int i;
return bfind (x, &i) ? &this->arrayZ[i] : not_found;
}
- template <typename T, typename ...Ts>
+ template <typename T>
const Type *bsearch (const T &x, const Type *not_found = nullptr) const
{
unsigned int i;
@@ -389,7 +389,7 @@ struct hb_sorted_array_t :
this->length,
sizeof (Type),
_hb_cmp_method<T, Type, Ts...>,
- ds...);
+ std::forward<Ts> (ds)...);
}
};
template <typename T> inline hb_sorted_array_t<T>
diff --git a/thirdparty/harfbuzz/src/hb-atomic.hh b/thirdparty/harfbuzz/src/hb-atomic.hh
index d6dfb0f57a..14c6fb3264 100644
--- a/thirdparty/harfbuzz/src/hb-atomic.hh
+++ b/thirdparty/harfbuzz/src/hb-atomic.hh
@@ -159,10 +159,13 @@ struct hb_atomic_int_t
hb_atomic_int_t () = default;
constexpr hb_atomic_int_t (int v) : v (v) {}
+ hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; }
+ operator int () const { return get_relaxed (); }
+
void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
- void set (int v_) { hb_atomic_int_impl_set (&v, v_); }
+ void set_release (int v_) { hb_atomic_int_impl_set (&v, v_); }
int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
- int get () const { return hb_atomic_int_impl_get (&v); }
+ int get_acquire () const { return hb_atomic_int_impl_get (&v); }
int inc () { return hb_atomic_int_impl_add (&v, 1); }
int dec () { return hb_atomic_int_impl_add (&v, -1); }
@@ -180,11 +183,11 @@ struct hb_atomic_ptr_t
void init (T* v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
- T *get () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
+ T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
- T * operator -> () const { return get (); }
- template <typename C> operator C * () const { return get (); }
+ T * operator -> () const { return get_acquire (); }
+ template <typename C> operator C * () const { return get_acquire (); }
T *v = nullptr;
};
diff --git a/thirdparty/harfbuzz/src/hb-bit-set.hh b/thirdparty/harfbuzz/src/hb-bit-set.hh
index 4765af67ce..a63887efda 100644
--- a/thirdparty/harfbuzz/src/hb-bit-set.hh
+++ b/thirdparty/harfbuzz/src/hb-bit-set.hh
@@ -56,7 +56,7 @@ struct hb_bit_set_t
{
successful = true;
population = 0;
- last_page_lookup.set_relaxed (0);
+ last_page_lookup = 0;
page_map.init ();
pages.init ();
}
@@ -614,7 +614,7 @@ struct hb_bit_set_t
const auto* page_map_array = page_map.arrayZ;
unsigned int major = get_major (*codepoint);
- unsigned int i = last_page_lookup.get_relaxed ();
+ unsigned int i = last_page_lookup;
if (unlikely (i >= page_map.length || page_map_array[i].major != major))
{
@@ -632,7 +632,7 @@ struct hb_bit_set_t
if (pages_array[current.index].next (codepoint))
{
*codepoint += current.major * page_t::PAGE_BITS;
- last_page_lookup.set_relaxed (i);
+ last_page_lookup = i;
return true;
}
i++;
@@ -645,11 +645,11 @@ struct hb_bit_set_t
if (m != INVALID)
{
*codepoint = current.major * page_t::PAGE_BITS + m;
- last_page_lookup.set_relaxed (i);
+ last_page_lookup = i;
return true;
}
}
- last_page_lookup.set_relaxed (0);
+ last_page_lookup = 0;
*codepoint = INVALID;
return false;
}
@@ -732,7 +732,7 @@ struct hb_bit_set_t
{
const auto* page_map_array = page_map.arrayZ;
unsigned int major = get_major (codepoint);
- unsigned int i = last_page_lookup.get_relaxed ();
+ unsigned int i = last_page_lookup;
if (unlikely (i >= page_map.length || page_map_array[i].major != major))
{
page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
@@ -773,7 +773,7 @@ struct hb_bit_set_t
{
const auto* page_map_array = page_map.arrayZ;
unsigned int major = get_major (codepoint);
- unsigned int i = last_page_lookup.get_relaxed ();
+ unsigned int i = last_page_lookup;
if (unlikely (i >= page_map.length || page_map_array[i].major != major))
{
page_map.bfind(major, &i, HB_NOT_FOUND_STORE_CLOSEST);
@@ -900,7 +900,7 @@ struct hb_bit_set_t
/* The extra page_map length is necessary; can't just rely on vector here,
* since the next check would be tricked because a null page also has
* major==0, which we can't distinguish from an actualy major==0 page... */
- unsigned i = last_page_lookup.get_relaxed ();
+ unsigned i = last_page_lookup;
if (likely (i < page_map.length))
{
auto &cached_page = page_map.arrayZ[i];
@@ -924,7 +924,7 @@ struct hb_bit_set_t
page_map[i] = map;
}
- last_page_lookup.set_relaxed (i);
+ last_page_lookup = i;
return &pages[page_map[i].index];
}
const page_t *page_for (hb_codepoint_t g) const
@@ -934,7 +934,7 @@ struct hb_bit_set_t
/* The extra page_map length is necessary; can't just rely on vector here,
* since the next check would be tricked because a null page also has
* major==0, which we can't distinguish from an actualy major==0 page... */
- unsigned i = last_page_lookup.get_relaxed ();
+ unsigned i = last_page_lookup;
if (likely (i < page_map.length))
{
auto &cached_page = page_map.arrayZ[i];
@@ -946,7 +946,7 @@ struct hb_bit_set_t
if (!page_map.bfind (key, &i))
return nullptr;
- last_page_lookup.set_relaxed (i);
+ last_page_lookup = i;
return &pages[page_map[i].index];
}
page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
diff --git a/thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh b/thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh
index 44c802a00c..87095855d6 100644
--- a/thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh
+++ b/thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh
@@ -32,7 +32,7 @@
#include "hb.hh"
-#line 33 "hb-buffer-deserialize-json.hh"
+#line 36 "hb-buffer-deserialize-json.hh"
static const unsigned char _deserialize_json_trans_keys[] = {
0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u,
48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u,
@@ -557,12 +557,12 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};
-#line 554 "hb-buffer-deserialize-json.hh"
+#line 561 "hb-buffer-deserialize-json.hh"
{
cs = deserialize_json_start;
}
-#line 557 "hb-buffer-deserialize-json.hh"
+#line 566 "hb-buffer-deserialize-json.hh"
{
int _slen;
int _trans;
@@ -774,7 +774,7 @@ _resume:
*end_ptr = p;
}
break;
-#line 735 "hb-buffer-deserialize-json.hh"
+#line 778 "hb-buffer-deserialize-json.hh"
}
_again:
diff --git a/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh b/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh
index 8fbcdcc18c..9062610de2 100644
--- a/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh
+++ b/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh
@@ -32,7 +32,7 @@
#include "hb.hh"
-#line 33 "hb-buffer-deserialize-text.hh"
+#line 36 "hb-buffer-deserialize-text.hh"
static const unsigned char _deserialize_text_trans_keys[] = {
0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 45u, 57u,
48u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u,
@@ -509,12 +509,12 @@ _hb_buffer_deserialize_text (hb_buffer_t *buffer,
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};
-#line 506 "hb-buffer-deserialize-text.hh"
+#line 513 "hb-buffer-deserialize-text.hh"
{
cs = deserialize_text_start;
}
-#line 509 "hb-buffer-deserialize-text.hh"
+#line 518 "hb-buffer-deserialize-text.hh"
{
int _slen;
int _trans;
@@ -894,7 +894,7 @@ _resume:
*end_ptr = p;
}
break;
-#line 826 "hb-buffer-deserialize-text.hh"
+#line 898 "hb-buffer-deserialize-text.hh"
}
_again:
@@ -1043,7 +1043,7 @@ _again:
*end_ptr = p;
}
break;
-#line 953 "hb-buffer-deserialize-text.hh"
+#line 1047 "hb-buffer-deserialize-text.hh"
}
}
diff --git a/thirdparty/harfbuzz/src/hb-buffer.h b/thirdparty/harfbuzz/src/hb-buffer.h
index c6af759fb9..8c17489835 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.h
+++ b/thirdparty/harfbuzz/src/hb-buffer.h
@@ -145,7 +145,7 @@ typedef struct hb_glyph_info_t {
* @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL: In scripts that use elongation (Arabic,
Mongolian, Syriac, etc.), this flag signifies
that it is safe to insert a U+0640 TATWEEL
- character *before* this cluster for elongation.
+ character before this cluster for elongation.
This flag does not determine the
script-specific elongation places, but only
when it is safe to do the elongation without
diff --git a/thirdparty/harfbuzz/src/hb-cache.hh b/thirdparty/harfbuzz/src/hb-cache.hh
index d6b229ed65..897f313fbd 100644
--- a/thirdparty/harfbuzz/src/hb-cache.hh
+++ b/thirdparty/harfbuzz/src/hb-cache.hh
@@ -32,12 +32,21 @@
/* Implements a lockfree cache for int->int functions. */
-template <unsigned int key_bits=16, unsigned int value_bits=8 + 32 - key_bits, unsigned int cache_bits=8>
+template <unsigned int key_bits=16,
+ unsigned int value_bits=8 + 32 - key_bits,
+ unsigned int cache_bits=8,
+ bool thread_safe=true>
struct hb_cache_t
{
+ using item_t = typename std::conditional<thread_safe,
+ hb_atomic_int_t,
+ typename std::conditional<key_bits + value_bits - cache_bits <= 16,
+ short,
+ int>::type
+ >::type;
+
static_assert ((key_bits >= cache_bits), "");
- static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (hb_atomic_int_t)), "");
- static_assert (sizeof (hb_atomic_int_t) == sizeof (unsigned int), "");
+ static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (item_t)), "");
void init () { clear (); }
void fini () {}
@@ -45,14 +54,14 @@ struct hb_cache_t
void clear ()
{
for (unsigned i = 0; i < ARRAY_LENGTH (values); i++)
- values[i].set_relaxed (-1);
+ values[i] = -1;
}
bool get (unsigned int key, unsigned int *value) const
{
unsigned int k = key & ((1u<<cache_bits)-1);
- unsigned int v = values[k].get_relaxed ();
- if ((key_bits + value_bits - cache_bits == 8 * sizeof (hb_atomic_int_t) && v == (unsigned int) -1) ||
+ unsigned int v = values[k];
+ if ((key_bits + value_bits - cache_bits == 8 * sizeof (item_t) && v == (unsigned int) -1) ||
(v >> value_bits) != (key >> cache_bits))
return false;
*value = v & ((1u<<value_bits)-1);
@@ -65,16 +74,13 @@ struct hb_cache_t
return false; /* Overflows */
unsigned int k = key & ((1u<<cache_bits)-1);
unsigned int v = ((key>>cache_bits)<<value_bits) | value;
- values[k].set_relaxed (v);
+ values[k] = v;
return true;
}
private:
- hb_atomic_int_t values[1u<<cache_bits];
+ item_t values[1u<<cache_bits];
};
-typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t;
-typedef hb_cache_t<16, 24, 8> hb_advance_cache_t;
-
#endif /* HB_CACHE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-common.cc b/thirdparty/harfbuzz/src/hb-common.cc
index e6512872e8..bbb6cd552b 100644
--- a/thirdparty/harfbuzz/src/hb-common.cc
+++ b/thirdparty/harfbuzz/src/hb-common.cc
@@ -99,7 +99,7 @@ _hb_options_init ()
}
/* This is idempotent and threadsafe. */
- _hb_options.set_relaxed (u.i);
+ _hb_options = u.i;
}
diff --git a/thirdparty/harfbuzz/src/hb-common.h b/thirdparty/harfbuzz/src/hb-common.h
index 7c7ad87c7c..e92feb9898 100644
--- a/thirdparty/harfbuzz/src/hb-common.h
+++ b/thirdparty/harfbuzz/src/hb-common.h
@@ -495,6 +495,8 @@ hb_language_matches (hb_language_t language,
* @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
* @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
* @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0
+ * @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0
+ * @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0
* @HB_SCRIPT_INVALID: No script set
*
* Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
@@ -716,6 +718,12 @@ typedef enum
*/
HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'),
+ /*
+ * Since 5.2.0
+ */
+ HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/
+ HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/
+
/* No script set. */
HB_SCRIPT_INVALID = HB_TAG_NONE,
diff --git a/thirdparty/harfbuzz/src/hb-config.hh b/thirdparty/harfbuzz/src/hb-config.hh
index db8ec0e908..5567ddaec3 100644
--- a/thirdparty/harfbuzz/src/hb-config.hh
+++ b/thirdparty/harfbuzz/src/hb-config.hh
@@ -35,6 +35,9 @@
#include "config.h"
#endif
+#ifndef HB_BORING_EXPANSION
+#define HB_NO_BORING_EXPANSION
+#endif
#ifdef HB_TINY
#define HB_LEAN
diff --git a/thirdparty/harfbuzz/src/hb-debug.hh b/thirdparty/harfbuzz/src/hb-debug.hh
index 905a46a087..cbe13e5214 100644
--- a/thirdparty/harfbuzz/src/hb-debug.hh
+++ b/thirdparty/harfbuzz/src/hb-debug.hh
@@ -67,12 +67,12 @@ hb_options ()
#endif
/* Make a local copy, so we can access bitfield threadsafely. */
hb_options_union_t u;
- u.i = _hb_options.get_relaxed ();
+ u.i = _hb_options;
if (unlikely (!u.i))
{
_hb_options_init ();
- u.i = _hb_options.get_relaxed ();
+ u.i = _hb_options;
}
return u.opts;
diff --git a/thirdparty/harfbuzz/src/hb-face.cc b/thirdparty/harfbuzz/src/hb-face.cc
index 61adbdd503..2160d6a010 100644
--- a/thirdparty/harfbuzz/src/hb-face.cc
+++ b/thirdparty/harfbuzz/src/hb-face.cc
@@ -132,7 +132,7 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
face->user_data = user_data;
face->destroy = destroy;
- face->num_glyphs.set_relaxed (-1);
+ face->num_glyphs = -1;
face->data.init0 (face);
face->table.init0 (face);
@@ -479,7 +479,7 @@ hb_face_set_upem (hb_face_t *face,
if (hb_object_is_immutable (face))
return;
- face->upem.set_relaxed (upem);
+ face->upem = upem;
}
/**
@@ -514,7 +514,7 @@ hb_face_set_glyph_count (hb_face_t *face,
if (hb_object_is_immutable (face))
return;
- face->num_glyphs.set_relaxed (glyph_count);
+ face->num_glyphs = glyph_count;
}
/**
diff --git a/thirdparty/harfbuzz/src/hb-face.hh b/thirdparty/harfbuzz/src/hb-face.hh
index 765f272858..12e10d01e0 100644
--- a/thirdparty/harfbuzz/src/hb-face.hh
+++ b/thirdparty/harfbuzz/src/hb-face.hh
@@ -83,7 +83,7 @@ struct hb_face_t
unsigned int get_upem () const
{
- unsigned int ret = upem.get_relaxed ();
+ unsigned int ret = upem;
if (unlikely (!ret))
{
return load_upem ();
@@ -93,7 +93,7 @@ struct hb_face_t
unsigned int get_num_glyphs () const
{
- unsigned int ret = num_glyphs.get_relaxed ();
+ unsigned int ret = num_glyphs;
if (unlikely (ret == UINT_MAX))
return load_num_glyphs ();
return ret;
diff --git a/thirdparty/harfbuzz/src/hb-ft.cc b/thirdparty/harfbuzz/src/hb-ft.cc
index ef073475cb..bcc1dd080f 100644
--- a/thirdparty/harfbuzz/src/hb-ft.cc
+++ b/thirdparty/harfbuzz/src/hb-ft.cc
@@ -80,16 +80,19 @@
*/
+using hb_ft_advance_cache_t = hb_cache_t<16, 24, 8, false>;
+
struct hb_ft_font_t
{
int load_flags;
bool symbol; /* Whether selected cmap is symbol cmap. */
bool unref; /* Whether to destroy ft_face when done. */
+ bool transform; /* Whether to apply FT_Face's transform. */
mutable hb_mutex_t lock;
FT_Face ft_face;
mutable unsigned cached_serial;
- mutable hb_advance_cache_t advance_cache;
+ mutable hb_ft_advance_cache_t advance_cache;
};
static hb_ft_font_t *
@@ -136,6 +139,8 @@ _hb_ft_font_destroy (void *data)
/* hb_font changed, update FT_Face. */
static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face)
{
+ hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
+
float x_mult = 1.f, y_mult = 1.f;
if (font->x_scale < 0) x_mult = -x_mult;
@@ -173,6 +178,7 @@ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face)
FT_Matrix matrix = { (int) roundf (x_mult * (1<<16)), 0,
0, (int) roundf (y_mult * (1<<16))};
FT_Set_Transform (ft_face, &matrix, nullptr);
+ ft_font->transform = true;
}
#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
@@ -428,13 +434,19 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
int load_flags = ft_font->load_flags;
+ float x_mult;
#ifdef HAVE_FT_GET_TRANSFORM
- FT_Matrix matrix;
- FT_Get_Transform (ft_face, &matrix, nullptr);
- float mult = matrix.xx / 65536.f;
-#else
- float mult = font->x_scale < 0 ? -1 : +1;
+ if (ft_font->transform)
+ {
+ FT_Matrix matrix;
+ FT_Get_Transform (ft_face, &matrix, nullptr);
+ x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
+ }
+ else
#endif
+ {
+ x_mult = font->x_scale < 0 ? -1 : +1;
+ }
for (unsigned int i = 0; i < count; i++)
{
@@ -450,7 +462,7 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
ft_font->advance_cache.set (glyph, v);
}
- *first_advance = (int) (v * mult + (1<<9)) >> 10;
+ *first_advance = (int) (v * x_mult + (1<<9)) >> 10;
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
@@ -466,13 +478,19 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Fixed v;
+ float y_mult;
#ifdef HAVE_FT_GET_TRANSFORM
- FT_Matrix matrix;
- FT_Get_Transform (ft_font->ft_face, &matrix, nullptr);
- float y_mult = matrix.yy / 65536.f;
-#else
- float y_mult = font->y_scale < 0 ? -1 : +1;
+ if (ft_font->transform)
+ {
+ FT_Matrix matrix;
+ FT_Get_Transform (ft_font->ft_face, &matrix, nullptr);
+ y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
+ }
+ else
#endif
+ {
+ y_mult = font->y_scale < 0 ? -1 : +1;
+ }
if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
return 0;
@@ -498,15 +516,21 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
+ float x_mult, y_mult;
#ifdef HAVE_FT_GET_TRANSFORM
- FT_Matrix matrix;
- FT_Get_Transform (ft_face, &matrix, nullptr);
- float x_mult = matrix.xx / 65536.f;
- float y_mult = matrix.yy / 65536.f;
-#else
- float x_mult = font->x_scale < 0 ? -1 : +1;
- float y_mult = font->y_scale < 0 ? -1 : +1;
+ if (ft_font->transform)
+ {
+ FT_Matrix matrix;
+ FT_Get_Transform (ft_face, &matrix, nullptr);
+ x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
+ y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
+ }
+ else
#endif
+ {
+ x_mult = font->x_scale < 0 ? -1 : +1;
+ y_mult = font->y_scale < 0 ? -1 : +1;
+ }
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
@@ -553,15 +577,21 @@ hb_ft_get_glyph_extents (hb_font_t *font,
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
+ float x_mult, y_mult;
#ifdef HAVE_FT_GET_TRANSFORM
- FT_Matrix matrix;
- FT_Get_Transform (ft_face, &matrix, nullptr);
- float x_mult = matrix.xx / 65536.f;
- float y_mult = matrix.yy / 65536.f;
-#else
- float x_mult = font->x_scale < 0 ? -1 : +1;
- float y_mult = font->y_scale < 0 ? -1 : +1;
+ if (ft_font->transform)
+ {
+ FT_Matrix matrix;
+ FT_Get_Transform (ft_face, &matrix, nullptr);
+ x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
+ y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
+ }
+ else
#endif
+ {
+ x_mult = font->x_scale < 0 ? -1 : +1;
+ y_mult = font->y_scale < 0 ? -1 : +1;
+ }
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
@@ -663,13 +693,19 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
+ float y_mult;
#ifdef HAVE_FT_GET_TRANSFORM
- FT_Matrix matrix;
- FT_Get_Transform (ft_face, &matrix, nullptr);
- float y_mult = matrix.yy / 65536.f;
-#else
- float y_mult = font->y_scale < 0 ? -1 : +1;
+ if (ft_font->transform)
+ {
+ FT_Matrix matrix;
+ FT_Get_Transform (ft_face, &matrix, nullptr);
+ y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
+ }
+ else
#endif
+ {
+ y_mult = font->y_scale < 0 ? -1 : +1;
+ }
if (ft_face->units_per_EM != 0)
{
@@ -1233,13 +1269,14 @@ hb_ft_font_set_funcs (hb_font_t *font)
if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
- _hb_ft_hb_font_changed (font, ft_face);
ft_face->generic.data = blob;
ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
_hb_ft_font_set_funcs (font, ft_face, true);
hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
+
+ _hb_ft_hb_font_changed (font, ft_face);
}
diff --git a/thirdparty/harfbuzz/src/hb-machinery.hh b/thirdparty/harfbuzz/src/hb-machinery.hh
index ff2a99f5ed..2571f22e15 100644
--- a/thirdparty/harfbuzz/src/hb-machinery.hh
+++ b/thirdparty/harfbuzz/src/hb-machinery.hh
@@ -176,12 +176,12 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
void init0 () {} /* Init, when memory is already set to 0. No-op for us. */
void init () { instance.set_relaxed (nullptr); }
- void fini () { do_destroy (instance.get ()); init (); }
+ void fini () { do_destroy (instance.get_acquire ()); init (); }
void free_instance ()
{
retry:
- Stored *p = instance.get ();
+ Stored *p = instance.get_acquire ();
if (unlikely (p && !cmpexch (p, nullptr)))
goto retry;
do_destroy (p);
@@ -203,7 +203,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
Stored * get_stored () const
{
retry:
- Stored *p = this->instance.get ();
+ Stored *p = this->instance.get_acquire ();
if (unlikely (!p))
{
if (unlikely (this->is_inert ()))
diff --git a/thirdparty/harfbuzz/src/hb-object.hh b/thirdparty/harfbuzz/src/hb-object.hh
index f6c7a56991..9876c2923c 100644
--- a/thirdparty/harfbuzz/src/hb-object.hh
+++ b/thirdparty/harfbuzz/src/hb-object.hh
@@ -144,14 +144,14 @@ struct hb_reference_count_t
{
mutable hb_atomic_int_t ref_count;
- void init (int v = 1) { ref_count.set_relaxed (v); }
- int get_relaxed () const { return ref_count.get_relaxed (); }
+ void init (int v = 1) { ref_count = v; }
+ int get_relaxed () const { return ref_count; }
int inc () const { return ref_count.inc (); }
int dec () const { return ref_count.dec (); }
- void fini () { ref_count.set_relaxed (-0x0000DEAD); }
+ void fini () { ref_count = -0x0000DEAD; }
- bool is_inert () const { return !ref_count.get_relaxed (); }
- bool is_valid () const { return ref_count.get_relaxed () > 0; }
+ bool is_inert () const { return !ref_count; }
+ bool is_valid () const { return ref_count > 0; }
};
@@ -214,15 +214,15 @@ static inline void hb_object_trace (const Type *obj, const char *function)
obj ? obj->header.ref_count.get_relaxed () : 0);
}
-template <typename Type>
-static inline Type *hb_object_create ()
+template <typename Type, typename ...Ts>
+static inline Type *hb_object_create (Ts... ds)
{
Type *obj = (Type *) hb_calloc (1, sizeof (Type));
if (unlikely (!obj))
return obj;
- new (obj) Type;
+ new (obj) Type (std::forward<Ts> (ds)...);
hb_object_init (obj);
hb_object_trace (obj, HB_FUNC);
@@ -233,7 +233,7 @@ template <typename Type>
static inline void hb_object_init (Type *obj)
{
obj->header.ref_count.init ();
- obj->header.writable.set_relaxed (true);
+ obj->header.writable = true;
obj->header.user_data.init ();
}
template <typename Type>
@@ -244,12 +244,12 @@ static inline bool hb_object_is_valid (const Type *obj)
template <typename Type>
static inline bool hb_object_is_immutable (const Type *obj)
{
- return !obj->header.writable.get_relaxed ();
+ return !obj->header.writable;
}
template <typename Type>
static inline void hb_object_make_immutable (const Type *obj)
{
- obj->header.writable.set_relaxed (false);
+ obj->header.writable = false;
}
template <typename Type>
static inline Type *hb_object_reference (Type *obj)
@@ -273,7 +273,8 @@ static inline bool hb_object_destroy (Type *obj)
hb_object_fini (obj);
- obj->~Type ();
+ if (!std::is_trivially_destructible<Type>::value)
+ obj->~Type ();
return true;
}
@@ -281,7 +282,7 @@ template <typename Type>
static inline void hb_object_fini (Type *obj)
{
obj->header.ref_count.fini (); /* Do this before user_data */
- hb_user_data_array_t *user_data = obj->header.user_data.get ();
+ hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
if (user_data)
{
user_data->fini ();
@@ -301,7 +302,7 @@ static inline bool hb_object_set_user_data (Type *obj,
assert (hb_object_is_valid (obj));
retry:
- hb_user_data_array_t *user_data = obj->header.user_data.get ();
+ hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
if (unlikely (!user_data))
{
user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1);
@@ -326,7 +327,7 @@ static inline void *hb_object_get_user_data (Type *obj,
if (unlikely (!obj || obj->header.is_inert ()))
return nullptr;
assert (hb_object_is_valid (obj));
- hb_user_data_array_t *user_data = obj->header.user_data.get ();
+ hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
if (!user_data)
return nullptr;
return user_data->get (key);
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
index 4aa337f78b..17b0296616 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
@@ -1379,7 +1379,7 @@ struct cff1
if (unlikely (!len)) return false;
retry:
- hb_sorted_vector_t<gname_t> *names = glyph_names.get ();
+ hb_sorted_vector_t<gname_t> *names = glyph_names.get_acquire ();
if (unlikely (!names))
{
names = (hb_sorted_vector_t<gname_t> *) hb_calloc (sizeof (hb_sorted_vector_t<gname_t>), 1);
diff --git a/thirdparty/harfbuzz/src/hb-ot-font.cc b/thirdparty/harfbuzz/src/hb-ot-font.cc
index 3f13b9994a..c90a65665c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-font.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-font.cc
@@ -59,13 +59,15 @@
* never need to call these functions directly.
**/
+using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>;
+
struct hb_ot_font_t
{
const hb_ot_face_t *ot_face;
/* h_advance caching */
mutable hb_atomic_int_t cached_coords_serial;
- mutable hb_atomic_ptr_t<hb_advance_cache_t> advance_cache;
+ mutable hb_atomic_ptr_t<hb_ot_font_advance_cache_t> advance_cache;
};
static hb_ot_font_t *
@@ -161,14 +163,14 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
bool use_cache = false;
#endif
- hb_advance_cache_t *cache = nullptr;
+ hb_ot_font_advance_cache_t *cache = nullptr;
if (use_cache)
{
retry:
- cache = ot_font->advance_cache.get ();
+ cache = ot_font->advance_cache.get_acquire ();
if (unlikely (!cache))
{
- cache = (hb_advance_cache_t *) hb_malloc (sizeof (hb_advance_cache_t));
+ cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_advance_cache_t));
if (unlikely (!cache))
{
use_cache = false;
@@ -181,7 +183,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
hb_free (cache);
goto retry;
}
- ot_font->cached_coords_serial.set (font->serial_coords);
+ ot_font->cached_coords_serial.set_release (font->serial_coords);
}
}
out:
@@ -197,10 +199,10 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
}
else
{ /* Use cache. */
- if (ot_font->cached_coords_serial.get () != (int) font->serial_coords)
+ if (ot_font->cached_coords_serial.get_acquire () != (int) font->serial_coords)
{
ot_font->advance_cache->init ();
- ot_font->cached_coords_serial.set (font->serial_coords);
+ ot_font->cached_coords_serial.set_release (font->serial_coords);
}
for (unsigned int i = 0; i < count; i++)
diff --git a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
index 50e4b54fde..96a394ba42 100644
--- a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
@@ -73,6 +73,8 @@ struct hmtxvmtx
return_trace (true);
}
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>* get_mtx_map (const hb_subset_plan_t *plan) const
+ { return T::is_horizontal ? plan->hmtx_map : plan->vmtx_map; }
bool subset_update_header (hb_subset_plan_t *plan,
unsigned int num_hmetrics) const
@@ -130,14 +132,15 @@ struct hmtxvmtx
accelerator_t _mtx (c->plan->source);
unsigned num_long_metrics;
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *mtx_map = get_mtx_map (c->plan);
{
/* Determine num_long_metrics to encode. */
auto& plan = c->plan;
+
num_long_metrics = plan->num_output_glyphs ();
- hb_codepoint_t old_gid = 0;
- unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance_without_var_unscaled (old_gid) : 0;
+ unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx);
while (num_long_metrics > 1 &&
- last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance_without_var_unscaled (old_gid) : 0))
+ last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx))
{
num_long_metrics--;
}
@@ -145,14 +148,18 @@ struct hmtxvmtx
auto it =
+ hb_range (c->plan->num_output_glyphs ())
- | hb_map ([c, &_mtx] (unsigned _)
+ | hb_map ([c, &_mtx, mtx_map] (unsigned _)
{
- hb_codepoint_t old_gid;
- if (!c->plan->old_gid_for_new_gid (_, &old_gid))
- return hb_pair (0u, 0);
- int lsb = 0;
- (void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
- return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
+ if (!mtx_map->has (_))
+ {
+ hb_codepoint_t old_gid;
+ if (!c->plan->old_gid_for_new_gid (_, &old_gid))
+ return hb_pair (0u, 0);
+ int lsb = 0;
+ (void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
+ return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
+ }
+ return mtx_map->get (_);
})
;
@@ -330,6 +337,24 @@ struct hmtxvmtx
hb_blob_ptr_t<V> var_table;
};
+ /* get advance: when no variations, call get_advance_without_var_unscaled.
+ * when there're variations, get advance value from mtx_map in subset_plan*/
+ unsigned get_new_gid_advance_unscaled (const hb_subset_plan_t *plan,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *mtx_map,
+ unsigned new_gid,
+ const accelerator_t &_mtx) const
+ {
+ if (mtx_map->is_empty () ||
+ (new_gid == 0 && !mtx_map->has (new_gid)))
+ {
+ hb_codepoint_t old_gid = 0;
+ return plan->old_gid_for_new_gid (new_gid, &old_gid) ?
+ _mtx.get_advance_without_var_unscaled (old_gid) : 0;
+ }
+ else
+ { return mtx_map->get (new_gid).first; }
+ }
+
protected:
UnsizedArrayOf<LongMetric>
longMetricZ; /* Paired advance width and leading
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
index 0532039aad..05916a252c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
@@ -84,10 +84,10 @@ using OT::Layout::MediumTypes;
namespace OT {
template<typename Iterator>
-static inline void ClassDef_serialize (hb_serialize_context_t *c,
+static inline bool ClassDef_serialize (hb_serialize_context_t *c,
Iterator it);
-static void ClassDef_remap_and_serialize (
+static bool ClassDef_remap_and_serialize (
hb_serialize_context_t *c,
const hb_set_t &klasses,
bool use_class_zero,
@@ -186,6 +186,7 @@ struct hb_subset_layout_context_t :
unsigned lookup_index_count;
};
+struct VariationStore;
struct hb_collect_variation_indices_context_t :
hb_dispatch_context_t<hb_collect_variation_indices_context_t>
{
@@ -194,15 +195,27 @@ struct hb_collect_variation_indices_context_t :
static return_t default_return_value () { return hb_empty_t (); }
hb_set_t *layout_variation_indices;
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map;
+ hb_font_t *font;
+ const VariationStore *var_store;
const hb_set_t *glyph_set;
const hb_map_t *gpos_lookups;
+ float *store_cache;
hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_,
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map_,
+ hb_font_t *font_,
+ const VariationStore *var_store_,
const hb_set_t *glyph_set_,
- const hb_map_t *gpos_lookups_) :
+ const hb_map_t *gpos_lookups_,
+ float *store_cache_) :
layout_variation_indices (layout_variation_indices_),
+ varidx_delta_map (varidx_delta_map_),
+ font (font_),
+ var_store (var_store_),
glyph_set (glyph_set_),
- gpos_lookups (gpos_lookups_) {}
+ gpos_lookups (gpos_lookups_),
+ store_cache (store_cache_) {}
};
template<typename OutputArray>
@@ -1380,17 +1393,14 @@ struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType>
*/
-static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
+static bool ClassDef_remap_and_serialize (hb_serialize_context_t *c,
const hb_set_t &klasses,
bool use_class_zero,
hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */
hb_map_t *klass_map /*IN/OUT*/)
{
if (!klass_map)
- {
- ClassDef_serialize (c, glyph_and_klass.iter ());
- return;
- }
+ return ClassDef_serialize (c, glyph_and_klass.iter ());
/* any glyph not assigned a class value falls into Class zero (0),
* if any glyph assigned to class 0, remapping must start with 0->0*/
@@ -1413,7 +1423,7 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
}
c->propagate_error (glyph_and_klass, klasses);
- ClassDef_serialize (c, glyph_and_klass.iter ());
+ return ClassDef_serialize (c, glyph_and_klass.iter ());
}
/*
@@ -1495,11 +1505,12 @@ struct ClassDefFormat1_3
? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter))
: glyph_map.get_population ();
use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length;
- ClassDef_remap_and_serialize (c->serializer,
- orig_klasses,
- use_class_zero,
- glyph_and_klass,
- klass_map);
+ if (!ClassDef_remap_and_serialize (c->serializer,
+ orig_klasses,
+ use_class_zero,
+ glyph_and_klass,
+ klass_map))
+ return_trace (false);
return_trace (keep_empty_table || (bool) glyph_and_klass);
}
@@ -1736,11 +1747,12 @@ struct ClassDefFormat2_4
? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter))
: glyph_map.get_population ();
use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length;
- ClassDef_remap_and_serialize (c->serializer,
- orig_klasses,
- use_class_zero,
- glyph_and_klass,
- klass_map);
+ if (!ClassDef_remap_and_serialize (c->serializer,
+ orig_klasses,
+ use_class_zero,
+ glyph_and_klass,
+ klass_map))
+ return_trace (false);
return_trace (keep_empty_table || (bool) glyph_and_klass);
}
@@ -2124,9 +2136,9 @@ struct ClassDef
};
template<typename Iterator>
-static inline void ClassDef_serialize (hb_serialize_context_t *c,
+static inline bool ClassDef_serialize (hb_serialize_context_t *c,
Iterator it)
-{ c->start_embed<ClassDef> ()->serialize (c, it); }
+{ return (c->start_embed<ClassDef> ()->serialize (c, it)); }
/*
@@ -2280,16 +2292,16 @@ struct VarData
unsigned int count = regionIndices.len;
bool is_long = longWords ();
unsigned word_count = wordCount ();
- unsigned int scount = is_long ? count - word_count : word_count;
+ unsigned int scount = is_long ? count : word_count;
unsigned int lcount = is_long ? word_count : 0;
const HBUINT8 *bytes = get_delta_bytes ();
- const HBUINT8 *row = bytes + inner * (scount + count);
+ const HBUINT8 *row = bytes + inner * get_row_size ();
float delta = 0.;
unsigned int i = 0;
- const HBINT16 *lcursor = reinterpret_cast<const HBINT16 *> (row);
+ const HBINT32 *lcursor = reinterpret_cast<const HBINT32 *> (row);
for (; i < lcount; i++)
{
float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
@@ -2563,7 +2575,7 @@ struct VariationStore
bool serialize (hb_serialize_context_t *c,
const VariationStore *src,
- const hb_array_t <hb_inc_bimap_t> &inner_maps)
+ const hb_array_t <const hb_inc_bimap_t> &inner_maps)
{
TRACE_SERIALIZE (this);
#ifdef HB_NO_VAR
@@ -2618,7 +2630,7 @@ struct VariationStore
return_trace (true);
}
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c, const hb_array_t<const hb_inc_bimap_t> &inner_maps) const
{
TRACE_SUBSET (this);
#ifdef HB_NO_VAR
@@ -2628,22 +2640,7 @@ struct VariationStore
VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> ();
if (unlikely (!varstore_prime)) return_trace (false);
- const hb_set_t *variation_indices = c->plan->layout_variation_indices;
- if (variation_indices->is_empty ()) return_trace (false);
-
- hb_vector_t<hb_inc_bimap_t> inner_maps;
- inner_maps.resize ((unsigned) dataSets.len);
-
- for (unsigned idx : c->plan->layout_variation_indices->iter ())
- {
- uint16_t major = idx >> 16;
- uint16_t minor = idx & 0xFFFF;
-
- if (major >= inner_maps.length)
- return_trace (false);
- inner_maps[major].add (minor);
- }
- varstore_prime->serialize (c->serializer, this, inner_maps.as_array ());
+ varstore_prime->serialize (c->serializer, this, inner_maps);
return_trace (
!c->serializer->in_error()
@@ -3169,28 +3166,36 @@ struct VariationDevice
VariationStore::cache_t *store_cache = nullptr) const
{ return font->em_scalef_y (get_delta (font, store, store_cache)); }
- VariationDevice* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map) const
+ VariationDevice* copy (hb_serialize_context_t *c,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
{
TRACE_SERIALIZE (this);
+ if (!layout_variation_idx_delta_map) return_trace (nullptr);
auto snap = c->snapshot ();
auto *out = c->embed (this);
if (unlikely (!out)) return_trace (nullptr);
- if (!layout_variation_idx_map || layout_variation_idx_map->is_empty ()) return_trace (out);
/* TODO Just get() and bail if NO_VARIATION. Needs to setup the map to return that. */
- if (!layout_variation_idx_map->has (varIdx))
+ if (!layout_variation_idx_delta_map->has (varIdx))
{
c->revert (snap);
return_trace (nullptr);
}
- unsigned new_idx = layout_variation_idx_map->get (varIdx);
+ unsigned new_idx = hb_first (layout_variation_idx_delta_map->get (varIdx));
out->varIdx = new_idx;
return_trace (out);
}
- void record_variation_index (hb_set_t *layout_variation_indices) const
+ void collect_variation_index (hb_collect_variation_indices_context_t *c) const
{
- layout_variation_indices->add (varIdx);
+ c->layout_variation_indices->add (varIdx);
+ int delta = 0;
+ if (c->font && c->var_store)
+ delta = roundf (get_delta (c->font, *c->var_store, c->store_cache));
+
+ /* set new varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX here, will remap
+ * varidx later*/
+ c->varidx_delta_map->set (varIdx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -3283,7 +3288,8 @@ struct Device
}
}
- Device* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map=nullptr) const
+ Device* copy (hb_serialize_context_t *c,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map=nullptr) const
{
TRACE_SERIALIZE (this);
switch (u.b.format) {
@@ -3295,14 +3301,14 @@ struct Device
#endif
#ifndef HB_NO_VAR
case 0x8000:
- return_trace (reinterpret_cast<Device *> (u.variation.copy (c, layout_variation_idx_map)));
+ return_trace (reinterpret_cast<Device *> (u.variation.copy (c, layout_variation_idx_delta_map)));
#endif
default:
return_trace (nullptr);
}
}
- void collect_variation_indices (hb_set_t *layout_variation_indices) const
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
switch (u.b.format) {
#ifndef HB_NO_HINTING
@@ -3313,7 +3319,7 @@ struct Device
#endif
#ifndef HB_NO_VAR
case 0x8000:
- u.variation.record_variation_index (layout_variation_indices);
+ u.variation.collect_variation_index (c);
return;
#endif
default:
@@ -3321,6 +3327,18 @@ struct Device
}
}
+ unsigned get_variation_index () const
+ {
+ switch (u.b.format) {
+#ifndef HB_NO_VAR
+ case 0x8000:
+ return u.variation.varIdx;
+#endif
+ default:
+ return HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+ }
+ }
+
protected:
union {
DeviceHeader b;
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh
index 5bc26d9182..22925fdfa9 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh
@@ -200,15 +200,34 @@ struct CaretValueFormat3
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- auto *out = c->serializer->embed (this);
+ auto *out = c->serializer->start_embed (*this);
if (unlikely (!out)) return_trace (false);
+ if (!c->serializer->embed (caretValueFormat)) return_trace (false);
+ if (!c->serializer->embed (coordinate)) return_trace (false);
+
+ unsigned varidx = (this+deviceTable).get_variation_index ();
+ if (c->plan->layout_variation_idx_delta_map->has (varidx))
+ {
+ int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (varidx));
+ if (delta != 0)
+ {
+ if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+ }
+ }
+
+ if (c->plan->all_axes_pinned)
+ return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
+
+ if (!c->serializer->embed (deviceTable))
+ return_trace (false);
return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
- hb_serialize_context_t::Head, c->plan->layout_variation_idx_map));
+ hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map));
}
- void collect_variation_indices (hb_set_t *layout_variation_indices) const
- { (this+deviceTable).collect_variation_indices (layout_variation_indices); }
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ { (this+deviceTable).collect_variation_indices (c); }
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -255,14 +274,14 @@ struct CaretValue
}
}
- void collect_variation_indices (hb_set_t *layout_variation_indices) const
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
switch (u.format) {
case 1:
case 2:
return;
case 3:
- u.format3.collect_variation_indices (layout_variation_indices);
+ u.format3.collect_variation_indices (c);
return;
default: return;
}
@@ -329,7 +348,7 @@ struct LigGlyph
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
for (const Offset16To<CaretValue>& offset : carets.iter ())
- (this+offset).collect_variation_indices (c->layout_variation_indices);
+ (this+offset).collect_variation_indices (c);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -586,7 +605,10 @@ struct GDEFVersion1_2
bool subset_varstore = false;
if (version.to_int () >= 0x00010003u)
{
- subset_varstore = out->varStore.serialize_subset (c, varStore, this);
+ if (c->plan->all_axes_pinned)
+ out->varStore = 0;
+ else
+ subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
}
if (subset_varstore)
@@ -846,7 +868,7 @@ struct GDEF
{ get_lig_caret_list ().collect_variation_indices (c); }
void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
- hb_map_t *layout_variation_idx_map /* OUT */) const
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
{
if (!has_var_store ()) return;
if (layout_variation_indices->is_empty ()) return;
@@ -864,7 +886,11 @@ struct GDEF
}
unsigned new_idx = (new_major << 16) + new_minor;
- layout_variation_idx_map->set (idx, new_idx);
+ if (!layout_variation_idx_delta_map->has (idx))
+ continue;
+ int delta = hb_second (layout_variation_idx_delta_map->get (idx));
+
+ layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
++new_minor;
last_major = major;
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
index c77ec12fbe..c15a42b0f1 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
@@ -4261,6 +4261,7 @@ struct GSUBGPOS
}
void prune_langsys (const hb_map_t *duplicate_feature_map,
+ const hb_set_t *layout_scripts,
hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map,
hb_set_t *new_feature_indexes /* OUT */) const
{
@@ -4269,6 +4270,8 @@ struct GSUBGPOS
unsigned count = get_script_count ();
for (unsigned script_index = 0; script_index < count; script_index++)
{
+ const Tag& tag = get_script_tag (script_index);
+ if (!layout_scripts->has (tag)) continue;
const Script& s = get_script (script_index);
s.prune_langsys (&c, script_index);
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.cc b/thirdparty/harfbuzz/src/hb-ot-layout.cc
index f9c0daa486..44e57987b7 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.cc
@@ -601,9 +601,13 @@ hb_ot_layout_table_select_script (hb_face_t *face,
* @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table
*
* Fetches a list of all feature tags in the given face's GSUB or GPOS table.
+ * Note that there might be duplicate feature tags, belonging to different
+ * script/language-system pairs of the table.
*
* Return value: Total number of feature tags.
*
+ * Since: 0.6.0
+ *
**/
unsigned int
hb_ot_layout_table_get_feature_tags (hb_face_t *face,
@@ -629,6 +633,9 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face,
* or GPOS table.
*
* Return value: `true` if the feature is found, `false` otherwise
+ *
+ * Since: 0.6.0
+ *
**/
bool
hb_ot_layout_table_find_feature (hb_face_t *face,
@@ -668,6 +675,8 @@ hb_ot_layout_table_find_feature (hb_face_t *face,
*
* Return value: Total number of language tags.
*
+ * Since: 0.6.0
+ *
**/
unsigned int
hb_ot_layout_script_get_language_tags (hb_face_t *face,
@@ -778,6 +787,8 @@ hb_ot_layout_script_select_language (hb_face_t *face,
*
* Return value: `true` if the feature is found, `false` otherwise
*
+ * Since: 0.6.0
+ *
**/
hb_bool_t
hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
@@ -846,6 +857,9 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face,
* returned will begin at the offset provided.
*
* Return value: Total number of features.
+ *
+ * Since: 0.6.0
+ *
**/
unsigned int
hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
@@ -879,6 +893,9 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
* returned will begin at the offset provided.
*
* Return value: Total number of feature tags.
+ *
+ * Since: 0.6.0
+ *
**/
unsigned int
hb_ot_layout_language_get_feature_tags (hb_face_t *face,
@@ -919,6 +936,8 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
*
* Return value: `true` if the feature is found, `false` otherwise
*
+ * Since: 0.6.0
+ *
**/
hb_bool_t
hb_ot_layout_language_find_feature (hb_face_t *face,
@@ -1167,9 +1186,12 @@ script_collect_features (hb_collect_features_context_t *c,
* hb_ot_layout_collect_features:
* @face: #hb_face_t to work upon
* @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
- * @scripts: The array of scripts to collect features for
- * @languages: The array of languages to collect features for
- * @features: The array of features to collect
+ * @scripts: (nullable) (array zero-terminated=1): The array of scripts to collect features for,
+ * terminated by %HB_TAG_NONE
+ * @languages: (nullable) (array zero-terminated=1): The array of languages to collect features for,
+ * terminated by %HB_TAG_NONE
+ * @features: (nullable) (array zero-terminated=1): The array of features to collect,
+ * terminated by %HB_TAG_NONE
* @feature_indexes: (out): The array of feature indexes found for the query
*
* Fetches a list of all feature indexes in the specified face's GSUB table
@@ -1216,9 +1238,12 @@ hb_ot_layout_collect_features (hb_face_t *face,
* hb_ot_layout_collect_lookups:
* @face: #hb_face_t to work upon
* @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
- * @scripts: The array of scripts to collect lookups for
- * @languages: The array of languages to collect lookups for
- * @features: The array of features to collect lookups for
+ * @scripts: (nullable) (array zero-terminated=1): The array of scripts to collect lookups for,
+ * terminated by %HB_TAG_NONE
+ * @languages: (nullable) (array zero-terminated=1): The array of languages to collect lookups for,
+ * terminated by %HB_TAG_NONE
+ * @features: (nullable) (array zero-terminated=1): The array of features to collect lookups for,
+ * terminated by %HB_TAG_NONE
* @lookup_indexes: (out): The array of lookup indexes found for the query
*
* Fetches a list of all feature-lookup indexes in the specified face's GSUB
@@ -1316,6 +1341,8 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
*
* Return value: `true` if feature variations were found, `false` otherwise.
*
+ * Since: 1.4.0
+ *
**/
hb_bool_t
hb_ot_layout_table_find_feature_variations (hb_face_t *face,
@@ -1347,6 +1374,8 @@ hb_ot_layout_table_find_feature_variations (hb_face_t *face,
*
* Return value: Total number of lookups.
*
+ * Since: 1.4.0
+ *
**/
unsigned int
hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
@@ -1379,6 +1408,8 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
*
* Return value: `true` if data found, `false` otherwise
*
+ * Since: 0.6.0
+ *
**/
hb_bool_t
hb_ot_layout_has_substitution (hb_face_t *face)
@@ -2297,11 +2328,6 @@ struct hb_get_glyph_alternates_dispatch_t :
static return_t default_return_value () { return 0; }
bool stop_sublookup_iteration (return_t r) const { return r; }
- hb_face_t *face;
-
- hb_get_glyph_alternates_dispatch_t (hb_face_t *face) :
- face (face) {}
-
private:
template <typename T, typename ...Ts> auto
_dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
@@ -2340,7 +2366,7 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face,
unsigned *alternate_count /* IN/OUT. May be NULL. */,
hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */)
{
- hb_get_glyph_alternates_dispatch_t c (face);
+ hb_get_glyph_alternates_dispatch_t c;
const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index);
auto ret = lookup.dispatch (&c, glyph, start_offset, alternate_count, alternate_glyphs);
if (!ret && alternate_count) *alternate_count = 0;
diff --git a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
index 3473afef54..c6e8fad6fc 100644
--- a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
@@ -166,6 +166,47 @@ struct OS2
}
}
+ float map_wdth_to_widthclass(float width) const
+ {
+ if (width < 50) return 1.0f;
+ if (width > 200) return 9.0f;
+
+ float ratio = (width - 50) / 12.5f;
+ int a = (int) floorf (ratio);
+ int b = (int) ceilf (ratio);
+
+ /* follow this maping:
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswidthclass
+ */
+ if (b <= 6) // 50-125
+ {
+ if (a == b) return a + 1.0f;
+ }
+ else if (b == 7) // no mapping for 137.5
+ {
+ a = 6;
+ b = 8;
+ }
+ else if (b == 8)
+ {
+ if (a == b) return 8.0f; // 150
+ a = 6;
+ }
+ else
+ {
+ if (a == b && a == 12) return 9.0f; //200
+ b = 12;
+ a = 8;
+ }
+
+ float va = 50 + a * 12.5f;
+ float vb = 50 + b * 12.5f;
+
+ float ret = a + (width - va) / (vb - va);
+ if (a <= 6) ret += 1.0f;
+ return ret;
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@@ -183,6 +224,26 @@ struct OS2
_update_unicode_ranges (c->plan->unicodes, os2_prime->ulUnicodeRange);
+ if (c->plan->user_axes_location->has (HB_TAG ('w','g','h','t')) &&
+ !c->plan->pinned_at_default)
+ {
+ float weight_class = c->plan->user_axes_location->get (HB_TAG ('w','g','h','t'));
+ if (!c->serializer->check_assign (os2_prime->usWeightClass,
+ roundf (hb_clamp (weight_class, 1.0f, 1000.0f)),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+ }
+
+ if (c->plan->user_axes_location->has (HB_TAG ('w','d','t','h')) &&
+ !c->plan->pinned_at_default)
+ {
+ float width = c->plan->user_axes_location->get (HB_TAG ('w','d','t','h'));
+ if (!c->serializer->check_assign (os2_prime->usWidthClass,
+ roundf (map_wdth_to_widthclass (width)),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+ }
+
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table.hh b/thirdparty/harfbuzz/src/hb-ot-post-table.hh
index a4c0c4aa17..80d02ffba7 100644
--- a/thirdparty/harfbuzz/src/hb-ot-post-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-post-table.hh
@@ -102,6 +102,14 @@ struct post
if (!serialize (c->serializer, glyph_names))
return_trace (false);
+ if (c->plan->user_axes_location->has (HB_TAG ('s','l','n','t')) &&
+ !c->plan->pinned_at_default)
+ {
+ float italic_angle = c->plan->user_axes_location->get (HB_TAG ('s','l','n','t'));
+ italic_angle = hb_max (-90.f, hb_min (italic_angle, 90.f));
+ post_prime->italicAngle.set_float (italic_angle);
+ }
+
if (glyph_names && version.major == 2)
return_trace (v2X.subset (c));
@@ -133,7 +141,7 @@ struct post
}
~accelerator_t ()
{
- hb_free (gids_sorted_by_name.get ());
+ hb_free (gids_sorted_by_name.get_acquire ());
table.destroy ();
}
@@ -160,7 +168,7 @@ struct post
if (unlikely (!len)) return false;
retry:
- uint16_t *gids = gids_sorted_by_name.get ();
+ uint16_t *gids = gids_sorted_by_name.get_acquire ();
if (unlikely (!gids))
{
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh
index a5ce3a6c93..c7b57820af 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh
@@ -6,10 +6,10 @@
*
* on files with these headers:
*
- * # ArabicShaping-14.0.0.txt
- * # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
- * # Scripts-14.0.0.txt
- * # Date: 2021-07-10, 00:35:31 GMT
+ * # ArabicShaping-15.0.0.txt
+ * # Date: 2022-02-14, 18:50:00 GMT [KW, RP]
+ * # Scripts-15.0.0.txt
+ * # Date: 2022-04-26, 23:15:02 GMT
*/
#ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh
index fd3d8645d1..d7670f2f95 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh
@@ -6,10 +6,10 @@
*
* on files with these headers:
*
- * # ArabicShaping-14.0.0.txt
- * # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
- * # Blocks-14.0.0.txt
- * # Date: 2021-01-22, 23:29:00 GMT [KW]
+ * # ArabicShaping-15.0.0.txt
+ * # Date: 2022-02-14, 18:50:00 GMT [KW, RP]
+ * # Blocks-15.0.0.txt
+ * # Date: 2022-01-28, 20:58:00 GMT [KW]
* UnicodeData.txt does not have a header.
*/
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh
index d3a7cce3de..d52b13f616 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh
@@ -53,7 +53,7 @@ enum indic_syllable_type_t {
};
-#line 54 "hb-ot-shaper-indic-machine.hh"
+#line 57 "hb-ot-shaper-indic-machine.hh"
#define indic_syllable_machine_ex_A 9u
#define indic_syllable_machine_ex_C 1u
#define indic_syllable_machine_ex_CM 16u
@@ -75,7 +75,7 @@ enum indic_syllable_type_t {
#define indic_syllable_machine_ex_ZWNJ 5u
-#line 74 "hb-ot-shaper-indic-machine.hh"
+#line 79 "hb-ot-shaper-indic-machine.hh"
static const unsigned char _indic_syllable_machine_trans_keys[] = {
8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 4u, 12u, 4u, 8u, 8u, 8u,
5u, 7u, 5u, 8u, 4u, 8u, 4u, 12u, 4u, 12u, 4u, 12u, 8u, 8u, 5u, 7u,
@@ -422,7 +422,7 @@ find_syllables_indic (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 415 "hb-ot-shaper-indic-machine.hh"
+#line 426 "hb-ot-shaper-indic-machine.hh"
{
cs = indic_syllable_machine_start;
ts = 0;
@@ -438,7 +438,7 @@ find_syllables_indic (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 427 "hb-ot-shaper-indic-machine.hh"
+#line 442 "hb-ot-shaper-indic-machine.hh"
{
int _slen;
int _trans;
@@ -452,7 +452,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 439 "hb-ot-shaper-indic-machine.hh"
+#line 456 "hb-ot-shaper-indic-machine.hh"
}
_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -555,7 +555,7 @@ _eof_trans:
#line 113 "hb-ot-shaper-indic-machine.rl"
{act = 6;}
break;
-#line 521 "hb-ot-shaper-indic-machine.hh"
+#line 559 "hb-ot-shaper-indic-machine.hh"
}
_again:
@@ -564,7 +564,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 528 "hb-ot-shaper-indic-machine.hh"
+#line 568 "hb-ot-shaper-indic-machine.hh"
}
if ( ++p != pe )
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc
index 8994f3ca59..bf6a2757bb 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc
@@ -6,12 +6,12 @@
*
* on files with these headers:
*
- * # IndicSyllabicCategory-14.0.0.txt
- * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
- * # IndicPositionalCategory-14.0.0.txt
- * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
- * # Blocks-14.0.0.txt
- * # Date: 2021-01-22, 23:29:00 GMT [KW]
+ * # IndicSyllabicCategory-15.0.0.txt
+ * # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
+ * # IndicPositionalCategory-15.0.0.txt
+ * # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
+ * # Blocks-15.0.0.txt
+ * # Date: 2022-01-28, 20:58:00 GMT [KW]
*/
#include "hb.hh"
@@ -92,7 +92,7 @@ static_assert (OT_VPst == M_Cat(VPst), "");
#define _OT_R OT_Ra /* 14 chars; Ra */
#define _OT_Rf OT_Repha /* 1 chars; Repha */
#define _OT_Rt OT_Robatic /* 3 chars; Robatic */
-#define _OT_SM OT_SM /* 55 chars; SM */
+#define _OT_SM OT_SM /* 56 chars; SM */
#define _OT_S OT_Symbol /* 22 chars; Symbol */
#define _OT_V OT_V /* 172 chars; V */
#define _OT_VA OT_VAbv /* 18 chars; VAbv */
@@ -117,7 +117,7 @@ static_assert (OT_VPst == M_Cat(VPst), "");
#define _POS_R POS_POST_C /* 13 chars; POST_C */
#define _POS_L POS_PRE_C /* 5 chars; PRE_C */
#define _POS_LM POS_PRE_M /* 14 chars; PRE_M */
-#define _POS_SM POS_SMVD /* 129 chars; SMVD */
+#define _POS_SM POS_SMVD /* 130 chars; SMVD */
#pragma GCC diagnostic pop
@@ -301,7 +301,7 @@ static const uint16_t indic_table[] = {
/* 0CD8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X),
/* 0CE0 */ _(V,C), _(V,C), _(M,BS), _(M,BS), _(X,X), _(X,X), _(GB,C), _(GB,C),
/* 0CE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
- /* 0CF0 */ _(X,X), _(CS,C), _(CS,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 0CF0 */ _(X,X), _(CS,C), _(CS,C),_(SM,SM), _(X,X), _(X,X), _(X,X), _(X,X),
/* 0CF8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
/* Malayalam */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc
index 6eb400ab16..55509c1101 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc
@@ -276,7 +276,7 @@ struct indic_shape_plan_t
{
bool load_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
{
- hb_codepoint_t glyph = virama_glyph.get_relaxed ();
+ hb_codepoint_t glyph = virama_glyph;
if (unlikely (glyph == (hb_codepoint_t) -1))
{
if (!config->virama || !font->get_nominal_glyph (config->virama, &glyph))
@@ -286,7 +286,7 @@ struct indic_shape_plan_t
/* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph
* during shape planning... Instead, overwrite it here. */
- virama_glyph.set_relaxed ((int) glyph);
+ virama_glyph = (int) glyph;
}
*pglyph = glyph;
@@ -330,7 +330,7 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
#ifndef HB_NO_UNISCRIBE_BUG_COMPATIBLE
indic_plan->uniscribe_bug_compatible = hb_options ().uniscribe_bug_compatible;
#endif
- indic_plan->virama_glyph.set_relaxed (-1);
+ indic_plan->virama_glyph = -1;
/* Use zero-context would_substitute() matching for new-spec of the main
* Indic scripts, and scripts with one spec only, but not for old-specs.
@@ -992,7 +992,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
* class of I_Cat(H) is desired but has been lost. */
/* We don't call load_virama_glyph(), since we know it's already
* loaded. */
- hb_codepoint_t virama_glyph = indic_plan->virama_glyph.get_relaxed ();
+ hb_codepoint_t virama_glyph = indic_plan->virama_glyph;
if (virama_glyph)
{
for (unsigned int i = start; i < end; i++)
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh
index 2c40663bdd..e18bd75ef1 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh
@@ -48,7 +48,7 @@ enum khmer_syllable_type_t {
};
-#line 49 "hb-ot-shaper-khmer-machine.hh"
+#line 52 "hb-ot-shaper-khmer-machine.hh"
#define khmer_syllable_machine_ex_C 1u
#define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u
#define khmer_syllable_machine_ex_H 4u
@@ -66,7 +66,7 @@ enum khmer_syllable_type_t {
#define khmer_syllable_machine_ex_ZWNJ 5u
-#line 65 "hb-ot-shaper-khmer-machine.hh"
+#line 70 "hb-ot-shaper-khmer-machine.hh"
static const unsigned char _khmer_syllable_machine_trans_keys[] = {
5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u,
5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u,
@@ -294,7 +294,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 287 "hb-ot-shaper-khmer-machine.hh"
+#line 298 "hb-ot-shaper-khmer-machine.hh"
{
cs = khmer_syllable_machine_start;
ts = 0;
@@ -310,7 +310,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 299 "hb-ot-shaper-khmer-machine.hh"
+#line 314 "hb-ot-shaper-khmer-machine.hh"
{
int _slen;
int _trans;
@@ -324,7 +324,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 311 "hb-ot-shaper-khmer-machine.hh"
+#line 328 "hb-ot-shaper-khmer-machine.hh"
}
_keys = _khmer_syllable_machine_trans_keys + (cs<<1);
@@ -394,7 +394,7 @@ _eof_trans:
#line 98 "hb-ot-shaper-khmer-machine.rl"
{act = 3;}
break;
-#line 368 "hb-ot-shaper-khmer-machine.hh"
+#line 398 "hb-ot-shaper-khmer-machine.hh"
}
_again:
@@ -403,7 +403,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 375 "hb-ot-shaper-khmer-machine.hh"
+#line 407 "hb-ot-shaper-khmer-machine.hh"
}
if ( ++p != pe )
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh
index 464cf796d4..b109708937 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh
@@ -50,7 +50,7 @@ enum myanmar_syllable_type_t {
};
-#line 51 "hb-ot-shaper-myanmar-machine.hh"
+#line 54 "hb-ot-shaper-myanmar-machine.hh"
#define myanmar_syllable_machine_ex_A 9u
#define myanmar_syllable_machine_ex_As 32u
#define myanmar_syllable_machine_ex_C 1u
@@ -77,7 +77,7 @@ enum myanmar_syllable_type_t {
#define myanmar_syllable_machine_ex_ZWNJ 5u
-#line 76 "hb-ot-shaper-myanmar-machine.hh"
+#line 81 "hb-ot-shaper-myanmar-machine.hh"
static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
1u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u,
5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 39u, 3u, 39u,
@@ -443,7 +443,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 436 "hb-ot-shaper-myanmar-machine.hh"
+#line 447 "hb-ot-shaper-myanmar-machine.hh"
{
cs = myanmar_syllable_machine_start;
ts = 0;
@@ -459,7 +459,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 448 "hb-ot-shaper-myanmar-machine.hh"
+#line 463 "hb-ot-shaper-myanmar-machine.hh"
{
int _slen;
int _trans;
@@ -473,7 +473,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 460 "hb-ot-shaper-myanmar-machine.hh"
+#line 477 "hb-ot-shaper-myanmar-machine.hh"
}
_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -519,7 +519,7 @@ _eof_trans:
#line 113 "hb-ot-shaper-myanmar-machine.rl"
{te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }}
break;
-#line 498 "hb-ot-shaper-myanmar-machine.hh"
+#line 523 "hb-ot-shaper-myanmar-machine.hh"
}
_again:
@@ -528,7 +528,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 505 "hb-ot-shaper-myanmar-machine.hh"
+#line 532 "hb-ot-shaper-myanmar-machine.hh"
}
if ( ++p != pe )
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh
index 5b3ec05616..41e8a34f3b 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh
@@ -53,7 +53,7 @@ enum use_syllable_type_t {
};
-#line 54 "hb-ot-shaper-use-machine.hh"
+#line 57 "hb-ot-shaper-use-machine.hh"
#define use_syllable_machine_ex_B 1u
#define use_syllable_machine_ex_CGJ 6u
#define use_syllable_machine_ex_CMAbv 31u
@@ -97,523 +97,669 @@ enum use_syllable_type_t {
#define use_syllable_machine_ex_ZWNJ 14u
-#line 96 "hb-ot-shaper-use-machine.hh"
+#line 101 "hb-ot-shaper-use-machine.hh"
static const unsigned char _use_syllable_machine_trans_keys[] = {
- 0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u,
- 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 53u,
- 23u, 53u, 23u, 53u, 23u, 53u, 12u, 53u, 23u, 53u, 12u, 53u, 12u, 53u, 12u, 53u,
- 11u, 53u, 1u, 1u, 1u, 48u, 11u, 53u, 41u, 42u, 42u, 42u, 11u, 53u, 11u, 53u,
- 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u,
- 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 53u, 23u, 53u, 23u, 53u, 23u, 53u,
- 12u, 53u, 23u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 1u, 1u, 48u,
- 13u, 13u, 4u, 4u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u,
- 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u,
- 22u, 53u, 23u, 53u, 23u, 53u, 23u, 53u, 12u, 53u, 23u, 53u, 12u, 53u, 12u, 53u,
- 12u, 53u, 11u, 53u, 1u, 1u, 1u, 48u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u,
- 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u,
- 1u, 1u, 24u, 48u, 22u, 53u, 23u, 53u, 23u, 53u, 23u, 53u, 12u, 53u, 23u, 53u,
- 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 1u, 1u, 48u, 4u, 4u, 13u, 13u,
- 1u, 53u, 11u, 53u, 41u, 42u, 42u, 42u, 1u, 5u, 50u, 52u, 49u, 52u, 49u, 51u,
- 0
+ 0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u,
+ 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u,
+ 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u,
+ 12u, 53u, 11u, 53u, 1u, 14u, 1u, 48u, 11u, 53u, 14u, 42u, 14u, 42u, 11u, 53u,
+ 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u,
+ 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u,
+ 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u,
+ 1u, 14u, 1u, 14u, 1u, 48u, 13u, 14u, 4u, 14u, 11u, 53u, 11u, 53u, 1u, 53u,
+ 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u,
+ 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u,
+ 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 14u, 1u, 14u,
+ 1u, 48u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u,
+ 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u,
+ 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u,
+ 12u, 53u, 11u, 53u, 1u, 14u, 1u, 48u, 4u, 14u, 13u, 14u, 1u, 53u, 11u, 53u,
+ 14u, 42u, 14u, 42u, 1u, 5u, 14u, 52u, 14u, 52u, 14u, 51u, 0
};
static const char _use_syllable_machine_key_spans[] = {
- 54, 43, 43, 53, 26, 24, 23, 22,
- 2, 1, 25, 25, 25, 1, 25, 32,
- 31, 31, 31, 42, 31, 42, 42, 42,
- 43, 1, 48, 43, 2, 1, 43, 43,
- 53, 26, 24, 23, 22, 2, 1, 25,
- 25, 25, 1, 25, 32, 31, 31, 31,
- 42, 31, 42, 42, 42, 43, 1, 48,
- 1, 1, 43, 43, 53, 26, 24, 23,
- 22, 2, 1, 25, 25, 25, 1, 25,
- 32, 31, 31, 31, 42, 31, 42, 42,
- 42, 43, 1, 48, 43, 43, 53, 26,
- 24, 23, 22, 2, 1, 25, 25, 25,
- 1, 25, 32, 31, 31, 31, 42, 31,
- 42, 42, 42, 43, 1, 48, 1, 1,
- 53, 43, 2, 1, 5, 3, 4, 3
+ 54, 43, 43, 53, 35, 34, 34, 34,
+ 33, 33, 1, 35, 35, 35, 14, 35,
+ 40, 40, 40, 40, 42, 40, 42, 42,
+ 42, 43, 14, 48, 43, 29, 29, 43,
+ 43, 53, 35, 34, 34, 34, 33, 33,
+ 1, 35, 35, 35, 14, 35, 40, 40,
+ 40, 40, 42, 40, 42, 42, 42, 43,
+ 14, 14, 48, 2, 11, 43, 43, 53,
+ 35, 34, 34, 34, 33, 33, 1, 35,
+ 35, 35, 14, 35, 40, 40, 40, 40,
+ 42, 40, 42, 42, 42, 43, 14, 14,
+ 48, 43, 43, 53, 35, 34, 34, 34,
+ 33, 33, 1, 35, 35, 35, 14, 35,
+ 40, 40, 40, 40, 42, 40, 42, 42,
+ 42, 43, 14, 48, 11, 2, 53, 43,
+ 29, 29, 5, 39, 39, 38
};
static const short _use_syllable_machine_index_offsets[] = {
- 0, 55, 99, 143, 197, 224, 249, 273,
- 296, 299, 301, 327, 353, 379, 381, 407,
- 440, 472, 504, 536, 579, 611, 654, 697,
- 740, 784, 786, 835, 879, 882, 884, 928,
- 972, 1026, 1053, 1078, 1102, 1125, 1128, 1130,
- 1156, 1182, 1208, 1210, 1236, 1269, 1301, 1333,
- 1365, 1408, 1440, 1483, 1526, 1569, 1613, 1615,
- 1664, 1666, 1668, 1712, 1756, 1810, 1837, 1862,
- 1886, 1909, 1912, 1914, 1940, 1966, 1992, 1994,
- 2020, 2053, 2085, 2117, 2149, 2192, 2224, 2267,
- 2310, 2353, 2397, 2399, 2448, 2492, 2536, 2590,
- 2617, 2642, 2666, 2689, 2692, 2694, 2720, 2746,
- 2772, 2774, 2800, 2833, 2865, 2897, 2929, 2972,
- 3004, 3047, 3090, 3133, 3177, 3179, 3228, 3230,
- 3232, 3286, 3330, 3333, 3335, 3341, 3345, 3350
+ 0, 55, 99, 143, 197, 233, 268, 303,
+ 338, 372, 406, 408, 444, 480, 516, 531,
+ 567, 608, 649, 690, 731, 774, 815, 858,
+ 901, 944, 988, 1003, 1052, 1096, 1126, 1156,
+ 1200, 1244, 1298, 1334, 1369, 1404, 1439, 1473,
+ 1507, 1509, 1545, 1581, 1617, 1632, 1668, 1709,
+ 1750, 1791, 1832, 1875, 1916, 1959, 2002, 2045,
+ 2089, 2104, 2119, 2168, 2171, 2183, 2227, 2271,
+ 2325, 2361, 2396, 2431, 2466, 2500, 2534, 2536,
+ 2572, 2608, 2644, 2659, 2695, 2736, 2777, 2818,
+ 2859, 2902, 2943, 2986, 3029, 3072, 3116, 3131,
+ 3146, 3195, 3239, 3283, 3337, 3373, 3408, 3443,
+ 3478, 3512, 3546, 3548, 3584, 3620, 3656, 3671,
+ 3707, 3748, 3789, 3830, 3871, 3914, 3955, 3998,
+ 4041, 4084, 4128, 4143, 4192, 4204, 4207, 4261,
+ 4305, 4335, 4365, 4371, 4411, 4451
};
static const unsigned char _use_syllable_machine_indicies[] = {
0, 1, 2, 2, 3, 4, 2, 2,
- 2, 2, 2, 5, 6, 7, 2, 2,
- 2, 2, 8, 2, 2, 2, 9, 10,
+ 2, 2, 2, 5, 6, 7, 8, 2,
+ 2, 2, 9, 2, 2, 2, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 2, 24, 25, 26,
+ 2, 27, 28, 29, 30, 31, 32, 33,
+ 30, 34, 2, 35, 2, 36, 2, 38,
+ 39, 37, 40, 37, 37, 37, 37, 37,
+ 37, 37, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54,
+ 37, 55, 56, 57, 37, 58, 59, 37,
+ 60, 61, 62, 63, 60, 37, 37, 37,
+ 37, 64, 37, 38, 39, 37, 40, 37,
+ 37, 37, 37, 37, 37, 37, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 51,
+ 51, 52, 53, 54, 37, 55, 56, 57,
+ 37, 37, 37, 37, 60, 61, 62, 63,
+ 60, 37, 37, 37, 37, 64, 37, 38,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 40, 37, 37, 37,
+ 37, 37, 37, 37, 37, 42, 43, 44,
+ 45, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 55, 56, 57, 37, 37,
+ 37, 37, 37, 61, 62, 63, 65, 37,
+ 37, 37, 37, 42, 37, 40, 37, 37,
+ 37, 37, 37, 37, 37, 37, 42, 43,
+ 44, 45, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 55, 56, 57, 37,
+ 37, 37, 37, 37, 61, 62, 63, 65,
+ 37, 40, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 43, 44, 45, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 61, 62, 63, 37, 40, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 44,
+ 45, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 61, 62, 63, 37, 40,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 45, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 61, 62,
+ 63, 37, 40, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 61, 62, 37, 40, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 62, 37, 40, 37,
+ 40, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 43, 44, 45, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 55,
+ 56, 57, 37, 37, 37, 37, 37, 61,
+ 62, 63, 65, 37, 40, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 43, 44,
+ 45, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 56, 57, 37, 37,
+ 37, 37, 37, 61, 62, 63, 65, 37,
+ 40, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 43, 44, 45, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 57, 37, 37, 37, 37, 37, 61,
+ 62, 63, 65, 37, 66, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 40, 37, 40, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 43, 44, 45,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 61, 62, 63, 65, 37, 40,
+ 37, 37, 37, 37, 37, 37, 37, 41,
+ 42, 43, 44, 45, 37, 37, 37, 37,
+ 37, 37, 52, 53, 54, 37, 55, 56,
+ 57, 37, 37, 37, 37, 37, 61, 62,
+ 63, 65, 37, 37, 37, 37, 42, 37,
+ 40, 37, 37, 37, 37, 37, 37, 37,
+ 37, 42, 43, 44, 45, 37, 37, 37,
+ 37, 37, 37, 52, 53, 54, 37, 55,
+ 56, 57, 37, 37, 37, 37, 37, 61,
+ 62, 63, 65, 37, 37, 37, 37, 42,
+ 37, 40, 37, 37, 37, 37, 37, 37,
+ 37, 37, 42, 43, 44, 45, 37, 37,
+ 37, 37, 37, 37, 37, 53, 54, 37,
+ 55, 56, 57, 37, 37, 37, 37, 37,
+ 61, 62, 63, 65, 37, 37, 37, 37,
+ 42, 37, 40, 37, 37, 37, 37, 37,
+ 37, 37, 37, 42, 43, 44, 45, 37,
+ 37, 37, 37, 37, 37, 37, 37, 54,
+ 37, 55, 56, 57, 37, 37, 37, 37,
+ 37, 61, 62, 63, 65, 37, 37, 37,
+ 37, 42, 37, 67, 37, 40, 37, 37,
+ 37, 37, 37, 37, 37, 41, 42, 43,
+ 44, 45, 37, 47, 48, 37, 37, 37,
+ 52, 53, 54, 37, 55, 56, 57, 37,
+ 37, 37, 37, 37, 61, 62, 63, 65,
+ 37, 37, 37, 37, 42, 37, 40, 37,
+ 37, 37, 37, 37, 37, 37, 37, 42,
+ 43, 44, 45, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 55, 56, 57,
+ 37, 37, 37, 37, 37, 61, 62, 63,
+ 65, 37, 37, 37, 37, 42, 37, 67,
+ 37, 40, 37, 37, 37, 37, 37, 37,
+ 37, 41, 42, 43, 44, 45, 37, 37,
+ 48, 37, 37, 37, 52, 53, 54, 37,
+ 55, 56, 57, 37, 37, 37, 37, 37,
+ 61, 62, 63, 65, 37, 37, 37, 37,
+ 42, 37, 67, 37, 40, 37, 37, 37,
+ 37, 37, 37, 37, 41, 42, 43, 44,
+ 45, 37, 37, 37, 37, 37, 37, 52,
+ 53, 54, 37, 55, 56, 57, 37, 37,
+ 37, 37, 37, 61, 62, 63, 65, 37,
+ 37, 37, 37, 42, 37, 67, 37, 40,
+ 37, 37, 37, 37, 37, 37, 37, 41,
+ 42, 43, 44, 45, 46, 47, 48, 37,
+ 37, 37, 52, 53, 54, 37, 55, 56,
+ 57, 37, 37, 37, 37, 37, 61, 62,
+ 63, 65, 37, 37, 37, 37, 42, 37,
+ 38, 39, 37, 40, 37, 37, 37, 37,
+ 37, 37, 37, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 37, 51, 52, 53,
+ 54, 37, 55, 56, 57, 37, 37, 37,
+ 37, 60, 61, 62, 63, 60, 37, 37,
+ 37, 37, 64, 37, 38, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 40, 37, 38, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 40, 37, 37, 37, 37, 37, 37, 37,
+ 37, 42, 43, 44, 45, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 55,
+ 56, 57, 37, 37, 37, 37, 37, 61,
+ 62, 63, 65, 37, 38, 39, 37, 40,
+ 37, 37, 37, 37, 37, 37, 37, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 37, 55, 56,
+ 57, 37, 37, 37, 37, 60, 61, 62,
+ 63, 60, 37, 37, 37, 37, 64, 37,
+ 40, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 58, 59, 37, 40, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 59, 37, 69, 70, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80,
+ 1, 81, 82, 83, 84, 68, 85, 86,
+ 87, 68, 68, 68, 68, 88, 89, 90,
+ 91, 92, 68, 68, 68, 68, 93, 68,
+ 69, 70, 68, 71, 68, 68, 68, 68,
+ 68, 68, 68, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 81, 82, 83,
+ 84, 68, 85, 86, 87, 68, 68, 68,
+ 68, 88, 89, 90, 91, 92, 68, 68,
+ 68, 68, 93, 68, 69, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 68, 73, 74, 75, 76, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 85, 86, 87, 68, 68, 68, 68, 68,
+ 89, 90, 91, 94, 68, 68, 68, 68,
+ 73, 68, 71, 68, 68, 68, 68, 68,
+ 68, 68, 68, 73, 74, 75, 76, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 85, 86, 87, 68, 68, 68, 68,
+ 68, 89, 90, 91, 94, 68, 71, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 74, 75, 76, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 89, 90, 91,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 75, 76, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 89, 90, 91, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 76, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 89, 90, 91, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 89, 90,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 90, 68, 71, 68, 71, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 74,
+ 75, 76, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 85, 86, 87, 68,
+ 68, 68, 68, 68, 89, 90, 91, 94,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 74, 75, 76, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 86, 87, 68, 68, 68, 68, 68,
+ 89, 90, 91, 94, 68, 71, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 74,
+ 75, 76, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 87, 68,
+ 68, 68, 68, 68, 89, 90, 91, 94,
+ 68, 96, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 95, 97, 95,
+ 71, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 74, 75, 76, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 89,
+ 90, 91, 94, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 72, 73, 74, 75,
+ 76, 68, 68, 68, 68, 68, 68, 82,
+ 83, 84, 68, 85, 86, 87, 68, 68,
+ 68, 68, 68, 89, 90, 91, 94, 68,
+ 68, 68, 68, 73, 68, 71, 68, 68,
+ 68, 68, 68, 68, 68, 68, 73, 74,
+ 75, 76, 68, 68, 68, 68, 68, 68,
+ 82, 83, 84, 68, 85, 86, 87, 68,
+ 68, 68, 68, 68, 89, 90, 91, 94,
+ 68, 68, 68, 68, 73, 68, 71, 68,
+ 68, 68, 68, 68, 68, 68, 68, 73,
+ 74, 75, 76, 68, 68, 68, 68, 68,
+ 68, 68, 83, 84, 68, 85, 86, 87,
+ 68, 68, 68, 68, 68, 89, 90, 91,
+ 94, 68, 68, 68, 68, 73, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 73, 74, 75, 76, 68, 68, 68, 68,
+ 68, 68, 68, 68, 84, 68, 85, 86,
+ 87, 68, 68, 68, 68, 68, 89, 90,
+ 91, 94, 68, 68, 68, 68, 73, 68,
+ 98, 68, 71, 68, 68, 68, 68, 68,
+ 68, 68, 72, 73, 74, 75, 76, 68,
+ 78, 79, 68, 68, 68, 82, 83, 84,
+ 68, 85, 86, 87, 68, 68, 68, 68,
+ 68, 89, 90, 91, 94, 68, 68, 68,
+ 68, 73, 68, 71, 68, 68, 68, 68,
+ 68, 68, 68, 68, 73, 74, 75, 76,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 85, 86, 87, 68, 68, 68,
+ 68, 68, 89, 90, 91, 94, 68, 68,
+ 68, 68, 73, 68, 98, 68, 71, 68,
+ 68, 68, 68, 68, 68, 68, 72, 73,
+ 74, 75, 76, 68, 68, 79, 68, 68,
+ 68, 82, 83, 84, 68, 85, 86, 87,
+ 68, 68, 68, 68, 68, 89, 90, 91,
+ 94, 68, 68, 68, 68, 73, 68, 98,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 72, 73, 74, 75, 76, 68, 68,
+ 68, 68, 68, 68, 82, 83, 84, 68,
+ 85, 86, 87, 68, 68, 68, 68, 68,
+ 89, 90, 91, 94, 68, 68, 68, 68,
+ 73, 68, 98, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 72, 73, 74, 75,
+ 76, 77, 78, 79, 68, 68, 68, 82,
+ 83, 84, 68, 85, 86, 87, 68, 68,
+ 68, 68, 68, 89, 90, 91, 94, 68,
+ 68, 68, 68, 73, 68, 69, 70, 68,
+ 71, 68, 68, 68, 68, 68, 68, 68,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 68, 81, 82, 83, 84, 68, 85,
+ 86, 87, 68, 68, 68, 68, 88, 89,
+ 90, 91, 92, 68, 68, 68, 68, 93,
+ 68, 69, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 100, 99,
+ 69, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 97, 95, 69,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 73, 74, 75,
+ 76, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 85, 86, 87, 68, 68,
+ 68, 68, 68, 89, 90, 91, 94, 68,
+ 102, 103, 101, 3, 104, 104, 104, 104,
+ 104, 104, 104, 104, 104, 105, 104, 106,
+ 107, 68, 71, 68, 68, 68, 68, 68,
+ 68, 68, 108, 109, 110, 111, 112, 113,
+ 114, 115, 116, 117, 118, 119, 120, 121,
+ 68, 122, 123, 124, 68, 58, 59, 68,
+ 125, 126, 127, 128, 129, 68, 68, 68,
+ 68, 130, 68, 106, 107, 68, 71, 68,
+ 68, 68, 68, 68, 68, 68, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 118,
+ 118, 119, 120, 121, 68, 122, 123, 124,
+ 68, 68, 68, 68, 125, 126, 127, 128,
+ 129, 68, 68, 68, 68, 130, 68, 106,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 109, 110, 111,
+ 112, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 122, 123, 124, 68, 68,
+ 68, 68, 68, 126, 127, 128, 131, 68,
+ 68, 68, 68, 109, 68, 71, 68, 68,
+ 68, 68, 68, 68, 68, 68, 109, 110,
+ 111, 112, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 122, 123, 124, 68,
+ 68, 68, 68, 68, 126, 127, 128, 131,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 110, 111, 112, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 126, 127, 128, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 111,
+ 112, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 126, 127, 128, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 112, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 126, 127,
+ 128, 68, 71, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 126, 127, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 127, 68, 71, 68,
+ 71, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 110, 111, 112, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 122,
+ 123, 124, 68, 68, 68, 68, 68, 126,
+ 127, 128, 131, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 110, 111,
+ 112, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 123, 124, 68, 68,
+ 68, 68, 68, 126, 127, 128, 131, 68,
+ 71, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 110, 111, 112, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 124, 68, 68, 68, 68, 68, 126,
+ 127, 128, 131, 68, 132, 95, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 97, 95, 71, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 110, 111, 112,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 126, 127, 128, 131, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 108,
+ 109, 110, 111, 112, 68, 68, 68, 68,
+ 68, 68, 119, 120, 121, 68, 122, 123,
+ 124, 68, 68, 68, 68, 68, 126, 127,
+ 128, 131, 68, 68, 68, 68, 109, 68,
+ 71, 68, 68, 68, 68, 68, 68, 68,
+ 68, 109, 110, 111, 112, 68, 68, 68,
+ 68, 68, 68, 119, 120, 121, 68, 122,
+ 123, 124, 68, 68, 68, 68, 68, 126,
+ 127, 128, 131, 68, 68, 68, 68, 109,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 68, 109, 110, 111, 112, 68, 68,
+ 68, 68, 68, 68, 68, 120, 121, 68,
+ 122, 123, 124, 68, 68, 68, 68, 68,
+ 126, 127, 128, 131, 68, 68, 68, 68,
+ 109, 68, 71, 68, 68, 68, 68, 68,
+ 68, 68, 68, 109, 110, 111, 112, 68,
+ 68, 68, 68, 68, 68, 68, 68, 121,
+ 68, 122, 123, 124, 68, 68, 68, 68,
+ 68, 126, 127, 128, 131, 68, 68, 68,
+ 68, 109, 68, 133, 68, 71, 68, 68,
+ 68, 68, 68, 68, 68, 108, 109, 110,
+ 111, 112, 68, 114, 115, 68, 68, 68,
+ 119, 120, 121, 68, 122, 123, 124, 68,
+ 68, 68, 68, 68, 126, 127, 128, 131,
+ 68, 68, 68, 68, 109, 68, 71, 68,
+ 68, 68, 68, 68, 68, 68, 68, 109,
+ 110, 111, 112, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 122, 123, 124,
+ 68, 68, 68, 68, 68, 126, 127, 128,
+ 131, 68, 68, 68, 68, 109, 68, 133,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 108, 109, 110, 111, 112, 68, 68,
+ 115, 68, 68, 68, 119, 120, 121, 68,
+ 122, 123, 124, 68, 68, 68, 68, 68,
+ 126, 127, 128, 131, 68, 68, 68, 68,
+ 109, 68, 133, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 108, 109, 110, 111,
+ 112, 68, 68, 68, 68, 68, 68, 119,
+ 120, 121, 68, 122, 123, 124, 68, 68,
+ 68, 68, 68, 126, 127, 128, 131, 68,
+ 68, 68, 68, 109, 68, 133, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 108,
+ 109, 110, 111, 112, 113, 114, 115, 68,
+ 68, 68, 119, 120, 121, 68, 122, 123,
+ 124, 68, 68, 68, 68, 68, 126, 127,
+ 128, 131, 68, 68, 68, 68, 109, 68,
+ 106, 107, 68, 71, 68, 68, 68, 68,
+ 68, 68, 68, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 68, 118, 119, 120,
+ 121, 68, 122, 123, 124, 68, 68, 68,
+ 68, 125, 126, 127, 128, 129, 68, 68,
+ 68, 68, 130, 68, 106, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 100, 99, 106, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95,
+ 97, 95, 106, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 109, 110, 111, 112, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 122, 123,
+ 124, 68, 68, 68, 68, 68, 126, 127,
+ 128, 131, 68, 106, 107, 68, 71, 68,
+ 68, 68, 68, 68, 68, 68, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117,
+ 118, 119, 120, 121, 68, 122, 123, 124,
+ 68, 68, 68, 68, 125, 126, 127, 128,
+ 129, 68, 68, 68, 68, 130, 68, 5,
+ 6, 134, 8, 134, 134, 134, 134, 134,
+ 134, 134, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 20, 20, 21, 22, 23,
+ 134, 24, 25, 26, 134, 134, 134, 134,
+ 30, 31, 32, 33, 30, 134, 134, 134,
+ 134, 36, 134, 5, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 8, 134, 134, 134, 134, 134, 134, 134,
+ 134, 11, 12, 13, 14, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 24,
+ 25, 26, 134, 134, 134, 134, 134, 31,
+ 32, 33, 135, 134, 134, 134, 134, 11,
+ 134, 8, 134, 134, 134, 134, 134, 134,
+ 134, 134, 11, 12, 13, 14, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 24, 25, 26, 134, 134, 134, 134, 134,
+ 31, 32, 33, 135, 134, 8, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 12,
+ 13, 14, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 31, 32, 33, 134,
+ 8, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 13, 14, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 31,
+ 32, 33, 134, 8, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 14,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 31, 32, 33, 134, 8, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 31, 32, 134,
+ 8, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 32, 134, 8, 134, 8, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 12, 13,
+ 14, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 24, 25, 26, 134, 134,
+ 134, 134, 134, 31, 32, 33, 135, 134,
+ 8, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 12, 13, 14, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 25, 26, 134, 134, 134, 134, 134, 31,
+ 32, 33, 135, 134, 8, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 12, 13,
+ 14, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 26, 134, 134,
+ 134, 134, 134, 31, 32, 33, 135, 134,
+ 136, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 8, 134, 8,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 12, 13, 14, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 31, 32,
+ 33, 135, 134, 8, 134, 134, 134, 134,
+ 134, 134, 134, 10, 11, 12, 13, 14,
+ 134, 134, 134, 134, 134, 134, 21, 22,
+ 23, 134, 24, 25, 26, 134, 134, 134,
+ 134, 134, 31, 32, 33, 135, 134, 134,
+ 134, 134, 11, 134, 8, 134, 134, 134,
+ 134, 134, 134, 134, 134, 11, 12, 13,
+ 14, 134, 134, 134, 134, 134, 134, 21,
+ 22, 23, 134, 24, 25, 26, 134, 134,
+ 134, 134, 134, 31, 32, 33, 135, 134,
+ 134, 134, 134, 11, 134, 8, 134, 134,
+ 134, 134, 134, 134, 134, 134, 11, 12,
+ 13, 14, 134, 134, 134, 134, 134, 134,
+ 134, 22, 23, 134, 24, 25, 26, 134,
+ 134, 134, 134, 134, 31, 32, 33, 135,
+ 134, 134, 134, 134, 11, 134, 8, 134,
+ 134, 134, 134, 134, 134, 134, 134, 11,
+ 12, 13, 14, 134, 134, 134, 134, 134,
+ 134, 134, 134, 23, 134, 24, 25, 26,
+ 134, 134, 134, 134, 134, 31, 32, 33,
+ 135, 134, 134, 134, 134, 11, 134, 137,
+ 134, 8, 134, 134, 134, 134, 134, 134,
+ 134, 10, 11, 12, 13, 14, 134, 16,
+ 17, 134, 134, 134, 21, 22, 23, 134,
+ 24, 25, 26, 134, 134, 134, 134, 134,
+ 31, 32, 33, 135, 134, 134, 134, 134,
+ 11, 134, 8, 134, 134, 134, 134, 134,
+ 134, 134, 134, 11, 12, 13, 14, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 24, 25, 26, 134, 134, 134, 134,
+ 134, 31, 32, 33, 135, 134, 134, 134,
+ 134, 11, 134, 137, 134, 8, 134, 134,
+ 134, 134, 134, 134, 134, 10, 11, 12,
+ 13, 14, 134, 134, 17, 134, 134, 134,
+ 21, 22, 23, 134, 24, 25, 26, 134,
+ 134, 134, 134, 134, 31, 32, 33, 135,
+ 134, 134, 134, 134, 11, 134, 137, 134,
+ 8, 134, 134, 134, 134, 134, 134, 134,
+ 10, 11, 12, 13, 14, 134, 134, 134,
+ 134, 134, 134, 21, 22, 23, 134, 24,
+ 25, 26, 134, 134, 134, 134, 134, 31,
+ 32, 33, 135, 134, 134, 134, 134, 11,
+ 134, 137, 134, 8, 134, 134, 134, 134,
+ 134, 134, 134, 10, 11, 12, 13, 14,
+ 15, 16, 17, 134, 134, 134, 21, 22,
+ 23, 134, 24, 25, 26, 134, 134, 134,
+ 134, 134, 31, 32, 33, 135, 134, 134,
+ 134, 134, 11, 134, 5, 6, 134, 8,
+ 134, 134, 134, 134, 134, 134, 134, 10,
11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 2, 23, 24, 25,
- 2, 26, 27, 28, 29, 30, 31, 32,
- 29, 33, 2, 34, 2, 35, 2, 37,
- 38, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 39, 40, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52,
- 36, 53, 54, 55, 36, 56, 57, 36,
- 58, 59, 60, 61, 58, 36, 36, 36,
- 36, 62, 36, 37, 38, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 49,
- 49, 50, 51, 52, 36, 53, 54, 55,
- 36, 36, 36, 36, 58, 59, 60, 61,
- 58, 36, 36, 36, 36, 62, 36, 37,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 40, 41, 42,
- 43, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 53, 54, 55, 36, 36,
- 36, 36, 36, 59, 60, 61, 63, 36,
- 36, 36, 36, 40, 36, 40, 41, 42,
- 43, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 53, 54, 55, 36, 36,
- 36, 36, 36, 59, 60, 61, 63, 36,
- 41, 42, 43, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 59, 60, 61,
- 36, 42, 43, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 59, 60, 61,
- 36, 43, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 59, 60, 61, 36,
- 59, 60, 36, 60, 36, 41, 42, 43,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 53, 54, 55, 36, 36, 36,
- 36, 36, 59, 60, 61, 63, 36, 41,
- 42, 43, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 54, 55, 36,
- 36, 36, 36, 36, 59, 60, 61, 63,
- 36, 41, 42, 43, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 55, 36, 36, 36, 36, 36, 59, 60,
- 61, 63, 36, 64, 36, 41, 42, 43,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 59, 60, 61, 63, 36, 39,
- 40, 41, 42, 43, 36, 36, 36, 36,
- 36, 36, 50, 51, 52, 36, 53, 54,
- 55, 36, 36, 36, 36, 36, 59, 60,
- 61, 63, 36, 36, 36, 36, 40, 36,
- 40, 41, 42, 43, 36, 36, 36, 36,
- 36, 36, 50, 51, 52, 36, 53, 54,
- 55, 36, 36, 36, 36, 36, 59, 60,
- 61, 63, 36, 36, 36, 36, 40, 36,
- 40, 41, 42, 43, 36, 36, 36, 36,
- 36, 36, 36, 51, 52, 36, 53, 54,
- 55, 36, 36, 36, 36, 36, 59, 60,
- 61, 63, 36, 36, 36, 36, 40, 36,
- 40, 41, 42, 43, 36, 36, 36, 36,
- 36, 36, 36, 36, 52, 36, 53, 54,
- 55, 36, 36, 36, 36, 36, 59, 60,
- 61, 63, 36, 36, 36, 36, 40, 36,
- 65, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 39, 40, 41, 42, 43, 36,
- 45, 46, 36, 36, 36, 50, 51, 52,
- 36, 53, 54, 55, 36, 36, 36, 36,
- 36, 59, 60, 61, 63, 36, 36, 36,
- 36, 40, 36, 40, 41, 42, 43, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 53, 54, 55, 36, 36, 36, 36,
- 36, 59, 60, 61, 63, 36, 36, 36,
- 36, 40, 36, 65, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 39, 40, 41,
- 42, 43, 36, 36, 46, 36, 36, 36,
- 50, 51, 52, 36, 53, 54, 55, 36,
- 36, 36, 36, 36, 59, 60, 61, 63,
- 36, 36, 36, 36, 40, 36, 65, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 39, 40, 41, 42, 43, 36, 36, 36,
- 36, 36, 36, 50, 51, 52, 36, 53,
- 54, 55, 36, 36, 36, 36, 36, 59,
- 60, 61, 63, 36, 36, 36, 36, 40,
- 36, 65, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 39, 40, 41, 42, 43,
- 44, 45, 46, 36, 36, 36, 50, 51,
- 52, 36, 53, 54, 55, 36, 36, 36,
- 36, 36, 59, 60, 61, 63, 36, 36,
- 36, 36, 40, 36, 37, 38, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 36, 49, 50, 51, 52, 36, 53, 54,
- 55, 36, 36, 36, 36, 58, 59, 60,
- 61, 58, 36, 36, 36, 36, 62, 36,
- 37, 36, 37, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 40, 41, 42, 43, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 53, 54,
- 55, 36, 36, 36, 36, 36, 59, 60,
- 61, 63, 36, 37, 38, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 52, 36, 53, 54, 55,
- 36, 36, 36, 36, 58, 59, 60, 61,
- 58, 36, 36, 36, 36, 62, 36, 56,
- 57, 36, 57, 36, 67, 68, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 69,
- 70, 71, 72, 73, 74, 75, 76, 77,
- 1, 78, 79, 80, 81, 66, 82, 83,
- 84, 66, 66, 66, 66, 85, 86, 87,
- 88, 89, 66, 66, 66, 66, 90, 66,
- 67, 68, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 69, 70, 71, 72, 73,
- 74, 75, 76, 77, 78, 78, 79, 80,
- 81, 66, 82, 83, 84, 66, 66, 66,
- 66, 85, 86, 87, 88, 89, 66, 66,
- 66, 66, 90, 66, 67, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 70, 71, 72, 73, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 82, 83, 84, 66, 66, 66, 66, 66,
- 86, 87, 88, 91, 66, 66, 66, 66,
- 70, 66, 70, 71, 72, 73, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 82, 83, 84, 66, 66, 66, 66, 66,
- 86, 87, 88, 91, 66, 71, 72, 73,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 86, 87, 88, 66, 72, 73,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 86, 87, 88, 66, 73, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 86, 87, 88, 66, 86, 87, 66,
- 87, 66, 71, 72, 73, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 82,
- 83, 84, 66, 66, 66, 66, 66, 86,
- 87, 88, 91, 66, 71, 72, 73, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 83, 84, 66, 66, 66, 66,
- 66, 86, 87, 88, 91, 66, 71, 72,
- 73, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 84, 66, 66,
- 66, 66, 66, 86, 87, 88, 91, 66,
- 93, 92, 71, 72, 73, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 86,
- 87, 88, 91, 66, 69, 70, 71, 72,
- 73, 66, 66, 66, 66, 66, 66, 79,
- 80, 81, 66, 82, 83, 84, 66, 66,
- 66, 66, 66, 86, 87, 88, 91, 66,
- 66, 66, 66, 70, 66, 70, 71, 72,
- 73, 66, 66, 66, 66, 66, 66, 79,
- 80, 81, 66, 82, 83, 84, 66, 66,
- 66, 66, 66, 86, 87, 88, 91, 66,
- 66, 66, 66, 70, 66, 70, 71, 72,
- 73, 66, 66, 66, 66, 66, 66, 66,
- 80, 81, 66, 82, 83, 84, 66, 66,
- 66, 66, 66, 86, 87, 88, 91, 66,
- 66, 66, 66, 70, 66, 70, 71, 72,
- 73, 66, 66, 66, 66, 66, 66, 66,
- 66, 81, 66, 82, 83, 84, 66, 66,
- 66, 66, 66, 86, 87, 88, 91, 66,
- 66, 66, 66, 70, 66, 94, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 69,
- 70, 71, 72, 73, 66, 75, 76, 66,
- 66, 66, 79, 80, 81, 66, 82, 83,
- 84, 66, 66, 66, 66, 66, 86, 87,
- 88, 91, 66, 66, 66, 66, 70, 66,
- 70, 71, 72, 73, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 82, 83,
- 84, 66, 66, 66, 66, 66, 86, 87,
- 88, 91, 66, 66, 66, 66, 70, 66,
- 94, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 69, 70, 71, 72, 73, 66,
- 66, 76, 66, 66, 66, 79, 80, 81,
- 66, 82, 83, 84, 66, 66, 66, 66,
- 66, 86, 87, 88, 91, 66, 66, 66,
- 66, 70, 66, 94, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 69, 70, 71,
- 72, 73, 66, 66, 66, 66, 66, 66,
- 79, 80, 81, 66, 82, 83, 84, 66,
- 66, 66, 66, 66, 86, 87, 88, 91,
- 66, 66, 66, 66, 70, 66, 94, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 69, 70, 71, 72, 73, 74, 75, 76,
- 66, 66, 66, 79, 80, 81, 66, 82,
- 83, 84, 66, 66, 66, 66, 66, 86,
- 87, 88, 91, 66, 66, 66, 66, 70,
- 66, 67, 68, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 69, 70, 71, 72,
- 73, 74, 75, 76, 77, 66, 78, 79,
- 80, 81, 66, 82, 83, 84, 66, 66,
- 66, 66, 85, 86, 87, 88, 89, 66,
- 66, 66, 66, 90, 66, 67, 95, 67,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 70, 71, 72,
- 73, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 82, 83, 84, 66, 66,
- 66, 66, 66, 86, 87, 88, 91, 66,
- 97, 96, 3, 98, 99, 100, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 101,
- 102, 103, 104, 105, 106, 107, 108, 109,
- 110, 111, 112, 113, 114, 66, 115, 116,
- 117, 66, 56, 57, 66, 118, 119, 120,
- 88, 121, 66, 66, 66, 66, 122, 66,
- 99, 100, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 101, 102, 103, 104, 105,
- 106, 107, 108, 109, 111, 111, 112, 113,
- 114, 66, 115, 116, 117, 66, 66, 66,
- 66, 118, 119, 120, 88, 121, 66, 66,
- 66, 66, 122, 66, 99, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 102, 103, 104, 105, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 115, 116, 117, 66, 66, 66, 66, 66,
- 119, 120, 88, 123, 66, 66, 66, 66,
- 102, 66, 102, 103, 104, 105, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 115, 116, 117, 66, 66, 66, 66, 66,
- 119, 120, 88, 123, 66, 103, 104, 105,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 119, 120, 88, 66, 104, 105,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 119, 120, 88, 66, 105, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 119, 120, 88, 66, 119, 120, 66,
- 120, 66, 103, 104, 105, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 115,
- 116, 117, 66, 66, 66, 66, 66, 119,
- 120, 88, 123, 66, 103, 104, 105, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 116, 117, 66, 66, 66, 66,
- 66, 119, 120, 88, 123, 66, 103, 104,
- 105, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 117, 66, 66,
- 66, 66, 66, 119, 120, 88, 123, 66,
- 124, 92, 103, 104, 105, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 119,
- 120, 88, 123, 66, 101, 102, 103, 104,
- 105, 66, 66, 66, 66, 66, 66, 112,
- 113, 114, 66, 115, 116, 117, 66, 66,
- 66, 66, 66, 119, 120, 88, 123, 66,
- 66, 66, 66, 102, 66, 102, 103, 104,
- 105, 66, 66, 66, 66, 66, 66, 112,
- 113, 114, 66, 115, 116, 117, 66, 66,
- 66, 66, 66, 119, 120, 88, 123, 66,
- 66, 66, 66, 102, 66, 102, 103, 104,
- 105, 66, 66, 66, 66, 66, 66, 66,
- 113, 114, 66, 115, 116, 117, 66, 66,
- 66, 66, 66, 119, 120, 88, 123, 66,
- 66, 66, 66, 102, 66, 102, 103, 104,
- 105, 66, 66, 66, 66, 66, 66, 66,
- 66, 114, 66, 115, 116, 117, 66, 66,
- 66, 66, 66, 119, 120, 88, 123, 66,
- 66, 66, 66, 102, 66, 125, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 101,
- 102, 103, 104, 105, 66, 107, 108, 66,
- 66, 66, 112, 113, 114, 66, 115, 116,
- 117, 66, 66, 66, 66, 66, 119, 120,
- 88, 123, 66, 66, 66, 66, 102, 66,
- 102, 103, 104, 105, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 115, 116,
- 117, 66, 66, 66, 66, 66, 119, 120,
- 88, 123, 66, 66, 66, 66, 102, 66,
- 125, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 101, 102, 103, 104, 105, 66,
- 66, 108, 66, 66, 66, 112, 113, 114,
- 66, 115, 116, 117, 66, 66, 66, 66,
- 66, 119, 120, 88, 123, 66, 66, 66,
- 66, 102, 66, 125, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 101, 102, 103,
- 104, 105, 66, 66, 66, 66, 66, 66,
- 112, 113, 114, 66, 115, 116, 117, 66,
- 66, 66, 66, 66, 119, 120, 88, 123,
- 66, 66, 66, 66, 102, 66, 125, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 101, 102, 103, 104, 105, 106, 107, 108,
- 66, 66, 66, 112, 113, 114, 66, 115,
- 116, 117, 66, 66, 66, 66, 66, 119,
- 120, 88, 123, 66, 66, 66, 66, 102,
- 66, 99, 100, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 101, 102, 103, 104,
- 105, 106, 107, 108, 109, 66, 111, 112,
- 113, 114, 66, 115, 116, 117, 66, 66,
- 66, 66, 118, 119, 120, 88, 121, 66,
- 66, 66, 66, 122, 66, 99, 95, 99,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 102, 103, 104,
- 105, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 115, 116, 117, 66, 66,
- 66, 66, 66, 119, 120, 88, 123, 66,
- 99, 100, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 101, 102, 103, 104, 105,
- 106, 107, 108, 109, 110, 111, 112, 113,
- 114, 66, 115, 116, 117, 66, 66, 66,
- 66, 118, 119, 120, 88, 121, 66, 66,
- 66, 66, 122, 66, 5, 6, 126, 126,
- 126, 126, 126, 126, 126, 126, 126, 9,
+ 134, 20, 21, 22, 23, 134, 24, 25,
+ 26, 134, 134, 134, 134, 30, 31, 32,
+ 33, 30, 134, 134, 134, 134, 36, 134,
+ 5, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 8, 134, 5,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 8, 134, 134, 134,
+ 134, 134, 134, 134, 134, 11, 12, 13,
+ 14, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 24, 25, 26, 134, 134,
+ 134, 134, 134, 31, 32, 33, 135, 134,
+ 138, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 8, 134, 7, 8, 134, 1,
+ 134, 134, 134, 1, 134, 134, 134, 134,
+ 134, 5, 6, 7, 8, 134, 134, 134,
+ 134, 134, 134, 134, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 134, 24, 25, 26, 134, 27,
+ 28, 134, 30, 31, 32, 33, 30, 134,
+ 134, 134, 134, 36, 134, 5, 6, 134,
+ 8, 134, 134, 134, 134, 134, 134, 134,
10, 11, 12, 13, 14, 15, 16, 17,
- 19, 19, 20, 21, 22, 126, 23, 24,
- 25, 126, 126, 126, 126, 29, 30, 31,
- 32, 29, 126, 126, 126, 126, 35, 126,
- 5, 126, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 10, 11,
- 12, 13, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 23, 24, 25, 126,
- 126, 126, 126, 126, 30, 31, 32, 127,
- 126, 126, 126, 126, 10, 126, 10, 11,
- 12, 13, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 23, 24, 25, 126,
- 126, 126, 126, 126, 30, 31, 32, 127,
- 126, 11, 12, 13, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 30, 31,
- 32, 126, 12, 13, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 30, 31,
- 32, 126, 13, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 30, 31, 32,
- 126, 30, 31, 126, 31, 126, 11, 12,
- 13, 126, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 23, 24, 25, 126, 126,
- 126, 126, 126, 30, 31, 32, 127, 126,
- 11, 12, 13, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 24, 25,
- 126, 126, 126, 126, 126, 30, 31, 32,
- 127, 126, 11, 12, 13, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 25, 126, 126, 126, 126, 126, 30,
- 31, 32, 127, 126, 128, 126, 11, 12,
- 13, 126, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 30, 31, 32, 127, 126,
- 9, 10, 11, 12, 13, 126, 126, 126,
- 126, 126, 126, 20, 21, 22, 126, 23,
- 24, 25, 126, 126, 126, 126, 126, 30,
- 31, 32, 127, 126, 126, 126, 126, 10,
- 126, 10, 11, 12, 13, 126, 126, 126,
- 126, 126, 126, 20, 21, 22, 126, 23,
- 24, 25, 126, 126, 126, 126, 126, 30,
- 31, 32, 127, 126, 126, 126, 126, 10,
- 126, 10, 11, 12, 13, 126, 126, 126,
- 126, 126, 126, 126, 21, 22, 126, 23,
- 24, 25, 126, 126, 126, 126, 126, 30,
- 31, 32, 127, 126, 126, 126, 126, 10,
- 126, 10, 11, 12, 13, 126, 126, 126,
- 126, 126, 126, 126, 126, 22, 126, 23,
- 24, 25, 126, 126, 126, 126, 126, 30,
- 31, 32, 127, 126, 126, 126, 126, 10,
- 126, 129, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 9, 10, 11, 12, 13,
- 126, 15, 16, 126, 126, 126, 20, 21,
- 22, 126, 23, 24, 25, 126, 126, 126,
- 126, 126, 30, 31, 32, 127, 126, 126,
- 126, 126, 10, 126, 10, 11, 12, 13,
- 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 126, 23, 24, 25, 126, 126, 126,
- 126, 126, 30, 31, 32, 127, 126, 126,
- 126, 126, 10, 126, 129, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 9, 10,
- 11, 12, 13, 126, 126, 16, 126, 126,
- 126, 20, 21, 22, 126, 23, 24, 25,
- 126, 126, 126, 126, 126, 30, 31, 32,
- 127, 126, 126, 126, 126, 10, 126, 129,
- 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 9, 10, 11, 12, 13, 126, 126,
- 126, 126, 126, 126, 20, 21, 22, 126,
- 23, 24, 25, 126, 126, 126, 126, 126,
- 30, 31, 32, 127, 126, 126, 126, 126,
- 10, 126, 129, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 9, 10, 11, 12,
- 13, 14, 15, 16, 126, 126, 126, 20,
- 21, 22, 126, 23, 24, 25, 126, 126,
- 126, 126, 126, 30, 31, 32, 127, 126,
- 126, 126, 126, 10, 126, 5, 6, 126,
- 126, 126, 126, 126, 126, 126, 126, 126,
- 9, 10, 11, 12, 13, 14, 15, 16,
- 17, 126, 19, 20, 21, 22, 126, 23,
- 24, 25, 126, 126, 126, 126, 29, 30,
- 31, 32, 29, 126, 126, 126, 126, 35,
- 126, 5, 126, 5, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 10, 11, 12, 13, 126, 126, 126,
- 126, 126, 126, 126, 126, 126, 126, 23,
- 24, 25, 126, 126, 126, 126, 126, 30,
- 31, 32, 127, 126, 130, 126, 7, 126,
- 1, 126, 126, 126, 1, 126, 126, 126,
- 126, 126, 5, 6, 7, 126, 126, 126,
- 126, 126, 126, 126, 126, 9, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 19,
- 20, 21, 22, 126, 23, 24, 25, 126,
- 26, 27, 126, 29, 30, 31, 32, 29,
- 126, 126, 126, 126, 35, 126, 5, 6,
- 126, 126, 126, 126, 126, 126, 126, 126,
- 126, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 126,
- 23, 24, 25, 126, 126, 126, 126, 29,
- 30, 31, 32, 29, 126, 126, 126, 126,
- 35, 126, 26, 27, 126, 27, 126, 1,
- 131, 131, 131, 1, 131, 133, 132, 33,
- 132, 33, 133, 132, 133, 132, 33, 132,
- 34, 132, 0
+ 18, 19, 20, 21, 22, 23, 134, 24,
+ 25, 26, 134, 134, 134, 134, 30, 31,
+ 32, 33, 30, 134, 134, 134, 134, 36,
+ 134, 8, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 27, 28, 134, 8,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 28, 134, 1, 139, 139,
+ 139, 1, 139, 141, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 142,
+ 140, 34, 140, 141, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 34, 142,
+ 140, 142, 140, 141, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 34, 140,
+ 35, 140, 0
};
static const char _use_syllable_machine_trans_targs[] = {
- 1, 30, 0, 56, 58, 85, 86, 110,
- 112, 98, 87, 88, 89, 90, 102, 104,
- 105, 106, 113, 107, 99, 100, 101, 93,
- 94, 95, 114, 115, 116, 108, 91, 92,
- 0, 117, 119, 109, 0, 2, 3, 15,
- 4, 5, 6, 7, 19, 21, 22, 23,
- 27, 24, 16, 17, 18, 10, 11, 12,
- 28, 29, 25, 8, 9, 0, 26, 13,
- 14, 20, 0, 31, 32, 44, 33, 34,
- 35, 36, 48, 50, 51, 52, 53, 45,
- 46, 47, 39, 40, 41, 54, 37, 38,
- 0, 54, 55, 42, 0, 43, 49, 0,
- 0, 57, 0, 59, 60, 72, 61, 62,
- 63, 64, 76, 78, 79, 80, 84, 81,
- 73, 74, 75, 67, 68, 69, 82, 65,
- 66, 82, 83, 70, 71, 77, 0, 96,
- 97, 103, 111, 0, 0, 118
+ 1, 31, 0, 59, 61, 90, 91, 116,
+ 0, 118, 104, 92, 93, 94, 95, 108,
+ 110, 111, 112, 119, 113, 105, 106, 107,
+ 99, 100, 101, 120, 121, 122, 114, 96,
+ 97, 98, 123, 125, 115, 0, 2, 3,
+ 0, 16, 4, 5, 6, 7, 20, 22,
+ 23, 24, 28, 25, 17, 18, 19, 11,
+ 12, 13, 29, 30, 26, 8, 9, 10,
+ 27, 14, 15, 21, 0, 32, 33, 0,
+ 46, 34, 35, 36, 37, 50, 52, 53,
+ 54, 55, 47, 48, 49, 41, 42, 43,
+ 56, 38, 39, 40, 57, 58, 44, 0,
+ 45, 0, 51, 0, 0, 0, 60, 0,
+ 0, 0, 62, 63, 76, 64, 65, 66,
+ 67, 80, 82, 83, 84, 89, 85, 77,
+ 78, 79, 71, 72, 73, 86, 68, 69,
+ 70, 87, 88, 74, 75, 81, 0, 102,
+ 103, 109, 117, 0, 0, 0, 124
};
static const char _use_syllable_machine_trans_actions[] = {
0, 0, 3, 0, 0, 0, 0, 0,
+ 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 5, 0, 0,
+ 6, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 4, 0, 0, 0, 5, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 0, 0, 8,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 6, 0, 0,
- 0, 0, 7, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 8, 0, 0,
- 9, 10, 0, 0, 11, 0, 0, 12,
- 13, 0, 14, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 9,
+ 0, 10, 0, 11, 12, 13, 0, 14,
+ 15, 16, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 8, 0,
- 0, 10, 0, 0, 0, 0, 15, 0,
- 0, 0, 0, 16, 17, 0
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 17, 0,
+ 0, 0, 0, 18, 19, 20, 0
};
static const char _use_syllable_machine_to_state_actions[] = {
@@ -631,7 +777,8 @@ static const char _use_syllable_machine_to_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0
};
static const char _use_syllable_machine_from_state_actions[] = {
@@ -649,25 +796,27 @@ static const char _use_syllable_machine_from_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0
};
static const short _use_syllable_machine_eof_trans[] = {
- 0, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 67, 67,
- 67, 67, 67, 67, 67, 67, 67, 67,
- 67, 67, 93, 67, 67, 67, 67, 67,
- 67, 67, 67, 67, 67, 67, 96, 67,
- 97, 99, 67, 67, 67, 67, 67, 67,
- 67, 67, 67, 67, 67, 67, 93, 67,
- 67, 67, 67, 67, 67, 67, 67, 67,
- 67, 67, 96, 67, 67, 127, 127, 127,
- 127, 127, 127, 127, 127, 127, 127, 127,
- 127, 127, 127, 127, 127, 127, 127, 127,
- 127, 127, 127, 127, 127, 127, 127, 127,
- 127, 127, 127, 127, 132, 133, 133, 133
+ 0, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 96, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 100, 96, 69, 102, 105, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 96, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 100, 96,
+ 69, 69, 135, 135, 135, 135, 135, 135,
+ 135, 135, 135, 135, 135, 135, 135, 135,
+ 135, 135, 135, 135, 135, 135, 135, 135,
+ 135, 135, 135, 135, 135, 135, 135, 135,
+ 135, 135, 140, 141, 141, 141
};
static const int use_syllable_machine_start = 0;
@@ -780,7 +929,7 @@ find_syllables_use (hb_buffer_t *buffer)
unsigned int act HB_UNUSED;
int cs;
-#line 773 "hb-ot-shaper-use-machine.hh"
+#line 933 "hb-ot-shaper-use-machine.hh"
{
cs = use_syllable_machine_start;
ts = 0;
@@ -793,7 +942,7 @@ find_syllables_use (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 782 "hb-ot-shaper-use-machine.hh"
+#line 946 "hb-ot-shaper-use-machine.hh"
{
int _slen;
int _trans;
@@ -807,7 +956,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 794 "hb-ot-shaper-use-machine.hh"
+#line 960 "hb-ot-shaper-use-machine.hh"
}
_keys = _use_syllable_machine_trans_keys + (cs<<1);
@@ -825,14 +974,34 @@ _eof_trans:
goto _again;
switch ( _use_syllable_machine_trans_actions[_trans] ) {
- case 9:
+ case 12:
+#line 170 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_virama_terminated_cluster); }}
+ break;
+ case 10:
+#line 171 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_sakot_terminated_cluster); }}
+ break;
+ case 8:
#line 172 "hb-ot-shaper-use-machine.rl"
{te = p+1;{ found_syllable (use_standard_cluster); }}
break;
+ case 16:
+#line 173 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_number_joiner_terminated_cluster); }}
+ break;
+ case 14:
+#line 174 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_numeral_cluster); }}
+ break;
case 6:
#line 175 "hb-ot-shaper-use-machine.rl"
{te = p+1;{ found_syllable (use_symbol_cluster); }}
break;
+ case 20:
+#line 176 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_hieroglyph_cluster); }}
+ break;
case 4:
#line 177 "hb-ot-shaper-use-machine.rl"
{te = p+1;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
@@ -842,6 +1011,10 @@ _eof_trans:
{te = p+1;{ found_syllable (use_non_cluster); }}
break;
case 11:
+#line 170 "hb-ot-shaper-use-machine.rl"
+ {te = p;p--;{ found_syllable (use_virama_terminated_cluster); }}
+ break;
+ case 9:
#line 171 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }}
break;
@@ -849,7 +1022,7 @@ _eof_trans:
#line 172 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_standard_cluster); }}
break;
- case 14:
+ case 15:
#line 173 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_number_joiner_terminated_cluster); }}
break;
@@ -861,43 +1034,19 @@ _eof_trans:
#line 175 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_symbol_cluster); }}
break;
- case 17:
+ case 19:
#line 176 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_hieroglyph_cluster); }}
break;
- case 15:
+ case 17:
#line 177 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
break;
- case 16:
+ case 18:
#line 178 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_non_cluster); }}
break;
- case 12:
-#line 1 "NONE"
- { switch( act ) {
- case 1:
- {{p = ((te))-1;} found_syllable (use_virama_terminated_cluster); }
- break;
- case 2:
- {{p = ((te))-1;} found_syllable (use_sakot_terminated_cluster); }
- break;
- }
- }
- break;
- case 8:
-#line 1 "NONE"
- {te = p+1;}
-#line 170 "hb-ot-shaper-use-machine.rl"
- {act = 1;}
- break;
- case 10:
-#line 1 "NONE"
- {te = p+1;}
-#line 171 "hb-ot-shaper-use-machine.rl"
- {act = 2;}
- break;
-#line 866 "hb-ot-shaper-use-machine.hh"
+#line 1050 "hb-ot-shaper-use-machine.hh"
}
_again:
@@ -906,7 +1055,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 873 "hb-ot-shaper-use-machine.hh"
+#line 1059 "hb-ot-shaper-use-machine.hh"
}
if ( ++p != pe )
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
index e45ea30e60..6395d689ae 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
@@ -6,18 +6,18 @@
*
* on files with these headers:
*
- * # IndicSyllabicCategory-14.0.0.txt
- * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
- * # IndicPositionalCategory-14.0.0.txt
- * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
- * # ArabicShaping-14.0.0.txt
- * # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
- * # DerivedCoreProperties-14.0.0.txt
- * # Date: 2021-08-12, 23:12:53 GMT
- * # Blocks-14.0.0.txt
- * # Date: 2021-01-22, 23:29:00 GMT [KW]
- * # Scripts-14.0.0.txt
- * # Date: 2021-07-10, 00:35:31 GMT
+ * # IndicSyllabicCategory-15.0.0.txt
+ * # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
+ * # IndicPositionalCategory-15.0.0.txt
+ * # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
+ * # ArabicShaping-15.0.0.txt
+ * # Date: 2022-02-14, 18:50:00 GMT [KW, RP]
+ * # DerivedCoreProperties-15.0.0.txt
+ * # Date: 2022-08-05, 22:17:05 GMT
+ * # Blocks-15.0.0.txt
+ * # Date: 2022-01-28, 20:58:00 GMT [KW]
+ * # Scripts-15.0.0.txt
+ * # Date: 2022-04-26, 23:15:02 GMT
* # Override values For Indic_Syllabic_Category
* # Not derivable
* # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
@@ -90,7 +90,7 @@
#pragma GCC diagnostic pop
static const uint8_t
-hb_use_u8[3083] =
+hb_use_u8[3115] =
{
16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
@@ -114,22 +114,22 @@ hb_use_u8[3083] =
47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 48, 49, 2, 2, 2,
2, 2, 2, 2, 2, 50, 51, 2, 52, 2, 2, 53, 2, 2, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 2, 64, 65, 2, 66, 67, 68, 69,
- 2, 70, 2, 71, 72, 73, 74, 2, 2, 75, 76, 77, 78, 2, 79, 2,
- 2, 80, 80, 80, 80, 80, 80, 80, 80, 81, 2, 2, 2, 2, 2, 2,
+ 2, 70, 2, 71, 72, 73, 74, 2, 2, 75, 76, 77, 78, 2, 79, 80,
+ 2, 81, 81, 81, 81, 81, 81, 81, 81, 82, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 82, 83, 2, 2, 2, 2, 2, 2, 2, 84,
- 85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 80, 80, 80, 86, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 83, 84, 2, 2, 2, 2, 2, 2, 2, 85,
+ 86, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 81, 81, 81, 87, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 87, 88, 2, 2, 2, 2, 2,
- 2, 2, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 88, 89, 2, 2, 2, 2, 2,
+ 2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 90, 2, 2, 91, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 92, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 93, 93, 94, 95, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
- 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
- 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 2, 2, 2, 91, 2, 2, 92, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 93, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 94, 94, 95, 96, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0,
@@ -147,7 +147,7 @@ hb_use_u8[3083] =
7, 0, 0, 0, 2, 2, 2, 2, 2, 39, 40, 41, 0, 0, 0, 0,
0, 10, 13, 28, 2, 2, 2, 2, 28, 2, 28, 2, 2, 2, 2, 2,
2, 7, 2, 28, 2, 2, 0, 15, 16, 17, 18, 19, 25, 20, 33, 22,
- 0, 0, 0, 0, 0, 28, 9, 39, 42, 10, 27, 28, 2, 2, 2, 7,
+ 0, 0, 0, 0, 0, 28, 39, 39, 42, 10, 27, 28, 2, 2, 2, 7,
28, 7, 2, 28, 2, 2, 0, 15, 43, 0, 0, 25, 20, 0, 0, 2,
28, 28, 0, 0, 0, 0, 0, 0, 0, 0, 44, 28, 2, 2, 7, 0,
2, 7, 2, 2, 0, 28, 7, 7, 2, 0, 28, 7, 0, 2, 7, 0,
@@ -191,75 +191,77 @@ hb_use_u8[3083] =
43, 100, 12, 0, 0, 0, 0, 0, 0, 2, 2, 59, 16, 46, 21, 111,
100, 100, 100, 112, 113, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 28,
2, 9, 44, 114, 114, 114, 9, 114, 114, 13, 114, 114, 114, 24, 0, 38,
- 0, 0, 0, 115, 116, 9, 3, 0, 0, 0, 0, 0, 0, 0, 117, 0,
- 0, 0, 0, 0, 0, 0, 4, 118, 119, 40, 40, 3, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 119, 119, 120, 119, 119, 119, 119, 119, 119, 119,
- 119, 0, 0, 121, 0, 0, 0, 0, 0, 0, 5, 121, 0, 0, 0, 0,
+ 0, 0, 0, 115, 49, 9, 3, 0, 0, 0, 0, 0, 0, 0, 116, 0,
+ 0, 0, 0, 0, 0, 0, 4, 117, 118, 40, 40, 3, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 118, 118, 119, 118, 118, 118, 118, 118, 118, 118,
+ 118, 0, 0, 120, 0, 0, 0, 0, 0, 0, 5, 120, 0, 0, 0, 0,
0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
0, 2, 2, 2, 2, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0,
- 122, 2, 51, 2, 106, 2, 8, 2, 2, 2, 63, 17, 14, 0, 0, 29,
+ 121, 2, 51, 2, 106, 2, 8, 2, 2, 2, 63, 17, 14, 0, 0, 29,
0, 2, 2, 0, 0, 0, 0, 0, 0, 27, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 123, 21, 21, 21, 21, 21, 21, 21, 124, 0, 0, 0, 0,
+ 2, 2, 2, 122, 21, 21, 21, 21, 21, 21, 21, 123, 0, 0, 0, 0,
0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0,
- 50, 2, 2, 2, 20, 20, 125, 114, 0, 2, 2, 2, 126, 18, 57, 18,
- 111, 100, 127, 0, 0, 0, 0, 0, 0, 9, 128, 2, 2, 2, 2, 2,
- 2, 2, 129, 21, 20, 18, 46, 130, 131, 132, 0, 0, 0, 0, 0, 0,
+ 50, 2, 2, 2, 20, 20, 124, 114, 0, 2, 2, 2, 125, 18, 57, 18,
+ 111, 100, 126, 0, 0, 0, 0, 0, 0, 9, 127, 2, 2, 2, 2, 2,
+ 2, 2, 128, 21, 20, 18, 46, 129, 130, 131, 0, 0, 0, 0, 0, 0,
0, 2, 2, 50, 28, 2, 2, 2, 2, 2, 2, 2, 2, 8, 20, 57,
- 97, 74, 133, 134, 135, 0, 0, 0, 0, 2, 136, 2, 2, 2, 2, 137,
- 0, 28, 2, 40, 3, 0, 77, 13, 2, 51, 20, 138, 50, 51, 2, 2,
- 103, 8, 7, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 139, 19,
- 23, 0, 0, 140, 141, 0, 0, 0, 0, 2, 63, 43, 21, 78, 45, 142,
+ 97, 74, 132, 133, 134, 0, 0, 0, 0, 2, 135, 2, 2, 2, 2, 136,
+ 0, 28, 2, 40, 3, 0, 77, 13, 2, 51, 20, 137, 50, 51, 2, 2,
+ 103, 8, 7, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 138, 19,
+ 23, 0, 0, 139, 140, 0, 0, 0, 0, 2, 63, 43, 21, 78, 45, 141,
0, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 0,
- 4, 119, 119, 119, 119, 120, 0, 0, 0, 2, 2, 2, 2, 2, 7, 2,
+ 4, 118, 118, 118, 118, 119, 0, 0, 0, 2, 2, 2, 2, 2, 7, 2,
2, 2, 7, 2, 28, 2, 2, 2, 2, 2, 28, 2, 2, 2, 28, 7,
- 0, 126, 18, 25, 29, 0, 0, 143, 144, 2, 2, 28, 2, 28, 2, 2,
- 2, 2, 2, 2, 0, 12, 35, 0, 145, 2, 2, 11, 35, 0, 28, 2,
+ 0, 125, 18, 25, 29, 0, 0, 142, 143, 2, 2, 28, 2, 28, 2, 2,
+ 2, 2, 2, 2, 0, 12, 35, 0, 144, 2, 2, 11, 35, 0, 28, 2,
2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 2, 2,
7, 2, 2, 9, 39, 0, 0, 0, 0, 2, 2, 2, 2, 2, 25, 36,
- 0, 2, 2, 2, 114, 114, 114, 114, 114, 146, 2, 7, 0, 0, 0, 0,
+ 0, 2, 2, 2, 114, 114, 114, 114, 114, 145, 2, 7, 0, 0, 0, 0,
0, 2, 12, 12, 0, 0, 0, 0, 0, 7, 2, 2, 7, 2, 2, 2,
- 2, 28, 2, 7, 0, 28, 2, 0, 0, 147, 148, 149, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 20, 20, 18, 18, 18, 20, 20, 132, 0, 0, 0,
- 0, 0, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 2, 2, 2, 2,
- 2, 51, 50, 51, 0, 0, 0, 0, 151, 9, 72, 2, 2, 2, 2, 2,
+ 2, 28, 2, 7, 0, 28, 2, 0, 0, 146, 147, 148, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 20, 20, 18, 18, 18, 20, 20, 131, 0, 0, 0,
+ 0, 0, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 2, 2, 2, 2,
+ 2, 51, 50, 51, 0, 0, 0, 0, 150, 9, 72, 2, 2, 2, 2, 2,
2, 16, 17, 19, 14, 22, 35, 0, 0, 0, 29, 0, 0, 0, 0, 0,
- 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 126, 18, 20, 152,
- 20, 19, 153, 154, 2, 2, 2, 2, 2, 0, 0, 63, 155, 0, 0, 0,
+ 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 18, 20, 151,
+ 20, 19, 152, 153, 2, 2, 2, 2, 2, 0, 0, 63, 154, 0, 0, 0,
0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20,
- 20, 106, 156, 0, 0, 157, 158, 29, 159, 28, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 160, 42, 0, 0, 0,
- 44, 2, 2, 2, 7, 7, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
- 28, 2, 2, 2, 2, 2, 2, 2, 8, 16, 17, 19, 20, 161, 29, 0,
- 0, 9, 9, 28, 2, 2, 2, 7, 28, 7, 2, 28, 2, 2, 56, 15,
- 21, 14, 21, 45, 30, 31, 30, 32, 0, 0, 0, 0, 33, 0, 0, 0,
- 2, 2, 21, 0, 9, 9, 9, 44, 0, 9, 9, 44, 0, 0, 0, 0,
- 0, 2, 2, 63, 23, 18, 18, 18, 20, 21, 124, 13, 15, 0, 0, 0,
- 0, 2, 2, 2, 2, 2, 0, 0, 162, 163, 0, 0, 0, 0, 0, 0,
- 0, 16, 17, 18, 18, 64, 97, 23, 159, 9, 164, 7, 0, 0, 0, 0,
- 0, 2, 2, 2, 2, 2, 2, 2, 63, 23, 18, 18, 0, 46, 46, 9,
- 165, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 18,
- 0, 21, 17, 18, 18, 19, 14, 80, 165, 36, 0, 0, 0, 0, 0, 0,
- 0, 2, 2, 2, 2, 2, 8, 166, 23, 18, 20, 20, 164, 7, 0, 0,
- 0, 2, 2, 2, 2, 2, 7, 41, 134, 21, 20, 18, 74, 19, 20, 0,
- 0, 2, 2, 2, 7, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 16,
- 17, 18, 19, 20, 103, 165, 35, 0, 0, 2, 2, 2, 7, 28, 0, 2,
- 2, 2, 2, 28, 7, 2, 2, 2, 2, 21, 21, 16, 30, 31, 10, 167,
- 168, 169, 170, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2,
- 2, 63, 23, 18, 18, 0, 20, 21, 27, 106, 0, 31, 0, 0, 0, 0,
- 0, 50, 18, 20, 20, 20, 138, 2, 2, 2, 171, 172, 9, 13, 173, 70,
- 174, 0, 0, 1, 145, 0, 0, 0, 0, 50, 18, 20, 14, 17, 18, 2,
- 2, 2, 2, 156, 156, 156, 175, 175, 175, 175, 175, 175, 13, 176, 0, 28,
- 0, 20, 18, 18, 29, 20, 20, 9, 165, 0, 59, 59, 59, 59, 59, 59,
- 59, 64, 19, 80, 44, 0, 0, 0, 0, 2, 2, 2, 7, 2, 28, 2,
- 2, 50, 20, 20, 29, 0, 36, 20, 25, 9, 158, 177, 173, 0, 0, 0,
- 0, 2, 2, 2, 28, 7, 2, 2, 2, 2, 2, 2, 2, 2, 21, 21,
- 45, 20, 33, 80, 66, 0, 0, 0, 0, 2, 178, 64, 45, 0, 0, 0,
+ 20, 106, 155, 0, 0, 156, 157, 29, 158, 28, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 159, 42, 0, 0, 0,
+ 47, 125, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 7, 7, 2, 2,
+ 28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
+ 8, 16, 17, 19, 20, 160, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7,
+ 28, 7, 2, 28, 2, 2, 56, 15, 21, 14, 21, 45, 30, 31, 30, 32,
+ 0, 0, 0, 0, 33, 0, 0, 0, 2, 2, 21, 0, 9, 9, 9, 44,
+ 0, 9, 9, 44, 0, 0, 0, 0, 0, 2, 2, 63, 23, 18, 18, 18,
+ 20, 21, 123, 13, 15, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0,
+ 161, 162, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 18, 64, 97, 23,
+ 158, 9, 163, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 63, 23, 18, 18, 0, 46, 46, 9, 164, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 18, 0, 21, 17, 18, 18, 19, 14, 80,
+ 164, 36, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 165,
+ 23, 18, 20, 20, 163, 7, 0, 0, 0, 2, 2, 2, 2, 2, 7, 41,
+ 133, 21, 20, 18, 74, 19, 20, 0, 0, 2, 2, 2, 7, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 164, 35, 0,
+ 0, 2, 2, 2, 7, 28, 0, 2, 2, 2, 2, 28, 7, 2, 2, 2,
+ 2, 21, 21, 16, 30, 31, 10, 166, 167, 168, 169, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 0, 2, 2, 2, 63, 23, 18, 18, 0, 20, 21,
+ 27, 106, 0, 31, 0, 0, 0, 0, 0, 50, 18, 20, 20, 20, 137, 2,
+ 2, 2, 170, 171, 9, 13, 172, 70, 173, 0, 0, 1, 144, 0, 0, 0,
+ 0, 50, 18, 20, 14, 17, 18, 2, 2, 2, 2, 155, 155, 155, 174, 174,
+ 174, 174, 174, 174, 13, 175, 0, 28, 0, 20, 18, 18, 29, 20, 20, 9,
+ 164, 0, 59, 59, 59, 59, 59, 59, 59, 64, 19, 80, 44, 0, 0, 0,
+ 0, 2, 2, 2, 7, 2, 28, 2, 2, 50, 20, 20, 29, 0, 36, 20,
+ 25, 9, 157, 176, 172, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2,
+ 2, 2, 2, 2, 2, 2, 21, 21, 45, 20, 33, 80, 66, 0, 0, 0,
+ 0, 2, 177, 64, 45, 0, 0, 0, 0, 9, 178, 2, 2, 2, 2, 2,
+ 2, 2, 2, 21, 20, 18, 29, 0, 46, 14, 140, 0, 0, 0, 0, 0,
0, 179, 179, 179, 106, 7, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0,
0, 2, 2, 2, 2, 2, 7, 0, 56, 180, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0,
38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56,
- 35, 0, 4, 119, 119, 119, 120, 0, 0, 9, 9, 9, 47, 2, 2, 2,
+ 35, 0, 4, 118, 118, 118, 119, 0, 0, 9, 9, 9, 47, 2, 2, 2,
0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 42, 42, 42, 90, 0,
0, O, O, O, GB, B, B, GB, O, O, WJ,FMPst,FMPst, O, CGJ, B,
@@ -268,7 +270,7 @@ hb_use_u8[3083] =
VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, O, O, VPre, VPre,
O, VPre, H, O, VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,
CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv,
- B, O, CS, CS, O, B, VAbv, VAbv, B, R, O, HVM, O, O, FBlw, O,
+ B, O, CS, CS,VMPst, B, VAbv, VAbv, B, R, O, HVM, O, O, FBlw, O,
CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB, SUB, O, SUB, SUB, O, FBlw, O, B,
VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,
VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ,
@@ -276,18 +278,18 @@ hb_use_u8[3083] =
CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst,
FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,
VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw,
- FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv, CS, CS,VMPst, O,FMAbv, ZWNJ, CGJ, WJ,
- WJ, WJ, O,FMPst, O, O, H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst,
- VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw,
- O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,
- VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O,
- HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R, O,FMBlw,CMBlw, VAbv, VPre,
- VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv,
- VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R, MBlw, MBlw, GB, FBlw,
- FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, H, H, O, VBlw,
+ FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ,
+ O,FMPst, O, O, H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,
+ VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B,
+ FAbv, FAbv, FPst, VBlw, B, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,
+ VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre,
+ VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R, O,FMBlw,CMBlw, VAbv, VPre,VMAbv,VMAbv,
+ H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv, VPst, IS,
+ R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R, MBlw, MBlw, GB, FBlw, FBlw,CMAbv,
+ IS, VBlw, IS, GB, VAbv, R,VMPst, H, H, O, VBlw,
};
static const uint16_t
-hb_use_u16[768] =
+hb_use_u16[776] =
{
0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0,
@@ -319,24 +321,25 @@ hb_use_u16[768] =
9, 9,173,170, 0, 0, 0, 0, 0, 0, 0, 9,174,175, 0, 9,
176, 0, 0,177,178, 0, 0, 0,179, 9, 9,180,181,182,183,184,
185, 9, 9,186,187, 0, 0, 0,188, 9,189,190,191, 9, 9,192,
- 185, 9, 9,193,194,105,195,102, 9, 33,196,197, 0, 0, 0, 0,
- 198,199, 94, 9, 9,200,201, 2,202, 20, 21,203,204,205,206,207,
- 9, 9, 9,208,209,210,211, 0,195, 9, 9,212,213, 2, 0, 0,
- 9, 9,214,215,216,217, 0, 0, 9, 9, 9,218,219, 2, 0, 0,
- 9, 9,220,221, 2, 0, 0, 0, 9,222,223,103,224, 0, 0, 0,
- 9, 9,225,226, 0, 0, 0, 0,227,228, 9,229,230, 2, 0, 0,
- 0, 0,231, 9, 9,232,233, 0,234, 9, 9,235,236,237, 9, 9,
- 238,239, 0, 0, 0, 0, 0, 0, 21, 9,214,240, 7, 9, 70, 18,
- 9,241, 73,242, 0, 0, 0, 0,243, 9, 9,244,245, 2,246, 9,
- 247,248, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,249,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 98,250, 0, 0, 0, 0,
- 0, 0, 0, 0, 2, 0, 0, 0, 9, 9, 9,251, 0, 0, 0, 0,
- 9, 9, 9, 9,252,253,254,254,255,256, 0, 0, 0, 0,257, 0,
- 9, 9, 9, 9, 9,258, 0, 0, 9, 9, 9, 9, 9, 9,105, 70,
- 94,259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,260,
- 9, 9, 70,261,262, 0, 0, 0, 0, 9,263, 0, 9, 9,264, 2,
- 9, 9, 9, 9,265, 2, 0, 0,129,129,129,129,129,129,129,129,
- 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,129,
+ 185, 9, 9,193,194,105,195,102, 9, 33,196,197,198, 0, 0, 0,
+ 199,200, 94, 9, 9,201,202, 2,203, 20, 21,204,205,206,207,208,
+ 9, 9, 9,209,210,211,212, 0,195, 9, 9,213,214, 2, 0, 0,
+ 9, 9,215,216,217,218, 0, 0, 9, 9, 9,219,220, 2, 0, 0,
+ 9, 9,221,222, 2, 0, 0, 0, 9,223,224,103,225, 0, 0, 0,
+ 9, 9,226,227, 0, 0, 0, 0,228,229, 9,230,231, 2, 0, 0,
+ 0, 0,232, 9, 9,233,234, 0,235, 9, 9,236,237,238, 9, 9,
+ 239,240, 0, 0, 0, 0, 0, 0, 21, 9,215,241, 7, 9, 70, 18,
+ 9,242, 73,243, 0, 0, 0, 0,244, 9, 9,245,246, 2,247, 9,
+ 248,249, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,250,
+ 251, 48, 9,252,253, 2, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 98,254, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 9, 9, 9,255, 0, 0, 0, 0, 9, 9, 9, 9,256,257,258,258,
+ 259,260, 0, 0, 0, 0,261, 0, 9, 9, 9, 9, 9,262, 0, 0,
+ 9, 9, 9, 9, 9, 9,105, 70, 94,263, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,264, 9, 9, 70,265,266, 0, 0, 0,
+ 0, 9,267, 0, 9, 9,268, 2, 9, 9, 9, 9,269, 2, 0, 0,
+ 129,129,129,129,129,129,129,129,160,160,160,160,160,160,160,160,
+ 160,160,160,160,160,160,160,129,
};
static inline unsigned
@@ -347,7 +350,7 @@ hb_use_b4 (const uint8_t* a, unsigned i)
static inline uint_fast8_t
hb_use_get_category (unsigned u)
{
- return u<921600u?hb_use_u8[2721+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+ return u<921600u?hb_use_u8[2753+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
}
#undef B
@@ -393,26 +396,5 @@ hb_use_get_category (unsigned u)
#undef VMPre
-#ifdef HB_USE_TABLE_MAIN
-int main (int argc, char **argv)
-{
- if (argc != 2)
- {
- for (unsigned u = 0; u < 0x10FFFFu; u++)
- printf ("U+%04X %d\n", u, hb_use_get_category (u));
- return 0;
- }
-
- hb_codepoint_t u;
- sscanf (argv[1], "%x", &u);
-
- printf ("%d\n", hb_use_get_category (u));
-
- return 0;
-}
-
-#endif
-
-
#endif /* HB_OT_SHAPER_USE_TABLE_HH */
/* == End of generated table == */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc
index be4ac813b1..cb4db4a8b2 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc
@@ -10,8 +10,8 @@
* # Date: 2015-03-12, 21:17:00 GMT [AG]
* # Date: 2019-11-08, 23:22:00 GMT [AG]
*
- * # Scripts-14.0.0.txt
- * # Date: 2021-07-10, 00:35:31 GMT
+ * # Scripts-15.0.0.txt
+ * # Date: 2022-04-26, 23:15:02 GMT
*/
#include "hb.hh"
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper.hh b/thirdparty/harfbuzz/src/hb-ot-shaper.hh
index e160987f83..b2d1acb39b 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper.hh
@@ -380,6 +380,10 @@ hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_TOTO:
case HB_SCRIPT_VITHKUQI:
+ /* Unicode-15.0 additions */
+ case HB_SCRIPT_KAWI:
+ case HB_SCRIPT_NAG_MUNDARI:
+
/* If the designer designed the font for the 'DFLT' script,
* (or we ended up arbitrarily pick 'latn'), use the default shaper.
* Otherwise, use the specific shaper.
diff --git a/thirdparty/harfbuzz/src/hb-ot-tag.cc b/thirdparty/harfbuzz/src/hb-ot-tag.cc
index ceb3bf6df5..1b18270cca 100644
--- a/thirdparty/harfbuzz/src/hb-ot-tag.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-tag.cc
@@ -307,12 +307,12 @@ hb_ot_tags_from_language (const char *lang_str,
hb_tag_t lang_tag = hb_tag_from_string (lang_str, first_len);
static hb_atomic_int_t last_tag_idx; /* Poor man's cache. */
- unsigned tag_idx = last_tag_idx.get_relaxed ();
+ unsigned tag_idx = last_tag_idx;
if (likely (tag_idx < ot_languages_len && ot_languages[tag_idx].language == lang_tag) ||
hb_sorted_array (ot_languages, ot_languages_len).bfind (lang_tag, &tag_idx))
{
- last_tag_idx.set_relaxed (tag_idx);
+ last_tag_idx = tag_idx;
unsigned int i;
while (tag_idx != 0 &&
ot_languages[tag_idx].language == ot_languages[tag_idx - 1].language)
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh
index 5946aef635..f60bc4a3ce 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh
@@ -206,11 +206,10 @@ struct avar
v = hb_clamp (v, -(1<<14), +(1<<14));
out.push (v);
}
-
- OT::VariationStore::destroy_cache (var_store_cache);
-
for (unsigned i = 0; i < coords_length; i++)
coords[i] = out[i];
+
+ OT::VariationStore::destroy_cache (var_store_cache);
#endif
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-mvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-mvar-table.hh
index 208db46741..420366fbb3 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-mvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-mvar-table.hh
@@ -43,7 +43,7 @@ struct VariationValueRecord
public:
Tag valueTag; /* Four-byte tag identifying a font-wide measure. */
- HBUINT32 varIdx; /* Outer/inner index into VariationStore item. */
+ VarIdx varIdx; /* Outer/inner index into VariationStore item. */
public:
DEFINE_SIZE_STATIC (8);
diff --git a/thirdparty/harfbuzz/src/hb-repacker.hh b/thirdparty/harfbuzz/src/hb-repacker.hh
index 61b142238e..40a5326118 100644
--- a/thirdparty/harfbuzz/src/hb-repacker.hh
+++ b/thirdparty/harfbuzz/src/hb-repacker.hh
@@ -276,33 +276,17 @@ bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
return resolution_attempted;
}
-/*
- * Attempts to modify the topological sorting of the provided object graph to
- * eliminate offset overflows in the links between objects of the graph. If a
- * non-overflowing ordering is found the updated graph is serialized it into the
- * provided serialization context.
- *
- * If necessary the structure of the graph may be modified in ways that do not
- * affect the functionality of the graph. For example shared objects may be
- * duplicated.
- *
- * For a detailed writeup describing how the algorithm operates see:
- * docs/repacker.md
- */
-template<typename T>
-inline hb_blob_t*
-hb_resolve_overflows (const T& packed,
- hb_tag_t table_tag,
- unsigned max_rounds = 20,
- bool recalculate_extensions = false) {
- graph_t sorted_graph (packed);
+inline bool
+hb_resolve_graph_overflows (hb_tag_t table_tag,
+ unsigned max_rounds ,
+ bool recalculate_extensions,
+ graph_t& sorted_graph /* IN/OUT */)
+{
sorted_graph.sort_shortest_distance ();
bool will_overflow = graph::will_overflow (sorted_graph);
if (!will_overflow)
- {
- return graph::serialize (sorted_graph);
- }
+ return true;
graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph);
if ((table_tag == HB_OT_TAG_GPOS
@@ -314,13 +298,13 @@ hb_resolve_overflows (const T& packed,
DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed.");
if (!_presplit_subtables_if_needed (ext_context)) {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Subtable splitting failed.");
- return nullptr;
+ return false;
}
DEBUG_MSG (SUBSET_REPACK, nullptr, "Promoting lookups to extensions if needed.");
if (!_promote_extensions_if_needed (ext_context)) {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed.");
- return nullptr;
+ return false;
}
}
@@ -360,15 +344,41 @@ hb_resolve_overflows (const T& packed,
if (sorted_graph.in_error ())
{
DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state.");
- return nullptr;
+ return false;
}
if (graph::will_overflow (sorted_graph))
{
DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed.");
- return nullptr;
+ return false;
}
+ return true;
+}
+
+/*
+ * Attempts to modify the topological sorting of the provided object graph to
+ * eliminate offset overflows in the links between objects of the graph. If a
+ * non-overflowing ordering is found the updated graph is serialized it into the
+ * provided serialization context.
+ *
+ * If necessary the structure of the graph may be modified in ways that do not
+ * affect the functionality of the graph. For example shared objects may be
+ * duplicated.
+ *
+ * For a detailed writeup describing how the algorithm operates see:
+ * docs/repacker.md
+ */
+template<typename T>
+inline hb_blob_t*
+hb_resolve_overflows (const T& packed,
+ hb_tag_t table_tag,
+ unsigned max_rounds = 20,
+ bool recalculate_extensions = false) {
+ graph_t sorted_graph (packed);
+ if (!hb_resolve_graph_overflows (table_tag, max_rounds, recalculate_extensions, sorted_graph))
+ return nullptr;
+
return graph::serialize (sorted_graph);
}
diff --git a/thirdparty/harfbuzz/src/hb-serialize.hh b/thirdparty/harfbuzz/src/hb-serialize.hh
index cecdcdeb74..f47cde5eb5 100644
--- a/thirdparty/harfbuzz/src/hb-serialize.hh
+++ b/thirdparty/harfbuzz/src/hb-serialize.hh
@@ -139,6 +139,14 @@ struct hb_serialize_context_t
objidx = o.objidx;
}
#endif
+
+ HB_INTERNAL static int cmp (const void* a, const void* b)
+ {
+ int cmp = ((const link_t*)a)->position - ((const link_t*)b)->position;
+ if (cmp) return cmp;
+
+ return ((const link_t*)a)->objidx - ((const link_t*)b)->objidx;
+ }
};
char *head;
@@ -315,7 +323,7 @@ struct hb_serialize_context_t
{
object_t *obj = current;
if (unlikely (!obj)) return;
- if (unlikely (in_error())) return;
+ if (unlikely (in_error() && !only_overflow ())) return;
current = current->next;
revert (obj->head, obj->tail);
diff --git a/thirdparty/harfbuzz/src/hb-static.cc b/thirdparty/harfbuzz/src/hb-static.cc
index af95615c16..5d4c7cda1b 100644
--- a/thirdparty/harfbuzz/src/hb-static.cc
+++ b/thirdparty/harfbuzz/src/hb-static.cc
@@ -94,7 +94,7 @@ hb_face_t::load_num_glyphs () const
ret = hb_max (ret, load_num_glyphs_from_maxp (this));
- num_glyphs.set_relaxed (ret);
+ num_glyphs = ret;
return ret;
}
@@ -102,7 +102,7 @@ unsigned int
hb_face_t::load_upem () const
{
unsigned int ret = table.head->get_upem ();
- upem.set_relaxed (ret);
+ upem = ret;
return ret;
}
diff --git a/thirdparty/harfbuzz/src/hb-subset-input.cc b/thirdparty/harfbuzz/src/hb-subset-input.cc
index 7d19496275..14ae210d49 100644
--- a/thirdparty/harfbuzz/src/hb-subset-input.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-input.cc
@@ -391,7 +391,7 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input,
*
* Return value: `true` if success, `false` otherwise
*
- * Since: REPLACEME
+ * Since: EXPERIMENTAL
**/
hb_bool_t
hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
@@ -415,7 +415,7 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
*
* Return value: `true` if success, `false` otherwise
*
- * Since: REPLACEME
+ * Since: EXPERIMENTAL
**/
hb_bool_t
hb_subset_input_pin_axis_location (hb_subset_input_t *input,
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc
index 7ff66333a8..079ab8bf99 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc
@@ -89,8 +89,6 @@ _remap_indexes (const hb_set_t *indexes,
}
#ifndef HB_NO_SUBSET_LAYOUT
-typedef void (*layout_collect_func_t) (hb_face_t *face, hb_tag_t table_tag, const hb_tag_t *scripts, const hb_tag_t *languages, const hb_tag_t *features, hb_set_t *lookup_indexes /* OUT */);
-
/*
* Removes all tags from 'tags' that are not in filter. Additionally eliminates any duplicates.
@@ -130,8 +128,8 @@ static bool _filter_tag_list(hb_vector_t<hb_tag_t>* tags, /* IN/OUT */
template <typename T>
static void _collect_layout_indices (hb_subset_plan_t *plan,
const T& table,
- layout_collect_func_t layout_collect_func,
- hb_set_t *indices /* OUT */)
+ hb_set_t *lookup_indices, /* OUT */
+ hb_set_t *feature_indices /* OUT */)
{
unsigned num_features = table.get_feature_count ();
hb_vector_t<hb_tag_t> features;
@@ -149,12 +147,23 @@ static void _collect_layout_indices (hb_subset_plan_t *plan,
|| !plan->check_success (!scripts.in_error ()) || !scripts)
return;
- layout_collect_func (plan->source,
- T::tableTag,
- retain_all_scripts ? nullptr : scripts.arrayZ,
- nullptr,
- retain_all_features ? nullptr : features.arrayZ,
- indices);
+ hb_ot_layout_collect_features (plan->source,
+ T::tableTag,
+ retain_all_scripts ? nullptr : scripts.arrayZ,
+ nullptr,
+ retain_all_features ? nullptr : features.arrayZ,
+ feature_indices);
+
+ for (unsigned feature_index : *feature_indices)
+ {
+ //TODO: replace HB_OT_LAYOUT_NO_VARIATIONS_INDEX with variation_index for
+ //instancing
+ const OT::Feature &f = table.get_feature_variation (feature_index, HB_OT_LAYOUT_NO_VARIATIONS_INDEX);
+ f.add_lookup_indexes_to (lookup_indices);
+ }
+
+ //TODO: update for instancing: only collect lookups from feature_indexes that have no variations
+ table.feature_variation_collect_lookups (feature_indices, lookup_indices);
}
@@ -232,11 +241,11 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
{
hb_blob_ptr_t<T> table = plan->source_table<T> ();
hb_tag_t table_tag = table->tableTag;
- hb_set_t lookup_indices;
+ hb_set_t lookup_indices, feature_indices;
_collect_layout_indices<T> (plan,
*table,
- hb_ot_layout_collect_lookups,
- &lookup_indices);
+ &lookup_indices,
+ &feature_indices);
if (table_tag == HB_OT_TAG_GSUB)
hb_ot_layout_lookups_substitute_closure (plan->source,
@@ -247,19 +256,13 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
&lookup_indices);
_remap_indexes (&lookup_indices, lookups);
- // Collect and prune features
- hb_set_t feature_indices;
- _collect_layout_indices<T> (plan,
- *table,
- hb_ot_layout_collect_features,
- &feature_indices);
-
+ // prune features
table->prune_features (lookups, &feature_indices);
hb_map_t duplicate_feature_map;
_GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, &duplicate_feature_map);
feature_indices.clear ();
- table->prune_langsys (&duplicate_feature_map, langsys_map, &feature_indices);
+ table->prune_langsys (&duplicate_feature_map, plan->layout_scripts, langsys_map, &feature_indices);
_remap_indexes (&feature_indices, features);
table.destroy ();
@@ -269,11 +272,46 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
#ifndef HB_NO_VAR
static inline void
-_collect_layout_variation_indices (hb_subset_plan_t* plan,
- const hb_set_t *glyphset,
- const hb_map_t *gpos_lookups,
- hb_set_t *layout_variation_indices,
- hb_map_t *layout_variation_idx_map)
+_generate_varstore_inner_maps (const hb_set_t& varidx_set,
+ unsigned subtable_count,
+ hb_vector_t<hb_inc_bimap_t> &inner_maps /* OUT */)
+{
+ if (varidx_set.is_empty () || subtable_count == 0) return;
+
+ inner_maps.resize (subtable_count);
+ for (unsigned idx : varidx_set)
+ {
+ uint16_t major = idx >> 16;
+ uint16_t minor = idx & 0xFFFF;
+
+ if (major >= subtable_count)
+ continue;
+ inner_maps[major].add (minor);
+ }
+}
+
+static inline hb_font_t*
+_get_hb_font_with_variations (const hb_subset_plan_t *plan)
+{
+ hb_font_t *font = hb_font_create (plan->source);
+
+ hb_vector_t<hb_variation_t> vars;
+ vars.alloc (plan->user_axes_location->get_population ());
+
+ for (auto _ : *plan->user_axes_location)
+ {
+ hb_variation_t var;
+ var.tag = _.first;
+ var.value = _.second;
+ vars.push (var);
+ }
+
+ hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ());
+ return font;
+}
+
+static inline void
+_collect_layout_variation_indices (hb_subset_plan_t* plan)
{
hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> ();
hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
@@ -284,13 +322,40 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan,
gpos.destroy ();
return;
}
- OT::hb_collect_variation_indices_context_t c (layout_variation_indices, glyphset, gpos_lookups);
+
+ const OT::VariationStore *var_store = nullptr;
+ hb_set_t varidx_set;
+ hb_font_t *font = nullptr;
+ float *store_cache = nullptr;
+ bool collect_delta = plan->pinned_at_default ? false : true;
+ if (collect_delta)
+ {
+ font = _get_hb_font_with_variations (plan);
+ if (gdef->has_var_store ())
+ {
+ var_store = &(gdef->get_var_store ());
+ store_cache = var_store->create_cache ();
+ }
+ }
+
+ OT::hb_collect_variation_indices_context_t c (&varidx_set,
+ plan->layout_variation_idx_delta_map,
+ font, var_store,
+ plan->_glyphset_gsub,
+ plan->gpos_lookups,
+ store_cache);
gdef->collect_variation_indices (&c);
if (hb_ot_layout_has_positioning (plan->source))
gpos->collect_variation_indices (&c);
- gdef->remap_layout_variation_indices (layout_variation_indices, layout_variation_idx_map);
+ hb_font_destroy (font);
+ var_store->destroy_cache (store_cache);
+
+ gdef->remap_layout_variation_indices (&varidx_set, plan->layout_variation_idx_delta_map);
+
+ unsigned subtable_count = gdef->has_var_store () ? gdef->get_var_store ().get_sub_table_count () : 0;
+ _generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps);
gdef.destroy ();
gpos.destroy ();
@@ -506,11 +571,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
#ifndef HB_NO_VAR
if (close_over_gdef)
- _collect_layout_variation_indices (plan,
- plan->_glyphset_gsub,
- plan->gpos_lookups,
- plan->layout_variation_indices,
- plan->layout_variation_idx_map);
+ _collect_layout_variation_indices (plan);
#endif
}
@@ -585,12 +646,9 @@ _nameid_closure (hb_face_t *face,
#ifndef HB_NO_VAR
static void
-_normalize_axes_location (hb_face_t *face,
- const hb_hashmap_t<hb_tag_t, float> *user_axes_location,
- hb_hashmap_t<hb_tag_t, int> *normalized_axes_location, /* OUT */
- bool &all_axes_pinned)
+_normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
{
- if (user_axes_location->is_empty ())
+ if (plan->user_axes_location->is_empty ())
return;
hb_array_t<const OT::AxisRecord> axes = face->table.fvar->get_axes ();
@@ -605,25 +663,27 @@ _normalize_axes_location (hb_face_t *face,
for (const auto& axis : axes)
{
hb_tag_t axis_tag = axis.get_axis_tag ();
- if (!user_axes_location->has (axis_tag))
+ if (!plan->user_axes_location->has (axis_tag))
{
axis_not_pinned = true;
}
else
{
- int normalized_v = axis.normalize_axis_value (user_axes_location->get (axis_tag));
+ int normalized_v = axis.normalize_axis_value (plan->user_axes_location->get (axis_tag));
if (has_avar && axis_count < face->table.avar->get_axis_count ())
{
normalized_v = seg_maps->map (normalized_v);
}
- normalized_axes_location->set (axis_tag, normalized_v);
+ plan->axes_location->set (axis_tag, normalized_v);
+ if (normalized_v != 0)
+ plan->pinned_at_default = false;
}
if (has_avar)
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
-
+
axis_count++;
}
- all_axes_pinned = !axis_not_pinned;
+ plan->all_axes_pinned = !axis_not_pinned;
}
#endif
/**
@@ -683,8 +743,8 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
plan->gpos_features = hb_map_create ();
plan->colrv1_layers = hb_map_create ();
plan->colr_palettes = hb_map_create ();
- plan->layout_variation_indices = hb_set_create ();
- plan->layout_variation_idx_map = hb_map_create ();
+ plan->check_success (plan->layout_variation_idx_delta_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
+ plan->gdef_varstore_inner_maps.init ();
plan->check_success (plan->sanitized_table_cache = hb_hashmap_create<hb_tag_t, hb::unique_ptr<hb_blob_t>> ());
plan->check_success (plan->axes_location = hb_hashmap_create<hb_tag_t, int> ());
@@ -692,12 +752,20 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
if (plan->user_axes_location && input->axes_location)
*plan->user_axes_location = *input->axes_location;
plan->all_axes_pinned = false;
+ plan->pinned_at_default = true;
+
+ plan->check_success (plan->vmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
+ plan->check_success (plan->hmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
if (unlikely (plan->in_error ())) {
hb_subset_plan_destroy (plan);
return nullptr;
}
+#ifndef HB_NO_VAR
+ _normalize_axes_location (face, plan);
+#endif
+
_populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan);
_populate_gids_to_retain (plan,
@@ -725,13 +793,6 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
plan->glyph_map->get(plan->unicode_to_new_gid_list.arrayZ[i].second);
}
-#ifndef HB_NO_VAR
- _normalize_axes_location (face,
- input->axes_location,
- plan->axes_location,
- plan->all_axes_pinned);
-#endif
-
_nameid_closure (face, plan->name_ids, plan->all_axes_pinned, plan->user_axes_location);
if (unlikely (plan->in_error ())) {
hb_subset_plan_destroy (plan);
@@ -754,44 +815,6 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
{
if (!hb_object_destroy (plan)) return;
- hb_set_destroy (plan->unicodes);
- hb_set_destroy (plan->name_ids);
- hb_set_destroy (plan->name_languages);
- hb_set_destroy (plan->layout_features);
- hb_set_destroy (plan->layout_scripts);
- hb_set_destroy (plan->glyphs_requested);
- hb_set_destroy (plan->drop_tables);
- hb_set_destroy (plan->no_subset_tables);
- hb_face_destroy (plan->source);
- hb_face_destroy (plan->dest);
- hb_map_destroy (plan->codepoint_to_glyph);
- hb_map_destroy (plan->glyph_map);
- hb_map_destroy (plan->reverse_glyph_map);
- hb_map_destroy (plan->glyph_map_gsub);
- hb_set_destroy (plan->_glyphset);
- hb_set_destroy (plan->_glyphset_gsub);
- hb_set_destroy (plan->_glyphset_mathed);
- hb_set_destroy (plan->_glyphset_colred);
- hb_map_destroy (plan->gsub_lookups);
- hb_map_destroy (plan->gpos_lookups);
- hb_map_destroy (plan->gsub_features);
- hb_map_destroy (plan->gpos_features);
- hb_map_destroy (plan->colrv1_layers);
- hb_map_destroy (plan->colr_palettes);
- hb_set_destroy (plan->layout_variation_indices);
- hb_map_destroy (plan->layout_variation_idx_map);
-
- hb_hashmap_destroy (plan->gsub_langsys);
- hb_hashmap_destroy (plan->gpos_langsys);
- hb_hashmap_destroy (plan->axes_location);
- hb_hashmap_destroy (plan->sanitized_table_cache);
-
- if (plan->user_axes_location)
- {
- hb_object_destroy (plan->user_axes_location);
- hb_free (plan->user_axes_location);
- }
-
hb_free (plan);
}
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.hh b/thirdparty/harfbuzz/src/hb-subset-plan.hh
index 8912ae70d5..98a45e5f6d 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.hh
@@ -33,10 +33,56 @@
#include "hb-subset-input.hh"
#include "hb-map.hh"
+#include "hb-bimap.hh"
#include "hb-set.hh"
struct hb_subset_plan_t
{
+ hb_subset_plan_t ()
+ {}
+
+ ~hb_subset_plan_t()
+ {
+ hb_set_destroy (unicodes);
+ hb_set_destroy (name_ids);
+ hb_set_destroy (name_languages);
+ hb_set_destroy (layout_features);
+ hb_set_destroy (layout_scripts);
+ hb_set_destroy (glyphs_requested);
+ hb_set_destroy (drop_tables);
+ hb_set_destroy (no_subset_tables);
+ hb_face_destroy (source);
+ hb_face_destroy (dest);
+ hb_map_destroy (codepoint_to_glyph);
+ hb_map_destroy (glyph_map);
+ hb_map_destroy (reverse_glyph_map);
+ hb_map_destroy (glyph_map_gsub);
+ hb_set_destroy (_glyphset);
+ hb_set_destroy (_glyphset_gsub);
+ hb_set_destroy (_glyphset_mathed);
+ hb_set_destroy (_glyphset_colred);
+ hb_map_destroy (gsub_lookups);
+ hb_map_destroy (gpos_lookups);
+ hb_map_destroy (gsub_features);
+ hb_map_destroy (gpos_features);
+ hb_map_destroy (colrv1_layers);
+ hb_map_destroy (colr_palettes);
+
+ hb_hashmap_destroy (gsub_langsys);
+ hb_hashmap_destroy (gpos_langsys);
+ hb_hashmap_destroy (axes_location);
+ hb_hashmap_destroy (sanitized_table_cache);
+ hb_hashmap_destroy (hmtx_map);
+ hb_hashmap_destroy (vmtx_map);
+ hb_hashmap_destroy (layout_variation_idx_delta_map);
+
+ if (user_axes_location)
+ {
+ hb_object_destroy (user_axes_location);
+ hb_free (user_axes_location);
+ }
+ }
+
hb_object_header_t header;
bool successful;
@@ -101,10 +147,11 @@ struct hb_subset_plan_t
hb_map_t *colrv1_layers;
hb_map_t *colr_palettes;
- //The set of layout item variation store delta set indices to be retained
- hb_set_t *layout_variation_indices;
- //Old -> New layout item variation store delta set index mapping
- hb_map_t *layout_variation_idx_map;
+ //Old layout item variation index -> (New varidx, delta) mapping
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map;
+
+ //gdef varstore retained varidx mapping
+ hb_vector_t<hb_inc_bimap_t> gdef_varstore_inner_maps;
hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>>* sanitized_table_cache;
//normalized axes location map
@@ -112,6 +159,12 @@ struct hb_subset_plan_t
//user specified axes location map
hb_hashmap_t<hb_tag_t, float> *user_axes_location;
bool all_axes_pinned;
+ bool pinned_at_default;
+
+ //hmtx metrics map: new gid->(advance, lsb)
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *hmtx_map;
+ //vmtx metrics map: new gid->(advance, lsb)
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *vmtx_map;
public:
diff --git a/thirdparty/harfbuzz/src/hb-subset.cc b/thirdparty/harfbuzz/src/hb-subset.cc
index f62e7e895b..1a0bcbd1fe 100644
--- a/thirdparty/harfbuzz/src/hb-subset.cc
+++ b/thirdparty/harfbuzz/src/hb-subset.cc
@@ -406,6 +406,27 @@ _passthrough (hb_subset_plan_t *plan, hb_tag_t tag)
}
static bool
+_dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag,
+ hb_set_t &visited_set, hb_set_t &revisit_set)
+{
+ switch (tag)
+ {
+ case HB_OT_TAG_hmtx:
+ case HB_OT_TAG_vmtx:
+ if (!plan->pinned_at_default &&
+ !visited_set.has (HB_OT_TAG_glyf))
+ {
+ revisit_set.add (tag);
+ return false;
+ }
+ return true;
+
+ default:
+ return true;
+ }
+}
+
+static bool
_subset_table (hb_subset_plan_t *plan,
hb_vector_t<char> &buf,
hb_tag_t tag)
@@ -514,7 +535,7 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
return nullptr;
}
- hb_set_t tags_set;
+ hb_set_t tags_set, revisit_set;
bool success = true;
hb_tag_t table_tags[32];
unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags);
@@ -527,10 +548,27 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
{
hb_tag_t tag = table_tags[i];
if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue;
+ if (!_dependencies_satisfied (plan, tag, tags_set, revisit_set)) continue;
tags_set.add (tag);
success = _subset_table (plan, buf, tag);
if (unlikely (!success)) goto end;
}
+
+ /*delayed subsetting for some tables since they might have dependency on other tables in some cases:
+ e.g: during instantiating glyf tables, hmetrics/vmetrics are updated and saved in subset plan,
+ hmtx/vmtx subsetting need to use these updated metrics values*/
+ while (!revisit_set.is_empty ())
+ {
+ hb_set_t revisit_temp;
+ for (hb_tag_t tag : revisit_set)
+ {
+ if (!_dependencies_satisfied (plan, tag, tags_set, revisit_temp)) continue;
+ tags_set.add (tag);
+ success = _subset_table (plan, buf, tag);
+ if (unlikely (!success)) goto end;
+ }
+ revisit_set = revisit_temp;
+ }
offset += num_tables;
}
diff --git a/thirdparty/harfbuzz/src/hb-ucd-table.hh b/thirdparty/harfbuzz/src/hb-ucd-table.hh
index 14734c91ea..a372a4afce 100644
--- a/thirdparty/harfbuzz/src/hb-ucd-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ucd-table.hh
@@ -4,7 +4,7 @@
*
* ./gen-ucd-table.py ucd.nounihan.grouped.xml
*
- * on file with this description: Unicode 14.0.0
+ * on file with this description: Unicode 15.0.0
*/
#ifndef HB_UCD_TABLE_HH
@@ -13,7 +13,7 @@
#include "hb.hh"
static const hb_script_t
-_hb_ucd_sc_map[163] =
+_hb_ucd_sc_map[165] =
{
HB_SCRIPT_COMMON, HB_SCRIPT_INHERITED,
HB_SCRIPT_UNKNOWN, HB_SCRIPT_ARABIC,
@@ -96,7 +96,8 @@ _hb_ucd_sc_map[163] =
HB_SCRIPT_YEZIDI, HB_SCRIPT_CYPRO_MINOAN,
HB_SCRIPT_OLD_UYGHUR, HB_SCRIPT_TANGSA,
HB_SCRIPT_TOTO, HB_SCRIPT_VITHKUQI,
- HB_SCRIPT_MATH,
+ HB_SCRIPT_MATH, HB_SCRIPT_KAWI,
+ HB_SCRIPT_NAG_MUNDARI,
};
static const uint16_t
_hb_ucd_dm1_p0_map[825] =
@@ -1068,7 +1069,7 @@ _hb_ucd_dm2_u64_map[388] =
#ifndef HB_OPTIMIZE_SIZE
static const uint8_t
-_hb_ucd_u8[17936] =
+_hb_ucd_u8[18260] =
{
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 11, 12, 13, 13, 13, 14,
@@ -1076,7 +1077,7 @@ _hb_ucd_u8[17936] =
25, 26, 22, 22, 22, 27, 28, 29, 22, 30, 31, 32, 33, 34, 35, 36,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 22, 42,
- 7, 7, 43, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 7, 7, 43, 7, 44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
@@ -1098,12 +1099,12 @@ _hb_ucd_u8[17936] =
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 45, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 46,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 47,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 34, 35, 36, 37, 38, 39, 34, 34, 34, 40, 41, 42, 43,
@@ -1122,35 +1123,36 @@ _hb_ucd_u8[17936] =
118,119,120,121,122,123,124,125,126,127,128,129, 34, 34,130,131,
132,133,134,135,136,137,138,139,140,141,142,122,143,144,145,146,
147,148,149,150,151,152,153,122,154,155,122,156,157,158,159,122,
- 160,161,162,163,164,165,122,122,166,167,168,169,122,170,122,171,
- 34, 34, 34, 34, 34, 34, 34,172,173, 34,174,122,122,122,122,122,
- 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,175,
- 34, 34, 34, 34, 34, 34, 34, 34,176,122,122,122,122,122,122,122,
+ 160,161,162,163,164,165,166,122,167,168,169,170,122,171,172,173,
+ 34, 34, 34, 34, 34, 34, 34,174,175, 34,176,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,177,
+ 34, 34, 34, 34, 34, 34, 34, 34,178,122,122,122,122,122,122,122,
122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,
- 122,122,122,122,122,122,122,122, 34, 34, 34, 34,177,122,122,122,
- 34, 34, 34, 34,178,179,180,181,122,122,122,122,182,183,184,185,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,186,
- 34, 34, 34, 34, 34, 34, 34, 34, 34,187,188,122,122,122,122,122,
- 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,189,
- 34, 34,190, 34, 34,191,122,122,122,122,122,122,122,122,122,122,
- 122,122,122,122,122,122,122,122,192,193,122,122,122,122,122,122,
- 122,122,122,122,122,122,122,122,122,122,122,122,122,122,194,195,
- 69,196,197,198,199,200,201,122,202,203,204,205,206,207,208,209,
- 69, 69, 69, 69,210,211,122,122,122,122,122,122,122,122,212,122,
- 213,122,214,122,122,215,122,122,122,122,122,122,122,122,122,216,
- 34,217,218,122,122,122,122,122,219,220,221,122,222,223,122,122,
- 224,225,226,227,228,122, 69,229, 69, 69, 69, 69, 69,230,231,232,
- 233,234, 69, 69,235,236, 69,237,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,238, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,239, 34,
- 240, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,241, 34, 34,
- 34, 34, 34, 34, 34, 34, 34,242,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34,243,122,122,122,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34, 34, 34,244,122,122,122,122,122,122,122,122,122,
- 245,122,246,247,122,122,122,122,122,122,122,122,122,122,122,122,
- 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,248,
- 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,249,
+ 122,122,122,122,122,122,122,122, 34, 34, 34, 34,179,122,122,122,
+ 34, 34, 34, 34,180,181,182,183,122,122,122,122,184,185,186,187,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,188,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34,189,190,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,191,
+ 34, 34,192, 34, 34,193,122,122,122,122,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,194,195,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,196,197,
+ 69,198,199,200,201,202,203,122,204,205,206,207,208,209,210,211,
+ 69, 69, 69, 69,212,213,122,122,122,122,122,122,122,122,214,122,
+ 215,216,217,122,122,218,122,122,122,219,122,122,122,122,122,220,
+ 34,221,222,122,122,122,122,122,223,224,225,122,226,227,122,122,
+ 228,229,230,231,232,122, 69,233, 69, 69, 69, 69, 69,234,235,236,
+ 237,238, 69, 69,239,240, 69,241,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,242, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,243, 34,
+ 244, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,245, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34,246,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34,247,122,122,122,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34, 34, 34,248, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34,249,122,122,122,122,122,122,122,122,
+ 250,122,251,252,122,122,122,122,122,122,122,122,122,122,122,122,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,253,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,254,
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2,
7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
@@ -1213,7 +1215,7 @@ _hb_ucd_u8[17936] =
44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91,
70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87,
86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61,
- 62, 61, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
+ 62, 94, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77,
44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36,
57, 86, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36,
@@ -1223,7 +1225,7 @@ _hb_ucd_u8[17936] =
36, 36, 36, 75, 43, 43, 43, 60, 7, 7, 7, 7, 7, 2, 44, 44,
44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36,
36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44,
- 36, 36, 61, 81, 43, 43, 43, 44, 7, 7, 7, 7, 7, 44, 36, 36,
+ 36, 36, 61, 81, 43, 43, 43, 80, 7, 7, 7, 7, 7, 44, 36, 36,
77, 67, 2, 2, 2, 2, 2, 2, 2, 97, 97, 67, 43, 67, 67, 67,
7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 50, 50, 50, 4, 4, 86,
36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44,
@@ -1390,18 +1392,19 @@ _hb_ucd_u8[17936] =
44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44,
16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44,
27, 27, 27, 27, 27, 27, 27,100, 36, 36, 36, 36, 36, 57,184, 44,
- 36, 44, 44, 44, 44, 44, 44, 44, 27, 27, 27, 95, 44, 44, 44, 44,
- 180, 27, 30, 2, 2, 44, 44, 44, 36, 43, 43, 2, 2, 44, 44, 44,
- 36, 36,183, 27, 27, 27, 44, 44, 87, 98, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 43, 60, 2, 2, 2, 44,
- 27, 27, 27, 7, 7, 7, 7, 7, 71, 70, 71, 44, 44, 44, 44, 57,
- 86, 87, 43, 85, 87, 60,185, 2, 2, 80, 44, 44, 44, 44, 79, 44,
- 43, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, 87, 43,
- 43, 43, 80, 7, 7, 7, 7, 7, 2, 2, 94, 98, 44, 44, 44, 44,
- 36, 70, 2, 61, 44, 44, 44, 44, 36, 94, 86, 43, 43, 43, 43, 85,
- 98, 36, 63, 2, 59, 43, 60, 87, 7, 7, 7, 7, 7, 63, 63, 2,
- 179, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44, 44, 44, 44, 44,
- 36, 36, 36, 36, 36, 36, 86, 87, 43, 86, 85, 43, 2, 2, 2, 80,
+ 36, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 57, 43,
+ 27, 27, 27, 95, 44, 44, 44, 44,180, 27, 30, 2, 2, 44, 44, 44,
+ 36, 43, 43, 2, 2, 44, 44, 44, 36, 36,183, 27, 27, 27, 44, 44,
+ 87, 98, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43,
+ 43, 43, 43, 60, 2, 2, 2, 44, 27, 27, 27, 7, 7, 7, 7, 7,
+ 71, 70, 71, 44, 44, 44, 44, 57, 86, 87, 43, 85, 87, 60,185, 2,
+ 2, 80, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 70, 43, 43, 87, 43, 43, 43, 80, 7, 7, 7, 7, 7,
+ 2, 2, 94, 98, 44, 44, 44, 44, 36, 70, 2, 61, 44, 44, 44, 44,
+ 36, 94, 86, 43, 43, 43, 43, 85, 98, 36, 63, 2, 59, 43, 60, 87,
+ 7, 7, 7, 7, 7, 63, 63, 2,179, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27,100, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 86, 87,
+ 43, 86, 85, 43, 2, 2, 2, 71, 70, 44, 44, 44, 44, 44, 44, 44,
36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62,
36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70,
86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62,
@@ -1423,17 +1426,20 @@ _hb_ucd_u8[17936] =
70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60,
2, 2, 2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36,
36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43, 2, 72, 2,
- 2, 64, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 87,
- 63, 2, 2, 44, 44, 44, 44, 44, 2, 36, 36, 36, 36, 36, 36, 36,
- 44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 89, 43, 43, 43,
- 85, 43, 87, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36,
- 70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44,
- 36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 86, 86, 90,
- 43, 89, 87, 87, 61, 44, 44, 44, 36, 70, 85,107, 64, 44, 44, 44,
+ 2, 64, 44, 44, 44, 44, 44, 44, 2, 2, 2, 2, 2, 44, 44, 44,
+ 43, 43, 43, 80, 43, 43, 43, 87, 63, 2, 2, 44, 44, 44, 44, 44,
+ 2, 36, 36, 36, 36, 36, 36, 36, 44, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 89, 43, 43, 43, 85, 43, 87, 80, 44, 44, 44, 44,
+ 36, 36, 36, 61, 36, 62, 36, 36, 70, 43, 43, 80, 44, 80, 43, 57,
+ 43, 43, 43, 70, 44, 44, 44, 44, 36, 36, 36, 62, 61, 36, 36, 36,
+ 36, 36, 36, 36, 36, 86, 86, 90, 43, 89, 87, 87, 61, 44, 44, 44,
+ 36, 70, 85,107, 64, 44, 44, 44, 43, 94, 36, 36, 36, 36, 36, 36,
+ 36, 36, 86, 43, 43, 80, 44, 86, 85, 60, 2, 2, 2, 2, 2, 2,
27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67,
67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181,
2, 2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44,
- 65, 65, 65, 65,132, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44,
+ 65, 65, 65, 65, 65, 65, 65, 65, 71, 36, 36, 70, 43, 43, 43, 43,
+ 43, 43, 43, 44, 44, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44,
43, 43, 43, 60, 2, 2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44,
7, 7, 7, 7, 7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36,
36, 36, 36, 36, 44, 44, 62, 36, 27, 27, 27, 30, 2, 64, 44, 44,
@@ -1441,7 +1447,8 @@ _hb_ucd_u8[17936] =
86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57,
43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44,
86, 44, 44, 44, 44, 44, 44, 44, 40, 40, 52, 40, 40, 40, 52, 81,
- 36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44,
+ 36, 61, 44, 44, 44, 44, 44, 44, 44, 61, 44, 44, 44, 44, 44, 44,
+ 36, 61, 62, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44,
36, 36, 36, 36, 36, 44, 50, 60, 65, 65, 44, 44, 44, 44, 44, 44,
43, 43, 43, 43, 43, 43, 43, 44, 43, 43, 43, 80, 44, 44, 44, 44,
67, 67, 67, 92, 55, 67, 67, 67, 67, 67,186, 87, 43, 67,186, 86,
@@ -1466,10 +1473,12 @@ _hb_ucd_u8[17936] =
43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67,
67, 67, 76, 21, 2, 2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43,
16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110,
- 43, 43, 43, 80, 43, 43, 43, 43, 43, 43, 43, 43, 80, 57, 43, 43,
- 43, 57, 80, 43, 43, 80, 44, 44, 43, 43, 43, 74, 40, 40, 40, 44,
- 7, 7, 7, 7, 7, 44, 44, 77, 36, 36, 36, 36, 36, 36, 36, 80,
- 36, 36, 36, 36, 36, 36, 43, 43, 7, 7, 7, 7, 7, 44, 44, 96,
+ 44, 44,150, 16, 16,110, 44, 44, 43, 43, 43, 80, 43, 43, 43, 43,
+ 43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44,
+ 40, 40, 40, 40, 40, 40, 40, 44, 44, 44, 44, 44, 44, 44, 44, 57,
+ 43, 43, 43, 74, 40, 40, 40, 44, 7, 7, 7, 7, 7, 44, 44, 77,
+ 36, 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 43, 43,
+ 7, 7, 7, 7, 7, 44, 44, 96, 36, 36, 36, 36, 36, 83, 43, 43,
36, 36, 36, 61, 36, 36, 62, 61, 36, 36, 61,179, 27, 27, 27, 27,
16, 16, 43, 43, 43, 74, 44, 44, 27, 27, 27, 27, 27, 27,163, 27,
188, 27,100, 44, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,163,
@@ -1482,138 +1491,141 @@ _hb_ucd_u8[17936] =
27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44,
44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44,
67, 67, 67, 67, 92, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44,
- 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 55, 67,
- 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 44, 67, 67, 92, 44,
+ 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 67, 67,
+ 67, 67, 67, 92, 44, 55, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44,
+ 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 44, 44, 44, 44, 67,
67, 92, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44,
- 65, 65, 65, 65, 65, 65, 65, 65,171,171,171,171,171,171,171, 44,
- 171,171,171,171,171,171,171, 0, 0, 0, 29, 21, 21, 21, 23, 21,
- 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9,
- 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0,
- 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15,
- 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7,
- 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12,
- 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, 25, 9, 26, 12, 11, 11,
- 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, 2, 12, 17, 12, 21, 12,
- 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, 1, 1, 21, 23, 26, 26,
- 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12,
- 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, 6, 2, 24, 7, 7, 6,
- 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 2, 10, 10, 2, 15, 26,
- 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, 21, 26, 10, 7, 21, 15,
- 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, 14, 14, 14, 7, 10, 21,
- 17, 21, 11, 12, 5, 2, 5, 6, 8, 8, 8, 24, 5, 24, 2, 24,
- 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, 20, 19, 22, 20, 27, 28,
- 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29,
- 1, 2, 15, 6, 18, 6, 23, 2, 12, 11, 9, 26, 26, 9, 26, 5,
- 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25,
- 18, 22, 5, 12, 2, 5, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14,
- 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15,
- 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3,
- 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25, 2, 25, 24, 2, 15,
- 12, 15, 14, 2, 21, 14, 7, 15, 12, 17, 21, 1, 26, 10, 10, 1,
- 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12,
- 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
- 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32,
- 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 34, 0, 35, 0, 0, 0, 0, 0, 0,
+ 171,171,171,171,171,171,171, 44,171,171,171,171,171,171,171, 0,
+ 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13,
+ 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5,
+ 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20,
+ 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25,
+ 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 7, 5,
+ 6, 6, 24, 24, 6, 24, 12, 12, 2, 2, 6, 5, 9, 21, 9, 2,
+ 2, 9, 25, 9, 26, 12, 11, 11, 2, 6, 5, 21, 17, 2, 2, 26,
+ 26, 23, 2, 12, 17, 12, 21, 12, 12, 21, 7, 2, 2, 7, 7, 21,
+ 21, 2, 1, 1, 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7,
+ 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 2, 1,
+ 12, 2, 6, 2, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12,
+ 21, 6, 2, 10, 10, 2, 15, 26, 26, 2, 2, 21, 7, 10, 15, 7,
+ 2, 23, 21, 26, 10, 7, 21, 15, 15, 2, 17, 7, 29, 7, 7, 22,
+ 18, 2, 14, 14, 14, 7, 10, 21, 17, 21, 11, 12, 5, 2, 5, 6,
+ 8, 8, 8, 24, 5, 24, 2, 24, 9, 24, 24, 2, 29, 29, 29, 1,
+ 17, 17, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16,
+ 16, 21, 25, 22, 18, 21, 21, 29, 1, 2, 15, 6, 18, 6, 23, 2,
+ 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15,
+ 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 2, 5, 22, 21,
+ 21, 22, 18, 17, 26, 6, 7, 14, 17, 22, 18, 18, 26, 14, 17, 6,
+ 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9,
+ 23, 26, 6, 10, 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16,
+ 25, 17, 25, 2, 25, 24, 2, 15, 12, 15, 14, 2, 21, 14, 7, 15,
+ 12, 17, 21, 1, 26, 10, 10, 1, 23, 15, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0,
+ 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0,
- 0, 0, 39, 40, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0,
- 0, 0, 0, 0, 6, 7, 8, 0, 9, 0, 10, 11, 0, 0, 12, 13,
- 14, 15, 16, 0, 0, 0, 0, 17, 18, 19, 20, 0, 21, 0, 22, 23,
- 0, 24, 25, 0, 0, 24, 26, 27, 0, 24, 26, 0, 0, 24, 26, 0,
- 0, 24, 26, 0, 0, 0, 26, 0, 0, 24, 28, 0, 0, 24, 26, 0,
- 0, 29, 26, 0, 0, 0, 30, 0, 0, 31, 32, 0, 0, 33, 34, 0,
- 35, 36, 0, 37, 38, 0, 39, 0, 0, 40, 0, 0, 41, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 43, 44, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 46, 0, 0,
- 0, 47, 0, 0, 0, 0, 0, 0, 48, 0, 0, 49, 0, 50, 51, 0,
- 0, 52, 53, 54, 0, 55, 0, 56, 0, 57, 0, 0, 0, 0, 58, 59,
- 0, 0, 0, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, 62, 63,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,
- 0, 0, 0, 65, 0, 0, 0, 66, 0, 67, 0, 0, 68, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 70, 0, 0, 71,
- 0, 0, 0, 0, 0, 0, 0, 0, 72, 73, 0, 0, 0, 0, 53, 74,
- 0, 75, 76, 0, 0, 77, 78, 0, 0, 0, 0, 0, 0, 79, 80, 81,
- 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0,
- 82, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 85,
- 0, 0, 0, 86, 0, 0, 0, 0, 87, 88, 0, 0, 0, 0, 0, 89,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35,
+ 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0,
- 0, 0, 92, 0, 93, 0, 0, 0, 0, 0, 72, 94, 0, 95, 0, 0,
- 96, 97, 0, 77, 0, 0, 98, 0, 0, 99, 0, 0, 0, 0, 0,100,
- 0,101, 26,102, 0, 0, 0, 0, 0, 0,103, 0, 0, 0,104, 0,
- 0, 0, 0, 0, 0, 65,105, 0, 0, 65, 0, 0, 0,106, 0, 0,
- 0,107, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0,
- 0,108,109, 0, 0, 0, 0, 78, 0, 44,110, 0,111, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0,
- 0, 0,112, 0,113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,114,
- 0,115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,116, 0, 0, 0, 0,117, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 40, 41, 42, 0, 43, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,118,119,120, 0, 0, 0, 0,121, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,122,123, 0, 0, 0, 0, 0, 0,
- 0,115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0,125,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0,
- 0, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10,
- 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 0, 0, 0, 0,
- 19, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 1,
- 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36,
- 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 38, 1, 39,
- 14, 39, 40, 41, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0,
- 0, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 0, 0,
- 0, 0, 19, 1, 21, 0, 0, 47, 0, 0, 0, 0, 0, 38, 48, 1,
- 1, 49, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0,
- 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 38, 14, 4, 1, 1, 1,
- 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 0, 0, 0, 0, 55,
- 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 56, 0, 60, 0, 0,
- 0, 0, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 69, 70, 0,
- 0, 0, 0, 0, 71, 72, 73, 74, 75, 76, 0, 0, 0, 0, 0, 0,
- 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 79, 0,
- 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49,
- 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0,
- 0, 0, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 19, 84, 0,
- 62, 0, 0, 0, 0, 49, 1, 85, 0, 0, 0, 0, 1, 52, 15, 86,
- 36, 10, 21, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0,
- 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0,
- 0, 0, 88, 0, 0, 0, 0, 0, 0, 89, 0, 0, 88, 0, 0, 0,
- 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 87, 9, 12, 4,
- 90, 8, 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1,
- 1, 1, 1, 1, 1, 94, 95, 96, 0, 0, 0, 0, 97, 1, 98, 58,
- 81, 99,100, 4, 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 61, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0,101,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,103, 0,
- 0, 0, 0, 19, 0, 1, 1, 50, 0, 0, 0, 0, 0, 0, 0, 38,
- 0, 0, 0, 0, 50, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 62, 0, 0, 0, 0, 1, 1, 1, 1, 50, 0, 0, 0,
- 0, 0,104, 68, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0,
- 0, 0, 0, 0, 78, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0,107,
- 1, 14, 4, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47,
- 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 87, 0,
- 0, 0, 0,108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,109, 61,
- 0,110, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 19, 58, 0, 0, 0, 0, 0,111, 14, 52, 84, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 0,
+ 9, 0, 10, 11, 0, 0, 12, 13, 14, 15, 16, 0, 0, 0, 0, 17,
+ 18, 19, 20, 0, 21, 0, 22, 23, 0, 24, 25, 0, 0, 24, 26, 27,
+ 0, 24, 26, 0, 0, 24, 26, 0, 0, 24, 26, 0, 0, 0, 26, 0,
+ 0, 24, 28, 0, 0, 24, 26, 0, 0, 29, 26, 0, 0, 0, 30, 0,
+ 0, 31, 32, 0, 0, 33, 34, 0, 35, 36, 0, 37, 38, 0, 39, 0,
+ 0, 40, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, 0, 0, 45, 0,
+ 0, 0, 0, 0, 0, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0,
+ 48, 0, 0, 49, 0, 50, 51, 0, 0, 52, 53, 54, 0, 55, 0, 56,
+ 0, 57, 0, 0, 0, 0, 58, 59, 0, 0, 0, 0, 0, 0, 60, 61,
+ 0, 0, 0, 0, 0, 0, 62, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 66,
+ 0, 67, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 69, 70, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0,
+ 72, 73, 0, 0, 0, 0, 53, 74, 0, 75, 76, 0, 0, 77, 78, 0,
+ 0, 0, 0, 0, 0, 79, 80, 81, 0, 0, 0, 0, 0, 0, 0, 26,
+ 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0,
+ 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84,
+ 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 86, 0, 0, 0, 0,
+ 87, 88, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 91, 0, 92, 0, 0, 93, 0, 94, 0, 0, 0,
+ 0, 0, 72, 95, 0, 96, 0, 0, 97, 98, 0, 77, 0, 0, 99, 0,
+ 0,100, 0, 0, 0, 0, 0,101, 0,102, 26,103, 0, 0, 0, 0,
+ 0, 0,104, 0, 0, 0,105, 0, 0, 0, 0, 0, 0, 65,106, 0,
+ 0, 65, 0, 0, 0,107, 0, 0, 0,108, 0, 0, 0, 0, 0, 0,
+ 0, 96, 0, 0, 0, 0, 0, 0, 0,109,110, 0, 0, 0, 0, 78,
+ 0, 44,111, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 65, 0, 0, 0, 0, 0, 0, 0, 0,113, 0,114, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,116, 0,117, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,
+ 0, 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,121,122, 0, 0,
+ 0, 0,123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 124,125, 0, 0,126, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,127, 0,128, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,129, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,130, 0, 0, 0,131, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4,
+ 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17,
+ 18, 1, 1, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28,
+ 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 31, 0,
+ 0, 0, 32, 33, 34, 35, 1, 36, 0, 0, 0, 0, 37, 0, 0, 0,
+ 0, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, 0, 0, 0, 0,
+ 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 43, 36, 44, 45,
+ 21, 45, 46, 0, 0, 0, 0, 0, 0, 0, 19, 1, 21, 0, 0, 47,
+ 0, 0, 0, 0, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 52, 1,
+ 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1,
+ 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0,
+ 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59,
+ 0, 0, 0, 56, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 61, 62,
+ 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0,
+ 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0,
+ 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0,
+ 0, 0, 0, 0, 0, 69, 70, 0, 0, 0, 0, 0, 71, 72, 73, 74,
+ 75, 76, 0, 0, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 80, 0, 0,
+ 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 63, 0, 0, 81,
+ 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0,
+ 0, 0, 0, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85,
+ 0, 0, 0, 0, 1, 52, 15, 86, 36, 10, 21, 87, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 55, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0,
+ 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0,
+ 0, 89, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0,
+ 0, 0, 0, 0, 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0,
+ 21, 1, 21, 92, 93, 1, 1, 1, 1, 1, 1, 1, 1, 94, 95, 96,
+ 0, 0, 0, 0, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0,
+ 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61,
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,101,102, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,103, 0, 0, 0, 0, 19, 0, 1, 1, 50,
+ 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 50, 0, 0, 0,
+ 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0,
+ 1, 1, 1, 1, 50, 0, 0, 0, 0, 0,104, 68, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0,
+ 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105,106, 58, 38,
+ 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 47, 84, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,109, 61, 0,110, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 19, 58, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 51, 0,111, 14, 52, 84, 0, 0, 0,
112, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 61,
0, 0, 0, 0, 0, 0,113, 0, 87, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0, 0, 0, 0,
@@ -1624,89 +1636,90 @@ _hb_ucd_u8[17936] =
0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79,
78, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 8, 91, 0, 0,
- 0, 0, 0, 0, 1, 87, 0, 0, 0, 0, 0, 0,116, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,117, 0,118,119,120,121, 0,104, 4,
- 122, 49, 23, 0, 0, 0, 0, 0, 0, 0, 38, 50, 0, 0, 0, 0,
- 38, 58, 0, 0, 0, 0, 0, 0, 1, 87, 1, 1, 1, 1, 39, 1,
- 48,105, 87, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0,
- 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4,122, 0, 0,
- 0, 1,123, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,
- 230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220,
- 220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220,
- 220,230,230,230,230,240,230,220,220,220,230,230,230,220,220, 0,
- 230,230,230,220,220,220,220,230,232,220,220,230,233,234,234,233,
- 234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230,220,230,
- 230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, 12, 13,
- 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,
- 230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31,
- 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0, 0, 0,
- 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220, 0, 0,
- 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230,220,230,
- 220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,230,230,
- 230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230, 0,220,
- 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,
- 230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9,
- 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,107,107,
- 118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220, 0,220,
- 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,
- 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,220, 0,
- 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0,
- 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, 0,220,
- 230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0,
- 230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,230,230,
- 230,230,232,228,228,220,218,230,233,220,230,220,230,230, 1, 1,
- 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228,
- 232,222,224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230,
- 220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0,
- 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0,
- 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0,
- 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,
- 220,220,220, 0,230,230, 7, 0, 16, 17, 17, 17, 17, 17, 17, 33,
- 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27,
- 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 0, 0, 0, 0, 0, 61, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 8, 91, 0, 0, 0, 0, 0, 0, 1, 87, 0, 0,
+ 0, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117,
+ 0,118,119,120,121, 0,104, 4,122, 49, 23, 0, 0, 0, 0, 0,
+ 0, 0, 38, 50, 0, 0, 0, 0, 38, 58, 0, 0, 0, 0, 0, 0,
+ 1, 87, 1, 1, 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 0,
+ 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,123, 0, 0, 0, 0,
+ 0, 0, 0, 0, 4,122, 0, 0, 0, 1,124, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,230,230,230,230,230,232,220,220,220,220,232,216,
+ 220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,
+ 1, 1, 1, 1, 1,220,220,220,220,230,230,230,230,240,230,220,
+ 220,220,230,230,230,220,220, 0,230,230,230,220,220,220,220,230,
+ 232,220,220,230,233,234,234,233,234,234,233,230, 0, 0, 0,230,
+ 0,220,230,230,230,230,220,230,230,230,222,220,230,230,220,220,
+ 230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20,
+ 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0,
+ 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,
+ 220,230,230,220, 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230,
+ 230, 0,220,230,230,220, 0, 0, 0, 36, 0, 0,230,220,230,230,
+ 220,220,230,220,220,230,220,230,220,230,230, 0, 0,220, 0, 0,
+ 230,230, 0,230, 0,230,230,230,230,230, 0, 0, 0,220,220,220,
+ 230,220,220,220,230,230, 0,220, 27, 28, 29,230, 7, 0, 0, 0,
+ 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0,230, 0,
+ 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 9, 0,
+ 103,103, 9, 0,107,107,107,107,118,118, 9, 0,122,122,122,122,
+ 220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0,
+ 132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230,
+ 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7, 0, 9, 9, 0,
+ 9, 9, 0, 0, 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220,
+ 220, 0, 0, 0,230, 0, 0,220,230,220, 0,220,230,230,230, 0,
+ 0, 0, 9, 9, 0, 0, 7, 0,230, 0, 1, 1, 1, 0, 0, 0,
+ 230,234,214,220,202,230,230,230,230,230,232,228,228,220,218,230,
+ 233,220,230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,
+ 220,230, 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0,
+ 0, 0, 0,220,230, 0,230,230,220, 0, 0,230, 0, 0, 26, 0,
+ 0,220, 0,230,230, 1,220, 0, 0,230,220, 0, 0, 0,220,220,
+ 0, 0,230,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 9, 7,
+ 6, 6, 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0,
+ 0,226,216,216,216,216,216, 0,220,220,220, 0,232,232,220,230,
+ 230,230, 7, 0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19,
+ 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2, 0, 3, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8, 9, 0, 0, 0,
- 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 24, 25, 26,
- 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 33,
- 34, 35, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 38, 39, 0, 0, 0, 0, 1, 2, 40, 41, 0, 1, 2, 2,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2,
- 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0, 0, 0, 6, 0,
- 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 8, 9,
- 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0,
- 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0, 0, 0, 0, 1,
- 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7, 20, 20, 20, 20,
- 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0, 20, 20, 25, 0,
- 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1, 28, 29, 30, 31,
- 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0,
- 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33,
- 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0,
- 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0,
- 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21, 0, 1, 0, 1,
- 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42,
- 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 46,
- 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 20, 20, 1, 20, 20, 0,
- 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24,
- 25, 26, 13, 13, 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17,237, 0, 1, 2, 2, 0, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 0, 6, 7, 8, 9, 0, 0, 0, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
+ 0, 0, 21, 22, 0, 0, 0, 0, 23, 24, 25, 26, 0, 27, 0, 28,
+ 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, 36, 0,
+ 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39,
+ 0, 0, 0, 0, 1, 2, 40, 41, 0, 1, 2, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
+ 0, 0, 3, 4, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0,
+ 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0,
+ 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 11, 12,
+ 0, 13, 0, 14, 15, 16, 0, 0, 0, 0, 0, 1, 17, 18, 0, 19,
+ 7, 1, 0, 0, 0, 20, 20, 7, 20, 20, 20, 20, 20, 20, 20, 8,
+ 21, 0, 22, 0, 7, 23, 24, 0, 20, 20, 25, 0, 0, 0, 26, 27,
+ 1, 7, 20, 20, 20, 20, 20, 1, 28, 29, 30, 31, 0, 0, 20, 0,
+ 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 20, 20,
+ 20, 1, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, 7, 20, 20, 20,
+ 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, 38, 1, 20, 20,
+ 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, 0, 0, 1, 0,
+ 0, 40, 1, 1, 0, 0, 8, 21, 0, 1, 0, 1, 0, 1, 0, 0,
+ 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 7, 20, 41,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, 43, 44, 0, 45,
+ 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 46, 7, 1, 10, 1,
+ 0, 0, 0, 1, 20, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 26, 34, 9, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0,
+ 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3,
+ 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24, 25, 26, 13, 13,
+ 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42,
- 7, 7, 43, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42, 7, 7, 43, 7,
+ 44, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
@@ -1727,411 +1740,419 @@ _hb_ucd_u8[17936] =
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 44, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38,
- 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2,
- 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59,
- 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69,
- 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45, 0, 0, 1,
+ 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, 53, 54, 55, 56,
+ 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61,
+ 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70,
- 70, 70, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84,
- 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 70, 70, 97, 98, 99,100,101,101,102,103,104,105,
- 106,107,108,109,110,111, 96,112,113,114,115,116,117,118,119,119,
- 120,121,122,123,124,125,126,127,128,129,130,131,132, 96,133,134,
- 135,136,137,138,139,140,141,142,143, 96,144,145, 96,146,147,148,
- 149, 96,150,151,152,153,154,155, 96, 96,156,157,158,159, 96,160,
- 96,161,162,162,162,162,162,162,162,163,164,162,165, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96,166,167,167,167,167,167,167,167,167,168, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,169,169,169,169,170, 96,
- 96, 96,171,171,171,171,172,173,174,175, 96, 96, 96, 96,176,177,
- 178,179,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
- 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
- 180,181,180,180,180,180,180,180,182,182,182,183,184, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96,185,186,187,188,189,189,190, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,191,192, 96, 96, 96, 96,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 193,194, 59,195,196,197,198,199,200, 96,201,202,203, 59, 59,204,
- 59,205,206,206,206,206,206,207, 96, 96, 96, 96, 96, 96, 96, 96,
- 208, 96,209, 96,210, 96, 96,211, 96, 96, 96, 96, 96, 96, 96, 96,
- 96,212,213,214,215, 96, 96, 96, 96, 96,216,217,218, 96,219,220,
- 96, 96,221,222, 59,223,224, 96, 59, 59, 59, 59, 59, 59, 59,225,
- 226,227,228,229, 59, 59,230,231, 59,232, 96, 96, 96, 96, 96, 96,
- 96, 96, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,233,
+ 70, 70, 97, 98, 99,100,101,101,102,103,104,105,106,107,108,109,
+ 110,111, 96,112,113,114,115,116,117,118,119,119,120,121,122,123,
+ 124,125,126,127,128,129,130,131,132, 96,133,134,135,136,137,138,
+ 139,140,141,142,143, 96,144,145, 96,146,147,148,149, 96,150,151,
+ 152,153,154,155,156, 96,157,158,159,160, 96,161,162,163,164,164,
+ 164,164,164,164,164,165,166,164,167, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,168,169,169,
+ 169,169,169,169,169,169,170, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96,171,171,171,171,172, 96, 96, 96,173,173,
+ 173,173,174,175,176,177, 96, 96, 96, 96,178,179,180,181,182,182,
+ 182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+ 182,182,182,182,182,182,182,182,182,182,182,182,182,183,182,182,
+ 182,182,182,182,184,184,184,185,186, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,187,188,189,
+ 190,191,191,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96,193,194, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,195,196, 59,197,
+ 198,199,200,201,202, 96,203,204,205, 59, 59,206, 59,207,208,208,
+ 208,208,208,209, 96, 96, 96, 96, 96, 96, 96, 96,210, 96,211,212,
+ 213, 96, 96,214, 96, 96, 96,215, 96, 96, 96, 96, 96,216,217,218,
+ 219, 96, 96, 96, 96, 96,220,221,222, 96,223,224, 96, 96,225,226,
+ 59,227,228, 96, 59, 59, 59, 59, 59, 59, 59,229,230,231,232,233,
+ 59, 59,234,235, 59,236, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,237, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,238, 70,239, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 234, 70,235, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,236,
- 70, 70, 70, 70, 70, 70, 70, 70, 70,237, 96, 96, 96, 96, 96, 96,
- 96, 96, 70, 70, 70, 70,238, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 70, 70, 70, 70, 70, 70,239, 96, 96, 96, 96, 96, 96, 96,
- 96, 96,240, 96,241,242, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3,
- 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0,
- 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19,
- 19, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0,
- 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
- 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9,
- 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9,
- 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
- 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1,
- 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4,
- 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2,
- 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0,
- 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37,
- 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2,
- 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64,
- 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
- 2, 2, 90, 90, 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95,
- 95, 95, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2,
- 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2,
- 2, 2, 3, 3, 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0,
- 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2,
- 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2,
- 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5,
- 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5,
- 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2,
- 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
- 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11,
- 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11,
- 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2,
- 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11,
- 11, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10,
- 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10,
- 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2,
- 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10,
- 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2,
- 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21,
- 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21,
- 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21,
- 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22,
- 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22,
- 2, 2, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2,
- 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2,
- 22, 22, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2,
- 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23,
- 23, 23, 23, 23, 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23,
- 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 23,
- 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2,
- 2, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2,
- 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16,
- 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16,
- 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2,
- 16, 16, 2, 16, 16, 2, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20,
- 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2,
- 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36,
- 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36,
- 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2,
- 36, 2, 2, 2, 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2,
- 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2,
- 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18,
- 2, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2,
- 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25,
- 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2,
- 2, 2, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0,
- 0, 0, 0, 25, 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33,
- 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 2, 8, 2, 2, 2, 2, 2, 8, 2, 2, 8, 8, 8, 0, 8, 8,
- 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30,
- 30, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 2,
- 2, 2, 30, 30, 2, 2, 2, 2, 2, 2, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28,
- 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 2,
- 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0,
- 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0,
- 0, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2,
- 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 2,
- 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 2, 2, 31, 31, 2, 2, 2, 2,
- 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2,
- 2, 2, 32, 32, 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28,
- 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 2, 48, 48, 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48,
- 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
- 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, 2,
- 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54,
- 54, 54, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2,
- 2, 91, 91, 91, 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91,
- 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 62, 62, 2, 2, 2, 62, 62, 62, 62, 62, 62,
- 62, 2, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93,
- 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93,
- 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70,
- 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73,
- 73, 73, 6, 2, 2, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8,
- 8, 8, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
- 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
- 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19,
- 9, 9, 9, 9, 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9,
- 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19,
- 19, 19, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 9, 9, 9, 9, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9,
- 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 2, 2,
- 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0,
- 0, 2, 19, 19, 19, 19, 19, 2, 2, 2, 0, 2, 2, 2, 2, 2,
- 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
- 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2,
- 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2,
- 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 56, 56, 56, 56, 56, 56,
- 56, 56, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55,
- 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2, 2, 2, 2, 2,
- 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
- 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13,
- 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13,
- 0, 13, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1,
- 12, 12, 13, 13, 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,240, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70,241, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70,242, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70, 70, 70,243, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70,244, 96, 96, 96, 96, 96, 96, 96, 96,245, 96,
+ 246,247, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0,
+ 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 0, 19, 0,
+ 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0,
+ 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9,
+ 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2,
+ 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4, 4, 4, 2, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2,
+ 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14,
+ 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3,
+ 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3,
+ 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90,
+ 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2, 2, 2, 3, 3,
+ 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3,
+ 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1,
+ 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 5, 5,
+ 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2,
+ 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
+ 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5,
+ 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 2, 2, 2,
+ 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 5, 5, 5,
+ 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 11,
+ 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2,
+ 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2,
+ 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11,
+ 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11, 2, 2, 2, 11,
+ 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, 11, 2, 2, 2,
+ 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 10,
+ 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10,
+ 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2,
+ 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10,
+ 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 2, 2, 10, 2,
+ 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10,
+ 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 2, 21,
+ 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2,
+ 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2,
+ 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21,
+ 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 2, 2, 2, 2,
+ 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21,
+ 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22,
+ 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22,
+ 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 22, 22, 22, 2,
+ 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22,
+ 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23,
+ 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 2,
+ 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 23, 2, 2, 23, 23,
+ 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16,
+ 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2,
+ 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 2, 16,
+ 16, 16, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 2, 2,
+ 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, 36,
+ 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36,
+ 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2,
+ 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2,
+ 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2, 2, 2, 2, 18,
+ 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18,
+ 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18,
+ 18, 18, 18, 18, 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25,
+ 25, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 2, 2, 2, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25,
+ 25, 25, 25, 0, 0, 0, 0, 25, 25, 2, 2, 2, 2, 2, 33, 33,
+ 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 2, 8, 2, 2, 2, 2, 2, 8, 2, 2, 8, 8,
+ 8, 0, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30,
+ 30, 30, 30, 30, 30, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30,
+ 30, 30, 30, 2, 2, 2, 30, 30, 2, 2, 2, 2, 2, 2, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28,
+ 28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 0, 0, 0, 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 0, 0, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 2, 2, 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 2, 2, 31, 31,
+ 2, 2, 2, 2, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, 2,
+ 2, 2, 2, 2, 2, 2, 32, 32, 32, 2, 2, 2, 2, 2, 28, 28,
+ 28, 28, 28, 28, 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 2, 48, 48, 48, 48, 2, 2, 2, 2, 48, 2,
+ 2, 2, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 2, 2, 2, 2, 58, 58,
+ 2, 2, 2, 2, 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91,
+ 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91,
+ 91, 91, 91, 2, 2, 91, 91, 91, 2, 2, 2, 2, 2, 2, 91, 91,
+ 91, 91, 91, 91, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 62, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 2, 2, 2, 62, 62,
+ 62, 62, 62, 62, 62, 2, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2,
+ 2, 2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2,
+ 2, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 73, 73,
+ 73, 73, 73, 73, 73, 73, 6, 2, 2, 2, 2, 2, 2, 2, 8, 8,
+ 8, 2, 2, 8, 8, 8, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0,
+ 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 19, 19,
+ 19, 19, 19, 19, 9, 9, 9, 9, 9, 6, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9,
+ 9, 19, 19, 19, 19, 19, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 9, 9, 9, 9, 9, 9, 9, 2, 2, 2, 9,
+ 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9,
+ 9, 9, 2, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2,
+ 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0,
+ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 19,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0,
+ 0, 0, 0, 0, 0, 2, 19, 19, 19, 19, 19, 2, 2, 2, 0, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 0, 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 0, 0,
+ 0, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0,
+ 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 56, 56,
+ 56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55,
+ 55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2,
+ 2, 2, 2, 2, 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 0, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 13, 13,
+ 13, 13, 13, 13, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 1, 1, 1, 1, 12, 12, 13, 13, 13, 13, 0, 0, 0, 0, 2, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17,
- 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 2, 12, 12, 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17,
- 17, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 2,
- 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 86, 86, 86, 86, 86, 86,
- 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2, 2,
- 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 19, 19, 19, 19,
- 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2,
- 2, 2, 19, 19, 2, 19, 2, 19, 19, 19, 19, 19, 2, 2, 2, 2,
- 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60,
- 60, 60, 60, 60, 60, 60, 60, 2, 2, 2, 0, 0, 2, 2, 2, 2,
- 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75,
- 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 2, 2,
- 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 74, 74,
- 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84,
- 84, 84, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2,
- 84, 84, 33, 33, 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68, 68, 68, 68, 68,
- 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92,
- 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2, 2, 92, 92, 92,
- 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 2, 2, 30, 30, 30, 30, 30, 30, 2, 19, 19, 19, 0, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19, 0, 0, 2, 2,
- 2, 2, 87, 87, 87, 87, 87, 87, 2, 2, 87, 87, 2, 2, 2, 2,
- 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12,
- 12, 12, 13, 13, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19,
- 19, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14, 14, 14, 14, 2,
- 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, 3, 3, 2, 2, 2,
- 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 0, 0, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2,
- 2, 3, 1, 1, 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0,
- 0, 0, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2,
- 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12,
- 12, 12, 2, 2, 12, 12, 12, 2, 2, 2, 2, 0, 0, 0, 0, 0,
- 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 2, 49, 49,
- 2, 49, 49, 49, 49, 49, 49, 49, 2, 2, 49, 49, 49, 2, 2, 2,
- 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2,
- 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2,
- 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71,
- 71, 71, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67,
- 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 0, 0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41,
- 41, 41, 41, 41, 41, 2, 2, 2, 2, 2,118,118,118,118,118,118,
- 118,118,118,118,118, 2, 2, 2, 2, 2, 53, 53, 53, 53, 53, 53,
- 53, 53, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, 59, 59, 59, 59, 59, 59,
- 2, 2, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51,
- 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 2, 2, 50, 50, 2, 2, 2, 2, 2, 2,135,135,135,135,135,135,
- 135,135,135,135,135,135, 2, 2, 2, 2,106,106,106,106,106,106,
- 106,106,104,104,104,104,104,104,104,104,104,104,104,104, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2,104,161,161,161,161,161,161,
- 161,161,161,161,161, 2,161,161,161,161,161,161,161, 2,161,161,
- 2,161,161,161, 2,161,161,161,161,161,161,161, 2,161,161, 2,
- 2, 2,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
- 110, 2,110,110,110,110,110,110, 2, 2, 19, 19, 19, 19, 19, 19,
- 2, 19, 19, 2, 19, 19, 19, 19, 19, 19, 47, 47, 47, 47, 47, 47,
- 2, 2, 47, 2, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2,
- 2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
- 2, 81,120,120,120,120,120,120,120,120,116,116,116,116,116,116,
- 116,116,116,116,116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2,
- 2,116,128,128,128,128,128,128,128,128,128,128,128, 2,128,128,
- 2, 2, 2, 2, 2,128,128,128,128,128, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72,
- 72, 72, 72, 72, 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98,
- 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 2, 2, 2, 2, 97, 97,
- 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 57, 57, 57, 57, 2, 57,
- 57, 2, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 2, 57,
- 57, 57, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
- 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2,
- 2, 57, 57, 2, 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88,
- 88, 88,117,117,117,117,117,117,117,117,112,112,112,112,112,112,
- 112,112,112,112,112,112,112,112,112, 2, 2, 2, 2,112,112,112,
- 112,112, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
- 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83,
- 83, 83, 83, 83, 83, 83, 83, 83, 2, 2, 82, 82, 82, 82, 82, 82,
- 82, 82, 82, 82, 82, 2, 2, 2, 2, 2,122,122,122,122,122,122,
- 122,122,122,122, 2, 2, 2, 2, 2, 2, 2,122,122,122,122, 2,
- 2, 2, 2,122,122,122,122,122,122,122, 89, 89, 89, 89, 89, 89,
- 89, 89, 89, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,
- 130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,
- 130,130,144,144,144,144,144,144,144,144,144,144, 2, 2, 2, 2,
- 2, 2,156,156,156,156,156,156,156,156,156,156, 2,156,156,156,
- 2, 2,156,156, 2, 2, 2, 2, 2, 2,147,147,147,147,147,147,
- 147,147,148,148,148,148,148,148,148,148,148,148, 2, 2, 2, 2,
- 2, 2,158,158,158,158,158,158,158,158,158,158, 2, 2, 2, 2,
- 2, 2,153,153,153,153,153,153,153,153,153,153,153,153, 2, 2,
- 2, 2,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
- 149, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
- 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2,
- 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,
- 101,101,101, 2, 2, 2, 2, 2, 2, 2,101,101, 2, 2, 2, 2,
- 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2,
- 96, 96,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
- 111, 2,100,100,100,100,100,100,100,100, 2, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,108,108,108,108,108,108,
- 108,108,108,108, 2,108,108,108,108,108,108,108,108,108,108,108,
- 108, 2,129,129,129,129,129,129,129, 2,129, 2,129,129,129,129,
- 2,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
- 2,129,129,129, 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,
- 109,109,109,109,109, 2, 2, 2, 2, 2,109,109, 2, 2, 2, 2,
- 2, 2,107,107,107,107, 2,107,107,107,107,107,107,107,107, 2,
- 2,107,107, 2, 2,107,107,107,107,107,107,107,107,107,107,107,
- 107,107,107, 2,107,107,107,107,107,107,107, 2,107,107, 2,107,
- 107,107,107,107, 2, 1,107,107,107,107,107, 2, 2,107,107,107,
- 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2, 2, 2, 2,107,
- 107,107,107,107,107,107, 2, 2,107,107,107,107,107,107,107, 2,
- 2, 2,137,137,137,137,137,137,137,137,137,137,137,137, 2,137,
- 137,137,137,137, 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,
- 124,124,124,124, 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,
- 123,123,123,123,123,123,123,123, 2, 2,114,114,114,114,114,114,
- 114,114,114,114,114,114,114, 2, 2, 2,114,114, 2, 2, 2, 2,
- 2, 2, 32, 32, 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,
- 102,102,102,102, 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,
- 126,126,126,126,126, 2, 2,126,126,126,126,126,126,126, 2, 2,
- 2, 2,126,126,126,126,126,126,126, 2,142,142,142,142,142,142,
- 142,142,142,142,142,142, 2, 2, 2, 2,125,125,125,125,125,125,
- 125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2,125,154,154,154,154,154,154,154, 2, 2,154, 2, 2,154,154,
- 154,154,154,154,154,154, 2,154,154, 2,154,154,154,154,154,154,
- 154,154,154,154,154,154,154,154, 2,154,154, 2, 2,154,154,154,
- 154,154,154,154, 2, 2, 2, 2, 2, 2,150,150,150,150,150,150,
- 150,150, 2, 2,150,150,150,150,150,150,150,150,150,150,150, 2,
- 2, 2,141,141,141,141,141,141,141,141,140,140,140,140,140,140,
- 140,140,140,140,140, 2, 2, 2, 2, 2,121,121,121,121,121,121,
- 121,121,121, 2, 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,
- 133,133,133, 2,133,133,133,133,133,133,133,133,133,133,133,133,
- 133, 2,133,133,133,133,133,133, 2, 2,133,133,133,133,133, 2,
- 2, 2,134,134,134,134,134,134,134,134, 2, 2,134,134,134,134,
- 134,134, 2,134,134,134,134,134,134,134,134,134,134,134,134,134,
- 134, 2,138,138,138,138,138,138,138, 2,138,138, 2,138,138,138,
- 138,138,138,138,138,138,138,138,138,138, 2, 2,138, 2,138,138,
- 2,138,138,138, 2, 2, 2, 2, 2, 2,143,143,143,143,143,143,
- 2,143,143, 2,143,143,143,143,143,143,143,143,143,143,143,143,
- 143,143,143,143,143,143,143,143,143, 2,143,143, 2,143,143,143,
- 143,143,143, 2, 2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, 2,
- 2, 2,145,145,145,145,145,145,145,145,145, 2, 2, 2, 2, 2,
- 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63,
- 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 63, 63, 63, 63, 2, 2,
- 2, 2,157,157,157,157,157,157,157,157,157,157,157, 2, 2, 2,
- 2, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
- 80, 2, 80, 2, 2, 2, 2, 2, 2, 2,127,127,127,127,127,127,
- 127,127,127,127,127,127,127,127,127, 2, 79, 2, 2, 2, 2, 2,
- 2, 2,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
- 115, 2,115,115, 2, 2, 2, 2,115,115,159,159,159,159,159,159,
- 159,159,159,159,159,159,159,159,159, 2,159,159, 2, 2, 2, 2,
- 2, 2,103,103,103,103,103,103,103,103,103,103,103,103,103,103,
- 2, 2,119,119,119,119,119,119,119,119,119,119,119,119,119,119,
- 2, 2,119,119, 2,119,119,119,119,119, 2, 2, 2, 2, 2,119,
- 119,119,146,146,146,146,146,146,146,146,146,146,146, 2, 2, 2,
- 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2,
- 2, 99, 2, 2, 2, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2,
- 2, 2,136,136,136,136,136,136,136,136,155,155,155,155,155,155,
- 155,155,155,155,155,155,155,155, 2, 2,136, 2, 2, 2, 2, 2,
- 2, 2, 17, 17, 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17,
- 17, 2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2,
- 2, 2, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17,
- 17, 17,139,139,139,139,139,139,139,139,139,139,139,139, 2, 2,
- 2, 2,105,105,105,105,105,105,105,105,105,105,105, 2, 2, 2,
- 2, 2,105,105,105,105,105, 2, 2, 2,105, 2, 2, 2, 2, 2,
- 2, 2,105,105, 2, 2,105,105,105,105, 1, 1, 1, 1, 1, 1,
- 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1,
- 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
- 0, 0, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 2,
- 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0,
- 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0,
- 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2, 0, 0, 0, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,131,131,131,131,131,131,
- 131,131,131,131,131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,
- 131,131, 2,131,131,131,131,131,131,131, 56, 56, 56, 56, 56, 56,
- 56, 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2,
- 56, 56, 56, 56, 56, 2, 2, 2, 2, 2,151,151,151,151,151,151,
- 151,151,151,151,151,151,151, 2, 2, 2,151,151,151,151,151,151,
- 2, 2,151,151, 2, 2, 2, 2,151,151,160,160,160,160,160,160,
- 160,160,160,160,160,160,160,160,160, 2,152,152,152,152,152,152,
- 152,152,152,152, 2, 2, 2, 2, 2,152, 30, 30, 30, 30, 2, 30,
- 30, 2,113,113,113,113,113,113,113,113,113,113,113,113,113, 2,
- 2,113,113,113,113,113,113,113,113, 2,132,132,132,132,132,132,
- 132,132,132,132,132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,
- 132,132, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2,
- 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3,
- 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2,
- 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 3,
- 2, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3,
- 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 13, 2, 2, 2, 2, 2,
- 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2,
- 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10,
- 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9,
+ 15, 15, 15, 15, 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 0, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 12, 0, 17, 17,
+ 17, 17, 17, 17, 17, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 86, 86,
+ 86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0,
+ 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19,
+ 19, 2, 2, 2, 2, 2, 19, 19, 2, 19, 2, 19, 19, 19, 19, 19,
+ 2, 2, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 2, 2, 2, 0, 0,
+ 2, 2, 2, 2, 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2,
+ 2, 2, 2, 2, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 0, 69, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84,
+ 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 2, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68,
+ 68, 68, 68, 68, 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2,
+ 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+ 87, 87, 87, 87, 87, 2, 2, 30, 30, 30, 30, 30, 30, 2, 19, 19,
+ 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19,
+ 0, 0, 2, 2, 2, 2, 87, 87, 87, 87, 87, 87, 2, 2, 87, 87,
+ 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2,
+ 2, 12, 12, 12, 12, 12, 13, 13, 2, 2, 2, 2, 2, 2, 19, 19,
+ 19, 19, 19, 19, 19, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2,
+ 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14,
+ 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, 3,
+ 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 0, 0, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2,
+ 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 6, 6, 0, 0,
+ 0, 2, 0, 0, 0, 0, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3,
+ 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, 2,
+ 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 2, 2, 2, 2, 0,
+ 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49,
+ 49, 2, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 2, 2, 49, 49,
+ 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0,
+ 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 2,
+ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 71, 71,
+ 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67,
+ 67, 67, 67, 67, 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 1, 0,
+ 0, 0, 0, 0, 0, 0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 42, 42, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 2, 2, 2, 2, 2,118,118,
+ 118,118,118,118,118,118,118,118,118, 2, 2, 2, 2, 2, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, 59, 59,
+ 59, 59, 59, 59, 2, 2, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51,
+ 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 2, 2, 50, 50, 2, 2, 2, 2, 2, 2,135,135,
+ 135,135,135,135,135,135,135,135,135,135, 2, 2, 2, 2,106,106,
+ 106,106,106,106,106,106,104,104,104,104,104,104,104,104,104,104,
+ 104,104, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,104,161,161,
+ 161,161,161,161,161,161,161,161,161, 2,161,161,161,161,161,161,
+ 161, 2,161,161, 2,161,161,161, 2,161,161,161,161,161,161,161,
+ 2,161,161, 2, 2, 2,110,110,110,110,110,110,110,110,110,110,
+ 110,110,110,110,110, 2,110,110,110,110,110,110, 2, 2, 19, 19,
+ 19, 19, 19, 19, 2, 19, 19, 2, 19, 19, 19, 19, 19, 19, 47, 47,
+ 47, 47, 47, 47, 2, 2, 47, 2, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2,
+ 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 2, 81,120,120,120,120,120,120,120,120,116,116,
+ 116,116,116,116,116,116,116,116,116,116,116,116,116, 2, 2, 2,
+ 2, 2, 2, 2, 2,116,128,128,128,128,128,128,128,128,128,128,
+ 128, 2,128,128, 2, 2, 2, 2, 2,128,128,128,128,128, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 2, 2, 2, 2, 2, 72, 98, 98,
+ 98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 2, 2,
+ 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 57, 57,
+ 57, 57, 2, 57, 57, 2, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57,
+ 57, 57, 2, 57, 57, 57, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+ 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57,
+ 57, 2, 2, 2, 2, 57, 57, 2, 2, 2, 2, 2, 2, 2, 88, 88,
+ 88, 88, 88, 88, 88, 88,117,117,117,117,117,117,117,117,112,112,
+ 112,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2,
+ 2,112,112,112,112,112, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+ 78, 78, 78, 78, 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 83, 83,
+ 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 2, 2, 82, 82,
+ 82, 82, 82, 82, 82, 82, 82, 82, 82, 2, 2, 2, 2, 2,122,122,
+ 122,122,122,122,122,122,122,122, 2, 2, 2, 2, 2, 2, 2,122,
+ 122,122,122, 2, 2, 2, 2,122,122,122,122,122,122,122, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 2, 2, 2, 2, 2, 2, 2,130,130,
+ 130,130,130,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2,
+ 130,130,130,130,130,130,144,144,144,144,144,144,144,144,144,144,
+ 2, 2, 2, 2, 2, 2,156,156,156,156,156,156,156,156,156,156,
+ 2,156,156,156, 2, 2,156,156, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 3, 3, 3,147,147,147,147,147,147,147,147,148,148,
+ 148,148,148,148,148,148,148,148, 2, 2, 2, 2, 2, 2,158,158,
+ 158,158,158,158,158,158,158,158, 2, 2, 2, 2, 2, 2,153,153,
+ 153,153,153,153,153,153,153,153,153,153, 2, 2, 2, 2,149,149,
+ 149,149,149,149,149,149,149,149,149,149,149,149,149, 2, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2,
+ 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2, 2, 94, 85, 85,
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,101,101,101, 2,
+ 2, 2, 2, 2, 2, 2,101,101, 2, 2, 2, 2, 2, 2, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 96, 96,111,111,
+ 111,111,111,111,111,111,111,111,111,111,111,111,111, 2,100,100,
+ 100,100,100,100,100,100, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 2, 2, 2,108,108,108,108,108,108,108,108,108,108,
+ 2,108,108,108,108,108,108,108, 2, 2, 2, 2, 2, 2,129,129,
+ 129,129,129,129,129, 2,129, 2,129,129,129,129, 2,129,129,129,
+ 129,129,129,129,129,129,129,129,129,129,129,129, 2,129,129,129,
+ 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109,
+ 109, 2, 2, 2, 2, 2,109,109, 2, 2, 2, 2, 2, 2,107,107,
+ 107,107, 2,107,107,107,107,107,107,107,107, 2, 2,107,107, 2,
+ 2,107,107,107,107,107,107,107,107,107,107,107,107,107,107, 2,
+ 107,107,107,107,107,107,107, 2,107,107, 2,107,107,107,107,107,
+ 2, 1,107,107,107,107,107, 2, 2,107,107,107, 2, 2,107, 2,
+ 2, 2, 2, 2, 2,107, 2, 2, 2, 2, 2,107,107,107,107,107,
+ 107,107, 2, 2,107,107,107,107,107,107,107, 2, 2, 2,137,137,
+ 137,137,137,137,137,137,137,137,137,137, 2,137,137,137,137,137,
+ 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124,
+ 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,123,123,123,123,
+ 123,123,123,123, 2, 2,114,114,114,114,114,114,114,114,114,114,
+ 114,114,114, 2, 2, 2,114,114, 2, 2, 2, 2, 2, 2, 32, 32,
+ 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,102,102,102,102,
+ 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,126,126,126,126,
+ 126, 2, 2,126,126,126,126,126,126,126, 2, 2, 2, 2,126,126,
+ 126,126,126,126,126, 2,142,142,142,142,142,142,142,142,142,142,
+ 142,142, 2, 2, 2, 2,125,125,125,125,125,125,125,125,125,125,
+ 125, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,125,154,154,
+ 154,154,154,154,154, 2, 2,154, 2, 2,154,154,154,154,154,154,
+ 154,154, 2,154,154, 2,154,154,154,154,154,154,154,154,154,154,
+ 154,154,154,154, 2,154,154, 2, 2,154,154,154,154,154,154,154,
+ 2, 2, 2, 2, 2, 2,150,150,150,150,150,150,150,150, 2, 2,
+ 150,150,150,150,150,150,150,150,150,150,150, 2, 2, 2,141,141,
+ 141,141,141,141,141,141,140,140,140,140,140,140,140,140,140,140,
+ 140, 2, 2, 2, 2, 2,121,121,121,121,121,121,121,121,121, 2,
+ 2, 2, 2, 2, 2, 2, 7, 7, 2, 2, 2, 2, 2, 2,133,133,
+ 133,133,133,133,133,133,133, 2,133,133,133,133,133,133,133,133,
+ 133,133,133,133,133, 2,133,133,133,133,133,133, 2, 2,133,133,
+ 133,133,133, 2, 2, 2,134,134,134,134,134,134,134,134, 2, 2,
+ 134,134,134,134,134,134, 2,134,134,134,134,134,134,134,134,134,
+ 134,134,134,134,134, 2,138,138,138,138,138,138,138, 2,138,138,
+ 2,138,138,138,138,138,138,138,138,138,138,138,138,138, 2, 2,
+ 138, 2,138,138, 2,138,138,138, 2, 2, 2, 2, 2, 2,143,143,
+ 143,143,143,143, 2,143,143, 2,143,143,143,143,143,143,143,143,
+ 143,143,143,143,143,143,143,143,143,143,143,143,143, 2,143,143,
+ 2,143,143,143,143,143,143, 2, 2, 2, 2, 2, 2, 2,143,143,
+ 2, 2, 2, 2, 2, 2,145,145,145,145,145,145,145,145,145, 2,
+ 2, 2, 2, 2, 2, 2,163,163,163,163,163,163,163,163,163, 2,
+ 163,163,163,163,163,163,163,163,163, 2, 2, 2,163,163,163,163,
+ 2, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 22, 22,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63,
+ 63, 63, 63, 63, 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 63, 63,
+ 63, 63, 2, 2, 2, 2,157,157,157,157,157,157,157,157,157,157,
+ 157, 2, 2, 2, 2, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 2, 2,127,127,127,127,127,127,127,127,127,127,
+ 127,127,127,127,127, 2, 79, 2, 2, 2, 2, 2, 2, 2,115,115,
+ 115,115,115,115,115,115,115,115,115,115,115,115,115, 2,115,115,
+ 2, 2, 2, 2,115,115,159,159,159,159,159,159,159,159,159,159,
+ 159,159,159,159,159, 2,159,159, 2, 2, 2, 2, 2, 2,103,103,
+ 103,103,103,103,103,103,103,103,103,103,103,103, 2, 2,119,119,
+ 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2,119,119,
+ 2,119,119,119,119,119, 2, 2, 2, 2, 2,119,119,119,146,146,
+ 146,146,146,146,146,146,146,146,146, 2, 2, 2, 2, 2, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 99, 2, 2,
+ 2, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, 2, 2,136,136,
+ 136,136,136,136,136,136,155,155,155,155,155,155,155,155,155,155,
+ 155,155,155,155, 2, 2,136, 2, 2, 2, 2, 2, 2, 2, 17, 17,
+ 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17, 17, 2, 17, 15,
+ 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, 2, 2, 2, 2,
+ 15, 2, 2, 2, 2, 2, 15, 15, 15, 2, 2, 17, 2, 2, 2, 2,
+ 2, 2, 17, 17, 17, 17,139,139,139,139,139,139,139,139,139,139,
+ 139,139, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105,
+ 105, 2, 2, 2, 2, 2,105,105,105,105,105, 2, 2, 2,105, 2,
+ 2, 2, 2, 2, 2, 2,105,105, 2, 2,105,105,105,105, 1, 1,
+ 1, 1, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0,
+ 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0,
+ 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2,
+ 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,131,131,
+ 131,131,131,131,131,131,131,131,131,131, 2, 2, 2, 2, 2, 2,
+ 2,131,131,131,131,131, 2,131,131,131,131,131,131,131, 2, 2,
+ 2, 2, 2, 19, 19, 19, 56, 56, 56, 56, 56, 56, 56, 2, 56, 2,
+ 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, 56, 56, 56, 56,
+ 56, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 6,151,151,151,151,151,151,151,151,151,151,
+ 151,151,151, 2, 2, 2,151,151,151,151,151,151, 2, 2,151,151,
+ 2, 2, 2, 2,151,151,160,160,160,160,160,160,160,160,160,160,
+ 160,160,160,160,160, 2,152,152,152,152,152,152,152,152,152,152,
+ 2, 2, 2, 2, 2,152,164,164,164,164,164,164,164,164,164,164,
+ 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 2, 30, 30, 2,113,113,
+ 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113,
+ 113,113,113,113,113, 2,132,132,132,132,132,132,132,132,132,132,
+ 132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,132,132, 3, 3,
+ 3, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3,
+ 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3,
+ 2, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
+ 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2,
+ 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 13, 2,
+ 2, 2, 2, 2, 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, 0,
+ 2, 2, 2, 2, 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 9, 9, 9, 10, 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 16, 17, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19,
+ 20, 9, 21, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
@@ -2140,60 +2161,61 @@ _hb_ucd_u8[17936] =
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 23, 24,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0,
- 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0,
- 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0,
- 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0,
- 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28,
+ 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0,
+ 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0,
- 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0,
+ 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0,
+ 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0,
+ 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65,
+ 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
- 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,
- 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0,
- 108, 0,109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, 0,
- 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0,
+ 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
+ 99,100,101,102,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,
+ 107, 0, 0, 0,108, 0,109, 0,110, 0,111,112,113, 0,114, 0,
+ 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,118,119,120,121, 0,122,123,124,125,126, 0,127,
+ 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121, 0,122,123,124,
+ 125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,128,129,130,131,132,133,134,135,136,137,138,139,
+ 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,
+ 156,157, 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162,163, 0,
+ 0, 0, 0, 0, 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
- 144,145,146,147,148,149,150,151,152,153,154,155,156,157, 0, 0,
- 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0,
- 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,169,170, 0, 0, 0, 0,171,
+ 172, 0, 0, 0,173,174,175,176,177,178,179,180,181,182,183,184,
+ 185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,
+ 201,202,203,204,205,206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,169,170, 0, 0, 0, 0,171,172, 0, 0, 0,
- 173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,
- 189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,
- 205,206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
+ 1, 2, 3, 4,
};
static const uint16_t
-_hb_ucd_u16[9200] =
+_hb_ucd_u16[9320] =
{
0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12,
13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23,
@@ -2267,509 +2289,517 @@ _hb_ucd_u16[9200] =
48, 48, 48, 468, 48, 469, 48, 470, 48, 471, 472, 140, 140, 140, 140, 140,
48, 48, 48, 48, 196, 140, 140, 140, 9, 9, 9, 473, 11, 11, 11, 474,
48, 48, 475, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 271, 476,
- 48, 48, 477, 478, 140, 140, 140, 140, 48, 464, 479, 48, 62, 480, 140, 48,
- 481, 140, 140, 48, 482, 140, 48, 314, 483, 48, 48, 484, 485, 457, 486, 487,
- 222, 48, 48, 488, 489, 48, 196, 192, 490, 48, 491, 492, 493, 48, 48, 494,
- 222, 48, 48, 495, 496, 497, 498, 499, 48, 97, 500, 501, 140, 140, 140, 140,
- 502, 503, 504, 48, 48, 505, 506, 192, 507, 83, 84, 508, 509, 510, 511, 512,
- 48, 48, 48, 513, 514, 515, 478, 140, 48, 48, 48, 516, 517, 192, 140, 140,
- 48, 48, 518, 519, 520, 521, 140, 140, 48, 48, 48, 522, 523, 192, 524, 140,
- 48, 48, 525, 526, 192, 140, 140, 140, 48, 173, 527, 528, 314, 140, 140, 140,
- 48, 48, 500, 529, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 530,
- 531, 532, 48, 533, 534, 192, 140, 140, 140, 140, 535, 48, 48, 536, 537, 140,
- 538, 48, 48, 539, 540, 541, 48, 48, 542, 543, 544, 48, 48, 48, 48, 196,
- 84, 48, 518, 545, 546, 148, 175, 547, 48, 548, 549, 550, 140, 140, 140, 140,
- 551, 48, 48, 552, 553, 192, 554, 48, 555, 556, 192, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 48, 557, 140, 140, 140, 100, 271, 558, 559, 560,
- 48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 561, 562,
- 48, 48, 48, 48, 388, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 563,
- 48, 48, 200, 564, 140, 140, 140, 140, 48, 48, 48, 48, 314, 140, 140, 140,
- 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 565,
- 48, 48, 48, 566, 567, 568, 569, 570, 48, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 9, 9, 11, 11, 271, 571, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 572, 573, 574, 574, 575, 576, 140, 140, 140, 140, 577, 578,
+ 48, 48, 477, 478, 140, 140, 140, 479, 48, 464, 480, 48, 62, 481, 140, 48,
+ 482, 140, 140, 48, 483, 140, 48, 314, 484, 48, 48, 485, 486, 457, 487, 488,
+ 222, 48, 48, 489, 490, 48, 196, 192, 491, 48, 492, 493, 494, 48, 48, 495,
+ 222, 48, 48, 496, 497, 498, 499, 500, 48, 97, 501, 502, 503, 140, 140, 140,
+ 504, 505, 506, 48, 48, 507, 508, 192, 509, 83, 84, 510, 511, 512, 513, 514,
+ 48, 48, 48, 515, 516, 517, 478, 140, 48, 48, 48, 518, 519, 192, 140, 140,
+ 48, 48, 520, 521, 522, 523, 140, 140, 48, 48, 48, 524, 525, 192, 526, 140,
+ 48, 48, 527, 528, 192, 140, 140, 140, 48, 173, 529, 530, 314, 140, 140, 140,
+ 48, 48, 501, 531, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 532,
+ 533, 534, 48, 535, 536, 192, 140, 140, 140, 140, 537, 48, 48, 538, 539, 140,
+ 540, 48, 48, 541, 542, 543, 48, 48, 544, 545, 546, 48, 48, 48, 48, 196,
+ 547, 140, 140, 140, 140, 140, 140, 140, 84, 48, 520, 548, 549, 148, 175, 550,
+ 48, 551, 552, 553, 140, 140, 140, 140, 554, 48, 48, 555, 556, 192, 557, 48,
+ 558, 559, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 560,
+ 561, 115, 48, 562, 563, 192, 140, 140, 140, 140, 140, 100, 271, 564, 565, 566,
+ 48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 567, 568,
+ 48, 48, 48, 48, 388, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 569,
+ 48, 48, 48, 570, 571, 572, 140, 140, 48, 48, 48, 48, 314, 140, 140, 140,
+ 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 573,
+ 48, 48, 48, 574, 575, 576, 577, 578, 48, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 9, 9, 11, 11, 271, 579, 140, 140, 140, 140, 140, 140,
+ 48, 48, 48, 48, 580, 581, 582, 582, 583, 584, 140, 140, 140, 140, 585, 586,
48, 48, 48, 48, 48, 48, 48, 440, 48, 48, 48, 48, 48, 199, 140, 140,
- 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 579,
- 48, 48, 580, 140, 140, 580, 581, 48, 48, 48, 48, 48, 48, 48, 48, 206,
- 48, 48, 48, 48, 48, 48, 71, 151, 196, 582, 583, 140, 140, 140, 140, 140,
- 32, 32, 584, 32, 585, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
- 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 586, 209, 209, 209, 587, 588,
- 589, 209, 590, 209, 209, 209, 288, 140, 209, 209, 209, 209, 591, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 271, 592, 209, 209, 209, 209, 209, 287, 271, 461,
- 9, 593, 11, 594, 595, 596, 241, 9, 597, 598, 599, 600, 601, 9, 593, 11,
- 602, 603, 11, 604, 605, 606, 607, 9, 608, 11, 9, 593, 11, 594, 595, 11,
- 241, 9, 597, 607, 9, 608, 11, 9, 593, 11, 609, 9, 610, 611, 612, 613,
- 11, 614, 9, 615, 616, 617, 618, 11, 619, 9, 620, 11, 621, 622, 622, 622,
- 32, 32, 32, 623, 32, 32, 624, 625, 626, 627, 45, 140, 140, 140, 140, 140,
- 628, 629, 140, 140, 140, 140, 140, 140, 630, 631, 632, 140, 140, 140, 140, 140,
- 48, 48, 151, 633, 634, 140, 140, 140, 140, 48, 635, 140, 48, 48, 636, 637,
- 140, 140, 140, 140, 140, 140, 638, 200, 48, 48, 48, 48, 639, 585, 140, 140,
- 9, 9, 597, 11, 640, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 498,
- 271, 271, 641, 642, 140, 140, 140, 140, 498, 271, 643, 644, 140, 140, 140, 140,
- 645, 48, 646, 647, 648, 649, 650, 651, 652, 206, 653, 206, 140, 140, 140, 654,
- 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 655, 655, 655, 209, 324,
- 656, 209, 209, 209, 209, 209, 209, 209, 209, 209, 657, 140, 140, 140, 658, 209,
- 659, 209, 209, 325, 660, 661, 324, 140, 209, 209, 209, 209, 209, 209, 209, 662,
- 209, 209, 209, 209, 209, 663, 426, 426, 209, 209, 209, 209, 209, 209, 209, 323,
- 209, 209, 209, 209, 209, 660, 325, 427, 325, 209, 209, 209, 664, 176, 209, 209,
- 664, 209, 657, 661, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 657, 665,
- 287, 209, 426, 288, 324, 176, 664, 287, 209, 666, 209, 209, 288, 140, 140, 192,
- 48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 196, 48, 48, 48, 48,
+ 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 587,
+ 48, 48, 588, 589, 140, 590, 591, 48, 48, 48, 48, 48, 48, 48, 48, 206,
+ 48, 48, 48, 48, 48, 48, 71, 151, 196, 592, 593, 140, 140, 140, 140, 140,
+ 32, 32, 594, 32, 595, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
+ 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 596, 209, 209, 209, 597, 598,
+ 599, 209, 600, 209, 209, 209, 288, 140, 209, 209, 209, 209, 601, 140, 140, 140,
+ 140, 140, 140, 140, 271, 602, 271, 602, 209, 209, 209, 209, 209, 287, 271, 461,
+ 9, 603, 11, 604, 605, 606, 241, 9, 607, 608, 609, 610, 611, 9, 603, 11,
+ 612, 613, 11, 614, 615, 616, 617, 9, 618, 11, 9, 603, 11, 604, 605, 11,
+ 241, 9, 607, 617, 9, 618, 11, 9, 603, 11, 619, 9, 620, 621, 622, 623,
+ 11, 624, 9, 625, 626, 627, 628, 11, 629, 9, 630, 11, 631, 632, 632, 632,
+ 32, 32, 32, 633, 32, 32, 634, 635, 636, 637, 45, 140, 140, 140, 140, 140,
+ 638, 639, 640, 140, 140, 140, 140, 140, 641, 642, 643, 27, 27, 27, 644, 140,
+ 645, 140, 140, 140, 140, 140, 140, 140, 48, 48, 151, 646, 647, 140, 140, 140,
+ 140, 48, 648, 140, 48, 48, 649, 650, 140, 140, 140, 140, 140, 48, 651, 192,
+ 140, 140, 140, 140, 140, 140, 652, 200, 48, 48, 48, 48, 653, 595, 140, 140,
+ 9, 9, 607, 11, 654, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 499,
+ 271, 271, 655, 656, 140, 140, 140, 140, 499, 271, 657, 658, 140, 140, 140, 140,
+ 659, 48, 660, 661, 662, 663, 664, 665, 666, 206, 667, 206, 140, 140, 140, 668,
+ 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 669, 669, 669, 209, 324,
+ 670, 209, 209, 209, 209, 209, 209, 209, 209, 209, 671, 140, 140, 140, 672, 209,
+ 673, 209, 209, 325, 674, 675, 324, 140, 209, 209, 209, 209, 209, 209, 209, 676,
+ 209, 209, 209, 209, 209, 677, 426, 426, 209, 209, 209, 209, 209, 209, 209, 678,
+ 209, 209, 209, 209, 209, 176, 325, 427, 325, 209, 209, 209, 679, 176, 209, 209,
+ 679, 209, 671, 675, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 671, 426,
+ 674, 209, 209, 680, 681, 325, 674, 674, 209, 682, 209, 209, 288, 140, 140, 192,
+ 48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 207, 48, 48, 48, 48,
48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 478, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 100, 140, 48, 204, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 71, 140, 140, 140, 667, 140, 668, 668, 668, 668, 668, 668,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140,
- 391, 391, 391, 391, 391, 391, 391, 669, 391, 391, 391, 391, 391, 391, 391, 670,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3,
- 0, 0, 0, 0, 0, 4, 0, 4, 2, 2, 5, 2, 2, 2, 5, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 6, 0, 0, 0, 0, 7, 8, 0, 0,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 11,
- 12, 13, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, 16, 17, 14, 14,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 20, 21, 21, 21, 22, 20, 21, 21, 21, 21,
- 21, 23, 24, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 27, 28, 26,
- 29, 30, 31, 32, 31, 31, 31, 31, 33, 34, 35, 31, 31, 31, 36, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 29, 31, 31, 31, 31,
- 37, 38, 37, 37, 37, 37, 37, 37, 37, 39, 31, 31, 31, 31, 31, 31,
- 40, 40, 40, 40, 40, 40, 41, 26, 42, 42, 42, 42, 42, 42, 42, 43,
- 44, 44, 44, 44, 44, 45, 44, 46, 47, 47, 47, 48, 37, 49, 31, 31,
- 31, 50, 51, 31, 31, 31, 31, 31, 31, 31, 31, 31, 52, 31, 31, 31,
- 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 53, 55, 53, 53, 53,
- 56, 57, 58, 59, 59, 60, 61, 62, 57, 63, 64, 65, 66, 59, 59, 67,
- 68, 69, 70, 71, 71, 72, 73, 74, 69, 75, 76, 77, 78, 71, 79, 26,
- 80, 81, 82, 83, 83, 84, 85, 86, 81, 87, 88, 26, 89, 83, 90, 91,
- 92, 93, 94, 95, 95, 96, 97, 98, 93, 99, 100, 101, 102, 95, 95, 26,
- 103, 104, 105, 106, 107, 104, 108, 109, 104, 105, 110, 26, 111, 108, 108, 112,
- 113, 114, 115, 113, 113, 115, 113, 116, 114, 117, 118, 119, 120, 113, 121, 113,
- 122, 123, 124, 122, 122, 124, 125, 126, 123, 127, 128, 128, 129, 122, 130, 26,
- 131, 132, 133, 131, 131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131,
- 136, 137, 138, 139, 137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145, 26,
- 146, 147, 147, 147, 147, 147, 147, 148, 147, 147, 147, 149, 26, 26, 26, 26,
- 150, 151, 152, 152, 153, 152, 152, 154, 155, 154, 152, 156, 26, 26, 26, 26,
- 157, 157, 157, 157, 157, 157, 157, 157, 157, 158, 157, 157, 157, 159, 158, 157,
- 157, 157, 157, 158, 157, 157, 157, 160, 157, 160, 161, 162, 26, 26, 26, 26,
- 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163,
- 163, 163, 163, 163, 164, 164, 164, 164, 165, 166, 164, 164, 164, 164, 164, 167,
- 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
- 169, 169, 169, 169, 169, 169, 169, 169, 169, 170, 171, 170, 169, 169, 169, 169,
- 169, 170, 169, 169, 169, 169, 170, 171, 170, 169, 171, 169, 169, 169, 169, 169,
- 169, 169, 170, 169, 169, 169, 169, 169, 169, 169, 169, 172, 169, 169, 169, 173,
- 169, 169, 169, 174, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 176,
- 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
- 178, 178, 178, 179, 180, 180, 180, 180, 180, 180, 180, 180, 180, 181, 180, 182,
- 183, 183, 184, 185, 186, 186, 187, 26, 188, 188, 189, 26, 190, 191, 192, 26,
- 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 194, 193, 195, 193, 195,
- 196, 197, 197, 198, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 199,
- 197, 197, 197, 197, 197, 200, 177, 177, 177, 177, 177, 177, 177, 177, 201, 26,
- 202, 202, 202, 203, 202, 204, 202, 204, 205, 202, 206, 206, 206, 207, 208, 26,
- 209, 209, 209, 209, 209, 210, 209, 209, 209, 211, 209, 212, 193, 193, 193, 193,
- 213, 213, 213, 214, 215, 215, 215, 215, 215, 215, 215, 216, 215, 215, 215, 217,
- 215, 218, 215, 218, 215, 219, 9, 9, 9, 220, 26, 26, 26, 26, 26, 26,
- 221, 221, 221, 221, 221, 221, 221, 221, 221, 222, 221, 221, 221, 221, 221, 223,
- 224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 226, 227,
- 228, 228, 228, 228, 228, 228, 228, 229, 228, 230, 231, 231, 231, 231, 231, 231,
- 18, 232, 164, 164, 164, 164, 164, 233, 224, 26, 234, 9, 235, 236, 237, 238,
- 2, 2, 2, 2, 239, 240, 2, 2, 2, 2, 2, 241, 242, 243, 2, 244,
- 2, 2, 2, 2, 2, 2, 2, 245, 9, 9, 9, 9, 9, 9, 9, 9,
- 14, 14, 246, 246, 14, 14, 14, 14, 246, 246, 14, 247, 14, 14, 14, 246,
- 14, 14, 14, 14, 14, 14, 248, 14, 248, 14, 249, 250, 14, 14, 251, 252,
- 0, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 255, 256,
- 0, 257, 2, 258, 0, 0, 0, 0, 259, 26, 9, 9, 9, 9, 260, 26,
- 0, 0, 0, 0, 261, 262, 4, 0, 0, 263, 0, 0, 2, 2, 2, 2,
- 2, 264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 140, 140, 140, 140, 140,
+ 683, 140, 570, 570, 570, 570, 570, 570, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 140, 391, 391, 391, 391, 391, 391, 391, 684,
+ 391, 391, 391, 391, 391, 391, 391, 685, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 2, 2, 3, 1, 2, 2, 3, 0, 0, 0, 0, 0, 4, 0, 4,
+ 2, 2, 5, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,
+ 0, 0, 0, 0, 7, 8, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 10, 11, 12, 13, 14, 14, 15, 14, 14, 14,
+ 14, 14, 14, 14, 16, 17, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 19, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 20, 21,
+ 21, 21, 22, 20, 21, 21, 21, 21, 21, 23, 24, 25, 25, 25, 25, 25,
+ 25, 26, 25, 25, 25, 27, 28, 26, 29, 30, 31, 32, 31, 31, 31, 31,
+ 33, 34, 35, 31, 31, 31, 36, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 29, 31, 31, 31, 31, 37, 38, 37, 37, 37, 37, 37, 37,
+ 37, 39, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 41, 26,
+ 42, 42, 42, 42, 42, 42, 42, 43, 44, 44, 44, 44, 44, 45, 44, 46,
+ 47, 47, 47, 48, 37, 49, 31, 31, 31, 50, 51, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 52, 31, 31, 31, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 54, 53, 55, 53, 53, 53, 56, 57, 58, 59, 59, 60, 61, 62,
+ 57, 63, 64, 65, 66, 59, 59, 67, 68, 69, 70, 71, 71, 72, 73, 74,
+ 69, 75, 76, 77, 78, 71, 79, 26, 80, 81, 82, 83, 83, 84, 85, 86,
+ 81, 87, 88, 26, 89, 83, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98,
+ 93, 99, 100, 101, 102, 95, 95, 26, 103, 104, 105, 106, 107, 104, 108, 109,
+ 104, 105, 110, 26, 111, 108, 108, 112, 113, 114, 115, 113, 113, 115, 113, 116,
+ 114, 117, 118, 119, 120, 113, 121, 113, 122, 123, 124, 122, 122, 124, 125, 126,
+ 123, 127, 128, 128, 129, 122, 130, 26, 131, 132, 133, 131, 131, 131, 131, 131,
+ 132, 133, 134, 131, 135, 131, 131, 131, 136, 137, 138, 139, 137, 137, 140, 141,
+ 138, 142, 143, 137, 144, 137, 145, 26, 146, 147, 147, 147, 147, 147, 147, 148,
+ 147, 147, 147, 149, 26, 26, 26, 26, 150, 151, 152, 152, 153, 152, 152, 154,
+ 155, 156, 152, 157, 26, 26, 26, 26, 158, 158, 158, 158, 158, 158, 158, 158,
+ 158, 159, 158, 158, 158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161,
+ 158, 161, 162, 163, 26, 26, 26, 26, 164, 164, 164, 164, 164, 164, 164, 164,
+ 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165,
+ 166, 167, 165, 165, 165, 165, 165, 168, 169, 169, 169, 169, 169, 169, 169, 169,
+ 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170,
+ 170, 171, 172, 171, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 171, 172,
+ 171, 170, 172, 170, 170, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 170,
+ 170, 170, 170, 173, 170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176,
+ 176, 176, 176, 176, 176, 176, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178,
+ 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181,
+ 181, 181, 181, 181, 181, 182, 181, 183, 184, 184, 185, 186, 187, 187, 188, 26,
+ 189, 189, 190, 26, 191, 192, 193, 26, 194, 194, 194, 194, 194, 194, 194, 194,
+ 194, 194, 194, 195, 194, 196, 194, 196, 197, 198, 198, 199, 198, 198, 198, 198,
+ 198, 198, 198, 198, 198, 198, 198, 200, 198, 198, 198, 198, 198, 201, 178, 178,
+ 178, 178, 178, 178, 178, 178, 202, 26, 203, 203, 203, 204, 203, 205, 203, 205,
+ 206, 203, 207, 207, 207, 208, 209, 26, 210, 210, 210, 210, 210, 211, 210, 210,
+ 210, 212, 210, 213, 194, 194, 194, 194, 214, 214, 214, 215, 216, 216, 216, 216,
+ 216, 216, 216, 217, 216, 216, 216, 218, 216, 219, 216, 219, 216, 220, 9, 9,
+ 9, 221, 26, 26, 26, 26, 26, 26, 222, 222, 222, 222, 222, 222, 222, 222,
+ 222, 223, 222, 222, 222, 222, 222, 224, 225, 225, 225, 225, 225, 225, 225, 225,
+ 226, 226, 226, 226, 226, 226, 227, 228, 229, 229, 229, 229, 229, 229, 229, 230,
+ 229, 231, 232, 232, 232, 232, 232, 232, 18, 233, 165, 165, 165, 165, 165, 234,
+ 225, 26, 235, 9, 236, 237, 238, 239, 2, 2, 2, 2, 240, 241, 2, 2,
+ 2, 2, 2, 242, 243, 244, 2, 245, 2, 2, 2, 2, 2, 2, 2, 246,
+ 9, 9, 9, 9, 9, 9, 9, 9, 14, 14, 247, 247, 14, 14, 14, 14,
+ 247, 247, 14, 248, 14, 14, 14, 247, 14, 14, 14, 14, 14, 14, 249, 14,
+ 249, 14, 250, 251, 14, 14, 252, 253, 0, 254, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 255, 0, 256, 257, 0, 258, 2, 259, 0, 0, 0, 0,
+ 260, 26, 9, 9, 9, 9, 261, 26, 0, 0, 0, 0, 262, 263, 4, 0,
+ 0, 264, 0, 0, 2, 2, 2, 2, 2, 265, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 257, 26, 26, 26, 0, 265, 26, 26, 0, 0, 0, 0,
- 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0,
- 0, 0, 268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 2, 2, 2, 2,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 270, 271,
- 164, 164, 164, 164, 165, 166, 272, 272, 272, 272, 272, 272, 272, 273, 274, 273,
- 169, 169, 171, 26, 171, 171, 171, 171, 171, 171, 171, 171, 18, 18, 18, 18,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26,
- 276, 276, 276, 277, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 278, 26,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 26, 26, 26, 0, 280,
- 281, 0, 0, 0, 282, 283, 0, 284, 285, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 287, 288, 289, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291,
- 292, 293, 293, 293, 293, 293, 294, 168, 168, 168, 168, 168, 168, 168, 168, 168,
- 168, 295, 0, 0, 293, 293, 293, 293, 0, 0, 0, 0, 280, 26, 290, 290,
- 168, 168, 168, 295, 0, 0, 0, 0, 0, 0, 0, 0, 168, 168, 168, 296,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 290, 290, 290, 290, 290, 297,
- 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 0, 0, 0, 0, 0,
- 276, 276, 276, 276, 276, 276, 276, 276, 0, 0, 0, 0, 0, 0, 0, 0,
- 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298,
- 298, 299, 298, 298, 298, 298, 298, 298, 300, 26, 301, 301, 301, 301, 301, 301,
- 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302,
- 302, 302, 302, 302, 302, 303, 26, 26, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 26,
- 0, 0, 0, 0, 305, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 306, 2, 2, 2, 2, 2, 2, 2, 307, 308, 309, 26, 26, 310, 2,
- 311, 311, 311, 311, 311, 312, 0, 313, 314, 314, 314, 314, 314, 314, 314, 26,
- 315, 315, 315, 315, 315, 315, 315, 315, 316, 317, 315, 318, 53, 53, 53, 53,
- 319, 319, 319, 319, 319, 320, 321, 321, 321, 321, 322, 323, 168, 168, 168, 324,
- 325, 325, 325, 325, 325, 325, 325, 325, 325, 326, 325, 327, 163, 163, 163, 328,
- 329, 329, 329, 329, 329, 329, 330, 26, 329, 331, 329, 332, 163, 163, 163, 163,
- 333, 333, 333, 333, 333, 333, 333, 333, 334, 26, 26, 335, 336, 336, 337, 26,
- 338, 338, 338, 26, 171, 171, 2, 2, 2, 2, 2, 339, 340, 341, 175, 175,
- 175, 175, 175, 175, 175, 175, 175, 175, 336, 336, 336, 336, 336, 342, 336, 343,
- 168, 168, 168, 168, 344, 26, 168, 168, 295, 345, 168, 168, 168, 168, 168, 344,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 26, 26, 26,
+ 0, 266, 26, 26, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267,
+ 267, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 269, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270,
+ 270, 270, 270, 270, 2, 2, 2, 2, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 271, 272, 165, 165, 165, 165, 166, 167, 273, 273,
+ 273, 273, 273, 273, 273, 274, 275, 274, 170, 170, 172, 26, 172, 172, 172, 172,
+ 172, 172, 172, 172, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 276, 26, 26, 26, 26, 277, 277, 277, 278, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 277, 279, 26, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 280, 26, 26, 26, 0, 281, 282, 0, 0, 0, 283, 284, 0, 285,
+ 286, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288, 289, 290, 291, 291, 291,
+ 291, 291, 291, 291, 291, 291, 291, 292, 293, 294, 294, 294, 294, 294, 295, 169,
+ 169, 169, 169, 169, 169, 169, 169, 169, 169, 296, 0, 0, 294, 294, 294, 294,
+ 0, 0, 0, 0, 281, 26, 291, 291, 169, 169, 169, 296, 0, 0, 0, 0,
+ 0, 0, 0, 0, 169, 169, 169, 297, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 291, 291, 291, 291, 291, 298, 291, 291, 291, 291, 291, 291, 291, 291,
+ 291, 291, 291, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277,
+ 0, 0, 0, 0, 0, 0, 0, 0, 299, 299, 299, 299, 299, 299, 299, 299,
+ 299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 299, 299, 299, 299, 299, 299,
+ 301, 26, 302, 302, 302, 302, 302, 302, 303, 303, 303, 303, 303, 303, 303, 303,
+ 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 304, 26, 26,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 305, 305, 305, 305,
+ 305, 305, 305, 305, 305, 305, 305, 26, 0, 0, 0, 0, 306, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 307, 2, 2, 2, 2, 2, 2,
+ 2, 308, 309, 310, 26, 26, 311, 2, 312, 312, 312, 312, 312, 313, 0, 314,
+ 315, 315, 315, 315, 315, 315, 315, 26, 316, 316, 316, 316, 316, 316, 316, 316,
+ 317, 318, 316, 319, 53, 53, 53, 53, 320, 320, 320, 320, 320, 321, 322, 322,
+ 322, 322, 323, 324, 169, 169, 169, 325, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 327, 326, 328, 164, 164, 164, 329, 330, 330, 330, 330, 330, 330, 331, 26,
+ 330, 332, 330, 333, 164, 164, 164, 164, 334, 334, 334, 334, 334, 334, 334, 334,
+ 335, 26, 26, 336, 337, 337, 338, 26, 339, 339, 339, 26, 172, 172, 2, 2,
+ 2, 2, 2, 340, 341, 342, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176,
+ 337, 337, 337, 337, 337, 343, 337, 344, 169, 169, 169, 169, 345, 26, 169, 169,
+ 296, 346, 169, 169, 169, 169, 169, 345, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 347, 26, 26, 26, 26, 348, 26, 349, 350, 25, 25, 351, 352,
+ 353, 25, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 354, 26, 355, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 356,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 357, 31, 31, 31, 31, 31,
+ 31, 358, 26, 26, 26, 26, 31, 31, 9, 9, 0, 314, 9, 359, 0, 0,
+ 0, 0, 360, 0, 258, 281, 361, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 362, 363, 0, 0, 0, 1, 2, 2, 3,
+ 1, 2, 2, 3, 364, 291, 290, 291, 291, 291, 291, 365, 169, 169, 169, 296,
+ 366, 366, 366, 367, 258, 258, 26, 368, 369, 370, 369, 369, 371, 369, 369, 372,
+ 369, 373, 369, 373, 26, 26, 26, 26, 369, 369, 369, 369, 369, 369, 369, 369,
+ 369, 369, 369, 369, 369, 369, 369, 374, 375, 0, 0, 0, 0, 0, 376, 0,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 253, 0, 377, 378, 26, 26, 26,
+ 26, 26, 0, 0, 0, 0, 0, 379, 380, 380, 380, 381, 382, 382, 382, 382,
+ 382, 382, 383, 26, 384, 0, 0, 281, 385, 385, 385, 385, 386, 387, 388, 388,
+ 388, 389, 390, 390, 390, 390, 390, 391, 392, 392, 392, 393, 394, 394, 394, 394,
+ 395, 394, 396, 26, 26, 26, 26, 26, 397, 397, 397, 397, 397, 397, 397, 397,
+ 397, 397, 398, 398, 398, 398, 398, 398, 399, 399, 399, 400, 399, 401, 402, 402,
+ 402, 402, 403, 402, 402, 402, 402, 403, 404, 404, 404, 404, 404, 26, 405, 405,
+ 405, 405, 405, 405, 406, 407, 408, 409, 408, 409, 410, 408, 411, 408, 411, 412,
+ 26, 26, 26, 26, 26, 26, 26, 26, 413, 413, 413, 413, 413, 413, 413, 413,
+ 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 414, 26,
+ 413, 413, 415, 26, 413, 26, 26, 26, 416, 2, 2, 2, 2, 2, 417, 308,
+ 26, 26, 26, 26, 26, 26, 26, 26, 418, 419, 420, 420, 420, 420, 421, 422,
+ 423, 423, 424, 423, 425, 425, 425, 425, 426, 426, 426, 427, 428, 426, 26, 26,
+ 26, 26, 26, 26, 429, 429, 430, 431, 432, 432, 432, 433, 434, 434, 434, 435,
+ 26, 26, 26, 26, 26, 26, 26, 26, 436, 436, 436, 436, 437, 437, 437, 438,
+ 437, 437, 439, 437, 437, 437, 437, 437, 440, 441, 442, 443, 444, 444, 445, 446,
+ 444, 447, 444, 447, 448, 448, 448, 448, 449, 449, 449, 449, 26, 26, 26, 26,
+ 450, 450, 450, 450, 451, 452, 451, 26, 453, 453, 453, 453, 453, 453, 454, 455,
+ 456, 456, 457, 456, 458, 458, 459, 458, 460, 460, 461, 462, 26, 463, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 464, 464, 464, 464, 464, 464, 464, 464,
+ 464, 465, 26, 26, 26, 26, 26, 26, 466, 466, 466, 466, 466, 466, 467, 26,
+ 466, 466, 466, 466, 466, 466, 467, 468, 469, 469, 469, 469, 469, 26, 469, 470,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 31, 31, 31, 50, 471, 471, 471, 471, 471, 472, 473, 26,
+ 26, 26, 26, 26, 26, 26, 26, 474, 475, 475, 475, 475, 475, 26, 476, 476,
+ 476, 476, 476, 477, 26, 26, 478, 478, 478, 479, 26, 26, 26, 26, 480, 480,
+ 480, 481, 26, 26, 482, 482, 483, 26, 484, 484, 484, 484, 484, 484, 484, 484,
+ 484, 485, 486, 484, 484, 484, 485, 487, 488, 488, 488, 488, 488, 488, 488, 488,
+ 489, 490, 491, 491, 491, 492, 491, 493, 494, 494, 494, 494, 494, 494, 495, 494,
+ 494, 26, 496, 496, 496, 496, 497, 26, 498, 498, 498, 498, 498, 498, 498, 498,
+ 498, 498, 498, 498, 499, 137, 500, 26, 501, 501, 502, 501, 501, 501, 501, 501,
+ 503, 26, 26, 26, 26, 26, 26, 26, 504, 505, 506, 507, 506, 508, 509, 509,
+ 509, 509, 509, 509, 509, 510, 509, 511, 512, 513, 514, 515, 515, 516, 517, 518,
+ 513, 519, 520, 521, 522, 523, 523, 26, 524, 524, 524, 524, 524, 524, 524, 524,
+ 524, 524, 524, 525, 526, 26, 26, 26, 527, 527, 527, 527, 527, 527, 527, 527,
+ 527, 26, 527, 528, 26, 26, 26, 26, 529, 529, 529, 529, 529, 529, 530, 529,
+ 529, 529, 529, 530, 26, 26, 26, 26, 531, 531, 531, 531, 531, 531, 531, 531,
+ 532, 26, 531, 533, 198, 534, 26, 26, 535, 535, 535, 535, 535, 535, 535, 536,
+ 535, 536, 26, 26, 26, 26, 26, 26, 537, 537, 537, 538, 537, 539, 537, 537,
+ 540, 26, 26, 26, 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 542,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 543, 543, 543, 543,
+ 543, 543, 543, 543, 543, 543, 544, 545, 546, 547, 548, 549, 549, 549, 550, 551,
+ 546, 26, 549, 552, 26, 26, 26, 26, 26, 26, 26, 26, 553, 554, 553, 553,
+ 553, 553, 553, 554, 555, 26, 26, 26, 556, 556, 556, 556, 556, 556, 556, 556,
+ 556, 26, 557, 557, 557, 557, 557, 557, 557, 557, 557, 557, 558, 26, 178, 178,
+ 559, 559, 559, 559, 559, 559, 559, 560, 53, 561, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 562, 563, 562, 562, 562, 562, 564, 562,
+ 565, 26, 562, 562, 562, 566, 567, 567, 567, 567, 568, 567, 567, 569, 570, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 571, 572, 573, 573, 573, 573, 571, 574,
+ 573, 26, 573, 575, 576, 577, 578, 578, 578, 579, 580, 581, 578, 582, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 583, 583, 583, 584, 585, 585, 586, 585, 585, 585, 585, 587,
+ 585, 585, 585, 588, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 589, 26,
+ 108, 108, 108, 108, 108, 108, 590, 591, 592, 592, 592, 592, 592, 592, 592, 592,
+ 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 593, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 592, 592, 592, 592, 592, 592, 592, 592,
+ 592, 592, 592, 592, 592, 594, 595, 26, 592, 592, 592, 592, 592, 592, 592, 592,
+ 596, 26, 26, 26, 26, 26, 26, 26, 26, 26, 597, 597, 597, 597, 597, 597,
+ 597, 597, 597, 597, 597, 597, 598, 26, 599, 599, 599, 599, 599, 599, 599, 599,
+ 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599,
+ 599, 599, 600, 26, 26, 26, 26, 26, 601, 601, 601, 601, 601, 601, 601, 601,
+ 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601,
+ 602, 26, 26, 26, 26, 26, 26, 26, 305, 305, 305, 305, 305, 305, 305, 305,
+ 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 603,
+ 604, 604, 604, 605, 604, 606, 607, 607, 607, 607, 607, 607, 607, 607, 607, 608,
+ 607, 609, 610, 610, 610, 611, 611, 26, 612, 612, 612, 612, 612, 612, 612, 612,
+ 613, 26, 612, 614, 614, 612, 612, 615, 612, 612, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 276, 276,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 346, 26, 26, 26, 26,
- 347, 26, 348, 349, 25, 25, 350, 351, 352, 25, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 353, 26, 354, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 355, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 356, 31, 31, 31, 31, 31, 31, 357, 26, 26, 26, 26, 31, 31,
- 9, 9, 0, 313, 9, 358, 0, 0, 0, 0, 359, 0, 257, 280, 360, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 361,
- 362, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, 363, 290, 289, 290,
- 290, 290, 290, 364, 168, 168, 168, 295, 365, 365, 365, 366, 257, 257, 26, 367,
- 368, 369, 368, 368, 370, 368, 368, 371, 368, 372, 368, 372, 26, 26, 26, 26,
- 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 373,
- 374, 0, 0, 0, 0, 0, 375, 0, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 252, 0, 376, 377, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 378,
- 379, 379, 379, 380, 381, 381, 381, 381, 381, 381, 382, 26, 383, 0, 0, 280,
- 384, 384, 384, 384, 385, 386, 387, 387, 387, 388, 389, 389, 389, 389, 389, 390,
- 391, 391, 391, 392, 393, 393, 393, 393, 394, 393, 395, 26, 26, 26, 26, 26,
- 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 397, 397, 397, 397, 397, 397,
- 398, 398, 398, 399, 398, 400, 401, 401, 401, 401, 402, 401, 401, 401, 401, 402,
- 403, 403, 403, 403, 403, 26, 404, 404, 404, 404, 404, 404, 405, 406, 407, 408,
- 407, 408, 409, 407, 410, 407, 410, 411, 26, 26, 26, 26, 26, 26, 26, 26,
- 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
- 412, 412, 412, 412, 412, 412, 413, 26, 412, 412, 414, 26, 412, 26, 26, 26,
- 415, 2, 2, 2, 2, 2, 416, 307, 26, 26, 26, 26, 26, 26, 26, 26,
- 417, 418, 419, 419, 419, 419, 420, 421, 422, 422, 423, 422, 424, 424, 424, 424,
- 425, 425, 425, 426, 427, 425, 26, 26, 26, 26, 26, 26, 428, 428, 429, 430,
- 431, 431, 431, 432, 433, 433, 433, 434, 26, 26, 26, 26, 26, 26, 26, 26,
- 435, 435, 435, 435, 436, 436, 436, 437, 436, 436, 438, 436, 436, 436, 436, 436,
- 439, 440, 441, 442, 443, 443, 444, 445, 443, 446, 443, 446, 447, 447, 447, 447,
- 448, 448, 448, 448, 26, 26, 26, 26, 449, 449, 449, 449, 450, 451, 450, 26,
- 452, 452, 452, 452, 452, 452, 453, 454, 455, 455, 456, 455, 457, 457, 458, 457,
- 459, 459, 460, 461, 26, 462, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 463, 463, 463, 463, 463, 463, 463, 463, 463, 464, 26, 26, 26, 26, 26, 26,
- 465, 465, 465, 465, 465, 465, 466, 26, 465, 465, 465, 465, 465, 465, 466, 467,
- 468, 468, 468, 468, 468, 26, 468, 469, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 31, 31, 31, 50,
- 470, 470, 470, 470, 470, 471, 472, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 473, 473, 473, 473, 473, 26, 474, 474, 474, 474, 474, 475, 26, 26, 476, 476,
- 476, 477, 26, 26, 26, 26, 478, 478, 478, 479, 26, 26, 480, 480, 481, 26,
- 482, 482, 482, 482, 482, 482, 482, 482, 482, 483, 484, 482, 482, 482, 483, 485,
- 486, 486, 486, 486, 486, 486, 486, 486, 487, 488, 489, 489, 489, 490, 489, 491,
- 492, 492, 492, 492, 492, 492, 493, 492, 492, 26, 494, 494, 494, 494, 495, 26,
- 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 497, 137, 498, 26,
- 499, 499, 500, 499, 499, 499, 499, 501, 26, 26, 26, 26, 26, 26, 26, 26,
- 502, 503, 504, 505, 504, 506, 507, 507, 507, 507, 507, 507, 507, 508, 507, 509,
- 510, 511, 512, 513, 513, 514, 515, 516, 511, 517, 518, 519, 520, 521, 521, 26,
- 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 523, 524, 26, 26, 26,
- 525, 525, 525, 525, 525, 525, 525, 525, 525, 26, 525, 526, 26, 26, 26, 26,
- 527, 527, 527, 527, 527, 527, 528, 527, 527, 527, 527, 528, 26, 26, 26, 26,
- 529, 529, 529, 529, 529, 529, 529, 529, 530, 26, 529, 531, 197, 532, 26, 26,
- 533, 533, 533, 533, 533, 533, 533, 534, 533, 534, 26, 26, 26, 26, 26, 26,
- 535, 535, 535, 536, 535, 537, 535, 535, 538, 26, 26, 26, 26, 26, 26, 26,
- 539, 539, 539, 539, 539, 539, 539, 540, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 542, 543,
- 544, 545, 546, 547, 547, 547, 548, 549, 544, 26, 547, 550, 26, 26, 26, 26,
- 26, 26, 26, 26, 551, 552, 551, 551, 551, 551, 551, 552, 553, 26, 26, 26,
- 554, 554, 554, 554, 554, 554, 554, 554, 554, 26, 555, 555, 555, 555, 555, 555,
- 555, 555, 555, 555, 556, 26, 177, 177, 557, 557, 557, 557, 557, 557, 557, 558,
- 559, 560, 559, 559, 559, 559, 561, 559, 562, 26, 559, 559, 559, 563, 564, 564,
- 564, 564, 565, 564, 564, 566, 567, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 568, 569, 570, 570, 570, 570, 568, 571, 570, 26, 570, 572, 573, 574, 575, 575,
- 575, 576, 577, 578, 575, 579, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 580, 580, 580, 581,
- 26, 26, 26, 26, 26, 26, 582, 26, 108, 108, 108, 108, 108, 108, 583, 584,
- 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585,
- 585, 585, 585, 586, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 587, 588, 26,
- 585, 585, 585, 585, 585, 585, 585, 585, 589, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 591, 26,
- 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592,
- 592, 592, 592, 592, 592, 593, 592, 594, 26, 26, 26, 26, 26, 26, 26, 26,
- 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595,
- 595, 595, 595, 595, 595, 595, 595, 595, 596, 26, 26, 26, 26, 26, 26, 26,
- 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304,
- 304, 304, 304, 304, 304, 304, 304, 597, 598, 598, 598, 599, 598, 600, 601, 601,
- 601, 601, 601, 601, 601, 601, 601, 602, 601, 603, 604, 604, 604, 605, 605, 26,
- 606, 606, 606, 606, 606, 606, 606, 606, 607, 26, 606, 608, 608, 606, 606, 609,
- 606, 606, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 610, 610, 610, 610, 610, 610, 610, 610,
- 610, 610, 610, 611, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 612, 612, 612, 612, 612, 612, 612, 612, 612, 613, 612, 612, 612, 612, 612, 612,
- 612, 614, 612, 612, 26, 26, 26, 26, 26, 26, 26, 26, 615, 26, 346, 26,
- 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616,
- 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 26,
- 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617,
- 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 618, 26, 26, 26, 26, 26,
- 616, 619, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 620, 621,
- 622, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 623, 26, 26, 26, 26, 26, 624, 26, 625, 26, 626, 626,
- 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626,
- 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 627,
- 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 629, 628, 630,
- 628, 631, 628, 632, 280, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 9, 9, 9, 9, 9, 633, 9, 9, 220, 26, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, 26, 26, 26, 26, 26, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26,
- 0, 0, 0, 0, 257, 362, 0, 0, 0, 0, 0, 0, 634, 635, 0, 636,
- 637, 638, 0, 0, 0, 639, 0, 0, 0, 0, 0, 0, 0, 265, 26, 26,
- 14, 14, 14, 14, 14, 14, 14, 14, 246, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 280, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 257, 26, 0, 0, 0, 259,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0,
- 0, 0, 0, 254, 640, 641, 0, 642, 643, 0, 0, 0, 0, 0, 0, 0,
- 268, 644, 254, 254, 0, 0, 0, 645, 646, 647, 648, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 0,
- 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649,
- 649, 650, 26, 651, 652, 649, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 2, 2, 2, 347, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 653, 269, 269, 654, 655, 656, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 657, 657, 657, 657, 657, 658, 657, 659, 657, 660, 26, 26, 26, 26, 26, 26,
- 26, 26, 661, 661, 661, 662, 26, 26, 663, 663, 663, 663, 663, 663, 663, 664,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 171, 665, 169, 171,
- 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666,
- 666, 666, 666, 666, 666, 666, 666, 666, 667, 666, 668, 26, 26, 26, 26, 26,
- 669, 669, 669, 669, 669, 669, 669, 669, 669, 670, 669, 671, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 362, 0,
- 0, 0, 0, 0, 0, 0, 376, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 362, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 26, 26,
- 672, 31, 31, 31, 673, 674, 675, 676, 677, 678, 673, 679, 673, 675, 675, 680,
- 31, 681, 31, 682, 683, 681, 31, 682, 26, 26, 26, 26, 26, 26, 51, 26,
- 0, 0, 0, 0, 0, 280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 280, 26, 0, 257, 362, 0, 362, 0, 362, 0, 0, 0, 275, 26,
- 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 684, 0, 0, 0,
- 685, 26, 0, 0, 0, 0, 0, 280, 0, 259, 313, 26, 275, 26, 26, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 686, 0, 376, 0, 376,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 280, 259, 26,
- 0, 280, 0, 0, 0, 0, 0, 0, 0, 26, 0, 313, 0, 0, 0, 0,
- 0, 26, 0, 0, 0, 275, 313, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, 0, 275, 376, 376,
- 257, 26, 0, 0, 0, 376, 0, 265, 275, 26, 0, 313, 0, 26, 257, 26,
- 0, 0, 359, 0, 0, 0, 0, 0, 0, 265, 26, 26, 26, 26, 0, 313,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 26, 26, 26, 26,
- 276, 276, 276, 276, 276, 276, 276, 687, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 276, 346, 26, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 687, 26, 26, 26,
- 276, 276, 276, 279, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 688, 26, 26, 26, 26, 26, 26,
- 689, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 617, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 618, 618, 618, 618, 618, 618, 618, 618,
+ 618, 619, 618, 618, 618, 618, 618, 618, 618, 620, 618, 618, 26, 26, 26, 26,
+ 26, 26, 26, 26, 621, 26, 347, 26, 622, 622, 622, 622, 622, 622, 622, 622,
+ 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622,
+ 622, 622, 622, 622, 622, 622, 622, 26, 623, 623, 623, 623, 623, 623, 623, 623,
+ 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
+ 623, 623, 624, 26, 26, 26, 26, 26, 622, 625, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 626, 627, 628, 287, 287, 287, 287, 287, 287, 287,
+ 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287,
+ 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 629, 26, 630, 26,
+ 26, 26, 631, 26, 632, 26, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633,
+ 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633,
+ 633, 633, 633, 633, 633, 633, 633, 634, 635, 635, 635, 635, 635, 635, 635, 635,
+ 635, 635, 635, 635, 635, 636, 635, 637, 635, 638, 635, 639, 281, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 9, 9, 9, 9, 9, 640, 9, 9,
+ 221, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 281, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 276, 26, 0, 0, 0, 0, 258, 363, 0, 0,
+ 0, 0, 0, 0, 641, 642, 0, 643, 644, 645, 0, 0, 0, 646, 0, 0,
+ 0, 0, 0, 0, 0, 266, 26, 26, 14, 14, 14, 14, 14, 14, 14, 14,
+ 247, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 0, 0, 281, 26, 0, 0, 281, 26, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 258, 26, 0, 0, 0, 260, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 647, 648, 0, 649,
+ 650, 0, 0, 0, 0, 0, 0, 0, 269, 651, 255, 255, 0, 0, 0, 652,
+ 653, 654, 655, 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 268, 0, 0, 0, 0, 0, 0, 656, 656, 656, 656, 656, 656, 656, 656,
+ 656, 656, 656, 656, 656, 656, 656, 656, 656, 657, 26, 658, 659, 656, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 348, 660, 308, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 661, 270, 270, 662, 663, 664, 18, 18,
+ 18, 18, 18, 18, 18, 665, 26, 26, 26, 666, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 667, 667, 667, 667, 667, 668, 667, 669,
+ 667, 670, 26, 26, 26, 26, 26, 26, 26, 26, 671, 671, 671, 672, 26, 26,
+ 673, 673, 673, 673, 673, 673, 673, 674, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 675, 675, 675, 675, 675, 676, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 172, 677, 170, 172, 678, 678, 678, 678, 678, 678, 678, 678,
+ 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678,
+ 679, 678, 680, 26, 26, 26, 26, 26, 681, 681, 681, 681, 681, 681, 681, 681,
+ 681, 682, 681, 683, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 0, 377, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 276,
+ 26, 26, 26, 26, 26, 26, 26, 26, 684, 31, 31, 31, 685, 686, 687, 688,
+ 689, 690, 685, 691, 685, 687, 687, 692, 31, 693, 31, 694, 695, 693, 31, 694,
+ 26, 26, 26, 26, 26, 26, 51, 26, 0, 0, 0, 0, 0, 281, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 281, 26, 0, 258, 363, 0,
+ 363, 0, 363, 0, 0, 0, 276, 26, 0, 0, 0, 0, 0, 276, 26, 26,
+ 26, 26, 26, 26, 696, 0, 0, 0, 697, 26, 0, 0, 0, 0, 0, 281,
+ 0, 260, 314, 26, 276, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 698, 0, 377, 0, 377, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 258, 699, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 314, 0, 281, 260, 26, 0, 281, 0, 0, 0, 0, 0, 0,
+ 0, 26, 0, 314, 0, 0, 0, 0, 0, 26, 0, 0, 0, 276, 314, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 281, 26, 0, 276, 0, 377, 0, 260, 0, 0, 0, 0, 0, 269,
+ 276, 696, 0, 281, 0, 260, 0, 260, 0, 0, 360, 0, 0, 0, 0, 0,
+ 0, 266, 26, 26, 26, 26, 0, 314, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 347,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 347, 26, 277, 277,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 700, 26, 26, 26, 277, 277, 277, 280, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 701, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 702, 26, 26, 26, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0,
+ 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962,
+ 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0,
+ 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147,
+ 1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0,
+ 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143,
+ 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160,
+ 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0,
+ 1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206,
+ 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035,
+ 1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250,
+ 1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0,
+ 1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299,
+ 1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,1093,1280, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340,
+ 1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177,
+ 1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0,
+ 1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165,
+ 1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279,
+ 1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130,
+ 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 10,1425, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5,
+ 1434,1438,1443, 0,1450, 0,1455,1461,1514, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1446,1458,1468,1476,1480,1486,1517, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1489,1503,1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522,
+ 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567,
+ 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549,
+ 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559,
+ 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0,
+ 1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648,
+ 1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662,
+ 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0,
+ 1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671,
+ 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0,
+ 1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142,
+ 1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381,
+ 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181,
+ 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210,
+ 1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222,
+ 1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243,
+ 1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389,
+ 1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284,
+ 1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291,
+ 1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260,
+ 1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343,
+ 1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696,
+ 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698,
+ 1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359,
+ 1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274,
+ 1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304,
+ 1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707,
+ 1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0,
+ 1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743,
+ 1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770,
+ 1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0,
+ 1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790,
+ 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800,
+ 1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24,
+ 1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714,
+ 1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750,
+ 1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807,
+ 1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825,
+ 1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829,
+ 1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515,
+ 1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518,
+ 1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830,
+ 1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0,
+ 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0,
+ 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847,
+ 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0,
+ 1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0,
+ 1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0,
+ 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0,
+ 1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890,
+ 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897,
+ 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0,
+ 1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917,
+ 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924,
+ 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929,
+ 1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825,
+ 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500,
+ 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679,
+ 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722,
+ 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540,
+ 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589,
+ 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101,
+ 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110,
+ 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801,
+ 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610,
+ 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494,
+ 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748,
+ 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161,
+ 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727,
+ 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684,
+ 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566,
+ 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729,
+ 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525,
+ 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0,
+ 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213,
+ 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458,
+ 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591,
+ 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735,
+ 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171,
+ 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325,
+ 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438,
+ 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526,
+ 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693,
+ 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777,
+ 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916,
+ 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0,
+ 1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599,
+ 1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1936, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1939,1940, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1944,1943, 0,1945, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1946,1947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1949,1950,1951,1952,1953,1954,1955, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
- 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0,
- 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
- 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303,
- 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
- 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
- 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199,
- 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0,
- 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231,
- 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
- 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275,
- 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0,
- 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093,
- 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010,
- 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347,
- 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
- 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365,
- 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
- 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182,
- 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
- 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461,
- 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486,
- 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0,
- 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0,
- 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0,
- 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553,
- 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560,
- 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0,
- 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0,
- 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627,
- 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0,
- 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0,
- 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0,
- 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0,
- 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0,
- 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0,
- 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0,
- 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0,
- 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
- 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
- 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
- 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
- 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
- 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
- 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
- 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
- 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
- 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0,
- 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
- 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
- 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
- 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
- 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
- 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0,
- 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
- 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0,
- 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
- 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
- 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0,
- 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793,
- 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
- 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0,
- 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
- 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
- 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
- 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0,
- 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828,
- 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833,
- 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3,
- 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0,
- 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838,
- 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0,
- 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0,
- 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938,
- 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0,
- 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870,
- 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0,
- 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0,
- 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0,
- 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0,
- 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0,
- 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0,
- 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0,
- 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0,
- 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0,
- 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
- 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
- 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
- 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
- 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
- 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
- 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
- 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
- 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
- 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
- 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
- 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
- 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
- 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
- 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
- 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
- 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0,
- 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0,
- 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773,
- 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
- 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
- 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
- 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0,
- 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
- 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
- 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
- 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
- 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
- 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
- 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575,
- 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0,
- 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950,
- 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959,
- 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131,
- 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37,
- 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
- 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
- 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
- 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
- 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259,
- 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
- 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934,
- 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312,
- 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
- 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
- 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381,
- 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399,
- 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417,
- 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
- 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460,
- 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
- 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505,
- 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64,
- 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538,
- 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567,
- 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592,
- 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
- 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627,
- 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
- 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83,
- 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85,
- 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696,
- 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
- 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90,
- 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787,
- 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807,
- 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0,
+ 0, 0, 0,1956,1957,1958,1960,1959,1961, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121,
+ 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142,
+ 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169,
+ 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185,
+ 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206,
+ 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224,
+ 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39,
+ 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266,
+ 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286,
+ 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852,
+ 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324,
+ 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351,
+ 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50,
+ 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78,
+ 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55,
+ 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861,
+ 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436,
+ 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467,
+ 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873,
+ 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875,
+ 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531,
+ 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559,
+ 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73,
+ 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898,
+ 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902,
+ 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904,
+ 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81,
+ 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669,
+ 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686,
+ 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719,
+ 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753,
+ 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925,
+ 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800,
+ 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816,
+ 817, 818, 819, 820, 821, 935, 0, 0,
};
static const int16_t
_hb_ucd_i16[196] =
@@ -2792,12 +2822,12 @@ _hb_ucd_i16[196] =
static inline uint_fast8_t
_hb_ucd_gc (unsigned u)
{
- return u<1114110u?_hb_ucd_u8[6664+(((_hb_ucd_u8[1296+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+ return u<1114110u?_hb_ucd_u8[6800+(((_hb_ucd_u8[1312+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
}
static inline uint_fast8_t
_hb_ucd_ccc (unsigned u)
{
- return u<125259u?_hb_ucd_u8[8984+(((_hb_ucd_u8[7960+(((_hb_ucd_u8[7288+(((_hb_ucd_u8[7042+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0;
+ return u<125259u?_hb_ucd_u8[9184+(((_hb_ucd_u8[8128+(((_hb_ucd_u8[7424+(((_hb_ucd_u8[7178+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0;
}
static inline unsigned
_hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -2807,24 +2837,24 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
static inline int_fast16_t
_hb_ucd_bmg (unsigned u)
{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9728+(((_hb_ucd_u8[9608+(((_hb_ucd_b4(9480+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9932+(((_hb_ucd_u8[9812+(((_hb_ucd_b4(9684+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
}
static inline uint_fast8_t
_hb_ucd_sc (unsigned u)
{
- return u<918000u?_hb_ucd_u8[11234+(((_hb_ucd_u16[2000+(((_hb_ucd_u8[10514+(((_hb_ucd_u8[10064+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
+ return u<918000u?_hb_ucd_u8[11454+(((_hb_ucd_u16[2040+(((_hb_ucd_u8[10718+(((_hb_ucd_u8[10268+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
}
static inline uint_fast16_t
_hb_ucd_dm (unsigned u)
{
- return u<195102u?_hb_ucd_u16[5888+(((_hb_ucd_u8[17136+(((_hb_ucd_u8[16754+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+ return u<195102u?_hb_ucd_u16[6008+(((_hb_ucd_u8[17460+(((_hb_ucd_u8[17078+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
}
#elif !defined(HB_NO_UCD_UNASSIGNED)
static const uint8_t
-_hb_ucd_u8[17564] =
+_hb_ucd_u8[17868] =
{
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 11, 12, 13, 13, 13, 14,
@@ -2832,7 +2862,7 @@ _hb_ucd_u8[17564] =
25, 26, 22, 22, 22, 27, 28, 29, 22, 30, 31, 32, 33, 34, 35, 36,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 22, 42,
- 7, 7, 43, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 7, 7, 43, 7, 44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
@@ -2854,12 +2884,12 @@ _hb_ucd_u8[17564] =
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 45, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 46,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 47,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 34, 35, 36, 37, 38, 39, 34, 34, 34, 40, 41, 42, 43,
@@ -2878,35 +2908,36 @@ _hb_ucd_u8[17564] =
118,119,120,121,122,123,124,125,126,127,128,129, 34, 34,130,131,
132,133,134,135,136,137,138,139,140,141,142,122,143,144,145,146,
147,148,149,150,151,152,153,122,154,155,122,156,157,158,159,122,
- 160,161,162,163,164,165,122,122,166,167,168,169,122,170,122,171,
- 34, 34, 34, 34, 34, 34, 34,172,173, 34,174,122,122,122,122,122,
- 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,175,
- 34, 34, 34, 34, 34, 34, 34, 34,176,122,122,122,122,122,122,122,
+ 160,161,162,163,164,165,166,122,167,168,169,170,122,171,172,173,
+ 34, 34, 34, 34, 34, 34, 34,174,175, 34,176,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,177,
+ 34, 34, 34, 34, 34, 34, 34, 34,178,122,122,122,122,122,122,122,
122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,
- 122,122,122,122,122,122,122,122, 34, 34, 34, 34,177,122,122,122,
- 34, 34, 34, 34,178,179,180,181,122,122,122,122,182,183,184,185,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,186,
- 34, 34, 34, 34, 34, 34, 34, 34, 34,187,188,122,122,122,122,122,
- 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,189,
- 34, 34,190, 34, 34,191,122,122,122,122,122,122,122,122,122,122,
- 122,122,122,122,122,122,122,122,192,193,122,122,122,122,122,122,
- 122,122,122,122,122,122,122,122,122,122,122,122,122,122,194,195,
- 69,196,197,198,199,200,201,122,202,203,204,205,206,207,208,209,
- 69, 69, 69, 69,210,211,122,122,122,122,122,122,122,122,212,122,
- 213,122,214,122,122,215,122,122,122,122,122,122,122,122,122,216,
- 34,217,218,122,122,122,122,122,219,220,221,122,222,223,122,122,
- 224,225,226,227,228,122, 69,229, 69, 69, 69, 69, 69,230,231,232,
- 233,234, 69, 69,235,236, 69,237,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,238, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,239, 34,
- 240, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,241, 34, 34,
- 34, 34, 34, 34, 34, 34, 34,242,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34,243,122,122,122,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34, 34, 34,244,122,122,122,122,122,122,122,122,122,
- 245,122,246,247,122,122,122,122,122,122,122,122,122,122,122,122,
- 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,248,
- 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,249,
+ 122,122,122,122,122,122,122,122, 34, 34, 34, 34,179,122,122,122,
+ 34, 34, 34, 34,180,181,182,183,122,122,122,122,184,185,186,187,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,188,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34,189,190,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,191,
+ 34, 34,192, 34, 34,193,122,122,122,122,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,194,195,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,196,197,
+ 69,198,199,200,201,202,203,122,204,205,206,207,208,209,210,211,
+ 69, 69, 69, 69,212,213,122,122,122,122,122,122,122,122,214,122,
+ 215,216,217,122,122,218,122,122,122,219,122,122,122,122,122,220,
+ 34,221,222,122,122,122,122,122,223,224,225,122,226,227,122,122,
+ 228,229,230,231,232,122, 69,233, 69, 69, 69, 69, 69,234,235,236,
+ 237,238, 69, 69,239,240, 69,241,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,242, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,243, 34,
+ 244, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,245, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34,246,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34,247,122,122,122,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34, 34, 34,248, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34,249,122,122,122,122,122,122,122,122,
+ 250,122,251,252,122,122,122,122,122,122,122,122,122,122,122,122,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,253,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,254,
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2,
7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
@@ -2969,7 +3000,7 @@ _hb_ucd_u8[17564] =
44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91,
70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87,
86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61,
- 62, 61, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
+ 62, 94, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77,
44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36,
57, 86, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36,
@@ -2979,7 +3010,7 @@ _hb_ucd_u8[17564] =
36, 36, 36, 75, 43, 43, 43, 60, 7, 7, 7, 7, 7, 2, 44, 44,
44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36,
36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44,
- 36, 36, 61, 81, 43, 43, 43, 44, 7, 7, 7, 7, 7, 44, 36, 36,
+ 36, 36, 61, 81, 43, 43, 43, 80, 7, 7, 7, 7, 7, 44, 36, 36,
77, 67, 2, 2, 2, 2, 2, 2, 2, 97, 97, 67, 43, 67, 67, 67,
7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 50, 50, 50, 4, 4, 86,
36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44,
@@ -3146,18 +3177,19 @@ _hb_ucd_u8[17564] =
44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44,
16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44,
27, 27, 27, 27, 27, 27, 27,100, 36, 36, 36, 36, 36, 57,184, 44,
- 36, 44, 44, 44, 44, 44, 44, 44, 27, 27, 27, 95, 44, 44, 44, 44,
- 180, 27, 30, 2, 2, 44, 44, 44, 36, 43, 43, 2, 2, 44, 44, 44,
- 36, 36,183, 27, 27, 27, 44, 44, 87, 98, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 43, 60, 2, 2, 2, 44,
- 27, 27, 27, 7, 7, 7, 7, 7, 71, 70, 71, 44, 44, 44, 44, 57,
- 86, 87, 43, 85, 87, 60,185, 2, 2, 80, 44, 44, 44, 44, 79, 44,
- 43, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, 87, 43,
- 43, 43, 80, 7, 7, 7, 7, 7, 2, 2, 94, 98, 44, 44, 44, 44,
- 36, 70, 2, 61, 44, 44, 44, 44, 36, 94, 86, 43, 43, 43, 43, 85,
- 98, 36, 63, 2, 59, 43, 60, 87, 7, 7, 7, 7, 7, 63, 63, 2,
- 179, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44, 44, 44, 44, 44,
- 36, 36, 36, 36, 36, 36, 86, 87, 43, 86, 85, 43, 2, 2, 2, 80,
+ 36, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 57, 43,
+ 27, 27, 27, 95, 44, 44, 44, 44,180, 27, 30, 2, 2, 44, 44, 44,
+ 36, 43, 43, 2, 2, 44, 44, 44, 36, 36,183, 27, 27, 27, 44, 44,
+ 87, 98, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43,
+ 43, 43, 43, 60, 2, 2, 2, 44, 27, 27, 27, 7, 7, 7, 7, 7,
+ 71, 70, 71, 44, 44, 44, 44, 57, 86, 87, 43, 85, 87, 60,185, 2,
+ 2, 80, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 70, 43, 43, 87, 43, 43, 43, 80, 7, 7, 7, 7, 7,
+ 2, 2, 94, 98, 44, 44, 44, 44, 36, 70, 2, 61, 44, 44, 44, 44,
+ 36, 94, 86, 43, 43, 43, 43, 85, 98, 36, 63, 2, 59, 43, 60, 87,
+ 7, 7, 7, 7, 7, 63, 63, 2,179, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27,100, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 86, 87,
+ 43, 86, 85, 43, 2, 2, 2, 71, 70, 44, 44, 44, 44, 44, 44, 44,
36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62,
36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70,
86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62,
@@ -3179,17 +3211,20 @@ _hb_ucd_u8[17564] =
70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60,
2, 2, 2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36,
36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43, 2, 72, 2,
- 2, 64, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 87,
- 63, 2, 2, 44, 44, 44, 44, 44, 2, 36, 36, 36, 36, 36, 36, 36,
- 44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 89, 43, 43, 43,
- 85, 43, 87, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36,
- 70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44,
- 36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 86, 86, 90,
- 43, 89, 87, 87, 61, 44, 44, 44, 36, 70, 85,107, 64, 44, 44, 44,
+ 2, 64, 44, 44, 44, 44, 44, 44, 2, 2, 2, 2, 2, 44, 44, 44,
+ 43, 43, 43, 80, 43, 43, 43, 87, 63, 2, 2, 44, 44, 44, 44, 44,
+ 2, 36, 36, 36, 36, 36, 36, 36, 44, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 89, 43, 43, 43, 85, 43, 87, 80, 44, 44, 44, 44,
+ 36, 36, 36, 61, 36, 62, 36, 36, 70, 43, 43, 80, 44, 80, 43, 57,
+ 43, 43, 43, 70, 44, 44, 44, 44, 36, 36, 36, 62, 61, 36, 36, 36,
+ 36, 36, 36, 36, 36, 86, 86, 90, 43, 89, 87, 87, 61, 44, 44, 44,
+ 36, 70, 85,107, 64, 44, 44, 44, 43, 94, 36, 36, 36, 36, 36, 36,
+ 36, 36, 86, 43, 43, 80, 44, 86, 85, 60, 2, 2, 2, 2, 2, 2,
27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67,
67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181,
2, 2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44,
- 65, 65, 65, 65,132, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44,
+ 65, 65, 65, 65, 65, 65, 65, 65, 71, 36, 36, 70, 43, 43, 43, 43,
+ 43, 43, 43, 44, 44, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44,
43, 43, 43, 60, 2, 2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44,
7, 7, 7, 7, 7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36,
36, 36, 36, 36, 44, 44, 62, 36, 27, 27, 27, 30, 2, 64, 44, 44,
@@ -3197,7 +3232,8 @@ _hb_ucd_u8[17564] =
86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57,
43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44,
86, 44, 44, 44, 44, 44, 44, 44, 40, 40, 52, 40, 40, 40, 52, 81,
- 36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44,
+ 36, 61, 44, 44, 44, 44, 44, 44, 44, 61, 44, 44, 44, 44, 44, 44,
+ 36, 61, 62, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44,
36, 36, 36, 36, 36, 44, 50, 60, 65, 65, 44, 44, 44, 44, 44, 44,
43, 43, 43, 43, 43, 43, 43, 44, 43, 43, 43, 80, 44, 44, 44, 44,
67, 67, 67, 92, 55, 67, 67, 67, 67, 67,186, 87, 43, 67,186, 86,
@@ -3222,10 +3258,12 @@ _hb_ucd_u8[17564] =
43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67,
67, 67, 76, 21, 2, 2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43,
16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110,
- 43, 43, 43, 80, 43, 43, 43, 43, 43, 43, 43, 43, 80, 57, 43, 43,
- 43, 57, 80, 43, 43, 80, 44, 44, 43, 43, 43, 74, 40, 40, 40, 44,
- 7, 7, 7, 7, 7, 44, 44, 77, 36, 36, 36, 36, 36, 36, 36, 80,
- 36, 36, 36, 36, 36, 36, 43, 43, 7, 7, 7, 7, 7, 44, 44, 96,
+ 44, 44,150, 16, 16,110, 44, 44, 43, 43, 43, 80, 43, 43, 43, 43,
+ 43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44,
+ 40, 40, 40, 40, 40, 40, 40, 44, 44, 44, 44, 44, 44, 44, 44, 57,
+ 43, 43, 43, 74, 40, 40, 40, 44, 7, 7, 7, 7, 7, 44, 44, 77,
+ 36, 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 43, 43,
+ 7, 7, 7, 7, 7, 44, 44, 96, 36, 36, 36, 36, 36, 83, 43, 43,
36, 36, 36, 61, 36, 36, 62, 61, 36, 36, 61,179, 27, 27, 27, 27,
16, 16, 43, 43, 43, 74, 44, 44, 27, 27, 27, 27, 27, 27,163, 27,
188, 27,100, 44, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,163,
@@ -3238,206 +3276,210 @@ _hb_ucd_u8[17564] =
27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44,
44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44,
67, 67, 67, 67, 92, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44,
- 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 55, 67,
- 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 44, 67, 67, 92, 44,
+ 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 67, 67,
+ 67, 67, 67, 92, 44, 55, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44,
+ 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 44, 44, 44, 44, 67,
67, 92, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44,
- 65, 65, 65, 65, 65, 65, 65, 65,171,171,171,171,171,171,171, 44,
- 171,171,171,171,171,171,171, 0, 0, 0, 29, 21, 21, 21, 23, 21,
- 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9,
- 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0,
- 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15,
- 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7,
- 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12,
- 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, 25, 9, 26, 12, 11, 11,
- 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, 2, 12, 17, 12, 21, 12,
- 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, 1, 1, 21, 23, 26, 26,
- 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12,
- 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, 6, 2, 24, 7, 7, 6,
- 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 2, 10, 10, 2, 15, 26,
- 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, 21, 26, 10, 7, 21, 15,
- 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, 14, 14, 14, 7, 10, 21,
- 17, 21, 11, 12, 5, 2, 5, 6, 8, 8, 8, 24, 5, 24, 2, 24,
- 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, 20, 19, 22, 20, 27, 28,
- 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29,
- 1, 2, 15, 6, 18, 6, 23, 2, 12, 11, 9, 26, 26, 9, 26, 5,
- 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25,
- 18, 22, 5, 12, 2, 5, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14,
- 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15,
- 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3,
- 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25, 2, 25, 24, 2, 15,
- 12, 15, 14, 2, 21, 14, 7, 15, 12, 17, 21, 1, 26, 10, 10, 1,
- 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12,
- 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 171,171,171,171,171,171,171, 44,171,171,171,171,171,171,171, 0,
+ 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13,
+ 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5,
+ 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20,
+ 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25,
+ 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 7, 5,
+ 6, 6, 24, 24, 6, 24, 12, 12, 2, 2, 6, 5, 9, 21, 9, 2,
+ 2, 9, 25, 9, 26, 12, 11, 11, 2, 6, 5, 21, 17, 2, 2, 26,
+ 26, 23, 2, 12, 17, 12, 21, 12, 12, 21, 7, 2, 2, 7, 7, 21,
+ 21, 2, 1, 1, 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7,
+ 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 2, 1,
+ 12, 2, 6, 2, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12,
+ 21, 6, 2, 10, 10, 2, 15, 26, 26, 2, 2, 21, 7, 10, 15, 7,
+ 2, 23, 21, 26, 10, 7, 21, 15, 15, 2, 17, 7, 29, 7, 7, 22,
+ 18, 2, 14, 14, 14, 7, 10, 21, 17, 21, 11, 12, 5, 2, 5, 6,
+ 8, 8, 8, 24, 5, 24, 2, 24, 9, 24, 24, 2, 29, 29, 29, 1,
+ 17, 17, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16,
+ 16, 21, 25, 22, 18, 21, 21, 29, 1, 2, 15, 6, 18, 6, 23, 2,
+ 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15,
+ 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 2, 5, 22, 21,
+ 21, 22, 18, 17, 26, 6, 7, 14, 17, 22, 18, 18, 26, 14, 17, 6,
+ 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9,
+ 23, 26, 6, 10, 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16,
+ 25, 17, 25, 2, 25, 24, 2, 15, 12, 15, 14, 2, 21, 14, 7, 15,
+ 12, 17, 21, 1, 26, 10, 10, 1, 23, 15, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0,
+ 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
- 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32,
- 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 34, 0, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35,
+ 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0,
- 0, 0, 39, 40, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 5,
- 6, 7, 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, 16, 17, 16, 18,
- 16, 19, 16, 19, 16, 19, 0, 19, 16, 20, 16, 19, 21, 19, 0, 22,
- 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 32, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 35,
- 0, 0, 36, 0, 37, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45,
- 46, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0,
- 0, 0, 0, 50, 0, 51, 0, 52, 53, 0, 54, 0, 0, 0, 0, 0,
- 0, 55, 56, 57, 0, 0, 0, 0, 58, 0, 0, 59, 60, 61, 62, 63,
- 0, 0, 64, 65, 0, 0, 0, 66, 0, 0, 0, 0, 67, 0, 0, 0,
- 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69,
- 0, 0, 0, 70, 0, 71, 0, 0, 72, 0, 0, 73, 0, 0, 0, 0,
- 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 75, 0, 0, 76, 77, 0,
- 0, 78, 79, 0, 80, 62, 0, 81, 82, 0, 0, 83, 84, 85, 0, 0,
- 0, 86, 0, 87, 0, 0, 51, 88, 51, 0, 89, 0, 90, 0, 0, 0,
- 79, 0, 0, 0, 91, 92, 0, 93, 94, 95, 96, 0, 0, 0, 0, 0,
- 51, 0, 0, 0, 0, 97, 98, 0, 0, 0, 0, 99,100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,101, 0, 0,102, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,103,104, 0, 0,105, 0, 0, 0, 0, 0, 0,
- 106, 0, 0, 0,100, 0, 0, 0, 0, 0,107,108, 0, 0, 0, 0,
- 0, 0, 0,109, 0,110, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
- 5, 6, 7, 0, 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, 0, 0,
- 0, 13, 0, 0, 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, 0, 20,
- 21, 0, 0, 0, 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, 0, 0,
- 0, 27, 0, 0, 28, 29, 30, 31, 0, 0, 0, 32, 33, 34, 0, 0,
- 33, 0, 0, 35, 33, 0, 0, 0, 33, 36, 0, 0, 0, 0, 0, 37,
- 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41,
- 42, 0, 0, 0, 0, 43, 0, 44, 0, 0, 0, 45, 46, 0, 0, 0,
- 47, 0, 0, 0, 0, 0, 0, 48, 49, 0, 0, 0, 0, 50, 0, 0,
- 0, 51, 0, 52, 0, 53, 0, 0, 0, 0, 54, 0, 0, 0, 0, 55,
- 0, 56, 0, 0, 0, 0, 57, 58, 0, 0, 0, 59, 60, 0, 0, 0,
- 0, 0, 0, 61, 52, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 66,
- 0, 0, 0, 67, 0, 68, 69, 70, 71, 72, 1, 73, 0, 74, 75, 76,
- 0, 0, 77, 78, 0, 0, 0, 79, 0, 0, 1, 1, 0, 0, 80, 0,
- 0, 81, 0, 0, 0, 0, 77, 82, 0, 83, 0, 0, 0, 0, 0, 78,
- 84, 0, 85, 0, 52, 0, 1, 78, 0, 0, 86, 0, 0, 87, 0, 0,
- 0, 0, 0, 88, 57, 0, 0, 0, 0, 0, 0, 89, 90, 0, 0, 84,
- 0, 0, 33, 0, 0, 91, 0, 0, 0, 0, 92, 0, 0, 0, 0, 49,
- 0, 0, 93, 0, 0, 0, 0, 94, 95, 0, 0, 96, 0, 0, 97, 0,
- 0, 0, 98, 0, 0, 0, 99, 0,100, 93, 0, 0,101, 0, 0, 0,
- 84, 0, 0,102, 0, 0, 0,103,104, 0, 0,105,106, 0, 0, 0,
- 0, 0, 0,107, 0, 0,108, 0, 0, 0, 0,109, 33, 0,110,111,
- 112, 35, 0, 0,113, 0, 0, 0,114, 0, 0, 0, 0, 0, 0,115,
- 0, 0,116, 0, 0, 0, 0,117, 88, 0, 0, 0, 0, 0, 57, 0,
- 0, 0, 0, 52,118, 0, 0, 0, 0,119, 0, 0,120, 0, 0, 0,
- 0,118, 0, 0, 0, 0, 0,121, 0, 0, 0,122, 0, 0, 0,123,
- 0,124, 0, 0, 0, 0,125,126,127, 0,128, 0,129, 0, 0, 0,
- 130,131,132, 0, 0, 0, 35, 0, 0, 0,133, 0, 0,134, 0, 0,
- 135, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4,
- 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17,
- 18, 1, 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24,
- 25, 26, 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33,
- 34, 35, 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41,
- 42, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1,
- 21, 0, 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0,
- 0, 0, 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52,
- 54, 21, 35, 1, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0,
- 0, 0, 0, 59, 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0,
- 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0,
- 0, 0, 68, 0, 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0,
- 0, 77, 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49,
- 0, 80, 0, 0, 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0,
- 0, 0, 83, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85,
- 1, 52, 15, 86, 36, 10, 21, 87, 0, 55, 0, 0, 0, 0, 19, 10,
- 1, 0, 0, 0, 0, 0, 88, 0, 0, 89, 0, 0, 88, 0, 0, 0,
- 0, 78, 0, 0, 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0,
- 21, 1, 21, 92, 93, 1, 1, 1, 1, 94, 95, 96, 97, 1, 98, 58,
- 81, 99,100, 4, 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0,
- 0, 0, 0, 61, 0, 0,101,102, 0, 0,103, 0, 0, 1, 1, 50,
- 0, 0, 0, 38, 0, 63, 0, 0, 0, 0, 0, 62, 0, 0,104, 68,
- 61, 0, 0, 0, 78, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0,
- 0, 0, 0,107, 1, 14, 4, 12, 84, 0, 0, 0, 0, 38, 87, 0,
- 0, 0, 0,108, 0, 0,109, 61, 0,110, 0, 0, 0, 1, 0, 0,
- 0, 0, 19, 58, 0,111, 14, 52,112, 41, 0, 0, 62, 0, 0, 61,
- 0, 0,113, 0, 87, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0,
- 0,113, 0, 0, 0, 0,114, 0, 0, 0, 78, 55, 0, 38, 1, 58,
- 1, 58, 0, 0, 63, 89, 0, 0,115, 0, 0, 0, 55, 0, 0, 0,
- 0,115, 0, 0, 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, 0, 0,
- 0, 0, 56, 0, 89, 80, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 40, 41, 42, 0, 43, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0,
+ 0, 0, 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, 0, 11,
+ 12, 13, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, 0, 19,
+ 16, 20, 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, 0, 0,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, 0, 48,
+ 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 52,
+ 53, 0, 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0,
+ 58, 0, 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, 0, 66,
+ 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 0,
+ 72, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0,
+ 0, 0, 75, 76, 0, 77, 78, 0, 0, 79, 80, 0, 81, 62, 0, 82,
+ 83, 0, 0, 84, 85, 86, 0, 0, 0, 87, 0, 88, 0, 0, 51, 89,
+ 51, 0, 90, 0, 91, 0, 0, 0, 80, 0, 0, 0, 92, 93, 0, 94,
+ 95, 96, 97, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 98, 99, 0,
+ 0, 0, 0, 0, 0,100, 0, 0, 0, 0, 0,101,102, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,103, 0, 0,104, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,105,106, 0, 0,107, 0, 0, 0, 0, 0, 0,
+ 108, 0,109, 0,102, 0, 0, 0, 0, 0,110,111, 0, 0, 0, 0,
+ 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0,113, 0,114, 0, 0,
+ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, 0, 0,
+ 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, 0, 16,
+ 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, 22, 23,
+ 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, 28, 29, 30, 31,
+ 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, 0, 0,
+ 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39,
+ 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, 0, 44,
+ 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48,
+ 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, 0, 0,
+ 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, 57, 58,
+ 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, 52, 0, 62, 63,
+ 0, 0, 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, 0, 68, 69, 70,
+ 71, 72, 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, 0, 0, 0, 79,
+ 0, 0, 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, 0, 0, 77, 82,
+ 0, 83, 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, 52, 0, 1, 78,
+ 0, 0, 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, 57, 0, 0, 0,
+ 0, 0, 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, 0, 91, 0, 0,
+ 0, 0, 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, 0, 0, 0, 94,
+ 95, 0, 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99, 0,
+ 0, 0, 0,100,101, 93, 0, 0,102, 0, 0, 0, 84, 0, 0,103,
+ 0, 0, 0,104,105, 0, 0,106,107, 0, 0, 0, 0, 0, 0,108,
+ 0, 0,109, 0, 0, 0, 0,110, 33, 0,111,112,113, 35, 0, 0,
+ 114, 0, 0, 0,115, 0, 0, 0, 0, 0, 0,116, 0, 0,117, 0,
+ 0, 0, 0,118, 88, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,
+ 119, 0, 0, 0, 0,120, 0, 0,121, 0, 0, 0, 0,119, 0, 0,
+ 122, 0, 0, 0, 0, 0, 0,123, 0, 0, 0,124, 0, 0, 0,125,
+ 0,126, 0, 0, 0, 0,127,128,129, 0,130, 0,131, 0, 0, 0,
+ 132,133,134, 0, 77, 0, 0, 0, 0, 0, 35, 0, 0, 0,135, 0,
+ 0, 0,136, 0, 0,137, 0, 0,138, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10,
+ 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 19, 1, 0, 0,
+ 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0,
+ 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, 37, 0, 0, 0,
+ 0, 38, 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, 43, 36, 44, 45,
+ 21, 45, 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, 0, 38, 48, 1,
+ 1, 49, 49, 50, 0, 0, 51, 0, 0, 0, 52, 1, 0, 0, 38, 14,
+ 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 55,
+ 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, 0, 60, 0, 0,
+ 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 65, 0,
+ 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 69, 70, 0,
+ 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, 0, 78, 79, 0,
+ 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, 0, 62, 0, 0,
+ 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0,
+ 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, 36, 10, 21, 87,
+ 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0,
+ 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 87, 9, 12, 4,
+ 90, 8, 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1,
+ 1, 94, 95, 96, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0,
+ 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,101,102,
+ 0, 0,103, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0,
+ 0, 0, 0, 62, 0, 0,104, 68, 61, 0, 0, 0, 78, 0, 0, 0,
+ 105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12,
+ 84, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0,109, 61,
+ 0,110, 0, 0, 0, 1, 0, 0, 0, 0, 19, 58, 0, 0, 0, 51,
+ 0,111, 14, 52,112, 41, 0, 0, 62, 0, 0, 61, 0, 0,113, 0,
+ 87, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0,113, 0, 0,
+ 0, 0,114, 0, 0, 0, 78, 55, 0, 38, 1, 58, 1, 58, 0, 0,
+ 63, 89, 0, 0,115, 0, 0, 0, 55, 0, 0, 0, 0,115, 0, 0,
+ 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, 0, 0, 0, 0, 56, 0,
+ 89, 80, 0, 0, 79, 0, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0,
116, 0, 0, 0, 0, 0, 0,117, 0,118,119,120,121, 0,104, 4,
122, 49, 23, 0, 0, 0, 38, 50, 38, 58, 0, 0, 1, 87, 1, 1,
- 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 1, 4,122, 0, 0,
- 0, 1,123, 0, 0, 0, 0, 0,230,230,230,230,230,232,220,220,
- 220,220,232,216,220,220,220,220,220,202,202,220,220,220,220,202,
- 202,220,220,220, 1, 1, 1, 1, 1,220,220,220,220,230,230,230,
- 230,240,230,220,220,220,230,230,230,220,220, 0,230,230,230,220,
- 220,220,220,230,232,220,220,230,233,234,234,233,234,234,233,230,
- 0, 0, 0,230, 0,220,230,230,230,230,220,230,230,230,222,220,
- 230,230,220,220,230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17,
- 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18,
- 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230,
- 230,220,220,230,220,230,230,220, 35, 0, 0, 0, 0, 0,230,230,
- 230, 0, 0,230,230, 0,220,230,230,220, 0, 0, 0, 36, 0, 0,
- 230,220,230,230,220,220,230,220,220,230,220,230,220,230,230, 0,
- 0,220, 0, 0,230,230, 0,230, 0,230,230,230,230,230, 0, 0,
- 0,220,220,220,230,220,220,220,230,230, 0,220, 27, 28, 29,230,
- 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0,
- 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0,
- 0, 0, 9, 0,103,103, 9, 0,107,107,107,107,118,118, 9, 0,
- 122,122,122,122,220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0,
- 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0,
- 130, 0,230,230, 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7,
- 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0, 0,228, 0, 0,
- 0,222,230,220,220, 0, 0, 0,230, 0, 0,220,230,220, 0,220,
- 230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0,230, 0, 1, 1,
- 1, 0, 0, 0,230,234,214,220,202,230,230,230,230,230,232,228,
- 228,220,218,230,233,220,230,220,230,230, 1, 1, 1, 1, 1,230,
- 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228,232,222,224,224,
- 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230,220, 0, 0,230,
- 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, 0,230,220, 0,
- 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0, 0, 7, 9, 0,
- 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0, 0,216,216, 1,
- 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,220,220,220, 0,
- 230,230, 7, 0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19,
- 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 1, 0, 0, 0,123,
+ 4,122, 0, 0, 0, 1,124, 0, 0, 0, 0, 0,230,230,230,230,
+ 230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220,
+ 220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220,
+ 220,230,230,230,230,240,230,220,220,220,230,230,230,220,220, 0,
+ 230,230,230,220,220,220,220,230,232,220,220,230,233,234,234,233,
+ 234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230,220,230,
+ 230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,
+ 230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31,
+ 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0, 0, 0,
+ 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220, 0, 0,
+ 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230,220,230,
+ 220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,230,230,
+ 230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230, 0,220,
+ 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,
+ 230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9,
+ 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,107,107,
+ 118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220, 0,220,
+ 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,
+ 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,220, 0,
+ 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0,
+ 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, 0,220,
+ 230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0,
+ 230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,230,230,
+ 230,230,232,228,228,220,218,230,233,220,230,220,230,230, 1, 1,
+ 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228,
+ 232,222,224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230,
+ 220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0,
+ 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0,
+ 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0,
+ 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,
+ 220,220,220, 0,232,232,220,230,230,230, 7, 0, 16, 17, 17, 17,
+ 17, 17, 17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,
+ 129,169, 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17,237, 0, 1, 2, 2, 0, 3, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 5, 0, 0, 0, 0, 6, 7, 8, 9, 0, 0, 0, 10, 11, 12, 13,
- 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
- 0, 0, 21, 22, 0, 0, 0, 0, 23, 24, 25, 26, 0, 27, 0, 28,
- 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, 36, 0,
- 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39,
- 0, 0, 0, 0, 1, 2, 40, 41, 0, 1, 2, 2, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
- 0, 0, 3, 4, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0,
- 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0,
- 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 11, 12,
- 0, 13, 0, 14, 15, 16, 0, 0, 0, 0, 0, 1, 17, 18, 0, 19,
- 7, 1, 0, 0, 0, 20, 20, 7, 20, 20, 20, 20, 20, 20, 20, 8,
- 21, 0, 22, 0, 7, 23, 24, 0, 20, 20, 25, 0, 0, 0, 26, 27,
- 1, 7, 20, 20, 20, 20, 20, 1, 28, 29, 30, 31, 0, 0, 20, 0,
- 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 20, 20,
- 20, 1, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, 7, 20, 20, 20,
- 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, 38, 1, 20, 20,
- 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, 0, 0, 1, 0,
- 0, 40, 1, 1, 0, 0, 8, 21, 0, 1, 0, 1, 0, 1, 0, 0,
- 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 7, 20, 41,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, 43, 44, 0, 45,
- 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 46, 7, 1, 10, 1,
- 0, 0, 0, 1, 20, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 26, 34, 9, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0,
- 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 3, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3,
- 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24, 25, 26, 13, 13,
- 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42, 7, 7, 43, 13,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2,
+ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8,
+ 9, 0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0,
+ 23, 24, 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0,
+ 0, 0, 0, 33, 34, 35, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 1, 2, 40, 41,
+ 0, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0,
+ 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0,
+ 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10,
+ 0, 0, 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0,
+ 0, 0, 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7,
+ 20, 20, 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0,
+ 20, 20, 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1,
+ 28, 29, 30, 31, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0,
+ 0, 0, 0, 0, 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4,
+ 0, 10, 0, 33, 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35,
+ 36, 34, 37, 0, 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8,
+ 21, 1, 20, 0, 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21,
+ 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 21, 0, 42, 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0,
+ 0, 0, 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 20, 20,
+ 1, 20, 20, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 12, 13,
+ 13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 13, 22, 13, 13, 13,
+ 13, 23, 24, 24, 25, 26, 13, 13, 13, 27, 28, 29, 13, 30, 31, 32,
+ 33, 34, 35, 36, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7,
+ 7, 41, 13, 42, 7, 7, 43, 7, 44, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
@@ -3459,130 +3501,131 @@ _hb_ucd_u8[17564] =
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 44, 0, 0, 1,
- 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, 53, 54, 55, 56,
- 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61,
- 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
- 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 13, 13, 13, 13, 45, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 37,
+ 37, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 2, 2, 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59,
+ 59, 59, 59, 59, 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 80, 80,
- 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84, 85, 86, 87, 88,
- 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 79, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81,
+ 82, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 96, 96,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, 97, 98, 99,100,101,101,
+ 102,103,104,105,106,107,108,109,110,111, 96,112,113,114,115,116,
+ 117,118,119,119,120,121,122,123,124,125,126,127,128,129,130,131,
+ 132, 96,133,134,135,136,137,138,139,140,141,142,143, 96,144,145,
+ 96,146,147,148,149, 96,150,151,152,153,154,155,156, 96,157,158,
+ 159,160, 96,161,162,163,164,164,164,164,164,164,164,165,166,164,
+ 167, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96,168,169,169,169,169,169,169,169,169,170, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,171,171,
+ 171,171,172, 96, 96, 96,173,173,173,173,174,175,176,177, 96, 96,
+ 96, 96,178,179,180,181,182,182,182,182,182,182,182,182,182,182,
+ 182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+ 182,182,182,182,182,183,182,182,182,182,182,182,184,184,184,185,
+ 186, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96,187,188,189,190,191,191,192, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,193,194,
96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 70, 70, 97, 98, 99,100,101,101,102,103,104,105,106,107,108,109,
- 110,111, 96,112,113,114,115,116,117,118,119,119,120,121,122,123,
- 124,125,126,127,128,129,130,131,132, 96,133,134,135,136,137,138,
- 139,140,141,142,143, 96,144,145, 96,146,147,148,149, 96,150,151,
- 152,153,154,155, 96, 96,156,157,158,159, 96,160, 96,161,162,162,
- 162,162,162,162,162,163,164,162,165, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,166,167,167,
- 167,167,167,167,167,167,168, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96,169,169,169,169,170, 96, 96, 96,171,171,
- 171,171,172,173,174,175, 96, 96, 96, 96,176,177,178,179,180,180,
- 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
- 180,180,180,180,180,180,180,180,180,180,180,180,180,181,180,180,
- 180,180,180,180,182,182,182,183,184, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,185,186,187,
- 188,189,189,190, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96,191,192, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,193,194, 59,195,
- 196,197,198,199,200, 96,201,202,203, 59, 59,204, 59,205,206,206,
- 206,206,206,207, 96, 96, 96, 96, 96, 96, 96, 96,208, 96,209, 96,
- 210, 96, 96,211, 96, 96, 96, 96, 96, 96, 96, 96, 96,212,213,214,
- 215, 96, 96, 96, 96, 96,216,217,218, 96,219,220, 96, 96,221,222,
- 59,223,224, 96, 59, 59, 59, 59, 59, 59, 59,225,226,227,228,229,
- 59, 59,230,231, 59,232, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,233, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,234, 70,235, 70,
+ 96, 96, 96, 96,195,196, 59,197,198,199,200,201,202, 96,203,204,
+ 205, 59, 59,206, 59,207,208,208,208,208,208,209, 96, 96, 96, 96,
+ 96, 96, 96, 96,210, 96,211,212,213, 96, 96,214, 96, 96, 96,215,
+ 96, 96, 96, 96, 96,216,217,218,219, 96, 96, 96, 96, 96,220,221,
+ 222, 96,223,224, 96, 96,225,226, 59,227,228, 96, 59, 59, 59, 59,
+ 59, 59, 59,229,230,231,232,233, 59, 59,234,235, 59,236, 96, 96,
+ 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70,237, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70,238, 70,239, 70, 70, 70, 70, 70, 70, 70, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,236, 70, 70, 70, 70,
- 70, 70, 70, 70, 70,237, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
- 70, 70,238, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
- 70, 70, 70, 70,239, 96, 96, 96, 96, 96, 96, 96, 96, 96,240, 96,
- 241,242, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0,
- 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 0, 19, 0,
- 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0,
- 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9,
- 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2,
- 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9,
- 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4, 4, 4, 2, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2,
- 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14,
- 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3,
- 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3,
- 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90,
- 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90,
- 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
- 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2, 2, 2, 3, 3,
- 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3,
- 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1,
- 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 5, 5,
- 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2,
- 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
- 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5,
- 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 2, 2, 2,
- 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 5, 5, 5,
- 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 11,
- 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2,
- 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2,
- 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11,
- 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11, 2, 2, 2, 11,
- 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, 11, 2, 2, 2,
- 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 10,
- 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10,
- 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2,
- 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10,
- 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 2, 2, 10, 2,
- 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10,
- 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 2, 21,
- 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2,
- 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2,
- 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21,
- 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 2, 2, 2, 2,
- 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21,
- 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22,
- 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22,
- 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 22, 22, 22, 2,
- 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22,
- 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23,
- 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 2,
- 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 23, 2, 2, 23, 23,
- 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16,
- 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2,
- 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 2, 16,
- 16, 2, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 2, 2,
- 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, 36,
- 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36,
- 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2,
- 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2,
- 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2, 2, 2, 2, 18,
- 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18,
- 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18,
+ 70, 70, 70,240, 70, 70, 70, 70, 70, 70, 70, 70, 70,241, 96, 96,
+ 96, 96, 96, 96, 96, 96, 70, 70, 70, 70,242, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70,243, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,244, 96, 96,
+ 96, 96, 96, 96, 96, 96,245, 96,246,247, 0, 1, 2, 2, 0, 1,
+ 2, 2, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 19, 19,
+ 19, 19, 19, 19, 19, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19,
+ 19, 19, 19, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2,
+ 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9,
+ 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 2, 9, 9, 9, 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 1, 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4,
+ 4, 2, 2, 4, 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 14, 14,
+ 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 0, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37,
+ 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+ 2, 2, 2, 2, 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, 2, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37,
+ 37, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3,
+ 2, 2, 2, 2, 2, 2, 3, 3, 0, 3, 3, 3, 3, 3, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7,
+ 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5,
+ 5, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2,
+ 5, 2, 2, 2, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2,
+ 2, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2,
+ 2, 2, 5, 5, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11,
+ 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2,
+ 11, 11, 2, 11, 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 2,
+ 2, 11, 11, 11, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11,
+ 11, 11, 11, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2,
+ 10, 10, 2, 10, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10,
+ 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10,
+ 10, 10, 2, 2, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10,
+ 10, 10, 10, 10, 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21,
+ 21, 21, 21, 2, 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2,
+ 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2,
+ 2, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2,
+ 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2,
+ 22, 22, 2, 22, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2,
+ 22, 22, 22, 22, 2, 2, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2,
+ 2, 22, 22, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 2, 2, 2, 2, 22, 22, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2,
+ 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2,
+ 23, 23, 23, 23, 23, 23, 23, 23, 2, 2, 23, 23, 23, 23, 23, 2,
+ 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23,
+ 23, 2, 2, 23, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, 2,
+ 2, 2, 2, 2, 2, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 2, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 2, 16, 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, 16, 2,
+ 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 16, 16,
+ 16, 16, 2, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, 2, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2,
+ 20, 20, 20, 20, 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20,
+ 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,
+ 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 36,
+ 36, 36, 36, 2, 36, 2, 2, 2, 2, 2, 2, 2, 36, 36, 2, 2,
+ 36, 36, 36, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24,
+ 24, 24, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18,
+ 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18,
+ 18, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 18, 18,
2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 2, 2, 25, 25,
25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25,
@@ -3741,49 +3784,50 @@ _hb_ucd_u8[17564] =
130, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,144,144,
144,144,144,144,144,144,144,144, 2, 2, 2, 2, 2, 2,156,156,
156,156,156,156,156,156,156,156, 2,156,156,156, 2, 2,156,156,
- 2, 2, 2, 2, 2, 2,147,147,147,147,147,147,147,147,148,148,
- 148,148,148,148,148,148,148,148, 2, 2, 2, 2, 2, 2,158,158,
- 158,158,158,158,158,158,158,158, 2, 2, 2, 2, 2, 2,153,153,
- 153,153,153,153,153,153,153,153,153,153, 2, 2, 2, 2,149,149,
- 149,149,149,149,149,149,149,149,149,149,149,149,149, 2, 94, 94,
- 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2,
- 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2, 2, 94, 85, 85,
- 85, 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,101,101,101, 2,
- 2, 2, 2, 2, 2, 2,101,101, 2, 2, 2, 2, 2, 2, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 96, 96,111,111,
- 111,111,111,111,111,111,111,111,111,111,111,111,111, 2,100,100,
- 100,100,100,100,100,100, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 2, 2, 2,108,108,108,108,108,108,108,108,108,108,
- 2,108,108,108,108,108,108,108,108,108,108,108,108, 2,129,129,
- 129,129,129,129,129, 2,129, 2,129,129,129,129, 2,129,129,129,
- 129,129,129,129,129,129,129,129,129,129,129,129, 2,129,129,129,
- 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109,
- 109, 2, 2, 2, 2, 2,109,109, 2, 2, 2, 2, 2, 2,107,107,
- 107,107, 2,107,107,107,107,107,107,107,107, 2, 2,107,107, 2,
- 2,107,107,107,107,107,107,107,107,107,107,107,107,107,107, 2,
- 107,107,107,107,107,107,107, 2,107,107, 2,107,107,107,107,107,
- 2, 1,107,107,107,107,107, 2, 2,107,107,107, 2, 2,107, 2,
- 2, 2, 2, 2, 2,107, 2, 2, 2, 2, 2,107,107,107,107,107,
- 107,107, 2, 2,107,107,107,107,107,107,107, 2, 2, 2,137,137,
- 137,137,137,137,137,137,137,137,137,137, 2,137,137,137,137,137,
- 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124,
- 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,123,123,123,123,
- 123,123,123,123, 2, 2,114,114,114,114,114,114,114,114,114,114,
- 114,114,114, 2, 2, 2,114,114, 2, 2, 2, 2, 2, 2, 32, 32,
- 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,102,102,102,102,
- 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,126,126,126,126,
- 126, 2, 2,126,126,126,126,126,126,126, 2, 2, 2, 2,126,126,
- 126,126,126,126,126, 2,142,142,142,142,142,142,142,142,142,142,
- 142,142, 2, 2, 2, 2,125,125,125,125,125,125,125,125,125,125,
- 125, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,125,154,154,
- 154,154,154,154,154, 2, 2,154, 2, 2,154,154,154,154,154,154,
- 154,154, 2,154,154, 2,154,154,154,154,154,154,154,154,154,154,
- 154,154,154,154, 2,154,154, 2, 2,154,154,154,154,154,154,154,
- 2, 2, 2, 2, 2, 2,150,150,150,150,150,150,150,150, 2, 2,
- 150,150,150,150,150,150,150,150,150,150,150, 2, 2, 2,141,141,
- 141,141,141,141,141,141,140,140,140,140,140,140,140,140,140,140,
- 140, 2, 2, 2, 2, 2,121,121,121,121,121,121,121,121,121, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,147,147,
+ 147,147,147,147,147,147,148,148,148,148,148,148,148,148,148,148,
+ 2, 2, 2, 2, 2, 2,158,158,158,158,158,158,158,158,158,158,
+ 2, 2, 2, 2, 2, 2,153,153,153,153,153,153,153,153,153,153,
+ 153,153, 2, 2, 2, 2,149,149,149,149,149,149,149,149,149,149,
+ 149,149,149,149,149, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2,
+ 2, 2, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+ 85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 85, 2, 2,101,101,
+ 101,101,101,101,101,101,101, 2, 2, 2, 2, 2, 2, 2,101,101,
+ 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 2, 96, 96,111,111,111,111,111,111,111,111,111,111,
+ 111,111,111,111,111, 2,100,100,100,100,100,100,100,100, 2, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,108,108,
+ 108,108,108,108,108,108,108,108, 2,108,108,108,108,108,108,108,
+ 2, 2, 2, 2, 2, 2,129,129,129,129,129,129,129, 2,129, 2,
+ 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129,
+ 129,129,129,129, 2,129,129,129, 2, 2, 2, 2, 2, 2,109,109,
+ 109,109,109,109,109,109,109,109,109, 2, 2, 2, 2, 2,109,109,
+ 2, 2, 2, 2, 2, 2,107,107,107,107, 2,107,107,107,107,107,
+ 107,107,107, 2, 2,107,107, 2, 2,107,107,107,107,107,107,107,
+ 107,107,107,107,107,107,107, 2,107,107,107,107,107,107,107, 2,
+ 107,107, 2,107,107,107,107,107, 2, 1,107,107,107,107,107, 2,
+ 2,107,107,107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2,
+ 2, 2, 2,107,107,107,107,107,107,107, 2, 2,107,107,107,107,
+ 107,107,107, 2, 2, 2,137,137,137,137,137,137,137,137,137,137,
+ 137,137, 2,137,137,137,137,137, 2, 2, 2, 2, 2, 2,124,124,
+ 124,124,124,124,124,124,124,124, 2, 2, 2, 2, 2, 2,123,123,
+ 123,123,123,123,123,123,123,123,123,123,123,123, 2, 2,114,114,
+ 114,114,114,114,114,114,114,114,114,114,114, 2, 2, 2,114,114,
+ 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 2, 2, 2,102,102,
+ 102,102,102,102,102,102,102,102, 2, 2, 2, 2, 2, 2,126,126,
+ 126,126,126,126,126,126,126,126,126, 2, 2,126,126,126,126,126,
+ 126,126, 2, 2, 2, 2,126,126,126,126,126,126,126, 2,142,142,
+ 142,142,142,142,142,142,142,142,142,142, 2, 2, 2, 2,125,125,
+ 125,125,125,125,125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154,
+ 2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,154,154,
+ 154,154,154,154,154,154,154,154,154,154,154,154, 2,154,154, 2,
+ 2,154,154,154,154,154,154,154, 2, 2, 2, 2, 2, 2,150,150,
+ 150,150,150,150,150,150, 2, 2,150,150,150,150,150,150,150,150,
+ 150,150,150, 2, 2, 2,141,141,141,141,141,141,141,141,140,140,
+ 140,140,140,140,140,140,140,140,140, 2, 2, 2, 2, 2,121,121,
+ 121,121,121,121,121,121,121, 2, 2, 2, 2, 2, 2, 2, 7, 7,
2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133, 2,
133,133,133,133,133,133,133,133,133,133,133,133,133, 2,133,133,
133,133,133,133, 2, 2,133,133,133,133,133, 2, 2, 2,134,134,
@@ -3795,29 +3839,31 @@ _hb_ucd_u8[17564] =
143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
143,143,143,143,143, 2,143,143, 2,143,143,143,143,143,143, 2,
2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, 2, 2, 2,145,145,
- 145,145,145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2, 86, 2,
+ 145,145,145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2,163,163,
+ 163,163,163,163,163,163,163, 2,163,163,163,163,163,163,163,163,
+ 163, 2, 2, 2,163,163,163,163, 2, 2, 2, 2, 2, 2, 86, 2,
2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 2, 63, 63,
63, 63, 63, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2,157,157,
157,157,157,157,157,157,157,157,157, 2, 2, 2, 2, 2, 80, 80,
- 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, 80, 2,
- 2, 2, 2, 2, 2, 2,127,127,127,127,127,127,127,127,127,127,
- 127,127,127,127,127, 2, 79, 2, 2, 2, 2, 2, 2, 2,115,115,
- 115,115,115,115,115,115,115,115,115,115,115,115,115, 2,115,115,
- 2, 2, 2, 2,115,115,159,159,159,159,159,159,159,159,159,159,
- 159,159,159,159,159, 2,159,159, 2, 2, 2, 2, 2, 2,103,103,
- 103,103,103,103,103,103,103,103,103,103,103,103, 2, 2,119,119,
- 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2,119,119,
- 2,119,119,119,119,119, 2, 2, 2, 2, 2,119,119,119,146,146,
- 146,146,146,146,146,146,146,146,146, 2, 2, 2, 2, 2, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 99, 2, 2,
- 2, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, 2, 2,136,136,
- 136,136,136,136,136,136,155,155,155,155,155,155,155,155,155,155,
- 155,155,155,155, 2, 2,136, 2, 2, 2, 2, 2, 2, 2, 17, 17,
- 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17, 17, 2, 17, 15,
- 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, 2, 2, 15, 15,
- 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17,139,139,
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, 2,127,127,
+ 127,127,127,127,127,127,127,127,127,127,127,127,127, 2, 79, 2,
+ 2, 2, 2, 2, 2, 2,115,115,115,115,115,115,115,115,115,115,
+ 115,115,115,115,115, 2,115,115, 2, 2, 2, 2,115,115,159,159,
+ 159,159,159,159,159,159,159,159,159,159,159,159,159, 2,159,159,
+ 2, 2, 2, 2, 2, 2,103,103,103,103,103,103,103,103,103,103,
+ 103,103,103,103, 2, 2,119,119,119,119,119,119,119,119,119,119,
+ 119,119,119,119, 2, 2,119,119, 2,119,119,119,119,119, 2, 2,
+ 2, 2, 2,119,119,119,146,146,146,146,146,146,146,146,146,146,
+ 146, 2, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, 99,136,139,
+ 13, 13,155, 2, 2, 2,136,136,136,136,136,136,136,136,155,155,
+ 155,155,155,155,155,155,155,155,155,155,155,155, 2, 2,136, 2,
+ 2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 17, 17, 17, 17, 17,
+ 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17,
+ 17, 2, 2, 2, 2, 2, 2, 2, 15, 2, 2, 2, 2, 2, 15, 15,
+ 15, 2, 2, 17, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17,139,139,
139,139,139,139,139,139,139,139,139,139, 2, 2, 2, 2,105,105,
105,105,105,105,105,105,105,105,105, 2, 2, 2, 2, 2,105,105,
105,105,105, 2, 2, 2,105, 2, 2, 2, 2, 2, 2, 2,105,105,
@@ -3831,24 +3877,27 @@ _hb_ucd_u8[17564] =
0, 0, 0, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0,131,131,131,131,131,131,131,131,131,131,
131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2,131,
- 131,131,131,131,131,131, 56, 56, 56, 56, 56, 56, 56, 2, 56, 2,
- 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, 56, 56, 56, 56,
- 56, 2, 2, 2, 2, 2,151,151,151,151,151,151,151,151,151,151,
- 151,151,151, 2, 2, 2,151,151,151,151,151,151, 2, 2,151,151,
- 2, 2, 2, 2,151,151,160,160,160,160,160,160,160,160,160,160,
- 160,160,160,160,160, 2,152,152,152,152,152,152,152,152,152,152,
- 2, 2, 2, 2, 2,152, 30, 30, 30, 30, 2, 30, 30, 2,113,113,
- 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113,
- 113,113,113,113,113, 2,132,132,132,132,132,132,132,132,132,132,
- 132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,132,132, 3, 3,
- 3, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3,
- 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3,
- 2, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
- 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2,
- 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 0, 0, 0, 13, 2, 2, 2, 2, 2, 2, 2, 13, 13,
+ 131,131,131,131,131,131, 2, 2, 2, 2, 2, 19, 19, 19, 56, 56,
+ 56, 56, 56, 56, 56, 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56,
+ 2, 56, 56, 2, 56, 56, 56, 56, 56, 2, 2, 2, 2, 2, 6, 6,
+ 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,151,151,
+ 151,151,151,151,151,151,151,151,151,151,151, 2, 2, 2,151,151,
+ 151,151,151,151, 2, 2,151,151, 2, 2, 2, 2,151,151,160,160,
+ 160,160,160,160,160,160,160,160,160,160,160,160,160, 2,152,152,
+ 152,152,152,152,152,152,152,152, 2, 2, 2, 2, 2,152,164,164,
+ 164,164,164,164,164,164,164,164, 2, 2, 2, 2, 2, 2, 30, 30,
+ 30, 30, 2, 30, 30, 2,113,113,113,113,113,113,113,113,113,113,
+ 113,113,113, 2, 2,113,113,113,113,113,113,113,113, 2,132,132,
+ 132,132,132,132,132,132,132,132,132,132, 2, 2, 2, 2,132,132,
+ 2, 2, 2, 2,132,132, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3,
+ 3, 2, 3, 2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2,
+ 3, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, 3,
+ 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 3,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3,
+ 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2,
+ 2, 0, 0, 0, 0, 0, 13, 2, 2, 2, 2, 2, 2, 2, 13, 13,
13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13,
9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9,
@@ -3926,7 +3975,7 @@ _hb_ucd_u8[17564] =
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
};
static const uint16_t
-_hb_ucd_u16[9200] =
+_hb_ucd_u16[9320] =
{
0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12,
13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23,
@@ -4000,509 +4049,517 @@ _hb_ucd_u16[9200] =
48, 48, 48, 468, 48, 469, 48, 470, 48, 471, 472, 140, 140, 140, 140, 140,
48, 48, 48, 48, 196, 140, 140, 140, 9, 9, 9, 473, 11, 11, 11, 474,
48, 48, 475, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 271, 476,
- 48, 48, 477, 478, 140, 140, 140, 140, 48, 464, 479, 48, 62, 480, 140, 48,
- 481, 140, 140, 48, 482, 140, 48, 314, 483, 48, 48, 484, 485, 457, 486, 487,
- 222, 48, 48, 488, 489, 48, 196, 192, 490, 48, 491, 492, 493, 48, 48, 494,
- 222, 48, 48, 495, 496, 497, 498, 499, 48, 97, 500, 501, 140, 140, 140, 140,
- 502, 503, 504, 48, 48, 505, 506, 192, 507, 83, 84, 508, 509, 510, 511, 512,
- 48, 48, 48, 513, 514, 515, 478, 140, 48, 48, 48, 516, 517, 192, 140, 140,
- 48, 48, 518, 519, 520, 521, 140, 140, 48, 48, 48, 522, 523, 192, 524, 140,
- 48, 48, 525, 526, 192, 140, 140, 140, 48, 173, 527, 528, 314, 140, 140, 140,
- 48, 48, 500, 529, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 530,
- 531, 532, 48, 533, 534, 192, 140, 140, 140, 140, 535, 48, 48, 536, 537, 140,
- 538, 48, 48, 539, 540, 541, 48, 48, 542, 543, 544, 48, 48, 48, 48, 196,
- 84, 48, 518, 545, 546, 148, 175, 547, 48, 548, 549, 550, 140, 140, 140, 140,
- 551, 48, 48, 552, 553, 192, 554, 48, 555, 556, 192, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 48, 557, 140, 140, 140, 100, 271, 558, 559, 560,
- 48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 561, 562,
- 48, 48, 48, 48, 388, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 563,
- 48, 48, 200, 564, 140, 140, 140, 140, 48, 48, 48, 48, 314, 140, 140, 140,
- 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 565,
- 48, 48, 48, 566, 567, 568, 569, 570, 48, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 9, 9, 11, 11, 271, 571, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 572, 573, 574, 574, 575, 576, 140, 140, 140, 140, 577, 578,
+ 48, 48, 477, 478, 140, 140, 140, 479, 48, 464, 480, 48, 62, 481, 140, 48,
+ 482, 140, 140, 48, 483, 140, 48, 314, 484, 48, 48, 485, 486, 457, 487, 488,
+ 222, 48, 48, 489, 490, 48, 196, 192, 491, 48, 492, 493, 494, 48, 48, 495,
+ 222, 48, 48, 496, 497, 498, 499, 500, 48, 97, 501, 502, 503, 140, 140, 140,
+ 504, 505, 506, 48, 48, 507, 508, 192, 509, 83, 84, 510, 511, 512, 513, 514,
+ 48, 48, 48, 515, 516, 517, 478, 140, 48, 48, 48, 518, 519, 192, 140, 140,
+ 48, 48, 520, 521, 522, 523, 140, 140, 48, 48, 48, 524, 525, 192, 526, 140,
+ 48, 48, 527, 528, 192, 140, 140, 140, 48, 173, 529, 530, 314, 140, 140, 140,
+ 48, 48, 501, 531, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 532,
+ 533, 534, 48, 535, 536, 192, 140, 140, 140, 140, 537, 48, 48, 538, 539, 140,
+ 540, 48, 48, 541, 542, 543, 48, 48, 544, 545, 546, 48, 48, 48, 48, 196,
+ 547, 140, 140, 140, 140, 140, 140, 140, 84, 48, 520, 548, 549, 148, 175, 550,
+ 48, 551, 552, 553, 140, 140, 140, 140, 554, 48, 48, 555, 556, 192, 557, 48,
+ 558, 559, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 560,
+ 561, 115, 48, 562, 563, 192, 140, 140, 140, 140, 140, 100, 271, 564, 565, 566,
+ 48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 567, 568,
+ 48, 48, 48, 48, 388, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 569,
+ 48, 48, 48, 570, 571, 572, 140, 140, 48, 48, 48, 48, 314, 140, 140, 140,
+ 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 573,
+ 48, 48, 48, 574, 575, 576, 577, 578, 48, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 9, 9, 11, 11, 271, 579, 140, 140, 140, 140, 140, 140,
+ 48, 48, 48, 48, 580, 581, 582, 582, 583, 584, 140, 140, 140, 140, 585, 586,
48, 48, 48, 48, 48, 48, 48, 440, 48, 48, 48, 48, 48, 199, 140, 140,
- 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 579,
- 48, 48, 580, 140, 140, 580, 581, 48, 48, 48, 48, 48, 48, 48, 48, 206,
- 48, 48, 48, 48, 48, 48, 71, 151, 196, 582, 583, 140, 140, 140, 140, 140,
- 32, 32, 584, 32, 585, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
- 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 586, 209, 209, 209, 587, 588,
- 589, 209, 590, 209, 209, 209, 288, 140, 209, 209, 209, 209, 591, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 271, 592, 209, 209, 209, 209, 209, 287, 271, 461,
- 9, 593, 11, 594, 595, 596, 241, 9, 597, 598, 599, 600, 601, 9, 593, 11,
- 602, 603, 11, 604, 605, 606, 607, 9, 608, 11, 9, 593, 11, 594, 595, 11,
- 241, 9, 597, 607, 9, 608, 11, 9, 593, 11, 609, 9, 610, 611, 612, 613,
- 11, 614, 9, 615, 616, 617, 618, 11, 619, 9, 620, 11, 621, 622, 622, 622,
- 32, 32, 32, 623, 32, 32, 624, 625, 626, 627, 45, 140, 140, 140, 140, 140,
- 628, 629, 140, 140, 140, 140, 140, 140, 630, 631, 632, 140, 140, 140, 140, 140,
- 48, 48, 151, 633, 634, 140, 140, 140, 140, 48, 635, 140, 48, 48, 636, 637,
- 140, 140, 140, 140, 140, 140, 638, 200, 48, 48, 48, 48, 639, 585, 140, 140,
- 9, 9, 597, 11, 640, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 498,
- 271, 271, 641, 642, 140, 140, 140, 140, 498, 271, 643, 644, 140, 140, 140, 140,
- 645, 48, 646, 647, 648, 649, 650, 651, 652, 206, 653, 206, 140, 140, 140, 654,
- 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 655, 655, 655, 209, 324,
- 656, 209, 209, 209, 209, 209, 209, 209, 209, 209, 657, 140, 140, 140, 658, 209,
- 659, 209, 209, 325, 660, 661, 324, 140, 209, 209, 209, 209, 209, 209, 209, 662,
- 209, 209, 209, 209, 209, 663, 426, 426, 209, 209, 209, 209, 209, 209, 209, 323,
- 209, 209, 209, 209, 209, 660, 325, 427, 325, 209, 209, 209, 664, 176, 209, 209,
- 664, 209, 657, 661, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 657, 665,
- 287, 209, 426, 288, 324, 176, 664, 287, 209, 666, 209, 209, 288, 140, 140, 192,
- 48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 196, 48, 48, 48, 48,
+ 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 587,
+ 48, 48, 588, 589, 140, 590, 591, 48, 48, 48, 48, 48, 48, 48, 48, 206,
+ 48, 48, 48, 48, 48, 48, 71, 151, 196, 592, 593, 140, 140, 140, 140, 140,
+ 32, 32, 594, 32, 595, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
+ 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 596, 209, 209, 209, 597, 598,
+ 599, 209, 600, 209, 209, 209, 288, 140, 209, 209, 209, 209, 601, 140, 140, 140,
+ 140, 140, 140, 140, 271, 602, 271, 602, 209, 209, 209, 209, 209, 287, 271, 461,
+ 9, 603, 11, 604, 605, 606, 241, 9, 607, 608, 609, 610, 611, 9, 603, 11,
+ 612, 613, 11, 614, 615, 616, 617, 9, 618, 11, 9, 603, 11, 604, 605, 11,
+ 241, 9, 607, 617, 9, 618, 11, 9, 603, 11, 619, 9, 620, 621, 622, 623,
+ 11, 624, 9, 625, 626, 627, 628, 11, 629, 9, 630, 11, 631, 632, 632, 632,
+ 32, 32, 32, 633, 32, 32, 634, 635, 636, 637, 45, 140, 140, 140, 140, 140,
+ 638, 639, 640, 140, 140, 140, 140, 140, 641, 642, 643, 27, 27, 27, 644, 140,
+ 645, 140, 140, 140, 140, 140, 140, 140, 48, 48, 151, 646, 647, 140, 140, 140,
+ 140, 48, 648, 140, 48, 48, 649, 650, 140, 140, 140, 140, 140, 48, 651, 192,
+ 140, 140, 140, 140, 140, 140, 652, 200, 48, 48, 48, 48, 653, 595, 140, 140,
+ 9, 9, 607, 11, 654, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 499,
+ 271, 271, 655, 656, 140, 140, 140, 140, 499, 271, 657, 658, 140, 140, 140, 140,
+ 659, 48, 660, 661, 662, 663, 664, 665, 666, 206, 667, 206, 140, 140, 140, 668,
+ 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 669, 669, 669, 209, 324,
+ 670, 209, 209, 209, 209, 209, 209, 209, 209, 209, 671, 140, 140, 140, 672, 209,
+ 673, 209, 209, 325, 674, 675, 324, 140, 209, 209, 209, 209, 209, 209, 209, 676,
+ 209, 209, 209, 209, 209, 677, 426, 426, 209, 209, 209, 209, 209, 209, 209, 678,
+ 209, 209, 209, 209, 209, 176, 325, 427, 325, 209, 209, 209, 679, 176, 209, 209,
+ 679, 209, 671, 675, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 671, 426,
+ 674, 209, 209, 680, 681, 325, 674, 674, 209, 682, 209, 209, 288, 140, 140, 192,
+ 48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 207, 48, 48, 48, 48,
48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 478, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 100, 140, 48, 204, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 71, 140, 140, 140, 667, 140, 668, 668, 668, 668, 668, 668,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140,
- 391, 391, 391, 391, 391, 391, 391, 669, 391, 391, 391, 391, 391, 391, 391, 670,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3,
- 0, 0, 0, 0, 0, 4, 0, 4, 2, 2, 5, 2, 2, 2, 5, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 6, 0, 0, 0, 0, 7, 8, 0, 0,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 11,
- 12, 13, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, 16, 17, 14, 14,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 20, 21, 21, 21, 22, 20, 21, 21, 21, 21,
- 21, 23, 24, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 27, 28, 26,
- 29, 30, 31, 32, 31, 31, 31, 31, 33, 34, 35, 31, 31, 31, 36, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 29, 31, 31, 31, 31,
- 37, 38, 37, 37, 37, 37, 37, 37, 37, 39, 31, 31, 31, 31, 31, 31,
- 40, 40, 40, 40, 40, 40, 41, 26, 42, 42, 42, 42, 42, 42, 42, 43,
- 44, 44, 44, 44, 44, 45, 44, 46, 47, 47, 47, 48, 37, 49, 31, 31,
- 31, 50, 51, 31, 31, 31, 31, 31, 31, 31, 31, 31, 52, 31, 31, 31,
- 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 53, 55, 53, 53, 53,
- 56, 57, 58, 59, 59, 60, 61, 62, 57, 63, 64, 65, 66, 59, 59, 67,
- 68, 69, 70, 71, 71, 72, 73, 74, 69, 75, 76, 77, 78, 71, 79, 26,
- 80, 81, 82, 83, 83, 84, 85, 86, 81, 87, 88, 26, 89, 83, 90, 91,
- 92, 93, 94, 95, 95, 96, 97, 98, 93, 99, 100, 101, 102, 95, 95, 26,
- 103, 104, 105, 106, 107, 104, 108, 109, 104, 105, 110, 26, 111, 108, 108, 112,
- 113, 114, 115, 113, 113, 115, 113, 116, 114, 117, 118, 119, 120, 113, 121, 113,
- 122, 123, 124, 122, 122, 124, 125, 126, 123, 127, 128, 128, 129, 122, 130, 26,
- 131, 132, 133, 131, 131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131,
- 136, 137, 138, 139, 137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145, 26,
- 146, 147, 147, 147, 147, 147, 147, 148, 147, 147, 147, 149, 26, 26, 26, 26,
- 150, 151, 152, 152, 153, 152, 152, 154, 155, 154, 152, 156, 26, 26, 26, 26,
- 157, 157, 157, 157, 157, 157, 157, 157, 157, 158, 157, 157, 157, 159, 158, 157,
- 157, 157, 157, 158, 157, 157, 157, 160, 157, 160, 161, 162, 26, 26, 26, 26,
- 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163,
- 163, 163, 163, 163, 164, 164, 164, 164, 165, 166, 164, 164, 164, 164, 164, 167,
- 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
- 169, 169, 169, 169, 169, 169, 169, 169, 169, 170, 171, 170, 169, 169, 169, 169,
- 169, 170, 169, 169, 169, 169, 170, 171, 170, 169, 171, 169, 169, 169, 169, 169,
- 169, 169, 170, 169, 169, 169, 169, 169, 169, 169, 169, 172, 169, 169, 169, 173,
- 169, 169, 169, 174, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 176,
- 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
- 178, 178, 178, 179, 180, 180, 180, 180, 180, 180, 180, 180, 180, 181, 180, 182,
- 183, 183, 184, 185, 186, 186, 187, 26, 188, 188, 189, 26, 190, 191, 192, 26,
- 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 194, 193, 195, 193, 195,
- 196, 197, 197, 198, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 199,
- 197, 197, 197, 197, 197, 200, 177, 177, 177, 177, 177, 177, 177, 177, 201, 26,
- 202, 202, 202, 203, 202, 204, 202, 204, 205, 202, 206, 206, 206, 207, 208, 26,
- 209, 209, 209, 209, 209, 210, 209, 209, 209, 211, 209, 212, 193, 193, 193, 193,
- 213, 213, 213, 214, 215, 215, 215, 215, 215, 215, 215, 216, 215, 215, 215, 217,
- 215, 218, 215, 218, 215, 219, 9, 9, 9, 220, 26, 26, 26, 26, 26, 26,
- 221, 221, 221, 221, 221, 221, 221, 221, 221, 222, 221, 221, 221, 221, 221, 223,
- 224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 226, 227,
- 228, 228, 228, 228, 228, 228, 228, 229, 228, 230, 231, 231, 231, 231, 231, 231,
- 18, 232, 164, 164, 164, 164, 164, 233, 224, 26, 234, 9, 235, 236, 237, 238,
- 2, 2, 2, 2, 239, 240, 2, 2, 2, 2, 2, 241, 242, 243, 2, 244,
- 2, 2, 2, 2, 2, 2, 2, 245, 9, 9, 9, 9, 9, 9, 9, 9,
- 14, 14, 246, 246, 14, 14, 14, 14, 246, 246, 14, 247, 14, 14, 14, 246,
- 14, 14, 14, 14, 14, 14, 248, 14, 248, 14, 249, 250, 14, 14, 251, 252,
- 0, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 255, 256,
- 0, 257, 2, 258, 0, 0, 0, 0, 259, 26, 9, 9, 9, 9, 260, 26,
- 0, 0, 0, 0, 261, 262, 4, 0, 0, 263, 0, 0, 2, 2, 2, 2,
- 2, 264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 140, 140, 140, 140, 140,
+ 683, 140, 570, 570, 570, 570, 570, 570, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 140, 391, 391, 391, 391, 391, 391, 391, 684,
+ 391, 391, 391, 391, 391, 391, 391, 685, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 2, 2, 3, 1, 2, 2, 3, 0, 0, 0, 0, 0, 4, 0, 4,
+ 2, 2, 5, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,
+ 0, 0, 0, 0, 7, 8, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 10, 11, 12, 13, 14, 14, 15, 14, 14, 14,
+ 14, 14, 14, 14, 16, 17, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 19, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 20, 21,
+ 21, 21, 22, 20, 21, 21, 21, 21, 21, 23, 24, 25, 25, 25, 25, 25,
+ 25, 26, 25, 25, 25, 27, 28, 26, 29, 30, 31, 32, 31, 31, 31, 31,
+ 33, 34, 35, 31, 31, 31, 36, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 29, 31, 31, 31, 31, 37, 38, 37, 37, 37, 37, 37, 37,
+ 37, 39, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 41, 26,
+ 42, 42, 42, 42, 42, 42, 42, 43, 44, 44, 44, 44, 44, 45, 44, 46,
+ 47, 47, 47, 48, 37, 49, 31, 31, 31, 50, 51, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 52, 31, 31, 31, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 54, 53, 55, 53, 53, 53, 56, 57, 58, 59, 59, 60, 61, 62,
+ 57, 63, 64, 65, 66, 59, 59, 67, 68, 69, 70, 71, 71, 72, 73, 74,
+ 69, 75, 76, 77, 78, 71, 79, 26, 80, 81, 82, 83, 83, 84, 85, 86,
+ 81, 87, 88, 26, 89, 83, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98,
+ 93, 99, 100, 101, 102, 95, 95, 26, 103, 104, 105, 106, 107, 104, 108, 109,
+ 104, 105, 110, 26, 111, 108, 108, 112, 113, 114, 115, 113, 113, 115, 113, 116,
+ 114, 117, 118, 119, 120, 113, 121, 113, 122, 123, 124, 122, 122, 124, 125, 126,
+ 123, 127, 128, 128, 129, 122, 130, 26, 131, 132, 133, 131, 131, 131, 131, 131,
+ 132, 133, 134, 131, 135, 131, 131, 131, 136, 137, 138, 139, 137, 137, 140, 141,
+ 138, 142, 143, 137, 144, 137, 145, 26, 146, 147, 147, 147, 147, 147, 147, 148,
+ 147, 147, 147, 149, 26, 26, 26, 26, 150, 151, 152, 152, 153, 152, 152, 154,
+ 155, 156, 152, 157, 26, 26, 26, 26, 158, 158, 158, 158, 158, 158, 158, 158,
+ 158, 159, 158, 158, 158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161,
+ 158, 161, 162, 163, 26, 26, 26, 26, 164, 164, 164, 164, 164, 164, 164, 164,
+ 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165,
+ 166, 167, 165, 165, 165, 165, 165, 168, 169, 169, 169, 169, 169, 169, 169, 169,
+ 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170,
+ 170, 171, 172, 171, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 171, 172,
+ 171, 170, 172, 170, 170, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 170,
+ 170, 170, 170, 173, 170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176,
+ 176, 176, 176, 176, 176, 176, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178,
+ 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181,
+ 181, 181, 181, 181, 181, 182, 181, 183, 184, 184, 185, 186, 187, 187, 188, 26,
+ 189, 189, 190, 26, 191, 192, 193, 26, 194, 194, 194, 194, 194, 194, 194, 194,
+ 194, 194, 194, 195, 194, 196, 194, 196, 197, 198, 198, 199, 198, 198, 198, 198,
+ 198, 198, 198, 198, 198, 198, 198, 200, 198, 198, 198, 198, 198, 201, 178, 178,
+ 178, 178, 178, 178, 178, 178, 202, 26, 203, 203, 203, 204, 203, 205, 203, 205,
+ 206, 203, 207, 207, 207, 208, 209, 26, 210, 210, 210, 210, 210, 211, 210, 210,
+ 210, 212, 210, 213, 194, 194, 194, 194, 214, 214, 214, 215, 216, 216, 216, 216,
+ 216, 216, 216, 217, 216, 216, 216, 218, 216, 219, 216, 219, 216, 220, 9, 9,
+ 9, 221, 26, 26, 26, 26, 26, 26, 222, 222, 222, 222, 222, 222, 222, 222,
+ 222, 223, 222, 222, 222, 222, 222, 224, 225, 225, 225, 225, 225, 225, 225, 225,
+ 226, 226, 226, 226, 226, 226, 227, 228, 229, 229, 229, 229, 229, 229, 229, 230,
+ 229, 231, 232, 232, 232, 232, 232, 232, 18, 233, 165, 165, 165, 165, 165, 234,
+ 225, 26, 235, 9, 236, 237, 238, 239, 2, 2, 2, 2, 240, 241, 2, 2,
+ 2, 2, 2, 242, 243, 244, 2, 245, 2, 2, 2, 2, 2, 2, 2, 246,
+ 9, 9, 9, 9, 9, 9, 9, 9, 14, 14, 247, 247, 14, 14, 14, 14,
+ 247, 247, 14, 248, 14, 14, 14, 247, 14, 14, 14, 14, 14, 14, 249, 14,
+ 249, 14, 250, 251, 14, 14, 252, 253, 0, 254, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 255, 0, 256, 257, 0, 258, 2, 259, 0, 0, 0, 0,
+ 260, 26, 9, 9, 9, 9, 261, 26, 0, 0, 0, 0, 262, 263, 4, 0,
+ 0, 264, 0, 0, 2, 2, 2, 2, 2, 265, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 257, 26, 26, 26, 0, 265, 26, 26, 0, 0, 0, 0,
- 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0,
- 0, 0, 268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 2, 2, 2, 2,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 270, 271,
- 164, 164, 164, 164, 165, 166, 272, 272, 272, 272, 272, 272, 272, 273, 274, 273,
- 169, 169, 171, 26, 171, 171, 171, 171, 171, 171, 171, 171, 18, 18, 18, 18,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26,
- 276, 276, 276, 277, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 278, 26,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 26, 26, 26, 0, 280,
- 281, 0, 0, 0, 282, 283, 0, 284, 285, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 287, 288, 289, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291,
- 292, 293, 293, 293, 293, 293, 294, 168, 168, 168, 168, 168, 168, 168, 168, 168,
- 168, 295, 0, 0, 293, 293, 293, 293, 0, 0, 0, 0, 280, 26, 290, 290,
- 168, 168, 168, 295, 0, 0, 0, 0, 0, 0, 0, 0, 168, 168, 168, 296,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 290, 290, 290, 290, 290, 297,
- 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 0, 0, 0, 0, 0,
- 276, 276, 276, 276, 276, 276, 276, 276, 0, 0, 0, 0, 0, 0, 0, 0,
- 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298,
- 298, 299, 298, 298, 298, 298, 298, 298, 300, 26, 301, 301, 301, 301, 301, 301,
- 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302,
- 302, 302, 302, 302, 302, 303, 26, 26, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 26,
- 0, 0, 0, 0, 305, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 306, 2, 2, 2, 2, 2, 2, 2, 307, 308, 309, 26, 26, 310, 2,
- 311, 311, 311, 311, 311, 312, 0, 313, 314, 314, 314, 314, 314, 314, 314, 26,
- 315, 315, 315, 315, 315, 315, 315, 315, 316, 317, 315, 318, 53, 53, 53, 53,
- 319, 319, 319, 319, 319, 320, 321, 321, 321, 321, 322, 323, 168, 168, 168, 324,
- 325, 325, 325, 325, 325, 325, 325, 325, 325, 326, 325, 327, 163, 163, 163, 328,
- 329, 329, 329, 329, 329, 329, 330, 26, 329, 331, 329, 332, 163, 163, 163, 163,
- 333, 333, 333, 333, 333, 333, 333, 333, 334, 26, 26, 335, 336, 336, 337, 26,
- 338, 338, 338, 26, 171, 171, 2, 2, 2, 2, 2, 339, 340, 341, 175, 175,
- 175, 175, 175, 175, 175, 175, 175, 175, 336, 336, 336, 336, 336, 342, 336, 343,
- 168, 168, 168, 168, 344, 26, 168, 168, 295, 345, 168, 168, 168, 168, 168, 344,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 26, 26, 26,
+ 0, 266, 26, 26, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267,
+ 267, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 269, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270,
+ 270, 270, 270, 270, 2, 2, 2, 2, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 271, 272, 165, 165, 165, 165, 166, 167, 273, 273,
+ 273, 273, 273, 273, 273, 274, 275, 274, 170, 170, 172, 26, 172, 172, 172, 172,
+ 172, 172, 172, 172, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 276, 26, 26, 26, 26, 277, 277, 277, 278, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 277, 279, 26, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 280, 26, 26, 26, 0, 281, 282, 0, 0, 0, 283, 284, 0, 285,
+ 286, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288, 289, 290, 291, 291, 291,
+ 291, 291, 291, 291, 291, 291, 291, 292, 293, 294, 294, 294, 294, 294, 295, 169,
+ 169, 169, 169, 169, 169, 169, 169, 169, 169, 296, 0, 0, 294, 294, 294, 294,
+ 0, 0, 0, 0, 281, 26, 291, 291, 169, 169, 169, 296, 0, 0, 0, 0,
+ 0, 0, 0, 0, 169, 169, 169, 297, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 291, 291, 291, 291, 291, 298, 291, 291, 291, 291, 291, 291, 291, 291,
+ 291, 291, 291, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277,
+ 0, 0, 0, 0, 0, 0, 0, 0, 299, 299, 299, 299, 299, 299, 299, 299,
+ 299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 299, 299, 299, 299, 299, 299,
+ 301, 26, 302, 302, 302, 302, 302, 302, 303, 303, 303, 303, 303, 303, 303, 303,
+ 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 304, 26, 26,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 305, 305, 305, 305,
+ 305, 305, 305, 305, 305, 305, 305, 26, 0, 0, 0, 0, 306, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 307, 2, 2, 2, 2, 2, 2,
+ 2, 308, 309, 310, 26, 26, 311, 2, 312, 312, 312, 312, 312, 313, 0, 314,
+ 315, 315, 315, 315, 315, 315, 315, 26, 316, 316, 316, 316, 316, 316, 316, 316,
+ 317, 318, 316, 319, 53, 53, 53, 53, 320, 320, 320, 320, 320, 321, 322, 322,
+ 322, 322, 323, 324, 169, 169, 169, 325, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 327, 326, 328, 164, 164, 164, 329, 330, 330, 330, 330, 330, 330, 331, 26,
+ 330, 332, 330, 333, 164, 164, 164, 164, 334, 334, 334, 334, 334, 334, 334, 334,
+ 335, 26, 26, 336, 337, 337, 338, 26, 339, 339, 339, 26, 172, 172, 2, 2,
+ 2, 2, 2, 340, 341, 342, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176,
+ 337, 337, 337, 337, 337, 343, 337, 344, 169, 169, 169, 169, 345, 26, 169, 169,
+ 296, 346, 169, 169, 169, 169, 169, 345, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 347, 26, 26, 26, 26, 348, 26, 349, 350, 25, 25, 351, 352,
+ 353, 25, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 354, 26, 355, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 356,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 357, 31, 31, 31, 31, 31,
+ 31, 358, 26, 26, 26, 26, 31, 31, 9, 9, 0, 314, 9, 359, 0, 0,
+ 0, 0, 360, 0, 258, 281, 361, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 362, 363, 0, 0, 0, 1, 2, 2, 3,
+ 1, 2, 2, 3, 364, 291, 290, 291, 291, 291, 291, 365, 169, 169, 169, 296,
+ 366, 366, 366, 367, 258, 258, 26, 368, 369, 370, 369, 369, 371, 369, 369, 372,
+ 369, 373, 369, 373, 26, 26, 26, 26, 369, 369, 369, 369, 369, 369, 369, 369,
+ 369, 369, 369, 369, 369, 369, 369, 374, 375, 0, 0, 0, 0, 0, 376, 0,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 253, 0, 377, 378, 26, 26, 26,
+ 26, 26, 0, 0, 0, 0, 0, 379, 380, 380, 380, 381, 382, 382, 382, 382,
+ 382, 382, 383, 26, 384, 0, 0, 281, 385, 385, 385, 385, 386, 387, 388, 388,
+ 388, 389, 390, 390, 390, 390, 390, 391, 392, 392, 392, 393, 394, 394, 394, 394,
+ 395, 394, 396, 26, 26, 26, 26, 26, 397, 397, 397, 397, 397, 397, 397, 397,
+ 397, 397, 398, 398, 398, 398, 398, 398, 399, 399, 399, 400, 399, 401, 402, 402,
+ 402, 402, 403, 402, 402, 402, 402, 403, 404, 404, 404, 404, 404, 26, 405, 405,
+ 405, 405, 405, 405, 406, 407, 408, 409, 408, 409, 410, 408, 411, 408, 411, 412,
+ 26, 26, 26, 26, 26, 26, 26, 26, 413, 413, 413, 413, 413, 413, 413, 413,
+ 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 414, 26,
+ 413, 413, 415, 26, 413, 26, 26, 26, 416, 2, 2, 2, 2, 2, 417, 308,
+ 26, 26, 26, 26, 26, 26, 26, 26, 418, 419, 420, 420, 420, 420, 421, 422,
+ 423, 423, 424, 423, 425, 425, 425, 425, 426, 426, 426, 427, 428, 426, 26, 26,
+ 26, 26, 26, 26, 429, 429, 430, 431, 432, 432, 432, 433, 434, 434, 434, 435,
+ 26, 26, 26, 26, 26, 26, 26, 26, 436, 436, 436, 436, 437, 437, 437, 438,
+ 437, 437, 439, 437, 437, 437, 437, 437, 440, 441, 442, 443, 444, 444, 445, 446,
+ 444, 447, 444, 447, 448, 448, 448, 448, 449, 449, 449, 449, 26, 26, 26, 26,
+ 450, 450, 450, 450, 451, 452, 451, 26, 453, 453, 453, 453, 453, 453, 454, 455,
+ 456, 456, 457, 456, 458, 458, 459, 458, 460, 460, 461, 462, 26, 463, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 464, 464, 464, 464, 464, 464, 464, 464,
+ 464, 465, 26, 26, 26, 26, 26, 26, 466, 466, 466, 466, 466, 466, 467, 26,
+ 466, 466, 466, 466, 466, 466, 467, 468, 469, 469, 469, 469, 469, 26, 469, 470,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 31, 31, 31, 50, 471, 471, 471, 471, 471, 472, 473, 26,
+ 26, 26, 26, 26, 26, 26, 26, 474, 475, 475, 475, 475, 475, 26, 476, 476,
+ 476, 476, 476, 477, 26, 26, 478, 478, 478, 479, 26, 26, 26, 26, 480, 480,
+ 480, 481, 26, 26, 482, 482, 483, 26, 484, 484, 484, 484, 484, 484, 484, 484,
+ 484, 485, 486, 484, 484, 484, 485, 487, 488, 488, 488, 488, 488, 488, 488, 488,
+ 489, 490, 491, 491, 491, 492, 491, 493, 494, 494, 494, 494, 494, 494, 495, 494,
+ 494, 26, 496, 496, 496, 496, 497, 26, 498, 498, 498, 498, 498, 498, 498, 498,
+ 498, 498, 498, 498, 499, 137, 500, 26, 501, 501, 502, 501, 501, 501, 501, 501,
+ 503, 26, 26, 26, 26, 26, 26, 26, 504, 505, 506, 507, 506, 508, 509, 509,
+ 509, 509, 509, 509, 509, 510, 509, 511, 512, 513, 514, 515, 515, 516, 517, 518,
+ 513, 519, 520, 521, 522, 523, 523, 26, 524, 524, 524, 524, 524, 524, 524, 524,
+ 524, 524, 524, 525, 526, 26, 26, 26, 527, 527, 527, 527, 527, 527, 527, 527,
+ 527, 26, 527, 528, 26, 26, 26, 26, 529, 529, 529, 529, 529, 529, 530, 529,
+ 529, 529, 529, 530, 26, 26, 26, 26, 531, 531, 531, 531, 531, 531, 531, 531,
+ 532, 26, 531, 533, 198, 534, 26, 26, 535, 535, 535, 535, 535, 535, 535, 536,
+ 535, 536, 26, 26, 26, 26, 26, 26, 537, 537, 537, 538, 537, 539, 537, 537,
+ 540, 26, 26, 26, 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 542,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 543, 543, 543, 543,
+ 543, 543, 543, 543, 543, 543, 544, 545, 546, 547, 548, 549, 549, 549, 550, 551,
+ 546, 26, 549, 552, 26, 26, 26, 26, 26, 26, 26, 26, 553, 554, 553, 553,
+ 553, 553, 553, 554, 555, 26, 26, 26, 556, 556, 556, 556, 556, 556, 556, 556,
+ 556, 26, 557, 557, 557, 557, 557, 557, 557, 557, 557, 557, 558, 26, 178, 178,
+ 559, 559, 559, 559, 559, 559, 559, 560, 53, 561, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 562, 563, 562, 562, 562, 562, 564, 562,
+ 565, 26, 562, 562, 562, 566, 567, 567, 567, 567, 568, 567, 567, 569, 570, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 571, 572, 573, 573, 573, 573, 571, 574,
+ 573, 26, 573, 575, 576, 577, 578, 578, 578, 579, 580, 581, 578, 582, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 583, 583, 583, 584, 585, 585, 586, 585, 585, 585, 585, 587,
+ 585, 585, 585, 588, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 589, 26,
+ 108, 108, 108, 108, 108, 108, 590, 591, 592, 592, 592, 592, 592, 592, 592, 592,
+ 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 593, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 592, 592, 592, 592, 592, 592, 592, 592,
+ 592, 592, 592, 592, 592, 594, 595, 26, 592, 592, 592, 592, 592, 592, 592, 592,
+ 596, 26, 26, 26, 26, 26, 26, 26, 26, 26, 597, 597, 597, 597, 597, 597,
+ 597, 597, 597, 597, 597, 597, 598, 26, 599, 599, 599, 599, 599, 599, 599, 599,
+ 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599,
+ 599, 599, 600, 26, 26, 26, 26, 26, 601, 601, 601, 601, 601, 601, 601, 601,
+ 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601,
+ 602, 26, 26, 26, 26, 26, 26, 26, 305, 305, 305, 305, 305, 305, 305, 305,
+ 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 603,
+ 604, 604, 604, 605, 604, 606, 607, 607, 607, 607, 607, 607, 607, 607, 607, 608,
+ 607, 609, 610, 610, 610, 611, 611, 26, 612, 612, 612, 612, 612, 612, 612, 612,
+ 613, 26, 612, 614, 614, 612, 612, 615, 612, 612, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 617, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 618, 618, 618, 618, 618, 618, 618, 618,
+ 618, 619, 618, 618, 618, 618, 618, 618, 618, 620, 618, 618, 26, 26, 26, 26,
+ 26, 26, 26, 26, 621, 26, 347, 26, 622, 622, 622, 622, 622, 622, 622, 622,
+ 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622,
+ 622, 622, 622, 622, 622, 622, 622, 26, 623, 623, 623, 623, 623, 623, 623, 623,
+ 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
+ 623, 623, 624, 26, 26, 26, 26, 26, 622, 625, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 276, 276,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 346, 26, 26, 26, 26,
- 347, 26, 348, 349, 25, 25, 350, 351, 352, 25, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 353, 26, 354, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 355, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 356, 31, 31, 31, 31, 31, 31, 357, 26, 26, 26, 26, 31, 31,
- 9, 9, 0, 313, 9, 358, 0, 0, 0, 0, 359, 0, 257, 280, 360, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 361,
- 362, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, 363, 290, 289, 290,
- 290, 290, 290, 364, 168, 168, 168, 295, 365, 365, 365, 366, 257, 257, 26, 367,
- 368, 369, 368, 368, 370, 368, 368, 371, 368, 372, 368, 372, 26, 26, 26, 26,
- 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 373,
- 374, 0, 0, 0, 0, 0, 375, 0, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 252, 0, 376, 377, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 378,
- 379, 379, 379, 380, 381, 381, 381, 381, 381, 381, 382, 26, 383, 0, 0, 280,
- 384, 384, 384, 384, 385, 386, 387, 387, 387, 388, 389, 389, 389, 389, 389, 390,
- 391, 391, 391, 392, 393, 393, 393, 393, 394, 393, 395, 26, 26, 26, 26, 26,
- 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 397, 397, 397, 397, 397, 397,
- 398, 398, 398, 399, 398, 400, 401, 401, 401, 401, 402, 401, 401, 401, 401, 402,
- 403, 403, 403, 403, 403, 26, 404, 404, 404, 404, 404, 404, 405, 406, 407, 408,
- 407, 408, 409, 407, 410, 407, 410, 411, 26, 26, 26, 26, 26, 26, 26, 26,
- 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
- 412, 412, 412, 412, 412, 412, 413, 26, 412, 412, 414, 26, 412, 26, 26, 26,
- 415, 2, 2, 2, 2, 2, 416, 307, 26, 26, 26, 26, 26, 26, 26, 26,
- 417, 418, 419, 419, 419, 419, 420, 421, 422, 422, 423, 422, 424, 424, 424, 424,
- 425, 425, 425, 426, 427, 425, 26, 26, 26, 26, 26, 26, 428, 428, 429, 430,
- 431, 431, 431, 432, 433, 433, 433, 434, 26, 26, 26, 26, 26, 26, 26, 26,
- 435, 435, 435, 435, 436, 436, 436, 437, 436, 436, 438, 436, 436, 436, 436, 436,
- 439, 440, 441, 442, 443, 443, 444, 445, 443, 446, 443, 446, 447, 447, 447, 447,
- 448, 448, 448, 448, 26, 26, 26, 26, 449, 449, 449, 449, 450, 451, 450, 26,
- 452, 452, 452, 452, 452, 452, 453, 454, 455, 455, 456, 455, 457, 457, 458, 457,
- 459, 459, 460, 461, 26, 462, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 463, 463, 463, 463, 463, 463, 463, 463, 463, 464, 26, 26, 26, 26, 26, 26,
- 465, 465, 465, 465, 465, 465, 466, 26, 465, 465, 465, 465, 465, 465, 466, 467,
- 468, 468, 468, 468, 468, 26, 468, 469, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 31, 31, 31, 50,
- 470, 470, 470, 470, 470, 471, 472, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 473, 473, 473, 473, 473, 26, 474, 474, 474, 474, 474, 475, 26, 26, 476, 476,
- 476, 477, 26, 26, 26, 26, 478, 478, 478, 479, 26, 26, 480, 480, 481, 26,
- 482, 482, 482, 482, 482, 482, 482, 482, 482, 483, 484, 482, 482, 482, 483, 485,
- 486, 486, 486, 486, 486, 486, 486, 486, 487, 488, 489, 489, 489, 490, 489, 491,
- 492, 492, 492, 492, 492, 492, 493, 492, 492, 26, 494, 494, 494, 494, 495, 26,
- 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 497, 137, 498, 26,
- 499, 499, 500, 499, 499, 499, 499, 501, 26, 26, 26, 26, 26, 26, 26, 26,
- 502, 503, 504, 505, 504, 506, 507, 507, 507, 507, 507, 507, 507, 508, 507, 509,
- 510, 511, 512, 513, 513, 514, 515, 516, 511, 517, 518, 519, 520, 521, 521, 26,
- 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 523, 524, 26, 26, 26,
- 525, 525, 525, 525, 525, 525, 525, 525, 525, 26, 525, 526, 26, 26, 26, 26,
- 527, 527, 527, 527, 527, 527, 528, 527, 527, 527, 527, 528, 26, 26, 26, 26,
- 529, 529, 529, 529, 529, 529, 529, 529, 530, 26, 529, 531, 197, 532, 26, 26,
- 533, 533, 533, 533, 533, 533, 533, 534, 533, 534, 26, 26, 26, 26, 26, 26,
- 535, 535, 535, 536, 535, 537, 535, 535, 538, 26, 26, 26, 26, 26, 26, 26,
- 539, 539, 539, 539, 539, 539, 539, 540, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 542, 543,
- 544, 545, 546, 547, 547, 547, 548, 549, 544, 26, 547, 550, 26, 26, 26, 26,
- 26, 26, 26, 26, 551, 552, 551, 551, 551, 551, 551, 552, 553, 26, 26, 26,
- 554, 554, 554, 554, 554, 554, 554, 554, 554, 26, 555, 555, 555, 555, 555, 555,
- 555, 555, 555, 555, 556, 26, 177, 177, 557, 557, 557, 557, 557, 557, 557, 558,
- 559, 560, 559, 559, 559, 559, 561, 559, 562, 26, 559, 559, 559, 563, 564, 564,
- 564, 564, 565, 564, 564, 566, 567, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 568, 569, 570, 570, 570, 570, 568, 571, 570, 26, 570, 572, 573, 574, 575, 575,
- 575, 576, 577, 578, 575, 579, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 580, 580, 580, 581,
- 26, 26, 26, 26, 26, 26, 582, 26, 108, 108, 108, 108, 108, 108, 583, 584,
- 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585,
- 585, 585, 585, 586, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 587, 588, 26,
- 585, 585, 585, 585, 585, 585, 585, 585, 589, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 591, 26,
- 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592,
- 592, 592, 592, 592, 592, 593, 592, 594, 26, 26, 26, 26, 26, 26, 26, 26,
- 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595,
- 595, 595, 595, 595, 595, 595, 595, 595, 596, 26, 26, 26, 26, 26, 26, 26,
- 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304,
- 304, 304, 304, 304, 304, 304, 304, 597, 598, 598, 598, 599, 598, 600, 601, 601,
- 601, 601, 601, 601, 601, 601, 601, 602, 601, 603, 604, 604, 604, 605, 605, 26,
- 606, 606, 606, 606, 606, 606, 606, 606, 607, 26, 606, 608, 608, 606, 606, 609,
- 606, 606, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 610, 610, 610, 610, 610, 610, 610, 610,
- 610, 610, 610, 611, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 612, 612, 612, 612, 612, 612, 612, 612, 612, 613, 612, 612, 612, 612, 612, 612,
- 612, 614, 612, 612, 26, 26, 26, 26, 26, 26, 26, 26, 615, 26, 346, 26,
- 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616,
- 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 26,
- 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617,
- 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 618, 26, 26, 26, 26, 26,
- 616, 619, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 620, 621,
- 622, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 623, 26, 26, 26, 26, 26, 624, 26, 625, 26, 626, 626,
- 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626,
- 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 627,
- 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 629, 628, 630,
- 628, 631, 628, 632, 280, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 9, 9, 9, 9, 9, 633, 9, 9, 220, 26, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, 26, 26, 26, 26, 26, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26,
- 0, 0, 0, 0, 257, 362, 0, 0, 0, 0, 0, 0, 634, 635, 0, 636,
- 637, 638, 0, 0, 0, 639, 0, 0, 0, 0, 0, 0, 0, 265, 26, 26,
- 14, 14, 14, 14, 14, 14, 14, 14, 246, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 280, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 257, 26, 0, 0, 0, 259,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0,
- 0, 0, 0, 254, 640, 641, 0, 642, 643, 0, 0, 0, 0, 0, 0, 0,
- 268, 644, 254, 254, 0, 0, 0, 645, 646, 647, 648, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 0,
- 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649,
- 649, 650, 26, 651, 652, 649, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 2, 2, 2, 347, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 653, 269, 269, 654, 655, 656, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 657, 657, 657, 657, 657, 658, 657, 659, 657, 660, 26, 26, 26, 26, 26, 26,
- 26, 26, 661, 661, 661, 662, 26, 26, 663, 663, 663, 663, 663, 663, 663, 664,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 171, 665, 169, 171,
- 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666,
- 666, 666, 666, 666, 666, 666, 666, 666, 667, 666, 668, 26, 26, 26, 26, 26,
- 669, 669, 669, 669, 669, 669, 669, 669, 669, 670, 669, 671, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 362, 0,
- 0, 0, 0, 0, 0, 0, 376, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 362, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 26, 26,
- 672, 31, 31, 31, 673, 674, 675, 676, 677, 678, 673, 679, 673, 675, 675, 680,
- 31, 681, 31, 682, 683, 681, 31, 682, 26, 26, 26, 26, 26, 26, 51, 26,
- 0, 0, 0, 0, 0, 280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 280, 26, 0, 257, 362, 0, 362, 0, 362, 0, 0, 0, 275, 26,
- 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 684, 0, 0, 0,
- 685, 26, 0, 0, 0, 0, 0, 280, 0, 259, 313, 26, 275, 26, 26, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 686, 0, 376, 0, 376,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 280, 259, 26,
- 0, 280, 0, 0, 0, 0, 0, 0, 0, 26, 0, 313, 0, 0, 0, 0,
- 0, 26, 0, 0, 0, 275, 313, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, 0, 275, 376, 376,
- 257, 26, 0, 0, 0, 376, 0, 265, 275, 26, 0, 313, 0, 26, 257, 26,
- 0, 0, 359, 0, 0, 0, 0, 0, 0, 265, 26, 26, 26, 26, 0, 313,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 26, 26, 26, 26,
- 276, 276, 276, 276, 276, 276, 276, 687, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 276, 346, 26, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 687, 26, 26, 26,
- 276, 276, 276, 279, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 688, 26, 26, 26, 26, 26, 26,
- 689, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 26, 26, 26, 26, 26, 26, 626, 627, 628, 287, 287, 287, 287, 287, 287, 287,
+ 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287,
+ 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 629, 26, 630, 26,
+ 26, 26, 631, 26, 632, 26, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633,
+ 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633,
+ 633, 633, 633, 633, 633, 633, 633, 634, 635, 635, 635, 635, 635, 635, 635, 635,
+ 635, 635, 635, 635, 635, 636, 635, 637, 635, 638, 635, 639, 281, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 9, 9, 9, 9, 9, 640, 9, 9,
+ 221, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 281, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 276, 26, 0, 0, 0, 0, 258, 363, 0, 0,
+ 0, 0, 0, 0, 641, 642, 0, 643, 644, 645, 0, 0, 0, 646, 0, 0,
+ 0, 0, 0, 0, 0, 266, 26, 26, 14, 14, 14, 14, 14, 14, 14, 14,
+ 247, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 0, 0, 281, 26, 0, 0, 281, 26, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 258, 26, 0, 0, 0, 260, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 647, 648, 0, 649,
+ 650, 0, 0, 0, 0, 0, 0, 0, 269, 651, 255, 255, 0, 0, 0, 652,
+ 653, 654, 655, 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 268, 0, 0, 0, 0, 0, 0, 656, 656, 656, 656, 656, 656, 656, 656,
+ 656, 656, 656, 656, 656, 656, 656, 656, 656, 657, 26, 658, 659, 656, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 348, 660, 308, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 661, 270, 270, 662, 663, 664, 18, 18,
+ 18, 18, 18, 18, 18, 665, 26, 26, 26, 666, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 667, 667, 667, 667, 667, 668, 667, 669,
+ 667, 670, 26, 26, 26, 26, 26, 26, 26, 26, 671, 671, 671, 672, 26, 26,
+ 673, 673, 673, 673, 673, 673, 673, 674, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 675, 675, 675, 675, 675, 676, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 172, 677, 170, 172, 678, 678, 678, 678, 678, 678, 678, 678,
+ 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678,
+ 679, 678, 680, 26, 26, 26, 26, 26, 681, 681, 681, 681, 681, 681, 681, 681,
+ 681, 682, 681, 683, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 0, 377, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 276,
+ 26, 26, 26, 26, 26, 26, 26, 26, 684, 31, 31, 31, 685, 686, 687, 688,
+ 689, 690, 685, 691, 685, 687, 687, 692, 31, 693, 31, 694, 695, 693, 31, 694,
+ 26, 26, 26, 26, 26, 26, 51, 26, 0, 0, 0, 0, 0, 281, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 281, 26, 0, 258, 363, 0,
+ 363, 0, 363, 0, 0, 0, 276, 26, 0, 0, 0, 0, 0, 276, 26, 26,
+ 26, 26, 26, 26, 696, 0, 0, 0, 697, 26, 0, 0, 0, 0, 0, 281,
+ 0, 260, 314, 26, 276, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 698, 0, 377, 0, 377, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 258, 699, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 314, 0, 281, 260, 26, 0, 281, 0, 0, 0, 0, 0, 0,
+ 0, 26, 0, 314, 0, 0, 0, 0, 0, 26, 0, 0, 0, 276, 314, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 281, 26, 0, 276, 0, 377, 0, 260, 0, 0, 0, 0, 0, 269,
+ 276, 696, 0, 281, 0, 260, 0, 260, 0, 0, 360, 0, 0, 0, 0, 0,
+ 0, 266, 26, 26, 26, 26, 0, 314, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 347,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 347, 26, 277, 277,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 700, 26, 26, 26, 277, 277, 277, 280, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 701, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 702, 26, 26, 26, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0,
+ 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962,
+ 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0,
+ 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147,
+ 1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0,
+ 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143,
+ 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160,
+ 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0,
+ 1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206,
+ 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035,
+ 1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250,
+ 1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0,
+ 1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299,
+ 1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,1093,1280, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340,
+ 1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177,
+ 1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0,
+ 1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165,
+ 1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279,
+ 1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130,
+ 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 10,1425, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5,
+ 1434,1438,1443, 0,1450, 0,1455,1461,1514, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1446,1458,1468,1476,1480,1486,1517, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1489,1503,1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522,
+ 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567,
+ 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549,
+ 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559,
+ 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0,
+ 1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648,
+ 1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662,
+ 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0,
+ 1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671,
+ 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0,
+ 1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142,
+ 1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381,
+ 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181,
+ 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210,
+ 1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222,
+ 1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243,
+ 1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389,
+ 1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284,
+ 1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291,
+ 1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260,
+ 1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343,
+ 1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696,
+ 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698,
+ 1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359,
+ 1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274,
+ 1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304,
+ 1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707,
+ 1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0,
+ 1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743,
+ 1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770,
+ 1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0,
+ 1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790,
+ 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800,
+ 1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24,
+ 1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714,
+ 1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750,
+ 1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807,
+ 1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825,
+ 1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829,
+ 1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515,
+ 1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518,
+ 1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830,
+ 1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0,
+ 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0,
+ 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847,
+ 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0,
+ 1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0,
+ 1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0,
+ 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0,
+ 1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890,
+ 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897,
+ 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0,
+ 1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917,
+ 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924,
+ 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929,
+ 1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825,
+ 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500,
+ 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679,
+ 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722,
+ 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540,
+ 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589,
+ 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101,
+ 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110,
+ 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801,
+ 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610,
+ 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494,
+ 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748,
+ 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161,
+ 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727,
+ 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684,
+ 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566,
+ 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729,
+ 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525,
+ 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0,
+ 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213,
+ 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458,
+ 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591,
+ 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735,
+ 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171,
+ 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325,
+ 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438,
+ 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526,
+ 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693,
+ 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777,
+ 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916,
+ 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0,
+ 1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599,
+ 1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1936, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1939,1940, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1944,1943, 0,1945, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1946,1947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1949,1950,1951,1952,1953,1954,1955, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
- 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0,
- 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
- 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303,
- 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
- 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
- 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199,
- 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0,
- 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231,
- 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
- 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275,
- 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0,
- 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093,
- 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010,
- 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347,
- 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
- 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365,
- 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
- 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182,
- 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
- 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461,
- 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486,
- 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0,
- 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0,
- 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0,
- 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553,
- 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560,
- 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0,
- 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0,
- 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627,
- 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0,
- 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0,
- 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0,
- 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0,
- 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0,
- 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0,
- 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0,
- 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0,
- 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
- 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
- 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
- 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
- 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
- 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
- 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
- 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
- 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
- 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0,
- 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
- 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
- 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
- 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
- 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
- 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0,
- 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
- 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0,
- 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
- 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
- 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0,
- 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793,
- 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
- 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0,
- 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
- 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
- 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
- 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0,
- 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828,
- 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833,
- 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3,
- 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0,
- 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838,
- 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0,
- 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0,
- 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938,
- 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0,
- 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870,
- 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0,
- 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0,
- 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0,
- 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0,
- 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0,
- 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0,
- 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0,
- 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0,
- 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0,
- 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
- 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
- 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
- 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
- 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
- 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
- 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
- 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
- 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
- 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
- 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
- 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
- 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
- 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
- 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
- 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
- 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0,
- 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0,
- 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773,
- 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
- 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
- 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
- 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0,
- 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
- 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
- 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
- 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
- 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
- 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
- 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575,
- 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0,
- 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950,
- 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959,
- 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131,
- 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37,
- 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
- 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
- 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
- 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
- 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259,
- 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
- 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934,
- 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312,
- 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
- 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
- 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381,
- 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399,
- 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417,
- 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
- 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460,
- 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
- 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505,
- 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64,
- 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538,
- 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567,
- 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592,
- 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
- 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627,
- 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
- 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83,
- 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85,
- 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696,
- 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
- 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90,
- 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787,
- 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807,
- 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0,
+ 0, 0, 0,1956,1957,1958,1960,1959,1961, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121,
+ 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142,
+ 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169,
+ 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185,
+ 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206,
+ 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224,
+ 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39,
+ 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266,
+ 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286,
+ 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852,
+ 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324,
+ 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351,
+ 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50,
+ 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78,
+ 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55,
+ 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861,
+ 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436,
+ 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467,
+ 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873,
+ 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875,
+ 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531,
+ 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559,
+ 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73,
+ 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898,
+ 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902,
+ 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904,
+ 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81,
+ 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669,
+ 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686,
+ 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719,
+ 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753,
+ 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925,
+ 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800,
+ 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816,
+ 817, 818, 819, 820, 821, 935, 0, 0,
};
static const int16_t
_hb_ucd_i16[196] =
@@ -4525,12 +4582,12 @@ _hb_ucd_i16[196] =
static inline uint_fast8_t
_hb_ucd_gc (unsigned u)
{
- return u<1114110u?_hb_ucd_u8[6664+(((_hb_ucd_u8[1296+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+ return u<1114110u?_hb_ucd_u8[6800+(((_hb_ucd_u8[1312+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
}
static inline uint_fast8_t
_hb_ucd_ccc (unsigned u)
{
- return u<125259u?_hb_ucd_u8[8612+(((_hb_ucd_u8[8068+(((_hb_ucd_u8[7624+(((_hb_ucd_u8[7288+(((_hb_ucd_u8[7042+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+ return u<125259u?_hb_ucd_u8[8792+(((_hb_ucd_u8[8236+(((_hb_ucd_u8[7776+(((_hb_ucd_u8[7424+(((_hb_ucd_u8[7178+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
}
static inline unsigned
_hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -4540,24 +4597,24 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
static inline int_fast16_t
_hb_ucd_bmg (unsigned u)
{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9356+(((_hb_ucd_u8[9236+(((_hb_ucd_b4(9108+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9540+(((_hb_ucd_u8[9420+(((_hb_ucd_b4(9292+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
}
static inline uint_fast8_t
_hb_ucd_sc (unsigned u)
{
- return u<918000u?_hb_ucd_u8[10862+(((_hb_ucd_u16[2000+(((_hb_ucd_u8[10142+(((_hb_ucd_u8[9692+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
+ return u<918000u?_hb_ucd_u8[11062+(((_hb_ucd_u16[2040+(((_hb_ucd_u8[10326+(((_hb_ucd_u8[9876+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
}
static inline uint_fast16_t
_hb_ucd_dm (unsigned u)
{
- return u<195102u?_hb_ucd_u16[5888+(((_hb_ucd_u8[16764+(((_hb_ucd_u8[16382+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+ return u<195102u?_hb_ucd_u16[6008+(((_hb_ucd_u8[17068+(((_hb_ucd_u8[16686+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
}
#else
static const uint8_t
-_hb_ucd_u8[13246] =
+_hb_ucd_u8[13370] =
{
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 7, 11, 12, 12, 12, 13,
@@ -4565,7 +4622,7 @@ _hb_ucd_u8[13246] =
7, 24, 21, 21, 21, 25, 26, 27, 21, 28, 29, 30, 31, 32, 33, 34,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 35, 21, 36,
- 7, 7, 37, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 7, 7, 7, 7, 35, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
@@ -4587,7 +4644,7 @@ _hb_ucd_u8[13246] =
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 38, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 37, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
@@ -4610,28 +4667,27 @@ _hb_ucd_u8[13246] =
34, 34,109,110,111,112,113,114,115,116,117,118, 34, 34, 34,119,
120,121,122,123,124,125,126,127, 34,128,129,111,130,131,132,133,
134,135,136,137,138,139,140,111,141,142,111,143,144,145,146,111,
- 147,148,149,150,151,152,111,111,153,154,155,156,111,157,111,158,
- 34, 34, 34, 34, 34, 34, 34, 34,159, 34, 34,111,111,111,111,111,
- 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,160,
- 34, 34, 34, 34, 34, 34, 34, 34,161,111,111,111,111,111,111,111,
+ 147,148,149,150,151,152,153,111,154,155,156,157,111,158,159,160,
+ 34, 34, 34, 34, 34, 34, 34, 34,161, 34, 34,111,111,111,111,111,
+ 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,162,
+ 34, 34, 34, 34, 34, 34, 34, 34,163,111,111,111,111,111,111,111,
111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
111,111,111,111,111,111,111,111, 34, 34, 34, 34, 34,111,111,111,
- 34, 34, 34, 34,162,163,164, 34,111,111,111,111,165,166,167,168,
+ 34, 34, 34, 34,164,165,166, 34,111,111,111,111,167,168,169,170,
34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,
111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,119,
34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,
- 111,111,111,111,111,111,111,111, 34,169,111,111,111,111,111,111,
- 111,111,111,111,111,111,111,111,111,111,111,111,111,111,170, 67,
- 67, 67,171,172,173,130, 65,111,174,175,176,177,178,179,180,181,
- 67, 67, 67, 67,182,183,111,111,111,111,111,111,111,111,184,111,
- 185,111,186,111,111,187,111,111,111,111,111,111,111,111,111, 34,
- 34,188,189,111,111,111,111,111,130,190,191,111, 34,192,111,111,
- 67, 67,193, 67, 67,111, 67,194, 67, 67, 67, 67, 67, 67, 67, 67,
- 67, 67, 67, 67, 67, 67, 67,195,111,111,111,111,111,111,111,111,
+ 111,111,111,111,111,111,111,111, 34,171,111,111,111,111,111,111,
+ 111,111,111,111,111,111,111,111,111,111,111,111,111,111,172, 67,
+ 67, 67,173,174,175,130, 65,111,176,177,178,179,180,181,182,183,
+ 67, 67, 67, 67,184,185,111,111,111,111,111,111,111,111,186,111,
+ 187,188,189,111,111,190,111,111,111,191,111,111,111,111,111, 34,
+ 34,192,193,111,111,111,111,111,130,194,195,111, 34,196,111,111,
+ 67, 67,197, 67, 67,111, 67,198, 67, 67, 67, 67, 67, 67, 67, 67,
+ 67, 67, 67, 67, 67, 67, 67,199,111,111,111,111,111,111,111,111,
34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,
34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,111,
- 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,
- 196,111,185,185,111,111,111,111,111,111,111,111,111,111,111,111,
+ 200,111,188,188,111,111,111,111,111,111,111,111,111,111,111,111,
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2,
7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
@@ -4687,7 +4743,7 @@ _hb_ucd_u8[13246] =
36, 36, 36, 36, 36, 36, 65, 43, 77, 78, 78, 43, 43, 43, 43, 43,
43, 43, 43, 43, 36, 36, 36, 36, 7, 7, 7, 85, 27, 27, 27, 84,
64, 78, 66, 36, 36, 36, 36, 36, 78, 78, 78, 77, 78, 78, 43, 43,
- 43, 43, 77, 78, 78, 78, 81, 36, 86, 36, 36, 36, 36, 36, 36, 36,
+ 43, 43, 77, 78, 78, 78, 81, 36, 86, 82, 78, 78, 78, 78, 78, 78,
43, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 65, 78,
79, 43, 43, 78, 78, 78, 79, 71, 61, 61, 36, 82, 27, 27, 27, 87,
27, 27, 27, 27, 84, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 77,
@@ -4827,7 +4883,7 @@ _hb_ucd_u8[13246] =
36, 64, 2, 36, 36, 36, 36, 36, 36, 82, 78, 43, 43, 43, 43, 77,
81, 36, 58, 2, 56, 43, 57, 79, 7, 7, 7, 7, 7, 58, 58, 2,
90, 27, 27, 27, 27, 27, 27, 27, 36, 36, 36, 36, 36, 36, 78, 79,
- 43, 78, 77, 43, 2, 2, 2, 43, 36, 36, 36, 36, 36, 36, 36, 64,
+ 43, 78, 77, 43, 2, 2, 2, 65, 36, 36, 36, 36, 36, 36, 36, 64,
77, 78, 78, 78, 78, 78, 78, 78, 36, 36, 36, 82, 78, 78, 81, 36,
36, 78, 78, 43, 43, 43, 43, 43, 36, 36, 82, 78, 43, 43, 43, 43,
78, 43, 77, 65, 36, 58, 2, 2, 7, 7, 7, 7, 7, 2, 2, 65,
@@ -4848,8 +4904,10 @@ _hb_ucd_u8[13246] =
43, 43, 43, 43, 77, 43, 43, 43, 77, 43, 79, 43, 43, 43, 43, 43,
43, 43, 43, 64, 43, 43, 43, 43, 36, 36, 36, 36, 36, 78, 78, 78,
43, 77, 79, 79, 36, 36, 36, 36, 36, 64, 77, 97, 2, 2, 2, 2,
- 27, 27, 84, 61, 61, 61, 53, 20,150, 61, 61, 61, 61, 61, 61, 61,
- 61, 61, 61, 61, 61, 61, 61, 21, 43, 43, 57, 2, 2, 2, 2, 2,
+ 43, 82, 36, 36, 36, 36, 36, 36, 36, 36, 78, 43, 43, 43, 43, 78,
+ 77, 57, 2, 2, 2, 2, 2, 2, 27, 27, 84, 61, 61, 61, 53, 20,
+ 150, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 21,
+ 65, 36, 36, 64, 43, 43, 43, 43, 43, 43, 57, 2, 2, 2, 2, 2,
43, 43, 43, 57, 2, 2, 61, 61, 40, 40, 89, 61, 61, 61, 61, 61,
7, 7, 7, 7, 7,167, 27, 27, 27, 87, 36, 36, 36, 36, 36, 36,
27, 27, 27, 30, 2, 2, 2, 2, 82, 78, 78, 78, 78, 78, 78, 78,
@@ -4872,462 +4930,469 @@ _hb_ucd_u8[13246] =
16, 16, 16, 16, 16, 39, 16, 16, 43, 43, 43, 68, 40, 40, 40, 40,
7, 7, 7, 7, 7, 7, 7, 71, 36, 36, 36, 36, 36, 36, 36, 43,
36, 36, 36, 36, 36, 36, 43, 43, 7, 7, 7, 7, 7, 7, 7,170,
- 16, 16, 43, 43, 43, 68, 40, 40, 27, 27, 27, 27, 27, 27,145, 27,
- 171, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,145,
- 27, 27, 27, 27, 27, 27, 84, 61, 61, 61, 61, 61, 61, 25, 41, 41,
- 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13,
- 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5,
- 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20,
- 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25,
- 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 7, 5,
- 6, 6, 24, 24, 6, 24, 12, 12, 6, 5, 9, 21, 25, 9, 26, 12,
- 11, 11, 9, 6, 5, 21, 17, 17, 17, 26, 26, 23, 23, 12, 17, 12,
- 21, 12, 12, 21, 7, 21, 1, 1, 21, 23, 26, 26, 1, 21, 6, 7,
- 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26,
- 26, 7, 21, 1, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12,
- 21, 6, 10, 7, 7, 10, 23, 7, 15, 26, 13, 21, 13, 7, 15, 7,
- 12, 23, 21, 26, 21, 15, 17, 7, 29, 7, 7, 22, 18, 18, 14, 14,
- 14, 7, 10, 21, 17, 21, 11, 12, 5, 6, 8, 8, 8, 24, 5, 24,
- 9, 24, 29, 29, 29, 1, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20,
- 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15, 6, 18, 6,
- 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15,
- 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 22, 21, 21, 22,
- 18, 17, 26, 6, 7, 14, 17, 22, 26, 14, 17, 6, 14, 6, 12, 24,
- 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10,
- 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 7, 1,
- 25, 24, 26, 1, 2, 2, 12, 15, 21, 14, 7, 15, 12, 17, 13, 15,
- 26, 10, 10, 1, 13, 23, 23, 15, 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 15, 0,
- 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 36, 36, 36, 36, 36, 75, 43, 43, 16, 16, 43, 43, 43, 68, 40, 40,
+ 27, 27, 27, 27, 27, 27,145, 27,171, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27,145, 27, 27, 27, 27, 27, 27, 84, 61,
+ 61, 61, 61, 61, 61, 25, 41, 41, 0, 0, 29, 21, 21, 21, 23, 21,
+ 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9,
+ 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0,
+ 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15,
+ 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7,
+ 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12,
+ 6, 5, 9, 21, 25, 9, 26, 12, 11, 11, 9, 6, 5, 21, 17, 17,
+ 17, 26, 26, 23, 23, 12, 17, 12, 21, 12, 12, 21, 7, 21, 1, 1,
+ 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1,
+ 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 21, 1, 24, 7, 7, 6,
+ 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 10, 7, 7, 10, 23, 7,
+ 15, 26, 13, 21, 13, 7, 15, 7, 12, 23, 21, 26, 21, 15, 17, 7,
+ 29, 7, 7, 22, 18, 18, 14, 14, 14, 7, 10, 21, 17, 21, 11, 12,
+ 5, 6, 8, 8, 8, 24, 5, 24, 9, 24, 29, 29, 29, 1, 20, 19,
+ 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22,
+ 18, 21, 21, 29, 15, 6, 18, 6, 12, 11, 9, 26, 26, 9, 26, 5,
+ 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25,
+ 18, 22, 5, 12, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14, 17, 22,
+ 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, 11, 21,
+ 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3, 7, 25, 17, 16,
+ 16, 22, 16, 16, 25, 17, 7, 1, 25, 24, 26, 1, 2, 2, 12, 15,
+ 21, 14, 7, 15, 12, 17, 13, 15, 26, 10, 10, 1, 13, 23, 23, 15,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 0,
+ 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, 25, 26,
- 27, 28, 29, 30, 31, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 21,
+ 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 35,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 35, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 37, 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 41, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0,
- 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, 0, 11, 12, 13,
- 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, 0, 19, 16, 20,
- 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0,
- 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0,
- 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, 0, 0, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, 0, 48, 0, 0,
- 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 52, 53, 0,
- 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 58, 0,
- 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, 0, 66, 0, 0,
- 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 0, 72, 0,
- 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0,
- 75, 0, 0, 76, 77, 0, 0, 78, 79, 0, 80, 62, 0, 81, 82, 0,
- 0, 83, 84, 85, 0, 0, 0, 86, 0, 87, 0, 0, 51, 88, 51, 0,
- 89, 0, 90, 0, 0, 0, 79, 0, 0, 0, 91, 92, 0, 93, 94, 95,
- 96, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 97, 98, 0, 0, 0,
- 0, 99,100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,101, 0, 0,
- 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,103,104, 0, 0,105,
- 0, 0, 0, 0, 0, 0,106, 0, 0, 0,100, 0, 0, 0, 0, 0,
- 107,108, 0, 0, 0, 0, 0, 0, 0,109, 0,110, 0, 0, 0, 0,
- 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, 0, 0, 0, 9,
- 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, 0, 16, 0, 17,
- 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, 22, 23, 0, 24,
- 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, 28, 29, 30, 31, 0, 0,
- 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, 0, 0, 33, 36,
- 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39, 40, 0,
- 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, 0, 44, 0, 0,
- 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48, 49, 0,
- 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, 0, 0, 0, 0,
- 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, 57, 58, 0, 0,
- 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, 52, 0, 62, 63, 0, 0,
- 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, 0, 68, 69, 70, 71, 72,
- 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, 0, 0, 0, 79, 0, 0,
- 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, 0, 0, 77, 82, 0, 83,
- 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, 52, 0, 1, 78, 0, 0,
- 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, 57, 0, 0, 0, 0, 0,
- 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, 0, 91, 0, 0, 0, 0,
- 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, 0, 0, 0, 94, 95, 0,
- 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99, 0,100, 93,
- 0, 0,101, 0, 0, 0, 84, 0, 0,102, 0, 0, 0,103,104, 0,
- 0,105,106, 0, 0, 0, 0, 0, 0,107, 0, 0,108, 0, 0, 0,
- 0,109, 33, 0,110,111,112, 35, 0, 0,113, 0, 0, 0,114, 0,
- 0, 0, 0, 0, 0,115, 0, 0,116, 0, 0, 0, 0,117, 88, 0,
- 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,118, 0, 0, 0, 0,119,
- 0, 0,120, 0, 0, 0, 0,118, 0, 0, 0, 0, 0,121, 0, 0,
- 0,122, 0, 0, 0,123, 0,124, 0, 0, 0, 0,125,126,127, 0,
- 128, 0,129, 0, 0, 0,130,131,132, 0, 0, 0, 35, 0, 0, 0,
- 133, 0, 0,134, 0, 0,135, 0, 0, 0, 0, 0, 0, 0, 1, 1,
- 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10, 1, 11,
- 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 19, 1, 0, 0, 20, 21,
- 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0, 1, 1,
- 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, 37, 0, 0, 0, 0, 38,
- 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, 43, 36, 44, 45, 21, 45,
- 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, 0, 38, 48, 1, 1, 49,
- 49, 50, 0, 0, 51, 0, 0, 0, 52, 1, 0, 0, 38, 14, 4, 1,
- 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 55, 0, 0,
- 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, 0, 60, 0, 0, 0, 0,
- 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 65, 0, 0, 0,
- 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 69, 70, 0, 71, 72,
- 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, 0, 78, 79, 0, 0, 0,
- 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, 0, 62, 0, 0, 63, 0,
- 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0, 62, 0,
- 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, 36, 10, 21, 87, 0, 55,
- 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0, 0, 89,
- 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 87, 9, 12, 4, 90, 8,
- 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1, 1, 94,
- 95, 96, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0, 0, 0,
- 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,101,102, 0, 0,
- 103, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0, 0, 0,
- 0, 62, 0, 0,104, 68, 61, 0, 0, 0, 78, 0, 0, 0,105,106,
- 58, 38, 81, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12, 84, 0,
- 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0,109, 61, 0,110,
- 0, 0, 0, 1, 0, 0, 0, 0, 19, 58, 0,111, 14, 52,112, 41,
- 0, 0, 62, 0, 0, 61, 0, 0,113, 0, 87, 0, 0, 0, 61, 62,
- 0, 0, 62, 0, 89, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0,
- 78, 55, 0, 38, 1, 58, 1, 58, 0, 0, 63, 89, 0, 0,115, 0,
- 0, 0, 55, 0, 0, 0, 0,115, 0, 0, 0, 0, 61, 0, 0, 0,
- 0, 79, 0, 61, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 8, 91,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0,
+ 40, 41, 42, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 5, 6, 7,
+ 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, 16, 17, 16, 18, 16, 19,
+ 16, 19, 16, 19, 0, 19, 16, 20, 16, 19, 21, 19, 0, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 0, 32, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 35, 0, 0,
+ 36, 0, 37, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 0,
+ 0, 47, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0,
+ 0, 50, 0, 51, 0, 52, 53, 0, 54, 0, 0, 0, 0, 0, 0, 55,
+ 56, 57, 0, 0, 0, 0, 58, 0, 0, 59, 60, 61, 62, 63, 0, 0,
+ 64, 65, 0, 0, 0, 66, 0, 0, 0, 0, 67, 0, 0, 0, 68, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0,
+ 0, 70, 0, 71, 0, 0, 72, 0, 0, 73, 0, 0, 0, 0, 0, 0,
+ 0, 0, 74, 0, 0, 0, 0, 0, 75, 76, 0, 77, 78, 0, 0, 79,
+ 80, 0, 81, 62, 0, 82, 83, 0, 0, 84, 85, 86, 0, 0, 0, 87,
+ 0, 88, 0, 0, 51, 89, 51, 0, 90, 0, 91, 0, 0, 0, 80, 0,
+ 0, 0, 92, 93, 0, 94, 95, 96, 97, 0, 0, 0, 0, 0, 51, 0,
+ 0, 0, 0, 98, 99, 0, 0, 0, 0, 0, 0,100, 0, 0, 0, 0,
+ 0,101,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,103, 0, 0,
+ 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105,106, 0, 0,107,
+ 0, 0, 0, 0, 0, 0,108, 0,109, 0,102, 0, 0, 0, 0, 0,
+ 110,111, 0, 0, 0, 0, 0, 0, 0,112, 0, 0, 0, 0, 0, 0,
+ 0,113, 0,114, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6,
+ 7, 0, 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, 0, 0, 0, 13,
+ 0, 0, 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, 0, 20, 21, 0,
+ 0, 0, 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, 0, 0, 0, 27,
+ 0, 0, 28, 29, 30, 31, 0, 0, 0, 32, 33, 34, 0, 0, 33, 0,
+ 0, 35, 33, 0, 0, 0, 33, 36, 0, 0, 0, 0, 0, 37, 38, 0,
+ 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 0,
+ 0, 0, 0, 43, 0, 44, 0, 0, 0, 45, 46, 0, 0, 0, 47, 0,
+ 0, 0, 0, 0, 0, 48, 49, 0, 0, 0, 0, 50, 0, 0, 0, 51,
+ 0, 52, 0, 53, 0, 0, 0, 0, 54, 0, 0, 0, 0, 55, 0, 56,
+ 0, 0, 0, 0, 57, 58, 0, 0, 0, 59, 60, 0, 0, 0, 0, 0,
+ 0, 61, 52, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 66, 0, 0,
+ 0, 67, 0, 68, 69, 70, 71, 72, 1, 73, 0, 74, 75, 76, 0, 0,
+ 77, 78, 0, 0, 0, 79, 0, 0, 1, 1, 0, 0, 80, 0, 0, 81,
+ 0, 0, 0, 0, 77, 82, 0, 83, 0, 0, 0, 0, 0, 78, 84, 0,
+ 85, 0, 52, 0, 1, 78, 0, 0, 86, 0, 0, 87, 0, 0, 0, 0,
+ 0, 88, 57, 0, 0, 0, 0, 0, 0, 89, 90, 0, 0, 84, 0, 0,
+ 33, 0, 0, 91, 0, 0, 0, 0, 92, 0, 0, 0, 0, 49, 0, 0,
+ 93, 0, 0, 0, 0, 94, 95, 0, 0, 96, 0, 0, 97, 0, 0, 0,
+ 98, 0, 0, 0, 99, 0, 0, 0, 0,100,101, 93, 0, 0,102, 0,
+ 0, 0, 84, 0, 0,103, 0, 0, 0,104,105, 0, 0,106,107, 0,
+ 0, 0, 0, 0, 0,108, 0, 0,109, 0, 0, 0, 0,110, 33, 0,
+ 111,112,113, 35, 0, 0,114, 0, 0, 0,115, 0, 0, 0, 0, 0,
+ 0,116, 0, 0,117, 0, 0, 0, 0,118, 88, 0, 0, 0, 0, 0,
+ 57, 0, 0, 0, 0, 52,119, 0, 0, 0, 0,120, 0, 0,121, 0,
+ 0, 0, 0,119, 0, 0,122, 0, 0, 0, 0, 0, 0,123, 0, 0,
+ 0,124, 0, 0, 0,125, 0,126, 0, 0, 0, 0,127,128,129, 0,
+ 130, 0,131, 0, 0, 0,132,133,134, 0, 77, 0, 0, 0, 0, 0,
+ 35, 0, 0, 0,135, 0, 0, 0,136, 0, 0,137, 0, 0,138, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6,
+ 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, 18, 1,
+ 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, 25, 26,
+ 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, 34, 35,
+ 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, 42, 0,
+ 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1, 21, 0,
+ 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0, 0, 0,
+ 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, 54, 21,
+ 35, 1, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0, 0, 0,
+ 0, 59, 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, 0, 0,
+ 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0,
+ 68, 0, 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0, 0, 77,
+ 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49, 0, 80,
+ 0, 0, 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, 0, 0,
+ 83, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85, 1, 52,
+ 15, 86, 36, 10, 21, 87, 0, 55, 0, 0, 0, 0, 19, 10, 1, 0,
+ 0, 0, 0, 0, 88, 0, 0, 89, 0, 0, 88, 0, 0, 0, 0, 78,
+ 0, 0, 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0, 21, 1,
+ 21, 92, 93, 1, 1, 1, 1, 94, 95, 96, 97, 1, 98, 58, 81, 99,
+ 100, 4, 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0, 0, 0,
+ 0, 61, 0, 0,101,102, 0, 0,103, 0, 0, 1, 1, 50, 0, 0,
+ 0, 38, 0, 63, 0, 0, 0, 0, 0, 62, 0, 0,104, 68, 61, 0,
+ 0, 0, 78, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0, 0, 0,
+ 0,107, 1, 14, 4, 12, 84, 0, 0, 0, 0, 38, 87, 0, 0, 0,
+ 0,108, 0, 0,109, 61, 0,110, 0, 0, 0, 1, 0, 0, 0, 0,
+ 19, 58, 0, 0, 0, 51, 0,111, 14, 52,112, 41, 0, 0, 62, 0,
+ 0, 61, 0, 0,113, 0, 87, 0, 0, 0, 61, 62, 0, 0, 62, 0,
+ 89, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0, 78, 55, 0, 38,
+ 1, 58, 1, 58, 0, 0, 63, 89, 0, 0,115, 0, 0, 0, 55, 0,
+ 0, 0, 0,115, 0, 0, 0, 0, 61, 0, 0, 0, 0, 79, 0, 61,
+ 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 79, 0, 0, 0, 8, 91,
0, 0, 1, 87, 0, 0,116, 0, 0, 0, 0, 0, 0,117, 0,118,
119,120,121, 0,104, 4,122, 49, 23, 0, 0, 0, 38, 50, 38, 58,
0, 0, 1, 87, 1, 1, 1, 1, 39, 1, 48,105, 87, 0, 0, 0,
- 0, 1, 4,122, 0, 0, 0, 1,123, 0, 0, 0, 0, 0,230,230,
- 230,230,230,232,220,220,220,220,232,216,220,220,220,220,220,202,
- 202,220,220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,
- 220,220,220,230,230,230,230,240,230,220,220,220,230,230,230,220,
- 220, 0,230,230,230,220,220,220,220,230,232,220,220,230,233,234,
- 234,233,234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230,
- 220,230,230,230,222,220,230,230,220,220,230,222,228,230, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24,
- 25, 0,230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29,
- 30, 31, 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0,
- 0, 0, 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220,
- 0, 0, 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230,
- 220,230,220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,
- 230,230,230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230,
- 0,220, 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,
- 220,230,230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0,
- 0, 9, 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,
- 107,107,118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220,
- 0,220, 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,
- 130,130,130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,
- 220, 0, 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230,
- 0, 0, 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0,
- 0,220,230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0,
- 7, 0,230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,
- 230,230,230,230,232,228,228,220,218,230,233,220,230,220,230,230,
- 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,
- 218,228,232,222,224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0,
- 230,230,220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,
- 220, 0, 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9,
- 7, 0, 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0,
- 1, 0, 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,
- 216, 0,220,220,220, 0,230,230, 7, 0, 16, 17, 17, 33, 17, 49,
- 17, 17, 84, 97,135,145, 26, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 0, 1, 0, 0, 0,123, 4,122, 0, 0, 0, 1,124, 0, 0, 0,
+ 0, 0,230,230,230,230,230,232,220,220,220,220,232,216,220,220,
+ 220,220,220,202,202,220,220,220,220,202,202,220,220,220, 1, 1,
+ 1, 1, 1,220,220,220,220,230,230,230,230,240,230,220,220,220,
+ 230,230,230,220,220, 0,230,230,230,220,220,220,220,230,232,220,
+ 220,230,233,234,234,233,234,234,233,230, 0, 0, 0,230, 0,220,
+ 230,230,230,230,220,230,230,230,222,220,230,230,220,220,230,222,
+ 228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22,
+ 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0, 0, 0,
+ 0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,220,230,
+ 230,220, 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230,230, 0,
+ 220,230,230,220, 0, 0, 0, 36, 0, 0,230,220,230,230,220,220,
+ 230,220,220,230,220,230,220,230,230, 0, 0,220, 0, 0,230,230,
+ 0,230, 0,230,230,230,230,230, 0, 0, 0,220,220,220,230,220,
+ 220,220,230,230, 0,220, 27, 28, 29,230, 7, 0, 0, 0, 0, 9,
+ 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0,230, 0, 0, 84,
+ 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 9, 0,103,103,
+ 9, 0,107,107,107,107,118,118, 9, 0,122,122,122,122,220,220,
+ 0, 0, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0,132, 0,
+ 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230, 9, 0,
+ 230,230, 0, 0,220, 0, 0, 0, 0, 7, 0, 9, 9, 0, 9, 9,
+ 0, 0, 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220,220, 0,
+ 0, 0,230, 0, 0,220,230,220, 0,220,230,230,230, 0, 0, 0,
+ 9, 9, 0, 0, 7, 0,230, 0, 1, 1, 1, 0, 0, 0,230,234,
+ 214,220,202,230,230,230,230,230,232,228,228,220,218,230,233,220,
+ 230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230,
+ 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0, 0, 0,
+ 0,220,230, 0,230,230,220, 0, 0,230, 0, 0, 26, 0, 0,220,
+ 0,230,230, 1,220, 0, 0,230,220, 0, 0, 0,220,220, 0, 0,
+ 230,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 9, 7, 6, 6,
+ 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0, 0,226,
+ 216,216,216,216,216, 0,220,220,220, 0,232,232,220,230,230,230,
+ 7, 0, 16, 17, 17, 33, 17, 49, 17, 17, 84, 97,135,145, 26, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17,177, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 5, 3, 3, 3,
+ 3, 3, 6, 7, 8, 3, 3, 3, 3, 3, 9, 10, 11, 12, 13, 3,
+ 3, 3, 3, 3, 3, 3, 3, 14, 3, 15, 3, 3, 3, 3, 3, 3,
+ 16, 17, 18, 19, 20, 21, 3, 3, 3, 22, 23, 24, 3, 3, 3, 3,
+ 3, 3, 25, 3, 3, 3, 3, 3, 3, 3, 3, 26, 3, 3, 27, 28,
+ 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0,
+ 0, 3, 0, 0, 0, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0,
+ 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 0,
+ 0, 14, 15, 16, 6, 0, 17, 18, 19, 19, 19, 20, 21, 22, 23, 24,
+ 19, 25, 0, 26, 27, 19, 19, 28, 29, 30, 0, 31, 0, 0, 0, 8,
+ 0, 0, 0, 0, 0, 0, 0, 19, 28, 0, 32, 33, 9, 34, 35, 19,
+ 0, 0, 36, 37, 38, 39, 40, 19, 0, 41, 42, 43, 44, 31, 0, 1,
+ 45, 42, 0, 0, 0, 0, 0, 32, 14, 14, 0, 0, 0, 0, 14, 0,
+ 0, 46, 47, 47, 47, 47, 48, 49, 47, 47, 47, 47, 50, 51, 52, 53,
+ 43, 21, 0, 0, 0, 0, 0, 0, 0, 54, 6, 55, 0, 14, 19, 1,
+ 0, 0, 0, 0, 56, 57, 0, 0, 0, 0, 0, 19, 58, 31, 0, 0,
+ 0, 0, 0, 0, 0, 59, 14, 0, 0, 0, 0, 1, 0, 2, 0, 0,
+ 0, 3, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 2, 3, 0, 4, 5, 0, 0, 6, 0, 0, 0, 7,
+ 0, 0, 0, 1, 1, 0, 0, 8, 9, 0, 8, 9, 0, 0, 0, 0,
+ 8, 9, 10, 11, 12, 0, 0, 0, 13, 0, 0, 0, 0, 14, 15, 16,
+ 17, 0, 0, 0, 1, 0, 0, 18, 19, 0, 0, 0, 20, 0, 0, 0,
+ 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 8, 21, 9,
+ 0, 0, 22, 0, 0, 0, 0, 1, 0, 23, 24, 25, 0, 0, 26, 0,
+ 0, 0, 8, 21, 27, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 28,
+ 29, 30, 0, 31, 32, 20, 1, 1, 0, 0, 0, 8, 21, 9, 1, 4,
+ 5, 0, 0, 0, 33, 9, 0, 1, 1, 1, 0, 8, 21, 21, 21, 21,
+ 34, 1, 35, 21, 21, 21, 9, 36, 0, 0, 37, 38, 1, 0, 39, 0,
+ 0, 0, 1, 0, 1, 0, 0, 0, 0, 8, 21, 9, 1, 0, 0, 0,
+ 40, 0, 8, 21, 21, 21, 21, 21, 21, 21, 21, 9, 0, 1, 1, 1,
+ 1, 8, 21, 21, 21, 9, 0, 0, 0, 41, 0, 42, 43, 0, 0, 0,
+ 1, 44, 0, 0, 0, 45, 8, 9, 1, 0, 0, 0, 8, 21, 21, 21,
+ 9, 0, 1, 0, 1, 1, 8, 21, 21, 9, 0, 4, 5, 8, 9, 1,
+ 0, 0, 0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 3, 3, 3, 3, 3, 3, 3, 15, 3, 16, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17,177, 0, 1, 2, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3,
- 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 6, 7, 8, 3, 3, 3,
- 3, 3, 9, 10, 11, 12, 13, 3, 3, 3, 3, 3, 3, 3, 3, 14,
- 3, 15, 3, 3, 3, 3, 3, 3, 16, 17, 18, 19, 20, 21, 3, 3,
- 3, 22, 23, 24, 3, 3, 3, 3, 3, 3, 25, 3, 3, 3, 3, 3,
- 3, 3, 3, 26, 3, 3, 27, 28, 0, 1, 0, 0, 0, 0, 0, 1,
- 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
- 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 8, 9, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 0, 0, 0,
- 0, 0, 0, 10, 11, 12, 13, 0, 0, 14, 15, 16, 6, 0, 17, 18,
- 19, 19, 19, 20, 21, 22, 23, 24, 19, 25, 0, 26, 27, 19, 19, 28,
- 29, 30, 0, 31, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 19,
- 28, 0, 32, 33, 9, 34, 35, 19, 0, 0, 36, 37, 38, 39, 40, 19,
- 0, 41, 42, 43, 44, 31, 0, 1, 45, 42, 0, 0, 0, 0, 0, 32,
- 14, 14, 0, 0, 0, 0, 14, 0, 0, 46, 47, 47, 47, 47, 48, 49,
- 47, 47, 47, 47, 50, 51, 52, 53, 43, 21, 0, 0, 0, 0, 0, 0,
- 0, 54, 6, 55, 0, 14, 19, 1, 0, 0, 0, 0, 56, 57, 0, 0,
- 0, 0, 0, 19, 58, 31, 0, 0, 0, 0, 0, 0, 0, 59, 14, 0,
- 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 60, 61, 0,
- 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 3, 0, 4,
- 5, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 1, 1, 0, 0, 8,
- 9, 0, 8, 9, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 0, 0,
- 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, 1, 0, 0, 18,
- 19, 0, 0, 0, 20, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1,
- 1, 1, 1, 1, 0, 8, 21, 9, 0, 0, 22, 0, 0, 0, 0, 1,
- 0, 23, 24, 25, 0, 0, 26, 0, 0, 0, 8, 21, 27, 0, 1, 0,
- 0, 1, 1, 1, 1, 0, 1, 28, 29, 30, 0, 31, 32, 20, 1, 1,
- 0, 0, 0, 8, 21, 9, 1, 4, 5, 0, 0, 0, 33, 9, 0, 1,
- 1, 1, 0, 8, 21, 21, 21, 21, 34, 1, 35, 21, 21, 21, 9, 36,
- 0, 0, 37, 38, 1, 0, 39, 0, 0, 0, 1, 0, 1, 0, 0, 0,
- 0, 8, 21, 9, 1, 0, 0, 0, 40, 0, 8, 21, 21, 21, 21, 21,
- 21, 21, 21, 9, 0, 1, 1, 1, 1, 8, 21, 21, 21, 9, 0, 0,
- 0, 41, 0, 42, 43, 0, 0, 0, 1, 44, 0, 0, 0, 45, 8, 9,
- 1, 0, 0, 0, 8, 21, 21, 21, 9, 0, 1, 0, 1, 1, 8, 21,
- 21, 9, 0, 4, 5, 8, 9, 1, 0, 0, 0, 1, 2, 3, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 3, 3, 3, 3, 3, 3,
- 3, 15, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 0, 0, 1, 2, 3,
- 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, 17,
- 18, 17, 19, 20, 21, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 25, 25, 26, 27,
- 28, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 53, 31,
- 31, 31, 31, 54, 55, 55, 56, 31, 31, 31, 31, 31, 31, 31, 57, 58,
+ 17, 17, 18, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 17, 17, 18, 17, 19, 20, 21, 22, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 25, 25, 26, 27, 28, 29, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 59, 60, 31, 61, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 63, 64, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 65, 66, 67, 31, 31, 31, 31, 68, 31, 31, 31, 31, 31,
- 31, 31, 31, 69, 70, 71, 17, 17, 72, 73, 31, 74, 75, 76, 31, 77,
- 78, 31, 79, 80, 17, 81, 17, 17, 17, 17, 31, 31, 23, 23, 23, 23,
- 23, 23, 31, 31, 31, 31, 31, 31, 23, 82, 31, 31, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 83, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 84, 0, 0, 1,
- 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3,
- 4, 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11, 11, 12, 11,
- 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 19, 27,
- 28, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36,
- 37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 42, 43, 44, 44, 45, 46,
- 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 49, 50, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 51,
- 60, 61, 62, 63, 64, 65, 66, 7, 67, 67, 68, 69, 70, 71, 72, 73,
- 74, 75, 76, 7, 4, 4, 4, 4, 77, 77, 77, 77, 78, 79, 80, 81,
- 82, 83, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 85, 85,
- 0, 0, 0, 0, 86, 87, 88, 88, 89, 90, 48, 91, 0, 0, 92, 92,
- 92, 92, 92, 93, 94, 95, 96, 97, 98, 47, 99,100,101,102, 0,103,
- 104,105, 0, 0, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
- 92, 92, 92, 0,106,106,106,106,106,106,106,106,106,106,106,107,
- 108,108,108,108,108, 11,109,110,111, 4,112, 4,113,114,115,116,
- 117,118,119,120,121,122,123,124,125,126, 50,127, 47, 47, 47, 47,
- 47, 47, 47, 47,128,128,128,128,128,128,128,128,128,128,128,128,
- 92, 92, 92, 92, 92, 92, 92, 92,129,130, 19, 19, 19, 19, 19, 19,
- 131, 19, 19, 19,132,133, 19,134,135,136,137,101,138,138,138,138,
- 0, 77,139,140,128,128,141,142,143,144,145,146,147,148,149,150,
- 151,152,153,153,154,154,154,154,154,154, 4, 4,155,156,157,158,
- 159,160,161,162,163,164,165,166,167,168,169,169,170,170,171,171,
- 172,172,128,128, 19, 19,173,173,174,175,176,177,178,178,179,180,
- 181,182,183,184,185,185,186,187,188,189,128,128,190,190,191,191,
- 128,128,192,192,193,194,195,195,196,196,128,128,197,197,198,198,
- 199,199,200,200,201,202,203,204,128,128,128,128,205,206,207,207,
- 208,209,210,210,128,128,211,211,128,128,212, 34,213,213,213,213,
- 213,213,213,213,213,213,213,213,213,213,128,128,128,128,128,128,
- 128,128,214,214,215,215,215,215,215,215,215,215,215,215,128,128,
- 128,128,128,128,216,216,216,216,216,216,216,216,216,216,128,128,
- 128,128,128,128,110,110,110,110,110,110,110,110,110,217,218,219,
- 220,220,220,220,221,221,221,221,222,222,222,223,224,224,224,224,
- 224,224,224,224,224,224,224,224,225,225,225,225,225,225,225,225,
- 224,224,128,128,128,128,128,128,128,128,104,104,226,227,227,227,
- 228,229,230,230,230,230,230,230,128,128,128,128,231,231,232, 0,
- 128,128,128,128,128,128,128,128, 7,233, 0, 0, 0, 0, 0, 0,
- 0,234,235, 0, 77, 77, 0, 0, 0, 0,128,128,236,236,236,236,
- 236,236,236,236,236,236,236,236,128,128,128,128,128,128,128,128,
- 4, 4,128,128, 86, 86,128,128,237,237,128,128,128,128,238,239,
- 128,128,128,128,128,128,128,128,128,128, 48, 48,240,240,240,240,
- 241,241,128,128, 0, 0, 0, 0, 0, 0,128,128, 19, 19, 19, 19,
- 128,128,128,128,242, 0,128,128, 0, 0, 0, 0, 92, 92,128,128,
- 128,128,128,128, 92, 92, 92, 92, 92, 92,128,128, 0, 0,128,128,
- 7, 7, 7, 7, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3,
- 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 4, 6, 0, 0, 7, 0,
- 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 11, 11, 11, 11, 12, 11,
- 13, 13, 13, 13, 14, 13, 13, 13, 13, 13, 13, 15, 16, 16, 16, 16,
- 16, 17, 18, 18, 18, 18, 18, 18, 19, 20, 21, 21, 22, 23, 21, 24,
- 21, 21, 21, 21, 21, 25, 21, 21, 26, 26, 26, 26, 26, 21, 21, 21,
- 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 26, 21,
- 21, 21, 31, 21, 32, 32, 32, 32, 32, 33, 34, 32, 35, 35, 35, 35,
- 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
- 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
- 44, 44, 44, 45, 44, 44, 44, 44, 46, 46, 46, 46, 47, 47, 47, 47,
- 47, 48, 47, 47, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51,
- 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54,
- 55, 55, 55, 55, 56, 56, 57, 57, 57, 57, 58, 57, 59, 59, 60, 61,
- 62, 62, 63, 63, 64, 64, 64, 64, 65, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 55, 67, 67, 67, 67, 67, 68, 68, 68, 69, 69, 69, 69,
- 69, 69, 64, 64, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71, 71, 8,
- 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75,
- 75, 76, 76, 76, 13, 50, 50, 50, 73, 77, 78, 79, 4, 4, 80, 4,
- 4, 81, 82, 83, 4, 4, 4, 84, 11, 11, 11, 11, 85, 0, 0, 0,
- 0, 0, 0, 86, 0, 4, 0, 0, 0, 8, 8, 8, 0, 0, 87, 88,
- 89, 0, 4, 4, 6, 0, 0, 0, 90, 90, 90, 90, 91, 91, 91, 91,
- 91, 91, 4, 4, 92, 92, 92, 92, 50, 50, 50, 93, 93, 93, 93, 93,
- 53, 53, 13, 13, 94, 94, 94, 94, 94, 94, 94, 0, 95, 0, 96, 97,
- 98, 99, 99, 99, 99,100,101,102,102,102,102,103,104,104,104,105,
- 52, 0,104,104, 0, 0, 0,102, 52, 52, 0, 0, 0, 0, 52,106,
- 0,102,102,107,102,102,102,102,102,108, 0, 0,109,109,109,109,
- 109,110,110,110,111,111,111,111, 13, 13,112,112,112,112,112,112,
- 0, 0,113, 4,114, 4, 4, 4,115,115,115, 0,116,116,116,116,
- 117,117,117,117,117,117, 32, 32,118,118,119,120,120,120, 52, 52,
- 121,121,121,121,122,121, 49, 49,123,123,123,123,123,123, 49, 49,
- 124,124,124,124,124,124,125,125, 53, 53, 53, 4, 4,126,127, 54,
- 125,125,125,125,128,128,128,128, 4,129, 18, 18, 18, 21, 21, 21,
- 21, 21, 21,130, 8, 0,131, 0, 0, 0, 0, 21, 21, 21, 21,132,
- 0, 0, 1, 2, 1, 2,133,101,102,134, 52, 52,135,135,135,135,
- 11, 0, 11, 11, 11, 0, 0,136,137,137,138,138,138,138,139, 0,
- 140,140,140,141,141,142,142,142,143,143,144,144,144,144,144,144,
- 145,145,145,145,145,146,146,146,147,147,147,148,148,148,148,148,
- 149,149,149,150,150,150,150,151,151,151,151,151,152,152,152,152,
- 153,153,153,153,154,154,155,155,156,156,156,156,156,156,157,157,
- 158,158,159,159,159,159,159,159,160,160,161,161,161,161,161,161,
- 162,162,162,162,162,162,163,163,164,164,164,164,165,165,165,165,
- 166,166,166,166,167,167,168,168,169,169,169,169,170,170,170,170,
- 171,171,171,171,172,172,172,172,173,173,173,173,174,174,174,175,
- 175,175,175,176,176,176,176,177,177,177,178,178,179,179,179,179,
- 180,180,180,180,180,181,181,181,182,182,182,182,182,183,183,183,
- 184,184,184,184,184,184,185, 43,186,186,186,186,187,187,187,188,
- 188,188,188,188,189,189,189,190,189,189,189,189,191,191,191,191,
- 192,192,192,192,193,193,193,193,194,194,194,194,194,194, 66, 66,
- 195,195,195,195,196,196,196,196,197,197,197,197,198,198,198,198,
- 199,199,199,199,200,200,200,200,201,201,201,201,201,202,202,202,
- 202,202,202, 55,203,203,203,203,204,204,204,204,204,204,204,205,
- 205,205,205,205,206,206,206,206,206,206,207,207,207,207,207,207,
- 208,208,208,208,110,110,110,110,209,209,209,209,210,210,210,210,
- 211,211,211,211,212,212,212,212,213,213,213,214,214,214,214,214,
- 214,215,215,215,216,216,216,216,217,217,217,217,218,218,218,218,
- 218,218,219, 94,220,220,220,220,221,221,221,221,222, 99, 99, 99,
- 99, 99, 99, 99, 99, 99,102,102,102, 99,223,224,224,224,224,224,
- 225,225,225,225,225,225, 0, 0, 8, 0, 0, 0, 0, 0,226,227,
- 228, 0,229, 0,230,230,230,230,231,231,231,231,232,232,232,232,
- 233,233,233,233,234,234,234,234,235,235,235,235,236, 0, 0, 0,
- 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 3, 0, 0, 0, 4, 0,
- 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 5, 0, 2, 5, 6, 0,
- 7, 7, 7, 7, 8, 9, 8, 10, 8, 11, 8, 8, 8, 8, 8, 8,
- 12, 13, 13, 13, 14, 14, 14, 14, 14, 15, 14, 14, 16, 17, 17, 17,
- 17, 17, 17, 17, 18, 19, 19, 19, 19, 19, 19, 19, 20, 21, 20, 22,
- 20, 20, 23, 23, 20, 20, 20, 20, 22, 20, 24, 7, 7, 25, 20, 20,
- 26, 20, 20, 20, 20, 20, 20, 21, 27, 27, 27, 27, 28, 28, 28, 28,
- 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 20, 20, 20,
- 33, 33, 33, 33, 34, 35, 33, 33, 33, 36, 33, 33, 37, 37, 37, 37,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 52, 53, 31, 31, 31, 31, 54, 55, 55, 56, 31,
+ 31, 31, 31, 31, 31, 31, 57, 58, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 59, 60, 31, 61, 62, 62, 62, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 63, 64, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 65, 66, 67, 31, 31,
+ 31, 31, 68, 31, 31, 31, 31, 31, 31, 31, 31, 69, 70, 71, 17, 17,
+ 72, 73, 31, 74, 75, 76, 77, 78, 79, 31, 80, 81, 17, 82, 17, 17,
+ 17, 17, 31, 31, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31,
+ 23, 83, 31, 31, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 84, 0, 0, 1, 0, 1, 2, 3, 0, 1, 2, 3,
+ 4, 5, 6, 7, 0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 5, 6,
+ 7, 8, 9, 10, 11, 11, 12, 11, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 19, 27, 28, 29, 30, 30, 31, 31, 32, 32,
+ 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 40, 41, 41,
+ 42, 42, 42, 43, 44, 44, 45, 46, 47, 47, 47, 47, 48, 48, 48, 48,
+ 48, 48, 49, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 53,
+ 54, 55, 56, 56, 57, 58, 59, 51, 60, 61, 62, 63, 64, 65, 66, 7,
+ 67, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 7, 4, 4, 4, 4,
+ 77, 77, 77, 77, 78, 79, 80, 81, 82, 83, 84, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 85, 85, 85, 85, 0, 0, 0, 0, 86, 87, 88, 88,
+ 89, 90, 48, 91, 0, 0, 92, 92, 92, 92, 92, 93, 94, 95, 96, 97,
+ 98, 47, 99,100,101,102, 0,103,104,105, 0, 0, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 0,106,106,106,106,
+ 106,106,106,106,106,106,106,107,108,108,108,108,108, 11,109,110,
+ 111, 4,112, 4,113,114,115,116,117,118,119,120,121,122,123,124,
+ 125,126, 50,127, 47, 47, 47, 47, 47, 47, 47, 47,128,128,128,128,
+ 128,128,128,128,128,128,128,128, 92, 92, 92, 92, 92, 92, 92, 92,
+ 129,130, 19, 19, 19, 19, 19, 19,131, 19, 19, 19,132,133, 19,134,
+ 135,136,137,101,138,138,138,138, 0, 77,139,140,128,128,141,142,
+ 143,144,145,146,147,148,149,150,151,152,153,153,154,154,154,154,
+ 154,154, 4, 4,155,156,157,158,159,160,161,162,163,164,165,166,
+ 167,168,169,169,170,170,171,171,172,172,128,128, 19, 19,173,174,
+ 175,176,177,178,179,179,180,181,182,183,184,185,186,186,187,188,
+ 189,190,128,128,191,191,192,192,128,128,193,193,194,195,196,196,
+ 197,197,128,128,198,198,199,199,200,200,201,201,202,203,204,205,
+ 28, 28,128,128,206,207,208,208,209,210,211,211,128,128,212,212,
+ 213,213,214, 34,215,215,215,215,215,215,215,215,215,215,215,215,
+ 215,215,128,128,128,128,128,128,128,128,216,216,217,217,217,217,
+ 217,217,217,217,217,217,128,128,128,128,128,128,218,218,218,218,
+ 218,218,218,218,218,218,128,128,128,128,128,128,110,110,110,110,
+ 110,110,110,110,110,219,220,221,222,222,222,222,223,223,223,223,
+ 224,224,224,225,226,226,226,226,226,226,226,226,226,226,226,226,
+ 227,227,227,227,227,227,227,227,226,226,128,128,128,128,128,128,
+ 128,128,104,104,228,229,229,229,230,231,232,232,232,232,232,232,
+ 128,128,128,128,233,233,234, 0,128,128,128,128,128,128,128,128,
+ 7,235, 0, 0, 0, 0, 0, 0, 0,236,237, 0, 77, 77, 0, 0,
+ 0, 0,128,128,238,238,238,238,238,238,238,238,238,238,238,238,
+ 128,128,128,128,128,128,128,128, 4, 4,128,128,239, 11, 11, 11,
+ 240,240,128,128,128,128,241,242,128,128,128,128,128,128,243,243,
+ 128,128,128,128,128,128,128,128,128,128, 48, 48,244,244,244,244,
+ 245,245,128,128, 0, 0, 0, 0, 0, 0,128,128, 19, 19, 19, 19,
+ 128,128,128,128,246, 0,128,128, 0, 0, 0, 0, 92, 92,128,128,
+ 128,128,128,128, 0, 0,128,128, 7, 7, 7, 7, 0, 0, 0, 0,
+ 1, 2, 1, 2, 0, 0, 3, 3, 4, 5, 4, 5, 4, 4, 4, 4,
+ 4, 4, 4, 6, 0, 0, 7, 0, 8, 8, 8, 8, 8, 8, 8, 9,
+ 10, 11, 11, 11, 11, 11, 12, 11, 13, 13, 13, 13, 14, 13, 13, 13,
+ 13, 13, 13, 15, 16, 16, 16, 16, 16, 17, 18, 18, 18, 18, 18, 18,
+ 19, 20, 21, 21, 22, 23, 21, 24, 21, 21, 21, 21, 21, 25, 21, 21,
+ 26, 26, 26, 26, 26, 21, 21, 21, 27, 27, 27, 27, 28, 28, 28, 28,
+ 29, 29, 29, 29, 30, 30, 26, 21, 21, 21, 31, 21, 32, 32, 32, 32,
+ 32, 33, 34, 32, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41,
- 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45,
- 46, 46, 46, 46, 46, 46, 46, 47, 48, 48, 48, 48, 49, 49, 49, 49,
- 49, 50, 51, 49, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 54, 53,
- 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58,
- 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 61, 62, 63, 63, 63, 63,
- 64, 64, 64, 64, 64, 65, 0, 0, 66, 66, 66, 66, 67, 67, 67, 67,
- 68, 68, 68, 68, 69, 70, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72,
- 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76,
- 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80,
- 81, 81, 81, 81, 82, 7, 7, 7, 83, 7, 84, 85, 0, 84, 86, 0,
- 2, 87, 88, 2, 2, 2, 2, 89, 90, 87, 91, 2, 2, 2, 92, 2,
- 2, 2, 2, 93, 0, 0, 0, 86, 1, 0, 0, 94, 0, 95, 96, 0,
- 4, 0, 0, 0, 0, 0, 0, 4, 97, 97, 97, 97, 98, 98, 98, 98,
- 13, 13, 13, 13, 99, 99, 99, 99,100,100,100,100, 0,101, 0, 0,
- 102,100,103,104, 0, 0,100, 0,105,106,106,106,106,106,106,106,
- 106,106,107,105,108,109,109,109,109,109,109,109,109,109,110,108,
- 111,111,111,111,112, 55, 55, 55, 55, 55, 55,113,109,109,109,110,
- 109,109, 0, 0,114,114,114,114,115,115,115,115,116,116,116,116,
- 117,117,117,117, 96, 2, 2, 2, 2, 2, 94, 2,118,118,118,118,
- 119,119,119,119,120,120,120,120,121,121,121,121,121,121,121,122,
- 123,123,123,123,124,124,124,124,124,124,124,125,126,126,126,126,
- 127,127,127,127,128,128,128,128, 2, 2, 3, 2, 2,129,130, 0,
- 131,131,131,131,132, 17, 17, 18, 20, 20, 20,133, 7, 7, 7,134,
- 20, 20, 20, 23, 0,135,109,109,109,109,109,136,137,137,137,137,
- 0, 0, 0,138,139,139,139,139,140,140,140,140, 84, 0, 0, 0,
- 141,141,141,141,142,142,142,142,143,143,143,143,144,144,144,144,
- 145,145,145,145,146,146,146,146,147,147,147,147,148,148,148,148,
- 149,149,149,149,150,150,150,150,151,151,151,151,152,152,152,152,
- 153,153,153,153,154,154,154,154,155,155,155,155,156,156,156,156,
- 157,157,157,157,158,158,158,158,159,159,159,159,160,160,160,160,
- 161,161,161,161,162,162,162,162,163,163,163,163,164,164,164,164,
- 165,165,165,165,166,166,166,166,167,167,167,167,168,168,168,168,
+ 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 45, 44, 44, 44, 44,
+ 46, 46, 46, 46, 47, 47, 47, 47, 47, 48, 47, 47, 49, 49, 49, 49,
+ 49, 49, 50, 50, 50, 50, 50, 51, 52, 52, 52, 52, 53, 53, 53, 53,
+ 53, 53, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 57, 57,
+ 57, 57, 58, 57, 59, 59, 60, 61, 62, 62, 63, 63, 64, 64, 64, 64,
+ 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 55, 67, 67, 67, 67,
+ 67, 68, 68, 68, 69, 69, 69, 69, 69, 69, 64, 64, 70, 70, 71, 71,
+ 71, 71, 71, 71, 71, 71, 71, 8, 72, 72, 72, 72, 73, 73, 73, 73,
+ 74, 74, 74, 74, 75, 75, 75, 75, 75, 76, 76, 76, 13, 50, 50, 50,
+ 73, 77, 78, 79, 4, 4, 80, 4, 4, 81, 82, 83, 4, 4, 4, 84,
+ 11, 11, 11, 11, 85, 0, 0, 0, 0, 0, 0, 86, 0, 4, 0, 0,
+ 0, 8, 8, 8, 0, 0, 87, 88, 89, 0, 4, 4, 6, 0, 0, 0,
+ 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 4, 4, 92, 92, 92, 92,
+ 50, 50, 50, 93, 93, 93, 93, 93, 53, 53, 13, 13, 94, 94, 94, 94,
+ 94, 94, 94, 0, 95, 0, 96, 97, 98, 99, 99, 99, 99,100,101,102,
+ 102,102,102,103,104,104,104,105, 52, 0,104,104, 0, 0, 0,102,
+ 52, 52, 0, 0, 0, 0, 52,106, 0,102,102,107,102,102,102,102,
+ 102,108, 0, 0,109,109,109,109,109,110,110,110,111,111,111,111,
+ 13, 13,112,112,112,112,112,112, 0, 0,113, 4,114, 4, 4, 4,
+ 115,115,115, 0,116,116,116,116,117,117,117,117,117,117, 32, 32,
+ 118,118,119,120,120,120, 52, 52,121,121,121,121,122,121, 49, 49,
+ 123,123,123,123,123,123, 49, 49,124,124,124,124,124,124,125,125,
+ 53, 53, 53, 4, 4,126,127, 54,125,125,125,125,128,128,128,128,
+ 4,129, 18, 18, 18, 21, 21, 21, 21, 21, 21,130, 8, 0,131, 0,
+ 0, 0, 0, 21, 21, 21, 21,132, 0, 0, 1, 2, 1, 2,133,101,
+ 102,134, 52, 52,135,135,135,135, 11, 0, 11, 11, 11, 0, 0,136,
+ 137,137,138,138,138,138,139, 0,140,140,140,141,141,142,142,142,
+ 143,143,144,144,144,144,144,144,145,145,145,145,145,146,146,146,
+ 147,147,147,148,148,148,148,148,149,149,149,150,150,150,150,151,
+ 151,151,151,151,152,152,152,152,153,153,153,153,154,154,155,155,
+ 156,156,156,156,156,156,157,157,158,158,159,159,159,159,159,159,
+ 160,160,161,161,161,161,161,161,162,162,162,162,162,162,163,163,
+ 164,164,164,164,165,165,165,165,166,166,166,166,167,167,168,168,
169,169,169,169,170,170,170,170,171,171,171,171,172,172,172,172,
- 173,173,173,173,174,174,174,174,175,175,175,175,176,176,176,176,
- 177,177,177,177,178,178,178,178,179,179,179,179,180,180,180,180,
- 181,181,181,181,182,182,182,182,183,183,183,183,184,184,184,184,
- 185,185,185,185,186, 45, 45, 45,187,187,187,187,188,188,188,188,
- 189,189,189,189,190,190,190,190,190,190,191,190,192,192,192,192,
- 193,193,193,193,194,194,194,194,195,195,195,195,196,196,196,196,
+ 173,173,173,173,173,173,173,174,175,175,175,176,176,176,176,177,
+ 177,177,177,178,178,178,179,179,180,180,180,180,181,181,181,181,
+ 181,182,182,182,183,183,183,183,183,184,184,184,185,185,185,185,
+ 185,185,186, 43,187,187,187,187,188,188,188,189,189,189,189,189,
+ 190,190,190,191,190,190,190,190,192,192,192,192,193,193,193,193,
+ 194,194,194,194,195,195,195,195,195,195, 66, 66,196,196,196,196,
197,197,197,197,198,198,198,198,199,199,199,199,200,200,200,200,
- 201,201,201,201,202,202,202,202,203,203,203,203,204,204,204,204,
- 205,205,205,205,206,206,206,206,207,207,207,207,208,208,208,208,
- 209,209,209,209,210,210,210,210,211,211,211,211,212,212,212,212,
- 213,213,213,213,214,214,214,214,215,215,215,215,216,216,216,216,
- 217,217,217,217,218,218,218,218,219,219,219,219,220,221,221,221,
- 222,222,222,222,221,221,221,221,223,106,106,106,106,109,109,109,
- 224,224,224,224,225,225,225,225, 0,226, 86, 0, 0, 0,226, 7,
- 82,138, 7, 0, 0, 0,227, 86,228,228,228,228,229,229,229,229,
- 230,230,230,230,231,231,231,231,232,232,232,232,233,233,233,233,
- 234, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 0, 0, 0, 19, 0, 19, 0, 0, 0, 0, 0, 26, 26,
- 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 0, 9,
- 9, 0, 9, 0, 9, 9, 55, 55, 55, 55, 55, 55, 6, 6, 6, 6,
- 6, 1, 1, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, 14, 14, 14,
- 14, 14, 14, 14, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 1, 1, 1, 3, 3, 1, 3, 3, 3,
- 37, 37, 37, 37, 38, 38, 38, 38, 64, 64, 64, 64, 90, 90, 90, 90,
- 95, 95, 95, 95, 3, 3, 0, 3, 7, 7, 7, 7, 7, 1, 1, 1,
- 1, 7, 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 11, 11, 11, 11,
- 10, 10, 10, 10, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
- 16, 16, 16, 16, 20, 20, 20, 20, 36, 36, 36, 36, 24, 24, 24, 24,
- 24, 24, 24, 0, 18, 18, 18, 18, 25, 25, 25, 25, 25, 0, 0, 0,
- 0, 25, 25, 25, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 0,
- 12, 12, 12, 12, 30, 30, 30, 30, 29, 29, 29, 29, 28, 28, 28, 28,
- 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, 35, 35,
- 45, 45, 45, 45, 44, 44, 44, 44, 44, 0, 0, 0, 43, 43, 43, 43,
- 46, 46, 46, 46, 31, 31, 31, 31, 32, 32, 0, 0, 32, 0, 32, 32,
- 32, 32, 32, 32, 48, 48, 48, 48, 52, 52, 52, 52, 58, 58, 58, 58,
- 54, 54, 54, 54, 91, 91, 91, 91, 62, 62, 62, 62, 76, 76, 76, 76,
- 93, 93, 93, 93, 70, 70, 70, 70, 73, 73, 73, 73, 1, 1, 1, 0,
- 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0,
- 19, 19, 9, 9, 9, 9, 9, 6, 19, 9, 9, 9, 9, 9, 19, 19,
- 9, 9, 9, 19, 6, 19, 19, 19, 19, 19, 19, 9, 0, 0, 0, 19,
- 0, 0, 9, 0, 0, 0, 19, 19, 27, 27, 27, 27, 56, 56, 56, 56,
- 61, 61, 61, 61, 13, 13, 13, 13, 0, 13, 0, 13, 0, 13, 13, 13,
- 13, 13, 1, 1, 1, 1, 12, 12, 0, 15, 15, 15, 15, 15, 15, 15,
- 15, 1, 1, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0,
- 26, 26, 26, 26, 26, 12, 12, 12, 12, 12, 12, 0, 39, 39, 39, 39,
- 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, 79, 79, 60, 60, 60, 60,
- 65, 65, 65, 65, 75, 75, 75, 75, 69, 69, 69, 69, 69, 69, 0, 69,
- 74, 74, 74, 74, 84, 84, 84, 84, 84, 84, 84, 0, 68, 68, 68, 68,
- 92, 92, 92, 92, 87, 87, 87, 87, 19, 9, 19, 19, 19, 19, 0, 0,
- 2, 2, 2, 2, 19, 19, 19, 4, 3, 3, 0, 0, 1, 1, 6, 6,
- 0, 0, 17, 17, 17, 17, 0, 0, 49, 49, 49, 49, 0, 1, 1, 1,
- 71, 71, 71, 71, 67, 67, 67, 67, 42, 42, 42, 42, 41, 41, 41, 41,
- 118,118,118,118, 53, 53, 53, 53, 59, 59, 59, 59, 40, 40, 40, 40,
- 51, 51, 51, 51, 50, 50, 50, 50,135,135,135,135,106,106,106,106,
- 104,104,104,104,161,161,161,161,110,110,110,110, 47, 47, 47, 47,
- 81, 81, 81, 81,120,120,120,120,116,116,116,116,128,128,128,128,
- 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98, 97, 97, 97, 97,
- 57, 57, 57, 57, 88, 88, 88, 88,117,117,117,117,112,112,112,112,
- 78, 78, 78, 78, 83, 83, 83, 83, 82, 82, 82, 82,122,122,122,122,
- 89, 89, 89, 89,130,130,130,130,144,144,144,144,156,156,156,156,
- 147,147,147,147,148,148,148,148,158,158,158,158,153,153,153,153,
- 149,149,149,149, 94, 94, 94, 94, 85, 85, 85, 85,101,101,101,101,
- 96, 96, 96, 96,111,111,111,111,100,100,100,100,100, 36, 36, 36,
- 108,108,108,108,129,129,129,129,109,109,109,109,107,107,107,107,
- 107,107,107, 1,137,137,137,137,124,124,124,124,123,123,123,123,
- 114,114,114,114,102,102,102,102,126,126,126,126,142,142,142,142,
- 125,125,125,125,154,154,154,154,150,150,150,150,141,141,141,141,
- 140,140,140,140,121,121,121,121,133,133,133,133,134,134,134,134,
- 138,138,138,138,143,143,143,143,145,145,145,145, 63, 63, 63, 63,
+ 201,201,201,201,202,202,202,202,202,203,203,203,203,203,203, 55,
+ 204,204,204,204,205,205,205,205,205,205,205,206,206,206,206,206,
+ 207,207,207,207,207,207,208,208,208,208,208,208,209,209,209,209,
+ 210,210,210,210,110,110,110,110,211,211,211,211,212,212,212,212,
+ 213,213,213,213,214,214,214,214,215,215,215,216,216,216,216,216,
+ 216,217,217,217,218,218,218,218,219,219,219,219,220,220,220,220,
+ 220,220,221, 94,222,222,222,222,223,223,223,223,224, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99,102,225, 99,226,102,227,227,227,227,227,
+ 228,228,228,228,228,228, 0, 0, 8, 0, 0, 0, 0, 0,229,230,
+ 231, 0,232, 0,233,233,233,233, 91, 91, 91, 13,234,234,234,234,
+ 235,235,235,235,236,236,236,236,237,237,237,237,238,238,238,238,
+ 239,239,239,239,240, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2,
+ 2, 2, 3, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, 2, 2,
+ 2, 2, 5, 0, 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, 8, 10,
+ 8, 11, 8, 8, 8, 8, 8, 8, 12, 13, 13, 13, 14, 14, 14, 14,
+ 14, 15, 14, 14, 16, 17, 17, 17, 17, 17, 17, 17, 18, 19, 19, 19,
+ 19, 19, 19, 19, 20, 21, 20, 22, 20, 20, 23, 23, 20, 20, 20, 20,
+ 22, 20, 24, 7, 7, 25, 20, 20, 26, 20, 20, 20, 20, 20, 20, 21,
+ 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30,
+ 31, 31, 31, 31, 32, 20, 20, 20, 33, 33, 33, 33, 34, 35, 33, 33,
+ 33, 36, 33, 33, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
+ 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
+ 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 47,
+ 48, 48, 48, 48, 49, 49, 49, 49, 49, 50, 51, 49, 52, 52, 52, 52,
+ 53, 53, 53, 53, 53, 53, 54, 53, 55, 55, 55, 55, 56, 56, 56, 56,
+ 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60,
+ 60, 60, 61, 62, 63, 63, 63, 63, 64, 64, 64, 64, 64, 65, 0, 0,
+ 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 70, 71, 71,
+ 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74,
+ 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78,
+ 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 7, 7, 7,
+ 83, 7, 84, 85, 0, 84, 86, 0, 2, 87, 88, 2, 2, 2, 2, 89,
+ 90, 87, 91, 2, 2, 2, 92, 2, 2, 2, 2, 93, 0, 0, 0, 86,
+ 1, 0, 0, 94, 0, 95, 96, 0, 4, 0, 0, 0, 0, 0, 0, 4,
+ 97, 97, 97, 97, 98, 98, 98, 98, 13, 13, 13, 13, 99, 99, 99, 99,
+ 100,100,100,100, 0,101, 0, 0,102,100,103,104, 0, 0,100, 0,
+ 105,106,106,106,106,106,106,106,106,106,107,105,108,109,109,109,
+ 109,109,109,109,109,109,110,108,111,111,111,111,112, 55, 55, 55,
+ 55, 55, 55,113,109,109,109,110,109,109, 0, 0,114,114,114,114,
+ 115,115,115,115,116,116,116,116,117,117,117,117, 96, 2, 2, 2,
+ 2, 2, 94, 2,118,118,118,118,119,119,119,119,120,120,120,120,
+ 121,121,121,121,121,121,121,122,123,123,123,123,124,124,124,124,
+ 124,124,124,125,126,126,126,126,127,127,127,127,128,128,128,128,
+ 2, 2, 3, 2, 2,129,130, 0,131,131,131,131,132, 17, 17, 18,
+ 20, 20, 20,133, 7, 7, 7,134, 20, 20, 20, 23, 0,135,109,109,
+ 109,109,109,136,137,137,137,137, 0, 0, 0,138,139,139,139,139,
+ 140,140,140,140, 84, 0, 0, 0,141,141,141,141,142,142,142,142,
+ 143,143,143,143,144,144,144,144,145,145,145,145,146,146,146,146,
+ 147,147,147,147,148,148,148,148,149,149,149,149,150,150,150,150,
+ 151,151,151,151,152,152,152,152,153,153,153,153,154,154,154,154,
+ 155,155,155,155,156,156,156,156,157,157,157,157,158,158,158,158,
+ 159,159,159,159,160,160,160,160,161,161,161,161,162,162,162,162,
+ 163,163,163,163,164,164,164,164,165,165,165,165,166,166,166,166,
+ 167,167,167,167,168,168,168,168,169,169,169,169,170,170,170,170,
+ 171,171,171,171,172,172,172,172,173,173,173,173,174,174,174,174,
+ 174,174,174,175,176,176,176,176,177,177,177,177,178,178,178,178,
+ 179,179,179,179,180,180,180,180,181,181,181,181,182,182,182,182,
+ 183,183,183,183,184,184,184,184,185,185,185,185,186,186,186,186,
+ 187, 45, 45, 45,188,188,188,188,189,189,189,189,190,190,190,190,
+ 191,191,191,191,191,191,192,191,193,193,193,193,194,194,194,194,
+ 195,195,195,195,196,196,196,196,197,197,197,197,198,198,198,198,
+ 199,199,199,199,200,200,200,200,201,201,201,201,202,202,202,202,
+ 203,203,203,203,204,204,204,204,205,205,205,205,206,206,206,206,
+ 207,207,207,207,208,208,208,208,209,209,209,209,210,210,210,210,
+ 211,211,211,211,212,212,212,212,213,213,213,213,214,214,214,214,
+ 215,215,215,215,216,216,216,216,217,217,217,217,218,218,218,218,
+ 219,219,219,219,220,220,220,220,221,221,221,221,222,223,223,223,
+ 224,224,224,224,223,223,223,223,225,106,106,106,226,106,106,106,
+ 106,227,109,109,228,228,228,228,229,229,229,229, 0,230, 86, 0,
+ 0, 0,230, 7, 82,138, 7, 0, 0, 0,231, 86,232,232,232,232,
+ 233,233,233,233,234,234,234,234,235,235,235,235,236,236,236,236,
+ 237,237,237,237,238,238,238,238,239, 0, 0, 0, 0, 0, 0, 0,
+ 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 0,
+ 19, 0, 0, 0, 0, 0, 26, 26, 1, 1, 1, 1, 9, 9, 9, 9,
+ 0, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 0, 9, 9, 55, 55,
+ 55, 55, 55, 55, 6, 6, 6, 6, 6, 1, 1, 6, 6, 4, 4, 4,
+ 4, 4, 4, 4, 4, 14, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3,
+ 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 1,
+ 1, 1, 3, 3, 1, 3, 3, 3, 37, 37, 37, 37, 38, 38, 38, 38,
+ 64, 64, 64, 64, 90, 90, 90, 90, 95, 95, 95, 95, 3, 3, 0, 3,
+ 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 0, 0, 7, 7,
+ 5, 5, 5, 5, 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21,
+ 22, 22, 22, 22, 23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20,
+ 36, 36, 36, 36, 24, 24, 24, 24, 24, 24, 24, 0, 18, 18, 18, 18,
+ 25, 25, 25, 25, 25, 0, 0, 0, 0, 25, 25, 25, 33, 33, 33, 33,
+ 8, 8, 8, 8, 8, 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30,
+ 29, 29, 29, 29, 28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35,
+ 35, 35, 35, 0, 0, 0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44,
+ 44, 0, 0, 0, 43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31,
+ 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48,
+ 52, 52, 52, 52, 58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91,
+ 62, 62, 62, 62, 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70,
+ 73, 73, 73, 73, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0,
+ 0, 1, 0, 0, 1, 1, 0, 0, 19, 19, 9, 9, 9, 9, 9, 6,
+ 19, 9, 9, 9, 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19,
+ 19, 19, 19, 9, 0, 0, 0, 19, 0, 0, 9, 0, 0, 0, 19, 19,
+ 27, 27, 27, 27, 56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13,
+ 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12,
+ 0, 15, 15, 15, 15, 15, 15, 15, 15, 1, 1, 0, 0, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 0, 26, 26, 26, 26, 26, 12, 12, 12,
+ 12, 12, 12, 0, 39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77,
+ 79, 79, 79, 79, 60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75,
+ 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 84, 84, 84, 84,
+ 84, 84, 84, 0, 68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87,
+ 19, 9, 19, 19, 19, 19, 0, 0, 2, 2, 2, 2, 19, 19, 19, 4,
+ 3, 3, 0, 0, 1, 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0,
+ 49, 49, 49, 49, 0, 1, 1, 1, 71, 71, 71, 71, 67, 67, 67, 67,
+ 42, 42, 42, 42, 41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53,
+ 59, 59, 59, 59, 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,
+ 135,135,135,135,106,106,106,106,104,104,104,104,161,161,161,161,
+ 110,110,110,110, 47, 47, 47, 47, 81, 81, 81, 81,120,120,120,120,
+ 116,116,116,116,128,128,128,128, 66, 66, 66, 66, 72, 72, 72, 72,
+ 98, 98, 98, 98, 97, 97, 97, 97, 57, 57, 57, 57, 88, 88, 88, 88,
+ 117,117,117,117,112,112,112,112, 78, 78, 78, 78, 83, 83, 83, 83,
+ 82, 82, 82, 82,122,122,122,122, 89, 89, 89, 89,130,130,130,130,
+ 144,144,144,144,156,156,156,156,156, 3, 3, 3,147,147,147,147,
+ 148,148,148,148,158,158,158,158,153,153,153,153,149,149,149,149,
+ 94, 94, 94, 94, 85, 85, 85, 85,101,101,101,101, 96, 96, 96, 96,
+ 111,111,111,111,100,100,100,100,100, 36, 36, 36,108,108,108,108,
+ 129,129,129,129,109,109,109,109,107,107,107,107,107,107,107, 1,
+ 137,137,137,137,124,124,124,124,123,123,123,123,114,114,114,114,
+ 102,102,102,102,126,126,126,126,142,142,142,142,125,125,125,125,
+ 154,154,154,154,150,150,150,150,141,141,141,141,140,140,140,140,
+ 121,121,121,121,133,133,133,133,134,134,134,134,138,138,138,138,
+ 143,143,143,143,145,145,145,145,163,163,163,163, 63, 63, 63, 63,
157,157,157,157, 80, 80, 80, 80,127,127,127,127,115,115,115,115,
159,159,159,159,103,103,103,103,119,119,119,119,146,146,146,146,
99, 99, 99, 99,136,139, 13, 13,155,155,155,155,136,136,136,136,
- 17, 15, 15, 15,139,139,139,139,105,105,105,105, 0, 0, 0, 1,
- 0, 0, 1, 1,131,131,131,131,151,151,151,151,160,160,160,160,
- 152,152,152,152,113,113,113,113,132,132,132,132, 15, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11,
- 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, 9, 9,
+ 17, 15, 15, 15, 17, 17, 15, 15, 15, 17, 17, 17,139,139,139,139,
+ 105,105,105,105, 0, 0, 0, 1, 0, 0, 1, 1,131,131,131,131,
+ 151,151,151,151,160,160,160,160,152,152,152,152,164,164,164,164,
+ 113,113,113,113,132,132,132,132, 15, 0, 0, 0, 0, 1, 2, 3,
+ 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13, 9, 9,
+ 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 18, 19, 20, 9, 21, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 22, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 22, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
@@ -5336,60 +5401,60 @@ _hb_ucd_u8[13246] =
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 23, 24, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20,
- 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32,
- 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 9, 9, 9, 9, 9, 9, 9, 9, 23, 24, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0,
+ 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33, 0, 34,
+ 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0,
- 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0,
- 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0,
- 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 45,
+ 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48, 0, 49,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51,
+ 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, 0,
+ 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 56, 0,
+ 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59,
+ 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0,
- 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68,
- 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 72,
- 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
- 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69, 70, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 95, 96, 97, 98, 99,100,101,102,103, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0,
+ 0, 0, 0,105,106, 0,107, 0, 0, 0,108, 0,109, 0,110, 0,
+ 111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0,108, 0,
- 109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0,
- 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,119,
+ 120,121, 0,122,123,124,125,126, 0,127, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,118,119,120,121, 0,122,123,124,125,126, 0,127, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129,130,131,132,133,
+ 134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,
+ 150,151,152,153,154,155,156,157, 0, 0, 0,158,159,160,161, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129,
- 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,
- 146,147,148,149,150,151,152,153,154,155,156,157, 0, 0, 0,158,
- 159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0, 0, 0,
- 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,162,163, 0, 0, 0, 0, 0, 0, 0,164, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,165, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,169,170, 0, 0, 0, 0,171,172, 0, 0, 0,173,174,
- 175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,
- 191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,169,
+ 170, 0, 0, 0, 0,171,172, 0, 0, 0,173,174,175,176,177,178,
+ 179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,
+ 195,196,197,198,199,200,201,202,203,204,205,206, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
+ 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
};
static const uint16_t
-_hb_ucd_u16[4888] =
+_hb_ucd_u16[4920] =
{
0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12,
13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23,
@@ -5456,39 +5521,41 @@ _hb_ucd_u16[4888] =
359, 47, 47, 360, 145, 66, 47, 361, 47, 362, 145, 145, 363, 47, 364, 66,
47, 47, 47, 365, 47, 366, 47, 366, 47, 365, 144, 145, 145, 145, 145, 145,
9, 9, 9, 9, 11, 11, 11, 367, 47, 47, 368, 160, 160, 160, 160, 160,
- 145, 145, 145, 145, 145, 145, 145, 145, 47, 47, 369, 47, 47, 47, 47, 47,
+ 145, 145, 145, 145, 145, 145, 145, 145, 47, 47, 369, 47, 47, 47, 47, 143,
47, 362, 370, 47, 60, 371, 66, 47, 372, 66, 66, 47, 373, 145, 47, 47,
374, 47, 47, 360, 375, 376, 377, 378, 180, 47, 47, 379, 380, 47, 47, 160,
97, 47, 381, 382, 383, 47, 47, 384, 180, 47, 47, 385, 386, 387, 388, 145,
- 47, 47, 389, 390, 32, 32, 32, 32, 47, 47, 365, 47, 47, 391, 172, 160,
+ 47, 47, 389, 390, 359, 32, 32, 32, 47, 47, 365, 47, 47, 391, 172, 160,
92, 47, 47, 113, 392, 393, 394, 32, 47, 47, 47, 395, 396, 397, 47, 47,
47, 47, 47, 398, 399, 160, 160, 160, 47, 47, 400, 401, 402, 403, 32, 32,
47, 47, 47, 404, 405, 160, 66, 66, 47, 47, 406, 407, 160, 160, 160, 160,
47, 143, 408, 409, 47, 47, 47, 47, 47, 47, 389, 410, 66, 66, 66, 66,
9, 9, 9, 9, 11, 11, 128, 411, 47, 47, 47, 412, 413, 160, 160, 160,
47, 47, 47, 47, 47, 414, 415, 416, 417, 47, 47, 418, 419, 420, 47, 47,
- 421, 422, 66, 47, 47, 47, 47, 47, 47, 47, 400, 423, 424, 128, 145, 425,
- 47, 156, 426, 427, 32, 32, 32, 32, 47, 47, 47, 359, 428, 160, 47, 47,
- 429, 430, 160, 160, 160, 160, 160, 160, 47, 47, 47, 47, 47, 47, 47, 431,
- 47, 47, 47, 47, 145, 432, 433, 434, 219, 219, 219, 219, 219, 219, 219, 66,
- 47, 47, 47, 47, 47, 47, 47, 424, 47, 47, 47, 208, 208, 208, 208, 208,
- 47, 47, 47, 47, 47, 47, 305, 47, 47, 47, 47, 47, 160, 47, 47, 435,
- 47, 47, 47, 436, 437, 438, 439, 47, 9, 9, 9, 9, 9, 9, 11, 11,
- 145, 440, 66, 66, 66, 66, 66, 66, 47, 47, 47, 47, 391, 441, 416, 416,
- 442, 443, 27, 27, 27, 27, 444, 416, 47, 445, 208, 208, 208, 208, 208, 208,
- 32, 32, 32, 32, 32, 146, 146, 146, 146, 146, 146, 146, 146, 146, 446, 447,
- 448, 146, 449, 146, 146, 146, 146, 146, 146, 146, 146, 146, 450, 146, 146, 146,
- 9, 451, 11, 452, 453, 11, 196, 9, 454, 455, 9, 456, 11, 9, 451, 11,
- 452, 453, 11, 196, 9, 454, 455, 9, 456, 11, 9, 451, 11, 452, 453, 11,
- 196, 9, 454, 455, 9, 456, 11, 9, 451, 11, 196, 9, 457, 458, 459, 460,
- 11, 461, 9, 462, 463, 464, 465, 11, 466, 9, 467, 11, 468, 160, 160, 160,
- 32, 32, 32, 469, 32, 32, 470, 471, 472, 473, 32, 32, 32, 32, 32, 32,
- 474, 11, 11, 11, 11, 11, 11, 11, 32, 32, 32, 32, 32, 32, 32, 32,
- 47, 47, 47, 475, 476, 146, 146, 146, 47, 47, 477, 32, 47, 47, 478, 479,
- 47, 47, 47, 47, 355, 32, 32, 32, 9, 9, 454, 11, 480, 305, 66, 66,
- 145, 145, 481, 482, 145, 145, 145, 145, 145, 145, 483, 145, 145, 145, 145, 145,
- 47, 47, 47, 47, 47, 47, 47, 226, 484, 146, 146, 146, 146, 146, 146, 146,
- 146, 146, 146, 146, 146, 146, 146, 485, 146, 146, 146, 146, 146, 146, 146, 160,
+ 421, 422, 66, 47, 47, 47, 47, 47, 66, 66, 66, 66, 66, 66, 66, 66,
+ 47, 47, 400, 423, 424, 128, 145, 425, 47, 156, 426, 427, 32, 32, 32, 32,
+ 47, 47, 47, 359, 428, 160, 47, 47, 429, 430, 160, 160, 160, 160, 160, 160,
+ 47, 47, 47, 47, 47, 47, 47, 431, 432, 47, 47, 433, 434, 160, 160, 160,
+ 47, 47, 47, 47, 145, 435, 436, 437, 219, 219, 219, 219, 219, 219, 219, 66,
+ 47, 47, 47, 47, 47, 47, 47, 424, 47, 47, 47, 208, 438, 32, 32, 32,
+ 47, 47, 47, 47, 47, 47, 305, 47, 47, 47, 47, 47, 160, 47, 47, 439,
+ 47, 47, 47, 440, 441, 442, 443, 47, 9, 9, 9, 9, 9, 9, 11, 11,
+ 145, 444, 66, 66, 66, 66, 66, 66, 47, 47, 47, 47, 391, 445, 416, 416,
+ 446, 447, 27, 27, 27, 27, 448, 416, 47, 449, 208, 208, 208, 208, 208, 208,
+ 32, 32, 32, 32, 32, 146, 146, 146, 146, 146, 146, 146, 146, 146, 450, 451,
+ 452, 146, 453, 146, 146, 146, 146, 146, 146, 146, 146, 146, 454, 146, 146, 146,
+ 9, 455, 11, 456, 457, 11, 196, 9, 458, 459, 9, 460, 11, 9, 455, 11,
+ 456, 457, 11, 196, 9, 458, 459, 9, 460, 11, 9, 455, 11, 456, 457, 11,
+ 196, 9, 458, 459, 9, 460, 11, 9, 455, 11, 196, 9, 461, 462, 463, 464,
+ 11, 465, 9, 466, 467, 468, 469, 11, 470, 9, 471, 11, 472, 160, 160, 160,
+ 32, 32, 32, 473, 32, 32, 474, 475, 476, 477, 32, 32, 32, 32, 32, 32,
+ 478, 11, 11, 11, 11, 11, 11, 11, 32, 32, 32, 27, 27, 27, 27, 27,
+ 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 47, 479, 480, 146, 146, 146,
+ 47, 47, 481, 32, 47, 47, 482, 483, 47, 47, 47, 47, 47, 47, 484, 160,
+ 47, 47, 47, 47, 355, 32, 32, 32, 9, 9, 458, 11, 485, 305, 66, 66,
+ 145, 145, 486, 487, 145, 145, 145, 145, 145, 145, 488, 145, 145, 145, 145, 145,
+ 47, 47, 47, 47, 47, 47, 47, 226, 489, 146, 146, 146, 146, 146, 146, 146,
+ 146, 146, 146, 146, 146, 146, 146, 490, 146, 146, 146, 146, 146, 146, 146, 160,
208, 208, 208, 208, 208, 208, 208, 208, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962,
969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0,
@@ -5712,12 +5779,12 @@ _hb_ucd_i16[92] =
static inline uint_fast8_t
_hb_ucd_gc (unsigned u)
{
- return u<1114112u?_hb_ucd_u8[5056+(((_hb_ucd_u8[1168+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+ return u<1114112u?_hb_ucd_u8[5080+(((_hb_ucd_u8[1152+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
}
static inline uint_fast8_t
_hb_ucd_ccc (unsigned u)
{
- return u<125259u?_hb_ucd_u8[6970+(((_hb_ucd_u8[6426+(((_hb_ucd_u8[5982+(((_hb_ucd_u8[5646+(((_hb_ucd_u8[5400+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+ return u<125259u?_hb_ucd_u8[7038+(((_hb_ucd_u8[6482+(((_hb_ucd_u8[6022+(((_hb_ucd_u8[5670+(((_hb_ucd_u8[5424+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
}
static inline unsigned
_hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -5727,17 +5794,17 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
static inline int_fast16_t
_hb_ucd_bmg (unsigned u)
{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7858+(((_hb_ucd_u8[7626+(((_hb_ucd_u8[7530+(((_hb_ucd_b4(7466+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7930+(((_hb_ucd_u8[7698+(((_hb_ucd_u8[7602+(((_hb_ucd_b4(7538+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
}
static inline uint_fast8_t
_hb_ucd_sc (unsigned u)
{
- return u<918016u?_hb_ucd_u8[11124+(((_hb_ucd_u8[10176+(((_hb_ucd_u8[9204+(((_hb_ucd_u8[8524+(((_hb_ucd_u8[8220+(((_hb_ucd_u8[8106+(u>>2>>2>>2>>3>>4)])<<4)+((u>>2>>2>>2>>3)&15u))])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
+ return u<918016u?_hb_ucd_u8[11228+(((_hb_ucd_u8[10264+(((_hb_ucd_u8[9276+(((_hb_ucd_u8[8596+(((_hb_ucd_u8[8292+(((_hb_ucd_u8[8178+(u>>2>>2>>2>>3>>4)])<<4)+((u>>2>>2>>2>>3)&15u))])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
}
static inline uint_fast16_t
_hb_ucd_dm (unsigned u)
{
- return u<195102u?_hb_ucd_u16[1576+(((_hb_ucd_u8[12446+(((_hb_ucd_u8[12064+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+ return u<195102u?_hb_ucd_u16[1608+(((_hb_ucd_u8[12570+(((_hb_ucd_u8[12188+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
}
#endif
diff --git a/thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh b/thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh
index 036c71a424..13b1c4b1d4 100644
--- a/thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh
+++ b/thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh
@@ -6,16 +6,16 @@
*
* on file with this header:
*
- * # emoji-data-14.0.0.txt
- * # Date: 2021-08-26, 17:22:22 GMT
- * # © 2021 Unicode®, Inc.
+ * # emoji-data.txt
+ * # Date: 2022-08-02, 00:26:10 GMT
+ * # © 2022 Unicode®, Inc.
* # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
- * # For terms of use, see http://www.unicode.org/terms_of_use.html
+ * # For terms of use, see https://www.unicode.org/terms_of_use.html
* #
* # Emoji Data for UTS #51
- * # Used with Emoji Version 14.0 and subsequent minor revisions (if any)
+ * # Used with Emoji Version 15.0 and subsequent minor revisions (if any)
* #
- * # For documentation and usage, see http://www.unicode.org/reports/tr51
+ * # For documentation and usage, see https://www.unicode.org/reports/tr51
*/
#ifndef HB_UNICODE_EMOJI_TABLE_HH
diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h
index a1586a58b6..fa7403cae7 100644
--- a/thirdparty/harfbuzz/src/hb-version.h
+++ b/thirdparty/harfbuzz/src/hb-version.h
@@ -47,7 +47,7 @@ HB_BEGIN_DECLS
*
* The minor component of the library version available at compile-time.
*/
-#define HB_VERSION_MINOR 1
+#define HB_VERSION_MINOR 2
/**
* HB_VERSION_MICRO:
*
@@ -60,7 +60,7 @@ HB_BEGIN_DECLS
*
* A string literal containing the library version available at compile-time.
*/
-#define HB_VERSION_STRING "5.1.0"
+#define HB_VERSION_STRING "5.2.0"
/**
* HB_VERSION_ATLEAST:
diff --git a/thirdparty/libpng/LICENSE b/thirdparty/libpng/LICENSE
index e0c5b531cf..c8ad24eecf 100644
--- a/thirdparty/libpng/LICENSE
+++ b/thirdparty/libpng/LICENSE
@@ -4,8 +4,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
PNG Reference Library License version 2
---------------------------------------
- * Copyright (c) 1995-2019 The PNG Reference Library Authors.
- * Copyright (c) 2018-2019 Cosmin Truta.
+ * Copyright (c) 1995-2022 The PNG Reference Library Authors.
+ * Copyright (c) 2018-2022 Cosmin Truta.
* Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
* Copyright (c) 1996-1997 Andreas Dilger.
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
diff --git a/thirdparty/libpng/arm/arm_init.c b/thirdparty/libpng/arm/arm_init.c
index a34ecdbef7..ab22525b38 100644
--- a/thirdparty/libpng/arm/arm_init.c
+++ b/thirdparty/libpng/arm/arm_init.c
@@ -1,7 +1,7 @@
/* arm_init.c - NEON optimised filter functions
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2022 Cosmin Truta
* Copyright (c) 2014,2016 Glenn Randers-Pehrson
* Written by Mans Rullgard, 2011.
*
@@ -10,9 +10,7 @@
* and license in png.h
*/
-/* Below, after checking __linux__, various non-C90 POSIX 1003.1 functions are
- * called.
- */
+/* This module requires POSIX 1003.1 functions. */
#define _POSIX_SOURCE 1
#include "../pngpriv.h"
@@ -33,21 +31,23 @@
* has partial support is contrib/arm-neon/linux.c - a generic Linux
* implementation which reads /proc/cpufino.
*/
+#include <signal.h> /* for sig_atomic_t */
+
#ifndef PNG_ARM_NEON_FILE
-# ifdef __linux__
-# define PNG_ARM_NEON_FILE "contrib/arm-neon/linux.c"
+# if defined(__aarch64__) || defined(_M_ARM64)
+ /* ARM Neon is expected to be unconditionally available on ARM64. */
+# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on this platform"
+# elif defined(__linux__)
+# define PNG_ARM_NEON_FILE "contrib/arm-neon/linux.c"
+# else
+# error "No support for run-time ARM Neon checking; use compile-time options"
# endif
#endif
-#ifdef PNG_ARM_NEON_FILE
-
-#include <signal.h> /* for sig_atomic_t */
static int png_have_neon(png_structp png_ptr);
-#include PNG_ARM_NEON_FILE
-
-#else /* PNG_ARM_NEON_FILE */
-# error "PNG_ARM_NEON_FILE undefined: no support for run-time ARM NEON checks"
-#endif /* PNG_ARM_NEON_FILE */
+#ifdef PNG_ARM_NEON_FILE
+# include PNG_ARM_NEON_FILE
+#endif
#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */
#ifndef PNG_ALIGNED_MEMORY_SUPPORTED
diff --git a/thirdparty/libpng/arm/filter_neon_intrinsics.c b/thirdparty/libpng/arm/filter_neon_intrinsics.c
index 553c0be21c..4466d48b20 100644
--- a/thirdparty/libpng/arm/filter_neon_intrinsics.c
+++ b/thirdparty/libpng/arm/filter_neon_intrinsics.c
@@ -18,7 +18,7 @@
/* This code requires -mfpu=neon on the command line: */
#if PNG_ARM_NEON_IMPLEMENTATION == 1 /* intrinsics code from pngpriv.h */
-#if defined(_MSC_VER) && defined(_M_ARM64)
+#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64)
# include <arm64_neon.h>
#else
# include <arm_neon.h>
diff --git a/thirdparty/libpng/arm/palette_neon_intrinsics.c b/thirdparty/libpng/arm/palette_neon_intrinsics.c
index b4d1fd2abf..92c7d6f9f6 100644
--- a/thirdparty/libpng/arm/palette_neon_intrinsics.c
+++ b/thirdparty/libpng/arm/palette_neon_intrinsics.c
@@ -14,7 +14,7 @@
#if PNG_ARM_NEON_IMPLEMENTATION == 1
-#if defined(_MSC_VER) && defined(_M_ARM64)
+#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64)
# include <arm64_neon.h>
#else
# include <arm_neon.h>
@@ -30,8 +30,6 @@ png_riffle_palette_neon(png_structrp png_ptr)
int num_trans = png_ptr->num_trans;
int i;
- png_debug(1, "in png_riffle_palette_neon");
-
/* Initially black, opaque. */
uint8x16x4_t w = {{
vdupq_n_u8(0x00),
@@ -40,6 +38,8 @@ png_riffle_palette_neon(png_structrp png_ptr)
vdupq_n_u8(0xff),
}};
+ png_debug(1, "in png_riffle_palette_neon");
+
/* First, riffle the RGB colours into an RGBA8 palette.
* The alpha component is set to opaque for now.
*/
@@ -65,11 +65,12 @@ png_do_expand_palette_rgba8_neon(png_structrp png_ptr, png_row_infop row_info,
png_uint_32 row_width = row_info->width;
const png_uint_32 *riffled_palette =
(const png_uint_32 *)png_ptr->riffled_palette;
- const png_int_32 pixels_per_chunk = 4;
- int i;
+ const png_uint_32 pixels_per_chunk = 4;
+ png_uint_32 i;
png_debug(1, "in png_do_expand_palette_rgba8_neon");
+ PNG_UNUSED(row)
if (row_width < pixels_per_chunk)
return 0;
@@ -109,10 +110,11 @@ png_do_expand_palette_rgb8_neon(png_structrp png_ptr, png_row_infop row_info,
png_uint_32 row_width = row_info->width;
png_const_bytep palette = (png_const_bytep)png_ptr->palette;
const png_uint_32 pixels_per_chunk = 8;
- int i;
+ png_uint_32 i;
png_debug(1, "in png_do_expand_palette_rgb8_neon");
+ PNG_UNUSED(row)
if (row_width <= pixels_per_chunk)
return 0;
diff --git a/thirdparty/libpng/png.c b/thirdparty/libpng/png.c
index 757c755f97..fc09564262 100644
--- a/thirdparty/libpng/png.c
+++ b/thirdparty/libpng/png.c
@@ -1,7 +1,7 @@
/* png.c - location for general purpose libpng functions
*
- * Copyright (c) 2018-2019 Cosmin Truta
+ * Copyright (c) 2018-2022 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -14,7 +14,7 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_37 Your_png_h_is_not_version_1_6_37;
+typedef png_libpng_version_1_6_38 Your_png_h_is_not_version_1_6_38;
#ifdef __GNUC__
/* The version tests may need to be added to, but the problem warning has
@@ -720,7 +720,7 @@ png_init_io(png_structrp png_ptr, png_FILE_p fp)
*
* Where UNSIGNED_MAX is the appropriate maximum unsigned value, so when the
* negative integral value is added the result will be an unsigned value
- * correspnding to the 2's complement representation.
+ * corresponding to the 2's complement representation.
*/
void PNGAPI
png_save_int_32(png_bytep buf, png_int_32 i)
@@ -815,8 +815,8 @@ png_get_copyright(png_const_structrp png_ptr)
return PNG_STRING_COPYRIGHT
#else
return PNG_STRING_NEWLINE \
- "libpng version 1.6.37" PNG_STRING_NEWLINE \
- "Copyright (c) 2018-2019 Cosmin Truta" PNG_STRING_NEWLINE \
+ "libpng version 1.6.38" PNG_STRING_NEWLINE \
+ "Copyright (c) 2018-2022 Cosmin Truta" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
PNG_STRING_NEWLINE \
"Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
@@ -1843,12 +1843,12 @@ png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,
# ifdef PNG_WARNINGS_SUPPORTED
else
{
- char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/
+ char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114 */
pos = png_safecat(message, (sizeof message), pos,
png_format_number(number, number+(sizeof number),
PNG_NUMBER_FORMAT_x, value));
- pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/
+ pos = png_safecat(message, (sizeof message), pos, "h: "); /* +2 = 116 */
}
# endif
/* The 'reason' is an arbitrary message, allow +79 maximum 195 */
diff --git a/thirdparty/libpng/png.h b/thirdparty/libpng/png.h
index b12174ba35..5fb494fb1a 100644
--- a/thirdparty/libpng/png.h
+++ b/thirdparty/libpng/png.h
@@ -1,9 +1,9 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.6.37 - April 14, 2019
+ * libpng version 1.6.38 - September 14, 2022
*
- * Copyright (c) 2018-2019 Cosmin Truta
+ * Copyright (c) 2018-2022 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -15,7 +15,7 @@
* libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
* libpng versions 0.97, January 1998, through 1.6.35, July 2018:
* Glenn Randers-Pehrson
- * libpng versions 1.6.36, December 2018, through 1.6.37, April 2019:
+ * libpng versions 1.6.36, December 2018, through 1.6.38, September 2022:
* Cosmin Truta
* See also "Contributing Authors", below.
*/
@@ -27,8 +27,8 @@
* PNG Reference Library License version 2
* ---------------------------------------
*
- * * Copyright (c) 1995-2019 The PNG Reference Library Authors.
- * * Copyright (c) 2018-2019 Cosmin Truta.
+ * * Copyright (c) 1995-2022 The PNG Reference Library Authors.
+ * * Copyright (c) 2018-2022 Cosmin Truta.
* * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
* * Copyright (c) 1996-1997 Andreas Dilger.
* * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -239,7 +239,7 @@
* ...
* 1.5.30 15 10530 15.so.15.30[.0]
* ...
- * 1.6.37 16 10637 16.so.16.37[.0]
+ * 1.6.38 16 10638 16.so.16.38[.0]
*
* Henceforth the source version will match the shared-library major and
* minor numbers; the shared-library major version number will be used for
@@ -278,8 +278,8 @@
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.37"
-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.37 - April 14, 2019\n"
+#define PNG_LIBPNG_VER_STRING "1.6.38"
+#define PNG_HEADER_VERSION_STRING " libpng version 1.6.38 - September 14, 2022\n"
#define PNG_LIBPNG_VER_SONUM 16
#define PNG_LIBPNG_VER_DLLNUM 16
@@ -287,7 +287,7 @@
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
#define PNG_LIBPNG_VER_MINOR 6
-#define PNG_LIBPNG_VER_RELEASE 37
+#define PNG_LIBPNG_VER_RELEASE 38
/* This should be zero for a public release, or non-zero for a
* development version. [Deprecated]
@@ -318,7 +318,7 @@
* From version 1.0.1 it is:
* XXYYZZ, where XX=major, YY=minor, ZZ=release
*/
-#define PNG_LIBPNG_VER 10637 /* 1.6.37 */
+#define PNG_LIBPNG_VER 10638 /* 1.6.38 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -330,10 +330,6 @@
# include "pnglibconf.h"
#endif
-#define PNG_APNG_SUPPORTED
-#define PNG_READ_APNG_SUPPORTED
-#define PNG_WRITE_APNG_SUPPORTED
-
#ifndef PNG_VERSION_INFO_ONLY
/* Machine specific configuration. */
# include "pngconf.h"
@@ -429,21 +425,10 @@ extern "C" {
* See pngconf.h for base types that vary by machine/system
*/
-#ifdef PNG_APNG_SUPPORTED
-/* dispose_op flags from inside fcTL */
-#define PNG_DISPOSE_OP_NONE 0x00U
-#define PNG_DISPOSE_OP_BACKGROUND 0x01U
-#define PNG_DISPOSE_OP_PREVIOUS 0x02U
-
-/* blend_op flags from inside fcTL */
-#define PNG_BLEND_OP_SOURCE 0x00U
-#define PNG_BLEND_OP_OVER 0x01U
-#endif /* PNG_APNG_SUPPORTED */
-
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
*/
-typedef char* png_libpng_version_1_6_37;
+typedef char* png_libpng_version_1_6_38;
/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
*
@@ -761,10 +746,6 @@ typedef png_unknown_chunk * * png_unknown_chunkpp;
#define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */
#define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */
#define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */
-#ifdef PNG_APNG_SUPPORTED
-#define PNG_INFO_acTL 0x20000U
-#define PNG_INFO_fcTL 0x40000U
-#endif
/* This is used for the transformation routines, as some of them
* change these values for the row. It also should enable using
@@ -802,10 +783,6 @@ typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32,
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
-#ifdef PNG_APNG_SUPPORTED
-typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
- png_uint_32));
-#endif
/* The following callback receives png_uint_32 row_number, int pass for the
* png_bytep data of the row. When transforming an interlaced image the
@@ -1469,7 +1446,7 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action,
* mainly useful for testing, as the defaults should work with most users.
* Those users who are tight on memory or want faster performance at the
* expense of compression can modify them. See the compression library
- * header file (zlib.h) for an explination of the compression functions.
+ * header file (zlib.h) for an explanation of the compression functions.
*/
/* Set the filtering method(s) used by libpng. Currently, the only valid
@@ -1524,7 +1501,7 @@ PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed,
* 0 - 9, corresponding directly to the zlib compression levels 0 - 9
* (0 - no compression, 9 - "maximal" compression). Note that tests have
* shown that zlib compression levels 3-6 usually perform as well as level 9
- * for PNG images, and do considerably fewer caclulations. In the future,
+ * for PNG images, and do considerably fewer calculations. In the future,
* these values may not correspond directly to the zlib compression levels.
*/
#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
@@ -3249,74 +3226,6 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
/*******************************************************************************
* END OF HARDWARE AND SOFTWARE OPTIONS
******************************************************************************/
-#ifdef PNG_APNG_SUPPORTED
-PNG_EXPORT(250, png_uint_32, png_get_acTL, (png_structp png_ptr,
- png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
-
-PNG_EXPORT(251, png_uint_32, png_set_acTL, (png_structp png_ptr,
- png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
-
-PNG_EXPORT(252, png_uint_32, png_get_num_frames, (png_structp png_ptr,
- png_infop info_ptr));
-
-PNG_EXPORT(253, png_uint_32, png_get_num_plays, (png_structp png_ptr,
- png_infop info_ptr));
-
-PNG_EXPORT(254, png_uint_32, png_get_next_frame_fcTL,
- (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
- png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
- png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op,
- png_byte *blend_op));
-
-PNG_EXPORT(255, png_uint_32, png_set_next_frame_fcTL,
- (png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
- png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
- png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
- png_byte blend_op));
-
-PNG_EXPORT(256, png_uint_32, png_get_next_frame_width,
- (png_structp png_ptr, png_infop info_ptr));
-PNG_EXPORT(257, png_uint_32, png_get_next_frame_height,
- (png_structp png_ptr, png_infop info_ptr));
-PNG_EXPORT(258, png_uint_32, png_get_next_frame_x_offset,
- (png_structp png_ptr, png_infop info_ptr));
-PNG_EXPORT(259, png_uint_32, png_get_next_frame_y_offset,
- (png_structp png_ptr, png_infop info_ptr));
-PNG_EXPORT(260, png_uint_16, png_get_next_frame_delay_num,
- (png_structp png_ptr, png_infop info_ptr));
-PNG_EXPORT(261, png_uint_16, png_get_next_frame_delay_den,
- (png_structp png_ptr, png_infop info_ptr));
-PNG_EXPORT(262, png_byte, png_get_next_frame_dispose_op,
- (png_structp png_ptr, png_infop info_ptr));
-PNG_EXPORT(263, png_byte, png_get_next_frame_blend_op,
- (png_structp png_ptr, png_infop info_ptr));
-PNG_EXPORT(264, png_byte, png_get_first_frame_is_hidden,
- (png_structp png_ptr, png_infop info_ptr));
-PNG_EXPORT(265, png_uint_32, png_set_first_frame_is_hidden,
- (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
-
-#ifdef PNG_READ_APNG_SUPPORTED
-PNG_EXPORT(266, void, png_read_frame_head, (png_structp png_ptr,
- png_infop info_ptr));
-#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-PNG_EXPORT(267, void, png_set_progressive_frame_fn, (png_structp png_ptr,
- png_progressive_frame_ptr frame_info_fn,
- png_progressive_frame_ptr frame_end_fn));
-#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
-#endif /* PNG_READ_APNG_SUPPORTED */
-
-#ifdef PNG_WRITE_APNG_SUPPORTED
-PNG_EXPORT(268, void, png_write_frame_head, (png_structp png_ptr,
- png_infop info_ptr, png_bytepp row_pointers,
- png_uint_32 width, png_uint_32 height,
- png_uint_32 x_offset, png_uint_32 y_offset,
- png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
- png_byte blend_op));
-
-PNG_EXPORT(269, void, png_write_frame_tail, (png_structp png_ptr,
- png_infop info_ptr));
-#endif /* PNG_WRITE_APNG_SUPPORTED */
-#endif /* PNG_APNG_SUPPORTED */
/* Maintainer: Put new public prototypes here ^, in libpng.3, in project
* defs, and in scripts/symbols.def.
@@ -3326,11 +3235,7 @@ PNG_EXPORT(269, void, png_write_frame_tail, (png_structp png_ptr,
* one to use is one more than this.)
*/
#ifdef PNG_EXPORT_LAST_ORDINAL
-#ifdef PNG_APNG_SUPPORTED
- PNG_EXPORT_LAST_ORDINAL(269);
-#else
PNG_EXPORT_LAST_ORDINAL(249);
-#endif /* PNG_APNG_SUPPORTED */
#endif
#ifdef __cplusplus
diff --git a/thirdparty/libpng/pngconf.h b/thirdparty/libpng/pngconf.h
index 927a769dbe..89d28f83a0 100644
--- a/thirdparty/libpng/pngconf.h
+++ b/thirdparty/libpng/pngconf.h
@@ -1,9 +1,9 @@
/* pngconf.h - machine-configurable file for libpng
*
- * libpng version 1.6.37
+ * libpng version 1.6.38
*
- * Copyright (c) 2018-2019 Cosmin Truta
+ * Copyright (c) 2018-2022 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -180,8 +180,8 @@
* compiler-specific macros to the values required to change the calling
* conventions of the various functions.
*/
-#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\
- defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#if defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \
+ defined(__CYGWIN__)
/* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or
* MinGW on any architecture currently supported by Windows. Also includes
* Watcom builds but these need special treatment because they are not
diff --git a/thirdparty/libpng/pngget.c b/thirdparty/libpng/pngget.c
index 9ed101aedc..e44933c0d2 100644
--- a/thirdparty/libpng/pngget.c
+++ b/thirdparty/libpng/pngget.c
@@ -1151,7 +1151,7 @@ png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr,
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
png_byte PNGAPI
-png_get_rgb_to_gray_status (png_const_structrp png_ptr)
+png_get_rgb_to_gray_status(png_const_structrp png_ptr)
{
return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0);
}
@@ -1192,27 +1192,27 @@ png_get_compression_buffer_size(png_const_structrp png_ptr)
/* These functions were added to libpng 1.2.6 and were enabled
* by default in libpng-1.4.0 */
png_uint_32 PNGAPI
-png_get_user_width_max (png_const_structrp png_ptr)
+png_get_user_width_max(png_const_structrp png_ptr)
{
return (png_ptr ? png_ptr->user_width_max : 0);
}
png_uint_32 PNGAPI
-png_get_user_height_max (png_const_structrp png_ptr)
+png_get_user_height_max(png_const_structrp png_ptr)
{
return (png_ptr ? png_ptr->user_height_max : 0);
}
/* This function was added to libpng 1.4.0 */
png_uint_32 PNGAPI
-png_get_chunk_cache_max (png_const_structrp png_ptr)
+png_get_chunk_cache_max(png_const_structrp png_ptr)
{
return (png_ptr ? png_ptr->user_chunk_cache_max : 0);
}
/* This function was added to libpng 1.4.1 */
png_alloc_size_t PNGAPI
-png_get_chunk_malloc_max (png_const_structrp png_ptr)
+png_get_chunk_malloc_max(png_const_structrp png_ptr)
{
return (png_ptr ? png_ptr->user_chunk_malloc_max : 0);
}
@@ -1221,13 +1221,13 @@ png_get_chunk_malloc_max (png_const_structrp png_ptr)
/* These functions were added to libpng 1.4.0 */
#ifdef PNG_IO_STATE_SUPPORTED
png_uint_32 PNGAPI
-png_get_io_state (png_const_structrp png_ptr)
+png_get_io_state(png_const_structrp png_ptr)
{
return png_ptr->io_state;
}
png_uint_32 PNGAPI
-png_get_io_chunk_type (png_const_structrp png_ptr)
+png_get_io_chunk_type(png_const_structrp png_ptr)
{
return png_ptr->chunk_name;
}
@@ -1246,166 +1246,4 @@ png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr)
# endif
#endif
-#ifdef PNG_APNG_SUPPORTED
-png_uint_32 PNGAPI
-png_get_acTL(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 *num_frames, png_uint_32 *num_plays)
-{
- png_debug1(1, "in %s retrieval function", "acTL");
-
- if (png_ptr != NULL && info_ptr != NULL &&
- (info_ptr->valid & PNG_INFO_acTL) &&
- num_frames != NULL && num_plays != NULL)
- {
- *num_frames = info_ptr->num_frames;
- *num_plays = info_ptr->num_plays;
- return (1);
- }
-
- return (0);
-}
-
-png_uint_32 PNGAPI
-png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_get_num_frames()");
-
- if (png_ptr != NULL && info_ptr != NULL)
- return (info_ptr->num_frames);
- return (0);
-}
-
-png_uint_32 PNGAPI
-png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_get_num_plays()");
-
- if (png_ptr != NULL && info_ptr != NULL)
- return (info_ptr->num_plays);
- return (0);
-}
-
-png_uint_32 PNGAPI
-png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 *width, png_uint_32 *height,
- png_uint_32 *x_offset, png_uint_32 *y_offset,
- png_uint_16 *delay_num, png_uint_16 *delay_den,
- png_byte *dispose_op, png_byte *blend_op)
-{
- png_debug1(1, "in %s retrieval function", "fcTL");
-
- if (png_ptr != NULL && info_ptr != NULL &&
- (info_ptr->valid & PNG_INFO_fcTL) &&
- width != NULL && height != NULL &&
- x_offset != NULL && y_offset != NULL &&
- delay_num != NULL && delay_den != NULL &&
- dispose_op != NULL && blend_op != NULL)
- {
- *width = info_ptr->next_frame_width;
- *height = info_ptr->next_frame_height;
- *x_offset = info_ptr->next_frame_x_offset;
- *y_offset = info_ptr->next_frame_y_offset;
- *delay_num = info_ptr->next_frame_delay_num;
- *delay_den = info_ptr->next_frame_delay_den;
- *dispose_op = info_ptr->next_frame_dispose_op;
- *blend_op = info_ptr->next_frame_blend_op;
- return (1);
- }
-
- return (0);
-}
-
-png_uint_32 PNGAPI
-png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_get_next_frame_width()");
-
- if (png_ptr != NULL && info_ptr != NULL)
- return (info_ptr->next_frame_width);
- return (0);
-}
-
-png_uint_32 PNGAPI
-png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_get_next_frame_height()");
-
- if (png_ptr != NULL && info_ptr != NULL)
- return (info_ptr->next_frame_height);
- return (0);
-}
-
-png_uint_32 PNGAPI
-png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_get_next_frame_x_offset()");
-
- if (png_ptr != NULL && info_ptr != NULL)
- return (info_ptr->next_frame_x_offset);
- return (0);
-}
-
-png_uint_32 PNGAPI
-png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_get_next_frame_y_offset()");
-
- if (png_ptr != NULL && info_ptr != NULL)
- return (info_ptr->next_frame_y_offset);
- return (0);
-}
-
-png_uint_16 PNGAPI
-png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_get_next_frame_delay_num()");
-
- if (png_ptr != NULL && info_ptr != NULL)
- return (info_ptr->next_frame_delay_num);
- return (0);
-}
-
-png_uint_16 PNGAPI
-png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_get_next_frame_delay_den()");
-
- if (png_ptr != NULL && info_ptr != NULL)
- return (info_ptr->next_frame_delay_den);
- return (0);
-}
-
-png_byte PNGAPI
-png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_get_next_frame_dispose_op()");
-
- if (png_ptr != NULL && info_ptr != NULL)
- return (info_ptr->next_frame_dispose_op);
- return (0);
-}
-
-png_byte PNGAPI
-png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_get_next_frame_blend_op()");
-
- if (png_ptr != NULL && info_ptr != NULL)
- return (info_ptr->next_frame_blend_op);
- return (0);
-}
-
-png_byte PNGAPI
-png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_first_frame_is_hidden()");
-
- if (png_ptr != NULL)
- return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
-
- PNG_UNUSED(info_ptr)
-
- return 0;
-}
-#endif /* PNG_APNG_SUPPORTED */
#endif /* READ || WRITE */
diff --git a/thirdparty/libpng/pnginfo.h b/thirdparty/libpng/pnginfo.h
index ac7b269132..1f98dedc42 100644
--- a/thirdparty/libpng/pnginfo.h
+++ b/thirdparty/libpng/pnginfo.h
@@ -263,18 +263,5 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
png_bytepp row_pointers; /* the image bits */
#endif
-#ifdef PNG_APNG_SUPPORTED
- png_uint_32 num_frames; /* including default image */
- png_uint_32 num_plays;
- png_uint_32 next_frame_width;
- png_uint_32 next_frame_height;
- png_uint_32 next_frame_x_offset;
- png_uint_32 next_frame_y_offset;
- png_uint_16 next_frame_delay_num;
- png_uint_16 next_frame_delay_den;
- png_byte next_frame_dispose_op;
- png_byte next_frame_blend_op;
-#endif
-
};
#endif /* PNGINFO_H */
diff --git a/thirdparty/libpng/pnglibconf.h b/thirdparty/libpng/pnglibconf.h
index e1e27e957e..89d5b4c8ad 100644
--- a/thirdparty/libpng/pnglibconf.h
+++ b/thirdparty/libpng/pnglibconf.h
@@ -1,8 +1,8 @@
/* pnglibconf.h - library build configuration */
-/* libpng version 1.6.37 */
+/* libpng version 1.6.38 */
-/* Copyright (c) 2018-2019 Cosmin Truta */
+/* Copyright (c) 2018-2022 Cosmin Truta */
/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
/* This code is released under the libpng license. */
diff --git a/thirdparty/libpng/pngpread.c b/thirdparty/libpng/pngpread.c
index 2eaeca08f7..e283627b77 100644
--- a/thirdparty/libpng/pngpread.c
+++ b/thirdparty/libpng/pngpread.c
@@ -195,106 +195,6 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
chunk_name = png_ptr->chunk_name;
-#ifdef PNG_READ_APNG_SUPPORTED
- if (png_ptr->num_frames_read > 0 &&
- png_ptr->num_frames_read < info_ptr->num_frames)
- {
- if (chunk_name == png_IDAT)
- {
- /* Discard trailing IDATs for the first frame */
- if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1)
- png_error(png_ptr, "out of place IDAT");
-
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
- return;
- }
- else if (chunk_name == png_fdAT)
- {
- if (png_ptr->buffer_size < 4)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_ensure_sequence_number(png_ptr, 4);
-
- if (!(png_ptr->mode & PNG_HAVE_fcTL))
- {
- /* Discard trailing fdATs for frames other than the first */
- if (png_ptr->num_frames_read < 2)
- png_error(png_ptr, "out of place fdAT");
-
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
- return;
- }
-
- else
- {
- /* frame data follows */
- png_ptr->idat_size = png_ptr->push_length - 4;
- png_ptr->mode |= PNG_HAVE_IDAT;
- png_ptr->process_mode = PNG_READ_IDAT_MODE;
-
- return;
- }
- }
-
- else if (chunk_name == png_fcTL)
- {
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_read_reset(png_ptr);
- png_ptr->mode &= ~PNG_HAVE_fcTL;
-
- png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
-
- if (!(png_ptr->mode & PNG_HAVE_fcTL))
- png_error(png_ptr, "missing required fcTL chunk");
-
- png_read_reinit(png_ptr, info_ptr);
- png_progressive_read_reset(png_ptr);
-
- if (png_ptr->frame_info_fn != NULL)
- (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
-
- png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
-
- return;
- }
-
- else
- {
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
- png_warning(png_ptr, "Skipped (ignored) a chunk "
- "between APNG chunks");
- png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
- return;
- }
-
- return;
- }
-#endif /* PNG_READ_APNG_SUPPORTED */
-
if (chunk_name == png_IDAT)
{
if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
@@ -361,9 +261,6 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
else if (chunk_name == png_IDAT)
{
-#ifdef PNG_READ_APNG_SUPPORTED
- png_have_info(png_ptr, info_ptr);
-#endif
png_ptr->idat_size = png_ptr->push_length;
png_ptr->process_mode = PNG_READ_IDAT_MODE;
png_push_have_info(png_ptr, info_ptr);
@@ -509,30 +406,6 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
}
#endif
-#ifdef PNG_READ_APNG_SUPPORTED
- else if (chunk_name == png_acTL)
- {
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
- }
-
- else if (chunk_name == png_fcTL)
- {
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
- }
-
-#endif /* PNG_READ_APNG_SUPPORTED */
else
{
@@ -666,11 +539,7 @@ png_push_read_IDAT(png_structrp png_ptr)
png_byte chunk_tag[4];
/* TODO: this code can be commoned up with the same code in push_read */
-#ifdef PNG_READ_APNG_SUPPORTED
- PNG_PUSH_SAVE_BUFFER_IF_LT(12)
-#else
PNG_PUSH_SAVE_BUFFER_IF_LT(8)
-#endif
png_push_fill_buffer(png_ptr, chunk_length, 4);
png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
png_reset_crc(png_ptr);
@@ -678,64 +547,17 @@ png_push_read_IDAT(png_structrp png_ptr)
png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
-#ifdef PNG_READ_APNG_SUPPORTED
- if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
- {
- if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)
- {
- png_ptr->process_mode = PNG_READ_CHUNK_MODE;
- if (png_ptr->frame_end_fn != NULL)
- (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
- png_ptr->num_frames_read++;
- return;
- }
- else
- {
- if (png_ptr->chunk_name == png_IEND)
- png_error(png_ptr, "Not enough image data");
- if (png_ptr->push_length + 4 > png_ptr->buffer_size)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
- png_warning(png_ptr, "Skipping (ignoring) a chunk between "
- "APNG chunks");
- png_crc_finish(png_ptr, png_ptr->push_length);
- png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
- return;
- }
- }
- else
-#endif
-#ifdef PNG_READ_APNG_SUPPORTED
- if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
-#else
if (png_ptr->chunk_name != png_IDAT)
-#endif
{
png_ptr->process_mode = PNG_READ_CHUNK_MODE;
if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
png_error(png_ptr, "Not enough compressed data");
-#ifdef PNG_READ_APNG_SUPPORTED
- if (png_ptr->frame_end_fn != NULL)
- (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
- png_ptr->num_frames_read++;
-#endif
-
return;
}
png_ptr->idat_size = png_ptr->push_length;
-
-#ifdef PNG_READ_APNG_SUPPORTED
- if (png_ptr->num_frames_read > 0)
- {
- png_ensure_sequence_number(png_ptr, 4);
- png_ptr->idat_size -= 4;
- }
-#endif
}
if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
@@ -809,15 +631,6 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,
if (!(buffer_length > 0) || buffer == NULL)
png_error(png_ptr, "No IDAT data (internal error)");
-#ifdef PNG_READ_APNG_SUPPORTED
- /* If the app is not APNG-aware, decode only the first frame */
- if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0)
- {
- png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
- return;
- }
-#endif
-
/* This routine must process all the data it has been given
* before returning, calling the row callback as required to
* handle the uncompressed results.
@@ -1272,18 +1085,6 @@ png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr,
png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
}
-#ifdef PNG_READ_APNG_SUPPORTED
-void PNGAPI
-png_set_progressive_frame_fn(png_structp png_ptr,
- png_progressive_frame_ptr frame_info_fn,
- png_progressive_frame_ptr frame_end_fn)
-{
- png_ptr->frame_info_fn = frame_info_fn;
- png_ptr->frame_end_fn = frame_end_fn;
- png_ptr->apng_flags |= PNG_APNG_APP;
-}
-#endif
-
png_voidp PNGAPI
png_get_progressive_ptr(png_const_structrp png_ptr)
{
diff --git a/thirdparty/libpng/pngpriv.h b/thirdparty/libpng/pngpriv.h
index 57e1bf989b..2e426cf47d 100644
--- a/thirdparty/libpng/pngpriv.h
+++ b/thirdparty/libpng/pngpriv.h
@@ -1,7 +1,7 @@
/* pngpriv.h - private declarations for use inside libpng
*
- * Copyright (c) 2018-2019 Cosmin Truta
+ * Copyright (c) 2018-2022 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -174,7 +174,7 @@
# else /* !defined __ARM_NEON__ */
/* The 'intrinsics' code simply won't compile without this -mfpu=neon:
*/
-# if !defined(__aarch64__)
+# if !defined(__aarch64__) && !defined(_M_ARM64)
/* The assembler code currently does not work on ARM64 */
# define PNG_ARM_NEON_IMPLEMENTATION 2
# endif /* __aarch64__ */
@@ -185,6 +185,8 @@
/* Use the intrinsics code by default. */
# define PNG_ARM_NEON_IMPLEMENTATION 1
# endif
+#else /* PNG_ARM_NEON_OPT == 0 */
+# define PNG_ARM_NEON_IMPLEMENTATION 0
#endif /* PNG_ARM_NEON_OPT > 0 */
#ifndef PNG_MIPS_MSA_OPT
@@ -263,11 +265,15 @@
# ifndef PNG_MIPS_MSA_IMPLEMENTATION
# define PNG_MIPS_MSA_IMPLEMENTATION 1
# endif
+#else
+# define PNG_MIPS_MSA_IMPLEMENTATION 0
#endif /* PNG_MIPS_MSA_OPT > 0 */
#if PNG_POWERPC_VSX_OPT > 0
# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_vsx
# define PNG_POWERPC_VSX_IMPLEMENTATION 1
+#else
+# define PNG_POWERPC_VSX_IMPLEMENTATION 0
#endif
@@ -492,16 +498,7 @@
static_cast<type>(static_cast<const void*>(value))
#else
# define png_voidcast(type, value) (value)
-# ifdef _WIN64
-# ifdef __GNUC__
- typedef unsigned long long png_ptruint;
-# else
- typedef unsigned __int64 png_ptruint;
-# endif
-# else
- typedef unsigned long png_ptruint;
-# endif
-# define png_constcast(type, value) ((type)(png_ptruint)(const void*)(value))
+# define png_constcast(type, value) ((type)(void*)(const void*)(value))
# define png_aligncast(type, value) ((void*)(value))
# define png_aligncastconst(type, value) ((const void*)(value))
#endif /* __cplusplus */
@@ -543,9 +540,8 @@
# include <alloc.h>
#endif
-#if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \
- defined(_WIN32) || defined(__WIN32__)
-# include <windows.h> /* defines _WINDOWS_ macro */
+#if defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
+# include <windows.h>
#endif
#endif /* PNG_VERSION_INFO_ONLY */
@@ -554,24 +550,20 @@
* functions that are passed far data must be model-independent.
*/
-/* Memory model/platform independent fns */
+/* Platform-independent functions */
#ifndef PNG_ABORT
-# ifdef _WINDOWS_
-# define PNG_ABORT() ExitProcess(0)
-# else
-# define PNG_ABORT() abort()
-# endif
+# define PNG_ABORT() abort()
#endif
/* These macros may need to be architecture dependent. */
-#define PNG_ALIGN_NONE 0 /* do not use data alignment */
-#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */
+#define PNG_ALIGN_NONE 0 /* do not use data alignment */
+#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */
#ifdef offsetof
-# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */
+# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */
#else
# define PNG_ALIGN_OFFSET -1 /* prevent the use of this */
#endif
-#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */
+#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */
#ifndef PNG_ALIGN_TYPE
/* Default to using aligned access optimizations and requiring alignment to a
@@ -585,26 +577,25 @@
/* This is used because in some compiler implementations non-aligned
* structure members are supported, so the offsetof approach below fails.
* Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access
- * is good for performance. Do not do this unless you have tested the result
- * and understand it.
+ * is good for performance. Do not do this unless you have tested the
+ * result and understand it.
*/
-# define png_alignof(type) (sizeof (type))
+# define png_alignof(type) (sizeof(type))
#else
# if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET
-# define png_alignof(type) offsetof(struct{char c; type t;}, t)
+# define png_alignof(type) offsetof(struct{char c; type t;}, t)
# else
-# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS
-# define png_alignof(type) (1)
-# endif
- /* Else leave png_alignof undefined to prevent use thereof */
+# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS
+# define png_alignof(type) 1
+# endif
+ /* Else leave png_alignof undefined to prevent use thereof */
# endif
#endif
-/* This implicitly assumes alignment is always to a power of 2. */
+/* This implicitly assumes alignment is always a multiple of 2. */
#ifdef png_alignof
-# define png_isaligned(ptr, type)\
- (((type)((const char*)ptr-(const char*)0) & \
- (type)(png_alignof(type)-1)) == 0)
+# define png_isaligned(ptr, type) \
+ (((type)(size_t)((const void*)(ptr)) & (type)(png_alignof(type)-1)) == 0)
#else
# define png_isaligned(ptr, type) 0
#endif
@@ -637,10 +628,6 @@
#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
/* 0x4000U (unused) */
#define PNG_IS_READ_STRUCT 0x8000U /* Else is a write struct */
-#ifdef PNG_APNG_SUPPORTED
-#define PNG_HAVE_acTL 0x10000U
-#define PNG_HAVE_fcTL 0x20000U
-#endif
/* Flags for the transformations the PNG library does on the image data */
#define PNG_BGR 0x0001U
@@ -877,16 +864,6 @@
#define png_tRNS PNG_U32(116, 82, 78, 83)
#define png_zTXt PNG_U32(122, 84, 88, 116)
-#ifdef PNG_APNG_SUPPORTED
-#define png_acTL PNG_U32( 97, 99, 84, 76)
-#define png_fcTL PNG_U32(102, 99, 84, 76)
-#define png_fdAT PNG_U32(102, 100, 65, 84)
-
-/* For png_struct.apng_flags: */
-#define PNG_FIRST_FRAME_HIDDEN 0x0001U
-#define PNG_APNG_APP 0x0002U
-#endif
-
/* The following will work on (signed char*) strings, whereas the get_uint_32
* macro will fail on top-bit-set values because of the sign extension.
*/
@@ -1658,47 +1635,6 @@ PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr,
*/
#endif
-#ifdef PNG_APNG_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
- png_uint_32 width, png_uint_32 height,
- png_uint_32 x_offset, png_uint_32 y_offset,
- png_uint_16 delay_num, png_uint_16 delay_den,
- png_byte dispose_op, png_byte blend_op), PNG_EMPTY);
-
-#ifdef PNG_READ_APNG_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 length),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr, png_infop info_ptr),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
- png_uint_32 length),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
- png_infop info_ptr),PNG_EMPTY);
-#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),PNG_EMPTY);
-#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
-#endif /* PNG_READ_APNG_SUPPORTED */
-
-#ifdef PNG_WRITE_APNG_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
- png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
- png_uint_32 width, png_uint_32 height,
- png_uint_32 x_offset, png_uint_32 y_offset,
- png_uint_16 delay_num, png_uint_16 delay_den,
- png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
- png_const_bytep data, png_size_t length),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
- png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
-#endif /* PNG_WRITE_APNG_SUPPORTED */
-#endif /* PNG_APNG_SUPPORTED */
-
/* Added at libpng version 1.4.0 */
#ifdef PNG_COLORSPACE_SUPPORTED
/* These internal functions are for maintaining the colorspace structure within
diff --git a/thirdparty/libpng/pngread.c b/thirdparty/libpng/pngread.c
index fa44d5a8e4..5ab9224038 100644
--- a/thirdparty/libpng/pngread.c
+++ b/thirdparty/libpng/pngread.c
@@ -161,9 +161,6 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
else if (chunk_name == png_IDAT)
{
-#ifdef PNG_READ_APNG_SUPPORTED
- png_have_info(png_ptr, info_ptr);
-#endif
png_ptr->idat_size = length;
break;
}
@@ -258,17 +255,6 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
png_handle_iTXt(png_ptr, info_ptr, length);
#endif
-#ifdef PNG_READ_APNG_SUPPORTED
- else if (chunk_name == png_acTL)
- png_handle_acTL(png_ptr, info_ptr, length);
-
- else if (chunk_name == png_fcTL)
- png_handle_fcTL(png_ptr, info_ptr, length);
-
- else if (chunk_name == png_fdAT)
- png_handle_fdAT(png_ptr, info_ptr, length);
-#endif
-
else
png_handle_unknown(png_ptr, info_ptr, length,
PNG_HANDLE_CHUNK_AS_DEFAULT);
@@ -276,72 +262,6 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
}
#endif /* SEQUENTIAL_READ */
-#ifdef PNG_READ_APNG_SUPPORTED
-void PNGAPI
-png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
-{
- png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
-
- png_debug(0, "Reading frame head");
-
- if (!(png_ptr->mode & PNG_HAVE_acTL))
- png_error(png_ptr, "attempt to png_read_frame_head() but "
- "no acTL present");
-
- /* do nothing for the main IDAT */
- if (png_ptr->num_frames_read == 0)
- return;
-
- png_read_reset(png_ptr);
- png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
- png_ptr->mode &= ~PNG_HAVE_fcTL;
-
- have_chunk_after_DAT = 0;
- for (;;)
- {
- png_uint_32 length = png_read_chunk_header(png_ptr);
-
- if (png_ptr->chunk_name == png_IDAT)
- {
- /* discard trailing IDATs for the first frame */
- if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
- png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
- png_crc_finish(png_ptr, length);
- }
-
- else if (png_ptr->chunk_name == png_fcTL)
- {
- png_handle_fcTL(png_ptr, info_ptr, length);
- have_chunk_after_DAT = 1;
- }
-
- else if (png_ptr->chunk_name == png_fdAT)
- {
- png_ensure_sequence_number(png_ptr, length);
-
- /* discard trailing fdATs for frames other than the first */
- if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
- png_crc_finish(png_ptr, length - 4);
- else if(png_ptr->mode & PNG_HAVE_fcTL)
- {
- png_ptr->idat_size = length - 4;
- png_ptr->mode |= PNG_HAVE_IDAT;
-
- break;
- }
- else
- png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
- }
- else
- {
- png_warning(png_ptr, "Skipped (ignored) a chunk "
- "between APNG chunks");
- png_crc_finish(png_ptr, length);
- }
- }
-}
-#endif /* PNG_READ_APNG_SUPPORTED */
-
/* Optional call to update the users info_ptr structure */
void PNGAPI
png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
@@ -3532,7 +3452,6 @@ png_image_read_background(png_voidp argument)
for (pass = 0; pass < passes; ++pass)
{
- png_bytep row = png_voidcast(png_bytep, display->first_row);
unsigned int startx, stepx, stepy;
png_uint_32 y;
@@ -3637,8 +3556,6 @@ png_image_read_background(png_voidp argument)
inrow += 2; /* gray and alpha channel */
}
-
- row += display->row_bytes;
}
}
}
diff --git a/thirdparty/libpng/pngrtran.c b/thirdparty/libpng/pngrtran.c
index 9a8fad9f4a..238f5afe7e 100644
--- a/thirdparty/libpng/pngrtran.c
+++ b/thirdparty/libpng/pngrtran.c
@@ -21,7 +21,7 @@
#ifdef PNG_ARM_NEON_IMPLEMENTATION
# if PNG_ARM_NEON_IMPLEMENTATION == 1
# define PNG_ARM_NEON_INTRINSICS_AVAILABLE
-# if defined(_MSC_VER) && defined(_M_ARM64)
+# if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64)
# include <arm64_neon.h>
# else
# include <arm_neon.h>
diff --git a/thirdparty/libpng/pngrutil.c b/thirdparty/libpng/pngrutil.c
index ae66a48a83..ca060dd15f 100644
--- a/thirdparty/libpng/pngrutil.c
+++ b/thirdparty/libpng/pngrutil.c
@@ -1,7 +1,7 @@
/* pngrutil.c - utilities to read a PNG file
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2022 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -302,7 +302,6 @@ png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn)
if (buffer != NULL && new_size > png_ptr->read_buffer_size)
{
png_ptr->read_buffer = NULL;
- png_ptr->read_buffer = NULL;
png_ptr->read_buffer_size = 0;
png_free(png_ptr, buffer);
buffer = NULL;
@@ -865,11 +864,6 @@ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
filter_type = buf[11];
interlace_type = buf[12];
-#ifdef PNG_READ_APNG_SUPPORTED
- png_ptr->first_frame_width = width;
- png_ptr->first_frame_height = height;
-#endif
-
/* Set internal variables */
png_ptr->width = width;
png_ptr->height = height;
@@ -2081,21 +2075,22 @@ png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
png_byte buf[1];
png_crc_read(png_ptr, buf, 1);
info_ptr->eXIf_buf[i] = buf[0];
- if (i == 1 && buf[0] != 'M' && buf[0] != 'I'
- && info_ptr->eXIf_buf[0] != buf[0])
+ if (i == 1)
{
- png_crc_finish(png_ptr, length);
- png_chunk_benign_error(png_ptr, "incorrect byte-order specifier");
- png_free(png_ptr, info_ptr->eXIf_buf);
- info_ptr->eXIf_buf = NULL;
- return;
+ if ((buf[0] != 'M' && buf[0] != 'I') ||
+ (info_ptr->eXIf_buf[0] != buf[0]))
+ {
+ png_crc_finish(png_ptr, length - 2);
+ png_chunk_benign_error(png_ptr, "incorrect byte-order specifier");
+ png_free(png_ptr, info_ptr->eXIf_buf);
+ info_ptr->eXIf_buf = NULL;
+ return;
+ }
}
}
- if (png_crc_finish(png_ptr, 0) != 0)
- return;
-
- png_set_eXIf_1(png_ptr, info_ptr, length, info_ptr->eXIf_buf);
+ if (png_crc_finish(png_ptr, 0) == 0)
+ png_set_eXIf_1(png_ptr, info_ptr, length, info_ptr->eXIf_buf);
png_free(png_ptr, info_ptr->eXIf_buf);
info_ptr->eXIf_buf = NULL;
@@ -2131,8 +2126,9 @@ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
num = length / 2 ;
- if (num != (unsigned int) png_ptr->num_palette ||
- num > (unsigned int) PNG_MAX_PALETTE_LENGTH)
+ if (length != num * 2 ||
+ num != (unsigned int)png_ptr->num_palette ||
+ num > (unsigned int)PNG_MAX_PALETTE_LENGTH)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "invalid");
@@ -2862,179 +2858,6 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
}
#endif
-#ifdef PNG_READ_APNG_SUPPORTED
-void /* PRIVATE */
-png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
-{
- png_byte data[8];
- png_uint_32 num_frames;
- png_uint_32 num_plays;
- png_uint_32 didSet;
-
- png_debug(1, "in png_handle_acTL");
-
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- {
- png_error(png_ptr, "Missing IHDR before acTL");
- }
- else if (png_ptr->mode & PNG_HAVE_IDAT)
- {
- png_warning(png_ptr, "Invalid acTL after IDAT skipped");
- png_crc_finish(png_ptr, length);
- return;
- }
- else if (png_ptr->mode & PNG_HAVE_acTL)
- {
- png_warning(png_ptr, "Duplicate acTL skipped");
- png_crc_finish(png_ptr, length);
- return;
- }
- else if (length != 8)
- {
- png_warning(png_ptr, "acTL with invalid length skipped");
- png_crc_finish(png_ptr, length);
- return;
- }
-
- png_crc_read(png_ptr, data, 8);
- png_crc_finish(png_ptr, 0);
-
- num_frames = png_get_uint_31(png_ptr, data);
- num_plays = png_get_uint_31(png_ptr, data + 4);
-
- /* the set function will do error checking on num_frames */
- didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
- if(didSet)
- png_ptr->mode |= PNG_HAVE_acTL;
-}
-
-void /* PRIVATE */
-png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
-{
- png_byte data[22];
- png_uint_32 width;
- png_uint_32 height;
- png_uint_32 x_offset;
- png_uint_32 y_offset;
- png_uint_16 delay_num;
- png_uint_16 delay_den;
- png_byte dispose_op;
- png_byte blend_op;
-
- png_debug(1, "in png_handle_fcTL");
-
- png_ensure_sequence_number(png_ptr, length);
-
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- {
- png_error(png_ptr, "Missing IHDR before fcTL");
- }
- else if (png_ptr->mode & PNG_HAVE_IDAT)
- {
- /* for any frames other then the first this message may be misleading,
- * but correct. PNG_HAVE_IDAT is unset before the frame head is read
- * i can't think of a better message */
- png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
- png_crc_finish(png_ptr, length-4);
- return;
- }
- else if (png_ptr->mode & PNG_HAVE_fcTL)
- {
- png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
- png_crc_finish(png_ptr, length-4);
- return;
- }
- else if (length != 26)
- {
- png_warning(png_ptr, "fcTL with invalid length skipped");
- png_crc_finish(png_ptr, length-4);
- return;
- }
-
- png_crc_read(png_ptr, data, 22);
- png_crc_finish(png_ptr, 0);
-
- width = png_get_uint_31(png_ptr, data);
- height = png_get_uint_31(png_ptr, data + 4);
- x_offset = png_get_uint_31(png_ptr, data + 8);
- y_offset = png_get_uint_31(png_ptr, data + 12);
- delay_num = png_get_uint_16(data + 16);
- delay_den = png_get_uint_16(data + 18);
- dispose_op = data[20];
- blend_op = data[21];
-
- if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
- {
- png_warning(png_ptr, "fcTL for the first frame must have zero offset");
- return;
- }
-
- if (info_ptr != NULL)
- {
- if (png_ptr->num_frames_read == 0 &&
- (width != info_ptr->width || height != info_ptr->height))
- {
- png_warning(png_ptr, "size in first frame's fcTL must match "
- "the size in IHDR");
- return;
- }
-
- /* The set function will do more error checking */
- png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
- x_offset, y_offset, delay_num, delay_den,
- dispose_op, blend_op);
-
- png_read_reinit(png_ptr, info_ptr);
-
- png_ptr->mode |= PNG_HAVE_fcTL;
- }
-}
-
-void /* PRIVATE */
-png_have_info(png_structp png_ptr, png_infop info_ptr)
-{
- if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL))
- {
- png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
- info_ptr->num_frames++;
- }
-}
-
-void /* PRIVATE */
-png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
-{
- png_ensure_sequence_number(png_ptr, length);
-
- /* This function is only called from png_read_end(), png_read_info(),
- * and png_push_read_chunk() which means that:
- * - the user doesn't want to read this frame
- * - or this is an out-of-place fdAT
- * in either case it is safe to ignore the chunk with a warning */
- png_warning(png_ptr, "ignoring fdAT chunk");
- png_crc_finish(png_ptr, length - 4);
- PNG_UNUSED(info_ptr)
-}
-
-void /* PRIVATE */
-png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
-{
- png_byte data[4];
- png_uint_32 sequence_number;
-
- if (length < 4)
- png_error(png_ptr, "invalid fcTL or fdAT chunk found");
-
- png_crc_read(png_ptr, data, 4);
- sequence_number = png_get_uint_31(png_ptr, data);
-
- if (sequence_number != png_ptr->next_seq_num)
- png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
- "number found");
-
- png_ptr->next_seq_num++;
-}
-#endif /* PNG_READ_APNG_SUPPORTED */
-
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
static int
@@ -4343,38 +4166,7 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
{
uInt avail_in;
png_bytep buffer;
-#ifdef PNG_READ_APNG_SUPPORTED
- png_uint_32 bytes_to_skip = 0;
-
- while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
- {
- png_crc_finish(png_ptr, bytes_to_skip);
- bytes_to_skip = 0;
-
- png_ptr->idat_size = png_read_chunk_header(png_ptr);
- if (png_ptr->num_frames_read == 0)
- {
- if (png_ptr->chunk_name != png_IDAT)
- png_error(png_ptr, "Not enough image data");
- }
- else
- {
- if (png_ptr->chunk_name == png_IEND)
- png_error(png_ptr, "Not enough image data");
- if (png_ptr->chunk_name != png_fdAT)
- {
- png_warning(png_ptr, "Skipped (ignored) a chunk "
- "between APNG chunks");
- bytes_to_skip = png_ptr->idat_size;
- continue;
- }
-
- png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
- png_ptr->idat_size -= 4;
- }
- }
-#else
while (png_ptr->idat_size == 0)
{
png_crc_finish(png_ptr, 0);
@@ -4386,7 +4178,7 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
if (png_ptr->chunk_name != png_IDAT)
png_error(png_ptr, "Not enough image data");
}
-#endif /* PNG_READ_APNG_SUPPORTED */
+
avail_in = png_ptr->IDAT_read_size;
if (avail_in > png_ptr->idat_size)
@@ -4449,9 +4241,6 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
png_ptr->mode |= PNG_AFTER_IDAT;
png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
-#ifdef PNG_READ_APNG_SUPPORTED
- png_ptr->num_frames_read++;
-#endif
if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
png_chunk_benign_error(png_ptr, "Extra compressed data");
@@ -4833,14 +4622,13 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
*/
{
png_bytep temp = png_ptr->big_row_buf + 32;
- int extra = (int)((temp - (png_bytep)0) & 0x0f);
+ size_t extra = (size_t)temp & 0x0f;
png_ptr->row_buf = temp - extra - 1/*filter byte*/;
temp = png_ptr->big_prev_row + 32;
- extra = (int)((temp - (png_bytep)0) & 0x0f);
+ extra = (size_t)temp & 0x0f;
png_ptr->prev_row = temp - extra - 1/*filter byte*/;
}
-
#else
/* Use 31 bytes of padding before and 17 bytes after row_buf. */
png_ptr->row_buf = png_ptr->big_row_buf + 31;
@@ -4890,80 +4678,4 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
png_ptr->flags |= PNG_FLAG_ROW_INIT;
}
-
-#ifdef PNG_READ_APNG_SUPPORTED
-/* This function is to be called after the main IDAT set has been read and
- * before a new IDAT is read. It resets some parts of png_ptr
- * to make them usable by the read functions again */
-void /* PRIVATE */
-png_read_reset(png_structp png_ptr)
-{
- png_ptr->mode &= ~PNG_HAVE_IDAT;
- png_ptr->mode &= ~PNG_AFTER_IDAT;
- png_ptr->row_number = 0;
- png_ptr->pass = 0;
-}
-
-void /* PRIVATE */
-png_read_reinit(png_structp png_ptr, png_infop info_ptr)
-{
- png_ptr->width = info_ptr->next_frame_width;
- png_ptr->height = info_ptr->next_frame_height;
- png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
- png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
- png_ptr->width);
- if (png_ptr->prev_row)
- memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
-}
-
-#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-/* same as png_read_reset() but for the progressive reader */
-void /* PRIVATE */
-png_progressive_read_reset(png_structp png_ptr)
-{
-#ifdef PNG_READ_INTERLACING_SUPPORTED
- /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
-
- /* Start of interlace block */
- const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
-
- /* Offset to next interlace block */
- const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
-
- /* Start of interlace block in the y direction */
- const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
-
- /* Offset to next interlace block in the y direction */
- const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
-
- if (png_ptr->interlaced)
- {
- if (!(png_ptr->transformations & PNG_INTERLACE))
- png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
- png_pass_ystart[0]) / png_pass_yinc[0];
- else
- png_ptr->num_rows = png_ptr->height;
-
- png_ptr->iwidth = (png_ptr->width +
- png_pass_inc[png_ptr->pass] - 1 -
- png_pass_start[png_ptr->pass]) /
- png_pass_inc[png_ptr->pass];
- }
- else
-#endif /* PNG_READ_INTERLACING_SUPPORTED */
- {
- png_ptr->num_rows = png_ptr->height;
- png_ptr->iwidth = png_ptr->width;
- }
- png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
- if (inflateReset(&(png_ptr->zstream)) != Z_OK)
- png_error(png_ptr, "inflateReset failed");
- png_ptr->zstream.avail_in = 0;
- png_ptr->zstream.next_in = 0;
- png_ptr->zstream.next_out = png_ptr->row_buf;
- png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
- png_ptr->iwidth) + 1;
-}
-#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
-#endif /* PNG_READ_APNG_SUPPORTED */
#endif /* READ */
diff --git a/thirdparty/libpng/pngset.c b/thirdparty/libpng/pngset.c
index a281db58ae..8c372cf415 100644
--- a/thirdparty/libpng/pngset.c
+++ b/thirdparty/libpng/pngset.c
@@ -1,7 +1,7 @@
/* pngset.c - storage of image information into info struct
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2022 Cosmin Truta
* Copyright (c) 1998-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -288,11 +288,6 @@ png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr,
info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
-
-#ifdef PNG_APNG_SUPPORTED
- /* for non-animated png. this may be overwritten from an acTL chunk later */
- info_ptr->num_frames = 1;
-#endif
}
#ifdef PNG_oFFs_SUPPORTED
@@ -1024,6 +1019,9 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
info_ptr->trans_alpha = png_voidcast(png_bytep,
png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
+
+ info_ptr->valid |= PNG_INFO_tRNS;
+ info_ptr->free_me |= PNG_FREE_TRNS;
}
png_ptr->trans_alpha = info_ptr->trans_alpha;
}
@@ -1163,147 +1161,6 @@ png_set_sPLT(png_const_structrp png_ptr,
}
#endif /* sPLT */
-#ifdef PNG_APNG_SUPPORTED
-png_uint_32 PNGAPI
-png_set_acTL(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 num_frames, png_uint_32 num_plays)
-{
- png_debug1(1, "in %s storage function", "acTL");
-
- if (png_ptr == NULL || info_ptr == NULL)
- {
- png_warning(png_ptr,
- "Call to png_set_acTL() with NULL png_ptr "
- "or info_ptr ignored");
- return (0);
- }
- if (num_frames == 0)
- {
- png_warning(png_ptr,
- "Ignoring attempt to set acTL with num_frames zero");
- return (0);
- }
- if (num_frames > PNG_UINT_31_MAX)
- {
- png_warning(png_ptr,
- "Ignoring attempt to set acTL with num_frames > 2^31-1");
- return (0);
- }
- if (num_plays > PNG_UINT_31_MAX)
- {
- png_warning(png_ptr,
- "Ignoring attempt to set acTL with num_plays "
- "> 2^31-1");
- return (0);
- }
-
- info_ptr->num_frames = num_frames;
- info_ptr->num_plays = num_plays;
-
- info_ptr->valid |= PNG_INFO_acTL;
-
- return (1);
-}
-
-/* delay_num and delay_den can hold any 16-bit values including zero */
-png_uint_32 PNGAPI
-png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 width, png_uint_32 height,
- png_uint_32 x_offset, png_uint_32 y_offset,
- png_uint_16 delay_num, png_uint_16 delay_den,
- png_byte dispose_op, png_byte blend_op)
-{
- png_debug1(1, "in %s storage function", "fcTL");
-
- if (png_ptr == NULL || info_ptr == NULL)
- {
- png_warning(png_ptr,
- "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
- "ignored");
- return (0);
- }
-
- png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
- delay_num, delay_den, dispose_op, blend_op);
-
- if (blend_op == PNG_BLEND_OP_OVER)
- {
- if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
- !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
- {
- png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
- "and wasteful for opaque images, ignored");
- blend_op = PNG_BLEND_OP_SOURCE;
- }
- }
-
- info_ptr->next_frame_width = width;
- info_ptr->next_frame_height = height;
- info_ptr->next_frame_x_offset = x_offset;
- info_ptr->next_frame_y_offset = y_offset;
- info_ptr->next_frame_delay_num = delay_num;
- info_ptr->next_frame_delay_den = delay_den;
- info_ptr->next_frame_dispose_op = dispose_op;
- info_ptr->next_frame_blend_op = blend_op;
-
- info_ptr->valid |= PNG_INFO_fcTL;
-
- return (1);
-}
-
-void /* PRIVATE */
-png_ensure_fcTL_is_valid(png_structp png_ptr,
- png_uint_32 width, png_uint_32 height,
- png_uint_32 x_offset, png_uint_32 y_offset,
- png_uint_16 delay_num, png_uint_16 delay_den,
- png_byte dispose_op, png_byte blend_op)
-{
- if (width == 0 || width > PNG_UINT_31_MAX)
- png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
- if (height == 0 || height > PNG_UINT_31_MAX)
- png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
- if (x_offset > PNG_UINT_31_MAX)
- png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
- if (y_offset > PNG_UINT_31_MAX)
- png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
- if (width + x_offset > png_ptr->first_frame_width ||
- height + y_offset > png_ptr->first_frame_height)
- png_error(png_ptr, "dimensions of a frame are greater than"
- "the ones in IHDR");
-
- if (dispose_op != PNG_DISPOSE_OP_NONE &&
- dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
- dispose_op != PNG_DISPOSE_OP_PREVIOUS)
- png_error(png_ptr, "invalid dispose_op in fcTL");
-
- if (blend_op != PNG_BLEND_OP_SOURCE &&
- blend_op != PNG_BLEND_OP_OVER)
- png_error(png_ptr, "invalid blend_op in fcTL");
-
- PNG_UNUSED(delay_num)
- PNG_UNUSED(delay_den)
-}
-
-png_uint_32 PNGAPI
-png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
- png_byte is_hidden)
-{
- png_debug(1, "in png_first_frame_is_hidden()");
-
- if (png_ptr == NULL)
- return 0;
-
- if (is_hidden)
- png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
- else
- png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
-
- PNG_UNUSED(info_ptr)
-
- return 1;
-}
-#endif /* PNG_APNG_SUPPORTED */
-
#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
static png_byte
check_location(png_const_structrp png_ptr, int location)
@@ -1472,7 +1329,7 @@ png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr,
#ifdef PNG_MNG_FEATURES_SUPPORTED
png_uint_32 PNGAPI
-png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features)
+png_permit_mng_features(png_structrp png_ptr, png_uint_32 mng_features)
{
png_debug(1, "in png_permit_mng_features");
@@ -1779,7 +1636,7 @@ png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask)
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
/* This function was added to libpng 1.2.6 */
void PNGAPI
-png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,
+png_set_user_limits(png_structrp png_ptr, png_uint_32 user_width_max,
png_uint_32 user_height_max)
{
/* Images with dimensions larger than these limits will be
@@ -1795,7 +1652,7 @@ png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,
/* This function was added to libpng 1.4.0 */
void PNGAPI
-png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
+png_set_chunk_cache_max(png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
{
if (png_ptr != NULL)
png_ptr->user_chunk_cache_max = user_chunk_cache_max;
@@ -1803,7 +1660,7 @@ png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
/* This function was added to libpng 1.4.1 */
void PNGAPI
-png_set_chunk_malloc_max (png_structrp png_ptr,
+png_set_chunk_malloc_max(png_structrp png_ptr,
png_alloc_size_t user_chunk_malloc_max)
{
if (png_ptr != NULL)
diff --git a/thirdparty/libpng/pngstruct.h b/thirdparty/libpng/pngstruct.h
index 2a2236f92e..e591d94d58 100644
--- a/thirdparty/libpng/pngstruct.h
+++ b/thirdparty/libpng/pngstruct.h
@@ -1,7 +1,7 @@
/* pngstruct.h - header file for PNG reference library
*
- * Copyright (c) 2018-2019 Cosmin Truta
+ * Copyright (c) 2018-2022 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -334,18 +334,8 @@ struct png_struct_def
size_t current_buffer_size; /* amount of data now in current_buffer */
int process_mode; /* what push library is currently doing */
int cur_palette; /* current push library palette index */
-
#endif /* PROGRESSIVE_READ */
-#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
-/* For the Borland special 64K segment handler */
- png_bytepp offset_table_ptr;
- png_bytep offset_table;
- png_uint_16 offset_table_number;
- png_uint_16 offset_table_count;
- png_uint_16 offset_table_count_free;
-#endif
-
#ifdef PNG_READ_QUANTIZE_SUPPORTED
png_bytep palette_lookup; /* lookup table for quantizing */
png_bytep quantize_index; /* index translation for palette files */
@@ -409,27 +399,6 @@ struct png_struct_def
png_byte filter_type;
#endif
-#ifdef PNG_APNG_SUPPORTED
- png_uint_32 apng_flags;
- png_uint_32 next_seq_num; /* next fcTL/fdAT chunk sequence number */
- png_uint_32 first_frame_width;
- png_uint_32 first_frame_height;
-
-#ifdef PNG_READ_APNG_SUPPORTED
- png_uint_32 num_frames_read; /* incremented after all image data of */
- /* a frame is read */
-#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
- png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
- png_progressive_frame_ptr frame_end_fn; /* frame data read callback */
-#endif
-#endif
-
-#ifdef PNG_WRITE_APNG_SUPPORTED
- png_uint_32 num_frames_to_write;
- png_uint_32 num_frames_written;
-#endif
-#endif /* PNG_APNG_SUPPORTED */
-
/* New members added in libpng-1.2.0 */
/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
diff --git a/thirdparty/libpng/pngwrite.c b/thirdparty/libpng/pngwrite.c
index 5e68032378..06c45d16ab 100644
--- a/thirdparty/libpng/pngwrite.c
+++ b/thirdparty/libpng/pngwrite.c
@@ -1,7 +1,7 @@
/* pngwrite.c - general routines to write a PNG file
*
- * Copyright (c) 2018-2019 Cosmin Truta
+ * Copyright (c) 2018-2022 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -128,10 +128,6 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
* the application continues writing the PNG. So check the 'invalid'
* flag here too.
*/
-#ifdef PNG_WRITE_APNG_SUPPORTED
- if (info_ptr->valid & PNG_INFO_acTL)
- png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
-#endif
#ifdef PNG_GAMMA_SUPPORTED
# ifdef PNG_WRITE_gAMA_SUPPORTED
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
@@ -374,11 +370,6 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
#endif
-#ifdef PNG_WRITE_APNG_SUPPORTED
- if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
- png_error(png_ptr, "Not enough frames written");
-#endif
-
/* See if user wants us to write information chunks */
if (info_ptr != NULL)
{
@@ -498,6 +489,16 @@ png_convert_from_time_t(png_timep ptime, time_t ttime)
png_debug(1, "in png_convert_from_time_t");
tbuf = gmtime(&ttime);
+ if (tbuf == NULL)
+ {
+ /* TODO: add a safe function which takes a png_ptr argument and raises
+ * a png_error if the ttime argument is invalid and the call to gmtime
+ * fails as a consequence.
+ */
+ memset(ptime, 0, sizeof(*ptime));
+ return;
+ }
+
png_convert_from_struct_tm(ptime, tbuf);
}
#endif
@@ -1470,43 +1471,6 @@ png_write_png(png_structrp png_ptr, png_inforp info_ptr,
}
#endif
-#ifdef PNG_WRITE_APNG_SUPPORTED
-void PNGAPI
-png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
- png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
- png_uint_32 x_offset, png_uint_32 y_offset,
- png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
- png_byte blend_op)
-{
- png_debug(1, "in png_write_frame_head");
-
- /* there is a chance this has been set after png_write_info was called,
- * so it would be set but not written. is there a way to be sure? */
- if (!(info_ptr->valid & PNG_INFO_acTL))
- png_error(png_ptr, "png_write_frame_head(): acTL not set");
-
- png_write_reset(png_ptr);
-
- png_write_reinit(png_ptr, info_ptr, width, height);
-
- if ( !(png_ptr->num_frames_written == 0 &&
- (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
- png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
- delay_num, delay_den, dispose_op, blend_op);
-
- PNG_UNUSED(row_pointers)
-}
-
-void PNGAPI
-png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
-{
- png_debug(1, "in png_write_frame_tail");
-
- png_ptr->num_frames_written++;
-
- PNG_UNUSED(info_ptr)
-}
-#endif /* PNG_WRITE_APNG_SUPPORTED */
#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
/* Initialize the write structure - general purpose utility. */
diff --git a/thirdparty/libpng/pngwutil.c b/thirdparty/libpng/pngwutil.c
index b4809cda6b..16345e4c0b 100644
--- a/thirdparty/libpng/pngwutil.c
+++ b/thirdparty/libpng/pngwutil.c
@@ -821,11 +821,6 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
/* Write the chunk */
png_write_complete_chunk(png_ptr, png_IHDR, buf, 13);
-#ifdef PNG_WRITE_APNG_SUPPORTED
- png_ptr->first_frame_width = width;
- png_ptr->first_frame_height = height;
-#endif
-
if ((png_ptr->do_filter) == PNG_NO_FILTERS)
{
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
@@ -1007,17 +1002,8 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
optimize_cmf(data, png_image_size(png_ptr));
#endif
- if (size > 0)
-#ifdef PNG_WRITE_APNG_SUPPORTED
- {
- if (png_ptr->num_frames_written == 0)
-#endif
- png_write_complete_chunk(png_ptr, png_IDAT, data, size);
-#ifdef PNG_WRITE_APNG_SUPPORTED
- else
- png_write_fdAT(png_ptr, data, size);
- }
-#endif /* PNG_WRITE_APNG_SUPPORTED */
+ if (size > 0)
+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
png_ptr->mode |= PNG_HAVE_IDAT;
png_ptr->zstream.next_out = data;
@@ -1064,17 +1050,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
#endif
if (size > 0)
-#ifdef PNG_WRITE_APNG_SUPPORTED
- {
- if (png_ptr->num_frames_written == 0)
-#endif
png_write_complete_chunk(png_ptr, png_IDAT, data, size);
-#ifdef PNG_WRITE_APNG_SUPPORTED
- else
- png_write_fdAT(png_ptr, data, size);
- }
-#endif /* PNG_WRITE_APNG_SUPPORTED */
-
png_ptr->zstream.avail_out = 0;
png_ptr->zstream.next_out = NULL;
png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
@@ -1909,82 +1885,6 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)
}
#endif
-#ifdef PNG_WRITE_APNG_SUPPORTED
-void /* PRIVATE */
-png_write_acTL(png_structp png_ptr,
- png_uint_32 num_frames, png_uint_32 num_plays)
-{
- png_byte buf[8];
-
- png_debug(1, "in png_write_acTL");
-
- png_ptr->num_frames_to_write = num_frames;
-
- if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN)
- num_frames--;
-
- png_save_uint_32(buf, num_frames);
- png_save_uint_32(buf + 4, num_plays);
-
- png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
-}
-
-void /* PRIVATE */
-png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
- png_uint_32 x_offset, png_uint_32 y_offset,
- png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
- png_byte blend_op)
-{
- png_byte buf[26];
-
- png_debug(1, "in png_write_fcTL");
-
- if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
- png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
- if (png_ptr->num_frames_written == 0 &&
- (width != png_ptr->first_frame_width ||
- height != png_ptr->first_frame_height))
- png_error(png_ptr, "width and/or height in the first frame's fcTL "
- "don't match the ones in IHDR");
-
- /* more error checking */
- png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
- delay_num, delay_den, dispose_op, blend_op);
-
- png_save_uint_32(buf, png_ptr->next_seq_num);
- png_save_uint_32(buf + 4, width);
- png_save_uint_32(buf + 8, height);
- png_save_uint_32(buf + 12, x_offset);
- png_save_uint_32(buf + 16, y_offset);
- png_save_uint_16(buf + 20, delay_num);
- png_save_uint_16(buf + 22, delay_den);
- buf[24] = dispose_op;
- buf[25] = blend_op;
-
- png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
-
- png_ptr->next_seq_num++;
-}
-
-void /* PRIVATE */
-png_write_fdAT(png_structp png_ptr,
- png_const_bytep data, png_size_t length)
-{
- png_byte buf[4];
-
- png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
-
- png_save_uint_32(buf, png_ptr->next_seq_num);
- png_write_chunk_data(png_ptr, buf, 4);
-
- png_write_chunk_data(png_ptr, data, length);
-
- png_write_chunk_end(png_ptr);
-
- png_ptr->next_seq_num++;
-}
-#endif /* PNG_WRITE_APNG_SUPPORTED */
-
/* Initializes the row writing capability of libpng */
void /* PRIVATE */
png_write_start_row(png_structrp png_ptr)
@@ -2878,39 +2778,4 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
}
#endif /* WRITE_FLUSH */
}
-
-#ifdef PNG_WRITE_APNG_SUPPORTED
-void /* PRIVATE */
-png_write_reset(png_structp png_ptr)
-{
- png_ptr->row_number = 0;
- png_ptr->pass = 0;
- png_ptr->mode &= ~PNG_HAVE_IDAT;
-}
-
-void /* PRIVATE */
-png_write_reinit(png_structp png_ptr, png_infop info_ptr,
- png_uint_32 width, png_uint_32 height)
-{
- if (png_ptr->num_frames_written == 0 &&
- (width != png_ptr->first_frame_width ||
- height != png_ptr->first_frame_height))
- png_error(png_ptr, "width and/or height in the first frame's fcTL "
- "don't match the ones in IHDR");
- if (width > png_ptr->first_frame_width ||
- height > png_ptr->first_frame_height)
- png_error(png_ptr, "width and/or height for a frame greater than"
- "the ones in IHDR");
-
- png_set_IHDR(png_ptr, info_ptr, width, height,
- info_ptr->bit_depth, info_ptr->color_type,
- info_ptr->interlace_type, info_ptr->compression_type,
- info_ptr->filter_type);
-
- png_ptr->width = width;
- png_ptr->height = height;
- png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
- png_ptr->usr_width = png_ptr->width;
-}
-#endif /* PNG_WRITE_APNG_SUPPORTED */
#endif /* WRITE */
diff --git a/version.py b/version.py
index f9aa1dd0f4..cfa1773b85 100644
--- a/version.py
+++ b/version.py
@@ -3,7 +3,7 @@ name = "Godot Engine"
major = 4
minor = 0
patch = 0
-status = "alpha"
+status = "beta"
module_config = ""
year = 2022
website = "https://godotengine.org"